pspp-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 08/17] pspp-sheet-view: Support rectangular selection, column pop


From: Ben Pfaff
Subject: [PATCH 08/17] pspp-sheet-view: Support rectangular selection, column popup menus.
Date: Sun, 22 Apr 2012 11:12:26 -0700

A "rectangular selection" is where you can click and drag to select
a rectangular group of columns and rows, like in a spreadsheet.

In this commit, rectangular selections don't interact well with
"quick-edit" mode where the first click on a cell starts editing,
because clicking in a quick-edit cell starts editing instead of
rectangular selection.  The following commit will fix the problem.

This commit also adds a gtk_widget_queue_draw() call to
pspp_sheet_view_update_rubber_band() that should really
invalidate less sheet area.
---
 src/ui/gui/marshaller-list          |    1 +
 src/ui/gui/pspp-sheet-private.h     |    4 +
 src/ui/gui/pspp-sheet-selection.c   |  226 +++++++++++++++++++----
 src/ui/gui/pspp-sheet-selection.h   |   37 +++-
 src/ui/gui/pspp-sheet-view-column.c |  356 ++++++++++++++++++++++++++++++++++-
 src/ui/gui/pspp-sheet-view-column.h |   18 ++-
 src/ui/gui/pspp-sheet-view.c        |  295 ++++++++++++++++++++++++++---
 7 files changed, 862 insertions(+), 75 deletions(-)

diff --git a/src/ui/gui/marshaller-list b/src/ui/gui/marshaller-list
index 3cf5a9c..1f85ee6 100644
--- a/src/ui/gui/marshaller-list
+++ b/src/ui/gui/marshaller-list
@@ -2,6 +2,7 @@
 
 BOOLEAN:BOOLEAN
 BOOLEAN:BOOLEAN,BOOLEAN,BOOLEAN
+BOOLEAN:BOXED
 BOOLEAN:ENUM
 BOOLEAN:ENUM,INT
 BOOLEAN:BOXED,BOXED
diff --git a/src/ui/gui/pspp-sheet-private.h b/src/ui/gui/pspp-sheet-private.h
index 4658955..9d99cbd 100644
--- a/src/ui/gui/pspp-sheet-private.h
+++ b/src/ui/gui/pspp-sheet-private.h
@@ -164,6 +164,7 @@ struct _PsppSheetViewPrivate
   gint n_columns;
   GList *columns;
   gint header_height;
+  gint n_selected_columns;
 
   PsppSheetViewColumnDropFunc column_drop_func;
   gpointer column_drop_func_data;
@@ -212,6 +213,9 @@ struct _PsppSheetViewPrivate
 
   int rubber_band_end_node;
 
+  /* Rectangular selection. */
+  PsppSheetViewColumn *anchor_column; /* XXX needs to be a weak pointer? */
+
   /* fixed height */
   gint fixed_height;
 
diff --git a/src/ui/gui/pspp-sheet-selection.c 
b/src/ui/gui/pspp-sheet-selection.c
index 91b7161..0cfd23f 100644
--- a/src/ui/gui/pspp-sheet-selection.c
+++ b/src/ui/gui/pspp-sheet-selection.c
@@ -86,7 +86,7 @@ pspp_sheet_selection_class_init (PsppSheetSelectionClass 
*class)
 static void
 pspp_sheet_selection_init (PsppSheetSelection *selection)
 {
-  selection->type = GTK_SELECTION_SINGLE;
+  selection->type = PSPP_SHEET_SELECTION_SINGLE;
 }
 
 static void
@@ -160,28 +160,27 @@ _pspp_sheet_selection_set_tree_view (PsppSheetSelection 
*selection,
  * @type: The selection mode
  *
  * Sets the selection mode of the @selection.  If the previous type was
- * #GTK_SELECTION_MULTIPLE, then the anchor is kept selected, if it was
- * previously selected.
+ * #PSPP_SHEET_SELECTION_MULTIPLE or #PSPP_SHEET_SELECTION_RECTANGLE, then the
+ * anchor is kept selected, if it was previously selected.
  **/
 void
 pspp_sheet_selection_set_mode (PsppSheetSelection *selection,
-                            GtkSelectionMode  type)
+                            PsppSheetSelectionMode  type)
 {
   g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
 
   if (selection->type == type)
     return;
 
-  
-  if (type == GTK_SELECTION_NONE)
+  if (type == PSPP_SHEET_SELECTION_NONE)
     {
       pspp_sheet_selection_unselect_all (selection);
 
       gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
       selection->tree_view->priv->anchor = NULL;
     }
-  else if (type == GTK_SELECTION_SINGLE ||
-          type == GTK_SELECTION_BROWSE)
+  else if (type == PSPP_SHEET_SELECTION_SINGLE ||
+          type == PSPP_SHEET_SELECTION_BROWSE)
     {
       int node = -1;
       gint selected = FALSE;
@@ -216,6 +215,8 @@ pspp_sheet_selection_set_mode (PsppSheetSelection 
*selection,
        gtk_tree_path_free (anchor_path);
     }
 
+  /* XXX unselect all columns when switching to/from rectangular selection? */
+
   selection->type = type;
 }
 
@@ -228,10 +229,10 @@ pspp_sheet_selection_set_mode (PsppSheetSelection 
*selection,
  *
  * Return value: the current selection mode
  **/
-GtkSelectionMode
+PsppSheetSelectionMode
 pspp_sheet_selection_get_mode (PsppSheetSelection *selection)
 {
-  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), 
GTK_SELECTION_SINGLE);
+  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), 
PSPP_SHEET_SELECTION_SINGLE);
 
   return selection->type;
 }
@@ -259,10 +260,11 @@ pspp_sheet_selection_get_tree_view (PsppSheetSelection 
*selection)
  * @iter: (allow-none): The #GtkTreeIter, or NULL.
  *
  * Sets @iter to the currently selected node if @selection is set to
- * #GTK_SELECTION_SINGLE or #GTK_SELECTION_BROWSE.  @iter may be NULL if you
- * just want to test if @selection has any selected nodes.  @model is filled
- * with the current model as a convenience.  This function will not work if you
- * use @selection is #GTK_SELECTION_MULTIPLE.
+ * #PSPP_SHEET_SELECTION_SINGLE or #PSPP_SHEET_SELECTION_BROWSE.  @iter may be
+ * NULL if you just want to test if @selection has any selected nodes.  @model
+ * is filled with the current model as a convenience.  This function will not
+ * work if @selection's mode is #PSPP_SHEET_SELECTION_MULTIPLE or
+ * #PSPP_SHEET_SELECTION_RECTANGLE.
  *
  * Return value: TRUE, if there is a selected node.
  **/
@@ -276,7 +278,9 @@ pspp_sheet_selection_get_selected (PsppSheetSelection  
*selection,
   gboolean retval;
 
   g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), FALSE);
-  g_return_val_if_fail (selection->type != GTK_SELECTION_MULTIPLE, FALSE);
+  g_return_val_if_fail (selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
+                        selection->type != PSPP_SHEET_SELECTION_RECTANGLE,
+                        FALSE);
   g_return_val_if_fail (selection->tree_view != NULL, FALSE);
 
   /* Clear the iter */
@@ -361,9 +365,10 @@ pspp_sheet_selection_get_selected_rows (PsppSheetSelection 
  *selection,
   if (selection->tree_view->priv->row_count == 0)
     return NULL;
 
-  if (selection->type == GTK_SELECTION_NONE)
+  if (selection->type == PSPP_SHEET_SELECTION_NONE)
     return NULL;
-  else if (selection->type != GTK_SELECTION_MULTIPLE)
+  else if (selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
+           selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
     {
       GtkTreeIter iter;
 
@@ -415,8 +420,8 @@ pspp_sheet_selection_count_selected_rows 
(PsppSheetSelection *selection)
   if (selection->tree_view->priv->row_count == 0)
     return 0;
 
-  if (selection->type == GTK_SELECTION_SINGLE ||
-      selection->type == GTK_SELECTION_BROWSE)
+  if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
+      selection->type == PSPP_SHEET_SELECTION_BROWSE)
     {
       if (pspp_sheet_selection_get_selected (selection, NULL, NULL))
        return 1;
@@ -471,8 +476,8 @@ pspp_sheet_selection_selected_foreach (PsppSheetSelection   
         *selection,
       selection->tree_view->priv->row_count == 0)
     return;
 
-  if (selection->type == GTK_SELECTION_SINGLE ||
-      selection->type == GTK_SELECTION_BROWSE)
+  if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
+      selection->type == PSPP_SHEET_SELECTION_BROWSE)
     {
       if (gtk_tree_row_reference_valid (selection->tree_view->priv->anchor))
        {
@@ -557,7 +562,8 @@ pspp_sheet_selection_select_path (PsppSheetSelection 
*selection,
   if (node < 0 || pspp_sheet_view_node_is_selected (selection->tree_view, 
node)) 
     return;
 
-  if (selection->type == GTK_SELECTION_MULTIPLE)
+  if (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
+      selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
     mode = GTK_TREE_SELECT_MODE_TOGGLE;
 
   _pspp_sheet_selection_internal_select_node (selection,
@@ -739,6 +745,7 @@ pspp_sheet_selection_real_select_all (PsppSheetSelection 
*selection)
     return FALSE;
 
   range_tower_set1 (selection->tree_view->priv->selected, 0, row_count);
+  pspp_sheet_selection_select_all_columns (selection);
 
   /* XXX we could invalidate individual visible rows instead */
   gdk_window_invalidate_rect (selection->tree_view->priv->bin_window, NULL, 
TRUE);
@@ -750,8 +757,8 @@ pspp_sheet_selection_real_select_all (PsppSheetSelection 
*selection)
  * pspp_sheet_selection_select_all:
  * @selection: A #PsppSheetSelection.
  *
- * Selects all the nodes. @selection must be set to #GTK_SELECTION_MULTIPLE
- * mode.
+ * Selects all the nodes and column. @selection must be set to
+ * #PSPP_SHEET_SELECTION_MULTIPLE or  #PSPP_SHEET_SELECTION_RECTANGLE mode.
  **/
 void
 pspp_sheet_selection_select_all (PsppSheetSelection *selection)
@@ -762,7 +769,8 @@ pspp_sheet_selection_select_all (PsppSheetSelection 
*selection)
   if (selection->tree_view->priv->row_count == 0 || 
selection->tree_view->priv->model == NULL)
     return;
 
-  g_return_if_fail (selection->type == GTK_SELECTION_MULTIPLE);
+  g_return_if_fail (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
+                    selection->type == PSPP_SHEET_SELECTION_RECTANGLE);
 
   if (pspp_sheet_selection_real_select_all (selection))
     g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
@@ -771,8 +779,8 @@ pspp_sheet_selection_select_all (PsppSheetSelection 
*selection)
 static gint
 pspp_sheet_selection_real_unselect_all (PsppSheetSelection *selection)
 {
-  if (selection->type == GTK_SELECTION_SINGLE ||
-      selection->type == GTK_SELECTION_BROWSE)
+  if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
+      selection->type == PSPP_SHEET_SELECTION_BROWSE)
     {
       int node = -1;
       GtkTreePath *anchor_path;
@@ -810,6 +818,7 @@ pspp_sheet_selection_real_unselect_all (PsppSheetSelection 
*selection)
   else
     {
       range_tower_set0 (selection->tree_view->priv->selected, 0, ULONG_MAX);
+      pspp_sheet_selection_unselect_all_columns (selection);
 
       /* XXX we could invalidate individual visible rows instead */
       gdk_window_invalidate_rect (selection->tree_view->priv->bin_window, 
NULL, TRUE);
@@ -822,7 +831,7 @@ pspp_sheet_selection_real_unselect_all (PsppSheetSelection 
*selection)
  * pspp_sheet_selection_unselect_all:
  * @selection: A #PsppSheetSelection.
  *
- * Unselects all the nodes.
+ * Unselects all the nodes and columns.
  **/
 void
 pspp_sheet_selection_unselect_all (PsppSheetSelection *selection)
@@ -923,7 +932,8 @@ pspp_sheet_selection_real_modify_range (PsppSheetSelection 
*selection,
  * @end_path: The final node of the range.
  *
  * Selects a range of nodes, determined by @start_path and @end_path inclusive.
- * @selection must be set to #GTK_SELECTION_MULTIPLE mode. 
+ * @selection must be set to #PSPP_SHEET_SELECTION_MULTIPLE or
+ * #PSPP_SHEET_SELECTION_RECTANGLE mode.
  **/
 void
 pspp_sheet_selection_select_range (PsppSheetSelection *selection,
@@ -932,7 +942,8 @@ pspp_sheet_selection_select_range (PsppSheetSelection 
*selection,
 {
   g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
   g_return_if_fail (selection->tree_view != NULL);
-  g_return_if_fail (selection->type == GTK_SELECTION_MULTIPLE);
+  g_return_if_fail (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
+                    selection->type == PSPP_SHEET_SELECTION_RECTANGLE);
   g_return_if_fail (selection->tree_view->priv->model != NULL);
 
   if (pspp_sheet_selection_real_modify_range (selection, RANGE_SELECT, 
start_path, end_path))
@@ -998,22 +1009,22 @@ _pspp_sheet_selection_internal_select_node 
(PsppSheetSelection *selection,
   gint dirty = FALSE;
   GtkTreePath *anchor_path = NULL;
 
-  if (selection->type == GTK_SELECTION_NONE)
+  if (selection->type == PSPP_SHEET_SELECTION_NONE)
     return;
 
   if (selection->tree_view->priv->anchor)
     anchor_path = gtk_tree_row_reference_get_path 
(selection->tree_view->priv->anchor);
 
-  if (selection->type == GTK_SELECTION_SINGLE ||
-      selection->type == GTK_SELECTION_BROWSE)
+  if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
+      selection->type == PSPP_SHEET_SELECTION_BROWSE)
     {
       /* just unselect */
-      if (selection->type == GTK_SELECTION_BROWSE && override_browse_mode)
+      if (selection->type == PSPP_SHEET_SELECTION_BROWSE && 
override_browse_mode)
         {
          dirty = pspp_sheet_selection_real_unselect_all (selection);
        }
       /* Did we try to select the same node again? */
-      else if (selection->type == GTK_SELECTION_SINGLE &&
+      else if (selection->type == PSPP_SHEET_SELECTION_SINGLE &&
               anchor_path && gtk_tree_path_compare (path, anchor_path) == 0)
        {
          if ((mode & GTK_TREE_SELECT_MODE_TOGGLE) == 
GTK_TREE_SELECT_MODE_TOGGLE)
@@ -1058,7 +1069,8 @@ _pspp_sheet_selection_internal_select_node 
(PsppSheetSelection *selection,
            }
        }
     }
-  else if (selection->type == GTK_SELECTION_MULTIPLE)
+  else if (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
+           selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
     {
       if ((mode & GTK_TREE_SELECT_MODE_EXTEND) == GTK_TREE_SELECT_MODE_EXTEND
           && (anchor_path == NULL))
@@ -1149,3 +1161,145 @@ pspp_sheet_selection_real_select_node 
(PsppSheetSelection *selection,
 
   return FALSE;
 }
+
+void
+pspp_sheet_selection_unselect_all_columns (PsppSheetSelection *selection)
+{
+  PsppSheetView *sheet_view = selection->tree_view;
+  gboolean changed;
+  GList *list;
+
+  changed = FALSE;
+  for (list = sheet_view->priv->columns; list; list = list->next)
+    {
+      PsppSheetViewColumn *column = list->data;
+      if (column->selected)
+        {
+          column->selected = FALSE;
+          changed = TRUE;
+        }
+    }
+  if (changed && selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
+    {
+      gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
+      _pspp_sheet_selection_emit_changed (selection);
+    }
+}
+
+GList *
+pspp_sheet_selection_get_selected_columns (PsppSheetSelection *selection)
+{
+  PsppSheetView *sheet_view = selection->tree_view;
+  GList *selected_columns = NULL;
+  GList *iter;
+
+  g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), NULL);
+  g_return_val_if_fail (selection->tree_view != NULL, NULL);
+
+  if (selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
+    return NULL;
+
+  for (iter = sheet_view->priv->columns; iter; iter = iter->next)
+    {
+      PsppSheetViewColumn *column = iter->data;
+      if (column->selected)
+        selected_columns = g_list_prepend (selected_columns, column);
+    }
+  return g_list_reverse (selected_columns);
+}
+
+gint
+pspp_sheet_selection_count_selected_columns (PsppSheetSelection *selection)
+{
+  PsppSheetView *sheet_view = selection->tree_view;
+  GList *list;
+  gint n;
+
+  n = 0;
+  for (list = sheet_view->priv->columns; list; list = list->next)
+    {
+      PsppSheetViewColumn *column = list->data;
+      if (column->selected)
+        n++;
+    }
+  return n;
+}
+
+void
+pspp_sheet_selection_select_all_columns (PsppSheetSelection *selection)
+{
+  PsppSheetView *sheet_view = selection->tree_view;
+  gboolean changed;
+  GList *list;
+
+  changed = FALSE;
+  for (list = sheet_view->priv->columns; list; list = list->next)
+    {
+      PsppSheetViewColumn *column = list->data;
+      if (!column->selected && column->selectable)
+        {
+          /* XXX should use pspp_sheet_view_column_set_selected() here (and
+             elsewhere) but we want to call
+             _pspp_sheet_selection_emit_changed() only once for all the
+             columns. */
+          column->selected = TRUE;
+          changed = TRUE;
+        }
+    }
+  if (changed && selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
+    {
+      _pspp_sheet_selection_emit_changed (selection);
+      gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
+    }
+}
+
+void
+pspp_sheet_selection_select_column (PsppSheetSelection        *selection,
+                                    PsppSheetViewColumn       *column)
+{
+  if (!column->selected && column->selectable)
+    {
+      column->selected = TRUE;
+      if (selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
+        {
+          _pspp_sheet_selection_emit_changed (selection);
+          gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
+        }
+    }
+}
+
+void
+pspp_sheet_selection_select_column_range  (PsppSheetSelection        
*selection,
+                                           PsppSheetViewColumn       *first,
+                                           PsppSheetViewColumn       *last)
+{
+  PsppSheetView *sheet_view = selection->tree_view;
+  gboolean in_range;
+  gboolean changed;
+  GList *list;
+
+  in_range = FALSE;
+  changed = FALSE;
+  for (list = sheet_view->priv->columns; list; list = list->next)
+    {
+      PsppSheetViewColumn *column = list->data;
+      gboolean c0 = column == first;
+      gboolean c1 = column == last;
+
+      if (in_range || c0 || c1)
+        {
+          if (!column->selected && column->selectable)
+            {
+              column->selected = TRUE;
+              changed = TRUE;
+            }
+        }
+
+      in_range = in_range ^ c0 ^ c1;
+    }
+  if (changed && selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
+    {
+      _pspp_sheet_selection_emit_changed (selection);
+      gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
+    }
+}
diff --git a/src/ui/gui/pspp-sheet-selection.h 
b/src/ui/gui/pspp-sheet-selection.h
index 306aa4a..4d8c50b 100644
--- a/src/ui/gui/pspp-sheet-selection.h
+++ b/src/ui/gui/pspp-sheet-selection.h
@@ -48,6 +48,19 @@ G_BEGIN_DECLS
 #define PSPP_IS_SHEET_SELECTION_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE 
((klass), PSPP_TYPE_SHEET_SELECTION))
 #define PSPP_SHEET_SELECTION_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS 
((obj), PSPP_TYPE_SHEET_SELECTION, PsppSheetSelectionClass))
 
+typedef enum
+  {
+    /* Same as GtkSelectionMode. */
+    PSPP_SHEET_SELECTION_NONE = GTK_SELECTION_NONE,
+    PSPP_SHEET_SELECTION_SINGLE = GTK_SELECTION_SINGLE,
+    PSPP_SHEET_SELECTION_BROWSE = GTK_SELECTION_BROWSE,
+    PSPP_SHEET_SELECTION_MULTIPLE = GTK_SELECTION_MULTIPLE,
+
+    /* PsppSheetView extension. */
+    PSPP_SHEET_SELECTION_RECTANGLE = 10
+  }
+PsppSheetSelectionMode;
+
 typedef gboolean (* PsppSheetSelectionFunc)    (PsppSheetSelection  *selection,
                                              GtkTreeModel      *model,
                                              GtkTreePath       *path,
@@ -65,7 +78,7 @@ struct _PsppSheetSelection
   /*< private >*/
 
   PsppSheetView *GSEAL (tree_view);
-  GtkSelectionMode GSEAL (type);
+  PsppSheetSelectionMode GSEAL (type);
 };
 
 struct _PsppSheetSelectionClass
@@ -85,8 +98,8 @@ struct _PsppSheetSelectionClass
 GType            pspp_sheet_selection_get_type            (void) G_GNUC_CONST;
 
 void             pspp_sheet_selection_set_mode            (PsppSheetSelection  
          *selection,
-                                                        GtkSelectionMode       
      type);
-GtkSelectionMode pspp_sheet_selection_get_mode        (PsppSheetSelection      
      *selection);
+                                                        PsppSheetSelectionMode 
            type);
+PsppSheetSelectionMode pspp_sheet_selection_get_mode        
(PsppSheetSelection            *selection);
 void             pspp_sheet_selection_set_select_function (PsppSheetSelection  
          *selection,
                                                         PsppSheetSelectionFunc 
        func,
                                                         gpointer               
      data,
@@ -96,8 +109,9 @@ PsppSheetView*     pspp_sheet_selection_get_tree_view       
(PsppSheetSelection
 
 PsppSheetSelectionFunc pspp_sheet_selection_get_select_function 
(PsppSheetSelection        *selection);
 
-/* Only meaningful if GTK_SELECTION_SINGLE or GTK_SELECTION_BROWSE is set */
-/* Use selected_foreach or get_selected_rows for GTK_SELECTION_MULTIPLE */
+/* Only meaningful if PSPP_SHEET_SELECTION_SINGLE or 
PSPP_SHEET_SELECTION_BROWSE is set */
+/* Use selected_foreach or get_selected_rows for
+   PSPP_SHEET_SELECTION_MULTIPLE */
 gboolean         pspp_sheet_selection_get_selected        (PsppSheetSelection  
          *selection,
                                                         GtkTreeModel           
    **model,
                                                         GtkTreeIter            
     *iter);
@@ -127,7 +141,18 @@ void             pspp_sheet_selection_select_range        
(PsppSheetSelection
 void             pspp_sheet_selection_unselect_range      (PsppSheetSelection  
          *selection,
                                                          GtkTreePath           
      *start_path,
                                                         GtkTreePath            
     *end_path);
-
+struct range_set *pspp_sheet_selection_get_range_set (PsppSheetSelection 
*selection);
+
+
+GList *          pspp_sheet_selection_get_selected_columns (PsppSheetSelection 
           *selection);
+gint             pspp_sheet_selection_count_selected_columns 
(PsppSheetSelection            *selection);
+void             pspp_sheet_selection_select_all_columns (PsppSheetSelection   
     *selection);
+void             pspp_sheet_selection_unselect_all_columns (PsppSheetSelection 
       *selection);
+void             pspp_sheet_selection_select_column        (PsppSheetSelection 
       *selection,
+                                                            
PsppSheetViewColumn       *column);
+void             pspp_sheet_selection_select_column_range  (PsppSheetSelection 
       *selection,
+                                                            
PsppSheetViewColumn       *first,
+                                                            
PsppSheetViewColumn       *last);
 
 G_END_DECLS
 
diff --git a/src/ui/gui/pspp-sheet-view-column.c 
b/src/ui/gui/pspp-sheet-view-column.c
index a59a14e..996a85a 100644
--- a/src/ui/gui/pspp-sheet-view-column.c
+++ b/src/ui/gui/pspp-sheet-view-column.c
@@ -43,6 +43,7 @@
 #include <string.h>
 
 #include "ui/gui/psppire-marshal.h"
+#include "ui/gui/pspp-sheet-selection.h"
 
 #define I_(STRING) STRING
 #define P_(STRING) STRING
@@ -68,13 +69,18 @@ enum
   PROP_SORT_INDICATOR,
   PROP_SORT_ORDER,
   PROP_SORT_COLUMN_ID,
-  PROP_QUICK_EDIT
+  PROP_QUICK_EDIT,
+  PROP_SELECTED,
+  PROP_SELECTABLE,
+  PROP_ROW_HEAD
 };
 
 enum
 {
   CLICKED,
   QUERY_TOOLTIP,
+  POPUP_MENU,
+  BUTTON_PRESS_EVENT,
   LAST_SIGNAL
 };
 
@@ -142,9 +148,14 @@ static gint pspp_sheet_view_column_button_event            
      (GtkWidget
                                                                gpointer        
         data);
 static void pspp_sheet_view_column_button_clicked                (GtkWidget    
           *widget,
                                                                gpointer        
         data);
+static void pspp_sheet_view_column_button_popup_menu (GtkWidget *widget,
+                                                      gpointer data);
 static gboolean pspp_sheet_view_column_mnemonic_activate         (GtkWidget 
*widget,
                                                                gboolean   
group_cycling,
                                                                gpointer   
data);
+static gboolean on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn 
*);
+static gboolean on_pspp_sheet_view_column_button_press_event 
(PsppSheetViewColumn *,
+                                                              GdkEventButton 
*);
 
 /* Property handlers */
 static void pspp_sheet_view_model_sort_column_changed            
(GtkTreeSortable         *sortable,
@@ -188,7 +199,8 @@ pspp_sheet_view_column_class_init (PsppSheetViewColumnClass 
*class)
 
   object_class = (GObjectClass*) class;
 
-  class->clicked = NULL;
+  class->clicked = on_pspp_sheet_view_column_button_clicked;
+  class->button_press_event = on_pspp_sheet_view_column_button_press_event;
 
   object_class->finalize = pspp_sheet_view_column_finalize;
   object_class->set_property = pspp_sheet_view_column_set_property;
@@ -199,6 +211,15 @@ pspp_sheet_view_column_class_init 
(PsppSheetViewColumnClass *class)
                   G_OBJECT_CLASS_TYPE (object_class),
                   G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (PsppSheetViewColumnClass, clicked),
+                  g_signal_accumulator_true_handled, NULL,
+                  psppire_marshal_BOOLEAN__VOID,
+                  G_TYPE_BOOLEAN, 0);
+
+  tree_column_signals[POPUP_MENU] =
+    g_signal_new (I_("popup-menu"),
+                  G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  0,
                   NULL, NULL,
                   g_cclosure_marshal_VOID__VOID,
                   G_TYPE_NONE, 0);
@@ -213,6 +234,16 @@ pspp_sheet_view_column_class_init 
(PsppSheetViewColumnClass *class)
                   G_TYPE_BOOLEAN, 1,
                   GTK_TYPE_TOOLTIP);
 
+  tree_column_signals[BUTTON_PRESS_EVENT] =
+    g_signal_new (I_("button-press-event"),
+                  G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (PsppSheetViewColumnClass, 
button_press_event),
+                  g_signal_accumulator_true_handled, NULL,
+                  psppire_marshal_BOOLEAN__BOXED,
+                  G_TYPE_BOOLEAN, 1,
+                  GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+
   g_object_class_install_property (object_class,
                                    PROP_VISIBLE,
                                    g_param_spec_boolean ("visible",
@@ -371,6 +402,30 @@ pspp_sheet_view_column_class_init 
(PsppSheetViewColumnClass *class)
                                                          P_("If true, editing 
starts upon the first click in the column.  If false, the first click selects 
the column and a second click is needed to begin editing.  This has no effect 
on cells that are not editable."),
                                                          TRUE,
                                                          GTK_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_SELECTED,
+                                   g_param_spec_boolean ("selected",
+                                                         P_("Selected"),
+                                                         P_("If true, this 
column is selected as part of a rectangular selection."),
+                                                         FALSE,
+                                                         GTK_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_SELECTABLE,
+                                   g_param_spec_boolean ("selectable",
+                                                         P_("Selectable"),
+                                                         P_("If true, this 
column may be selected as part of a rectangular selection."),
+                                                         TRUE,
+                                                         GTK_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_ROW_HEAD,
+                                   g_param_spec_boolean ("row-head",
+                                                         P_("Row head"),
+                                                         P_("If true, this 
column is a \"row head\", equivalent to a column head.  If rectangular 
selection is enabled, then shift+click and control+click in the column select 
row ranges and toggle row selection, respectively.  The column should 
ordinarily include a button cell; clicking on the button will select the row 
(and deselect all other rows)."),
+                                                         FALSE,
+                                                         GTK_PARAM_READWRITE));
 }
 
 static void
@@ -410,6 +465,9 @@ pspp_sheet_view_column_init (PsppSheetViewColumn 
*tree_column)
   tree_column->expand = FALSE;
   tree_column->clickable = FALSE;
   tree_column->dirty = TRUE;
+  tree_column->selected = FALSE;
+  tree_column->selectable = TRUE;
+  tree_column->row_head = FALSE;
   tree_column->sort_order = GTK_SORT_ASCENDING;
   tree_column->show_sort_indicator = FALSE;
   tree_column->property_changed_signal = 0;
@@ -547,6 +605,21 @@ pspp_sheet_view_column_set_property (GObject         
*object,
                                              g_value_get_boolean (value));
       break;
 
+    case PROP_SELECTED:
+      pspp_sheet_view_column_set_selected (tree_column,
+                                             g_value_get_boolean (value));
+      break;
+
+    case PROP_SELECTABLE:
+      pspp_sheet_view_column_set_selectable (tree_column,
+                                             g_value_get_boolean (value));
+      break;
+
+    case PROP_ROW_HEAD:
+      pspp_sheet_view_column_set_row_head (tree_column,
+                                             g_value_get_boolean (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -650,6 +723,21 @@ pspp_sheet_view_column_get_property (GObject         
*object,
                            pspp_sheet_view_column_get_quick_edit 
(tree_column));
       break;
 
+    case PROP_SELECTED:
+      g_value_set_boolean (value,
+                           pspp_sheet_view_column_get_selected (tree_column));
+      break;
+
+    case PROP_SELECTABLE:
+      g_value_set_boolean (value,
+                           pspp_sheet_view_column_get_selectable 
(tree_column));
+      break;
+
+    case PROP_ROW_HEAD:
+      g_value_set_boolean (value,
+                           pspp_sheet_view_column_get_row_head (tree_column));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -860,6 +948,19 @@ on_query_tooltip (GtkWidget  *widget,
   return handled;
 }
 
+static gboolean
+on_button_pressed (GtkWidget *widget, GdkEventButton *event,
+                   gpointer user_data)
+{
+  PsppSheetViewColumn *tree_column = user_data;
+  gboolean handled;
+
+  /* XXX See "Implement GtkWidget::popup_menu" in GTK+ reference manual. */
+  g_signal_emit (tree_column, tree_column_signals[BUTTON_PRESS_EVENT],
+                 0, event, &handled);
+  return handled;
+}
+
 /* Helper functions
  */
 
@@ -893,6 +994,11 @@ pspp_sheet_view_column_create_button (PsppSheetViewColumn 
*tree_column)
   g_signal_connect (tree_column->button, "clicked",
                    G_CALLBACK (pspp_sheet_view_column_button_clicked),
                    tree_column);
+  g_signal_connect (tree_column->button, "popup-menu",
+                   G_CALLBACK (pspp_sheet_view_column_button_popup_menu),
+                   tree_column);
+  g_signal_connect (tree_column->button, "button-press-event",
+                    G_CALLBACK (on_button_pressed), tree_column);
 
   g_signal_connect (tree_column->button, "query-tooltip",
                     G_CALLBACK (on_query_tooltip), tree_column);
@@ -1151,9 +1257,6 @@ pspp_sheet_view_column_button_event (GtkWidget *widget,
     {
       switch (event->type)
        {
-       case GDK_BUTTON_PRESS:
-       case GDK_2BUTTON_PRESS:
-       case GDK_3BUTTON_PRESS:
        case GDK_MOTION_NOTIFY:
        case GDK_BUTTON_RELEASE:
        case GDK_ENTER_NOTIFY:
@@ -1166,11 +1269,126 @@ pspp_sheet_view_column_button_event (GtkWidget *widget,
   return FALSE;
 }
 
+static gboolean
+all_rows_selected (PsppSheetView *sheet_view)
+{
+  PsppSheetSelection *selection = sheet_view->priv->selection;
+  gint n_rows, n_selected_rows;
+
+  n_rows = sheet_view->priv->row_count;
+  n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
+
+  return n_rows > 0 && n_selected_rows >= n_rows;
+}
+
+static gboolean
+on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *column,
+                                              GdkEventButton *event)
+{
+  PsppSheetView *sheet_view = PSPP_SHEET_VIEW (column->tree_view);
+  PsppSheetSelection *selection;
+  GSignalInvocationHint *hint;
+  guint modifiers;
+
+  /* We only want to run first, not last, but combining that with return type
+     `gboolean' makes GObject warn, so just ignore the run_last call. */
+  hint = g_signal_get_invocation_hint (column);
+  g_return_val_if_fail (hint != NULL, FALSE);
+  if (hint->run_type != G_SIGNAL_RUN_FIRST)
+    return FALSE;
+
+  g_return_val_if_fail (sheet_view != NULL, FALSE);
+
+  selection = sheet_view->priv->selection;
+  g_return_val_if_fail (selection != NULL, FALSE);
+
+  if (pspp_sheet_selection_get_mode (selection) != 
PSPP_SHEET_SELECTION_RECTANGLE)
+    return FALSE;
+
+  modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
+  if (event->type == GDK_BUTTON_PRESS && event->button == 3)
+    {
+      if (pspp_sheet_selection_count_selected_columns (selection) <= 1
+          || !all_rows_selected (sheet_view))
+        {
+          pspp_sheet_selection_select_all (selection);
+          pspp_sheet_selection_unselect_all_columns (selection);
+          pspp_sheet_selection_select_column (selection, column);
+          sheet_view->priv->anchor_column = column;
+        }
+      return FALSE;
+    }
+  else if (event->type == GDK_BUTTON_PRESS && event->button == 1
+           && modifiers == GDK_CONTROL_MASK)
+    {
+      gboolean is_selected;
+
+      if (!all_rows_selected (sheet_view))
+        {
+          pspp_sheet_selection_select_all (selection);
+          pspp_sheet_selection_unselect_all_columns (selection);
+        }
+      sheet_view->priv->anchor_column = column;
+
+      is_selected = pspp_sheet_view_column_get_selected (column);
+      pspp_sheet_view_column_set_selected (column, !is_selected);
+
+      return TRUE;
+    }
+  else if (event->type == GDK_BUTTON_PRESS && event->button == 1
+           && modifiers == GDK_SHIFT_MASK)
+    {
+      if (!all_rows_selected (sheet_view))
+        {
+          pspp_sheet_selection_select_all (selection);
+          pspp_sheet_selection_unselect_all_columns (selection);
+          sheet_view->priv->anchor_column = column;
+        }
+      else if (sheet_view->priv->anchor_column == NULL)
+        sheet_view->priv->anchor_column = column;
+
+      pspp_sheet_selection_unselect_all_columns (selection);
+      pspp_sheet_selection_select_column_range (selection,
+                                                
sheet_view->priv->anchor_column,
+                                                column);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *column)
+{
+  PsppSheetSelection *selection;
+  PsppSheetView *sheet_view;
+
+  sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (column));
+  selection = pspp_sheet_view_get_selection (sheet_view);
+  if (pspp_sheet_selection_get_mode (selection) == 
PSPP_SHEET_SELECTION_RECTANGLE)
+    {
+      pspp_sheet_selection_select_all (selection);
+      pspp_sheet_selection_unselect_all_columns (selection);
+      pspp_sheet_selection_select_column (selection, column);
+      sheet_view->priv->anchor_column = column;
+      return TRUE;
+    }
+  return FALSE;
+}
 
 static void
 pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
 {
-  g_signal_emit_by_name (data, "clicked");
+  PsppSheetViewColumn *column = data;
+  gboolean handled;
+
+  g_signal_emit (column, tree_column_signals[CLICKED], 0, &handled);
+}
+
+static void
+pspp_sheet_view_column_button_popup_menu (GtkWidget *widget, gpointer data)
+{
+  g_signal_emit_by_name (data, "popup-menu");
 }
 
 static gboolean
@@ -2389,6 +2607,132 @@ pspp_sheet_view_column_get_quick_edit 
(PsppSheetViewColumn *tree_column)
 
 
 /**
+ * pspp_sheet_view_column_set_selected:
+ * @tree_column: A #PsppSheetViewColumn
+ * @selected: If true, the column is selected as part of a rectangular
+ * selection.
+ **/
+void
+pspp_sheet_view_column_set_selected (PsppSheetViewColumn *tree_column,
+                                     gboolean           selected)
+{
+  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
+
+  selected = !!selected;
+  if (tree_column->selected != selected)
+    {
+      PsppSheetSelection *selection;
+      PsppSheetView *sheet_view;
+
+      if (tree_column->tree_view != NULL)
+        gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
+      tree_column->selected = (selected?TRUE:FALSE);
+      g_object_notify (G_OBJECT (tree_column), "selected");
+
+      sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
+                                      tree_column));
+      selection = pspp_sheet_view_get_selection (sheet_view);
+      _pspp_sheet_selection_emit_changed (selection);
+    }
+}
+
+/**
+ * pspp_sheet_view_column_get_selected:
+ * @tree_column: A #PsppSheetViewColumn
+ *
+ * Returns %TRUE if the column is selected as part of a rectangular
+ * selection.
+ *
+ * Return value: %TRUE if the column is selected as part of a rectangular
+ * selection.
+ **/
+gboolean
+pspp_sheet_view_column_get_selected (PsppSheetViewColumn *tree_column)
+{
+  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
+
+  return tree_column->selected;
+}
+
+/**
+ * pspp_sheet_view_column_set_selectable:
+ * @tree_column: A #PsppSheetViewColumn
+ * @selectable: If true, the column may be selected as part of a rectangular
+ * selection.
+ **/
+void
+pspp_sheet_view_column_set_selectable (PsppSheetViewColumn *tree_column,
+                                     gboolean           selectable)
+{
+  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
+
+  selectable = !!selectable;
+  if (tree_column->selectable != selectable)
+    {
+      if (tree_column->tree_view != NULL)
+        gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
+      tree_column->selectable = (selectable?TRUE:FALSE);
+      g_object_notify (G_OBJECT (tree_column), "selectable");
+    }
+}
+
+/**
+ * pspp_sheet_view_column_get_selectable:
+ * @tree_column: A #PsppSheetViewColumn
+ *
+ * Returns %TRUE if the column may be selected as part of a rectangular
+ * selection.
+ *
+ * Return value: %TRUE if the column may be selected as part of a rectangular
+ * selection.
+ **/
+gboolean
+pspp_sheet_view_column_get_selectable (PsppSheetViewColumn *tree_column)
+{
+  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
+
+  return tree_column->selectable;
+}
+
+
+/**
+ * pspp_sheet_view_column_set_row_head:
+ * @tree_column: A #PsppSheetViewColumn
+ * @row_head: If true, the column is a "row head", analogous to a column head.
+ * See the description of the row-head property for more information.
+ **/
+void
+pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column,
+                                     gboolean           row_head)
+{
+  g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
+
+  row_head = !!row_head;
+  if (tree_column->row_head != row_head)
+    {
+      tree_column->row_head = (row_head?TRUE:FALSE);
+      g_object_notify (G_OBJECT (tree_column), "row_head");
+    }
+}
+
+/**
+ * pspp_sheet_view_column_get_row_head:
+ * @tree_column: A #PsppSheetViewColumn
+ *
+ * Returns %TRUE if the column is a row head.
+ *
+ * Return value: %TRUE if the column is a row head.
+ **/
+gboolean
+pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column)
+{
+  g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
+
+  return tree_column->row_head;
+}
+
+
+/**
  * pspp_sheet_view_column_set_sort_column_id:
  * @tree_column: a #PsppSheetViewColumn
  * @sort_column_id: The @sort_column_id of the model to sort on.
diff --git a/src/ui/gui/pspp-sheet-view-column.h 
b/src/ui/gui/pspp-sheet-view-column.h
index 419a326..8e4df86 100644
--- a/src/ui/gui/pspp-sheet-view-column.h
+++ b/src/ui/gui/pspp-sheet-view-column.h
@@ -40,7 +40,6 @@
 
 G_BEGIN_DECLS
 
-
 #define PSPP_TYPE_SHEET_VIEW_COLUMN         (pspp_sheet_view_column_get_type 
())
 #define PSPP_SHEET_VIEW_COLUMN(obj)         (G_TYPE_CHECK_INSTANCE_CAST 
((obj), PSPP_TYPE_SHEET_VIEW_COLUMN, PsppSheetViewColumn))
 #define PSPP_SHEET_VIEW_COLUMN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST 
((klass), PSPP_TYPE_SHEET_VIEW_COLUMN, PsppSheetViewColumnClass))
@@ -107,13 +106,18 @@ struct _PsppSheetViewColumn
   guint GSEAL (use_resized_width)   : 1;
   guint GSEAL (expand)              : 1;
   guint GSEAL (quick_edit)          : 1;
+  guint GSEAL (selected)            : 1;
+  guint GSEAL (selectable)          : 1;
+  guint GSEAL (row_head)            : 1;
 };
 
 struct _PsppSheetViewColumnClass
 {
   GtkObjectClass parent_class;
 
-  void (*clicked) (PsppSheetViewColumn *tree_column);
+  gboolean (*clicked) (PsppSheetViewColumn *tree_column);
+  gboolean (*button_press_event) (PsppSheetViewColumn *,
+                                  GdkEventButton *);
 
   /* Padding for future expansion */
   void (*_gtk_reserved1) (void);
@@ -198,6 +202,16 @@ gboolean                
pspp_sheet_view_column_get_reorderable     (PsppSheetVie
 void                    pspp_sheet_view_column_set_quick_edit     
(PsppSheetViewColumn       *tree_column,
                                                                  gboolean      
           quick_edit);
 gboolean                pspp_sheet_view_column_get_quick_edit     
(PsppSheetViewColumn       *tree_column);
+void                    pspp_sheet_view_column_set_selected     
(PsppSheetViewColumn       *tree_column,
+                                                                 gboolean      
           selected);
+gboolean                pspp_sheet_view_column_get_selected     
(PsppSheetViewColumn       *tree_column);
+
+void                    pspp_sheet_view_column_set_selectable     
(PsppSheetViewColumn       *tree_column,
+                                                                 gboolean      
           selectable);
+gboolean                pspp_sheet_view_column_get_selectable     
(PsppSheetViewColumn       *tree_column);
+void                    pspp_sheet_view_column_set_row_head     
(PsppSheetViewColumn       *tree_column,
+                                                                 gboolean      
           row_head);
+gboolean                pspp_sheet_view_column_get_row_head     
(PsppSheetViewColumn       *tree_column);
 
 
 
diff --git a/src/ui/gui/pspp-sheet-view.c b/src/ui/gui/pspp-sheet-view.c
index fc38eb8..c96babf 100644
--- a/src/ui/gui/pspp-sheet-view.c
+++ b/src/ui/gui/pspp-sheet-view.c
@@ -386,6 +386,10 @@ static void     pspp_sheet_view_put                       
(PsppSheetView      *t
                                                         gint              
height);
 static gboolean pspp_sheet_view_start_editing             (PsppSheetView      
*tree_view,
                                                         GtkTreePath      
*cursor_path);
+static gboolean pspp_sheet_view_editable_button_press_event (GtkWidget *,
+                                                             GdkEventButton *,
+                                                             PsppSheetView *);
+static void pspp_sheet_view_editable_clicked (GtkButton *, PsppSheetView *);
 static void pspp_sheet_view_real_start_editing (PsppSheetView       *tree_view,
                                              PsppSheetViewColumn *column,
                                              GtkTreePath       *path,
@@ -578,7 +582,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class)
      * Enables of disables the hover selection mode of @tree_view.
      * Hover selection makes the selected row follow the pointer.
      * Currently, this works only for the selection modes 
-     * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
+     * %PSPP_SHEET_SELECTION_SINGLE and %PSPP_SHEET_SELECTION_BROWSE.
      *
      * This mode is primarily intended for treeviews in popups, e.g.
      * in #GtkComboBox or #GtkEntryCompletion.
@@ -1007,6 +1011,8 @@ pspp_sheet_view_init (PsppSheetView *tree_view)
   tree_view->priv->prelight_node = -1;
   tree_view->priv->rubber_band_start_node = -1;
   tree_view->priv->rubber_band_end_node = -1;
+
+  tree_view->priv->anchor_column = NULL;
 }
 
 
@@ -2034,6 +2040,137 @@ pspp_sheet_view_node_prev (PsppSheetView *tree_view,
 }
 
 static gboolean
+all_columns_selected (PsppSheetView *tree_view)
+{
+  GList *list;
+
+  for (list = tree_view->priv->columns; list; list = list->next)
+    {
+      PsppSheetViewColumn *column = list->data;
+      if (column->selectable && !column->selected)
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+pspp_sheet_view_row_head_clicked (PsppSheetView *tree_view,
+                                  gint node,
+                                  PsppSheetViewColumn *column,
+                                  GdkEventButton *event)
+{
+  PsppSheetSelection *selection;
+  PsppSheetSelectionMode mode;
+  GtkTreePath *path;
+  gboolean update_anchor;
+  gboolean handled;
+  guint modifiers;
+
+  g_return_val_if_fail (tree_view != NULL, FALSE);
+  g_return_val_if_fail (column != NULL, FALSE);
+
+  selection = tree_view->priv->selection;
+  mode = pspp_sheet_selection_get_mode (selection);
+  if (mode != PSPP_SHEET_SELECTION_RECTANGLE)
+    return FALSE;
+
+  if (!column->row_head)
+    return FALSE;
+
+  if (event)
+    {
+      modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
+      if (event->type != GDK_BUTTON_PRESS
+          || (modifiers != GDK_CONTROL_MASK && modifiers != GDK_SHIFT_MASK))
+        return FALSE;
+    }
+  else
+    modifiers = 0;
+
+  path = gtk_tree_path_new_from_indices (node, -1);
+  if (event == NULL)
+    {
+      pspp_sheet_selection_unselect_all (selection);
+      pspp_sheet_selection_select_path (selection, path);
+      pspp_sheet_selection_select_all_columns (selection);
+      update_anchor = TRUE;
+      handled = TRUE;
+    }
+  else if (event->type == GDK_BUTTON_PRESS && event->button == 3)
+    {
+      if (pspp_sheet_selection_count_selected_rows (selection) <= 1
+          || !all_columns_selected (tree_view))
+        {
+          pspp_sheet_selection_unselect_all (selection);
+          pspp_sheet_selection_select_path (selection, path);
+          pspp_sheet_selection_select_all_columns (selection);
+          update_anchor = TRUE;
+          handled = FALSE;
+        }
+      else
+        update_anchor = handled = FALSE;
+    }
+  else if (event->type == GDK_BUTTON_PRESS && event->button == 1
+           && modifiers == GDK_CONTROL_MASK)
+    {
+      if (!all_columns_selected (tree_view))
+        {
+          pspp_sheet_selection_unselect_all (selection);
+          pspp_sheet_selection_select_all_columns (selection);
+        }
+
+      if (pspp_sheet_selection_path_is_selected (selection, path))
+        pspp_sheet_selection_unselect_path (selection, path);
+      else
+        pspp_sheet_selection_select_path (selection, path);
+      update_anchor = TRUE;
+      handled = TRUE;
+    }
+  else if (event->type == GDK_BUTTON_PRESS && event->button == 1
+           && modifiers == GDK_SHIFT_MASK)
+    {
+      GtkTreeRowReference *anchor = tree_view->priv->anchor;
+      GtkTreePath *anchor_path;
+
+      if (all_columns_selected (tree_view)
+          && gtk_tree_row_reference_valid (anchor))
+        {
+          update_anchor = FALSE;
+          anchor_path = gtk_tree_row_reference_get_path (anchor);
+        }
+      else
+        {
+          update_anchor = TRUE;
+          anchor_path = gtk_tree_path_copy (path);
+        }
+
+      pspp_sheet_selection_unselect_all (selection);
+      pspp_sheet_selection_select_range (selection, anchor_path, path);
+      pspp_sheet_selection_select_all_columns (selection);
+
+      gtk_tree_path_free (anchor_path);
+
+      handled = TRUE;
+    }
+  else
+    update_anchor = handled = FALSE;
+
+  if (update_anchor)
+    {
+      if (tree_view->priv->anchor)
+        gtk_tree_row_reference_free (tree_view->priv->anchor);
+      tree_view->priv->anchor =
+        gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
+                                          tree_view->priv->model,
+                                          path);
+    }
+
+  gtk_tree_path_free (path);
+  return handled;
+}
+
+static gboolean
 pspp_sheet_view_button_press (GtkWidget      *widget,
                            GdkEventButton *event)
 {
@@ -2075,6 +2212,7 @@ pspp_sheet_view_button_press (GtkWidget      *widget,
       gboolean row_double_click = FALSE;
       gboolean rtl;
       gboolean node_selected;
+      guint modifiers;
 
       /* Empty tree? */
       if (tree_view->priv->row_count == 0)
@@ -2143,8 +2281,8 @@ pspp_sheet_view_button_press (GtkWidget      *widget,
       tree_view->priv->focus_column = column;
 
       /* decide if we edit */
-      if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
-         !(event->state & gtk_accelerator_get_default_mod_mask ()))
+      modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
+      if (event->type == GDK_BUTTON_PRESS && event->button == 1 && !modifiers)
        {
          GtkTreePath *anchor;
          GtkTreeIter iter;
@@ -2160,7 +2298,7 @@ pspp_sheet_view_button_press (GtkWidget      *widget,
            anchor = NULL;
 
          if (pspp_sheet_view_column_get_quick_edit (column)
-              || (anchor && !gtk_tree_path_compare (anchor, path))
+              //|| (anchor && !gtk_tree_path_compare (anchor, path))
               || !_pspp_sheet_view_column_has_editable_cell (column))
            {
              GtkCellEditable *cell_editable = NULL;
@@ -2182,6 +2320,10 @@ pspp_sheet_view_button_press (GtkWidget      *widget,
                      gint left, right;
                      GdkRectangle area;
 
+                      pspp_sheet_view_real_set_cursor (tree_view, path,
+                                                       TRUE, TRUE);
+                      gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+
                      area = cell_area;
                      _pspp_sheet_view_column_get_neighbor_sizes (column,       
_pspp_sheet_view_column_get_edited_cell (column), &left, &right);
 
@@ -2208,6 +2350,9 @@ pspp_sheet_view_button_press (GtkWidget      *widget,
            gtk_tree_path_free (anchor);
        }
 
+      if (pspp_sheet_view_row_head_clicked (tree_view, node, column, event))
+        return TRUE;
+
       /* select */
       node_selected = pspp_sheet_view_node_is_selected (tree_view, node);
       pre_val = tree_view->priv->vadjustment->value;
@@ -2232,7 +2377,7 @@ pspp_sheet_view_button_press (GtkWidget      *widget,
             }
           else if (event->state & GDK_SHIFT_MASK)
             {
-              pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE);
+              pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE);
               pspp_sheet_view_real_select_cursor_row (tree_view, FALSE);
             }
           else
@@ -2240,6 +2385,14 @@ pspp_sheet_view_button_press (GtkWidget      *widget,
               pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE);
             }
 
+          if (tree_view->priv->anchor_column == NULL ||
+              !(event->state & GDK_SHIFT_MASK))
+            tree_view->priv->anchor_column = column;
+          pspp_sheet_selection_unselect_all_columns 
(tree_view->priv->selection);
+          pspp_sheet_selection_select_column_range (tree_view->priv->selection,
+                                                    
tree_view->priv->anchor_column,
+                                                    column);
+
           tree_view->priv->ctrl_pressed = FALSE;
           tree_view->priv->shift_pressed = FALSE;
         }
@@ -2265,8 +2418,9 @@ pspp_sheet_view_button_press (GtkWidget      *widget,
           tree_view->priv->press_start_y = event->y;
 
          if (tree_view->priv->rubber_banding_enable
-             && !node_selected
-             && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+             //&& !node_selected
+             && (tree_view->priv->selection->type == 
PSPP_SHEET_SELECTION_MULTIPLE ||
+                  tree_view->priv->selection->type == 
PSPP_SHEET_SELECTION_RECTANGLE))
            {
              tree_view->priv->press_start_y += tree_view->priv->dy;
              tree_view->priv->rubber_band_x = event->x;
@@ -2277,6 +2431,7 @@ pspp_sheet_view_button_press (GtkWidget      *widget,
                tree_view->priv->rubber_band_ctrl = TRUE;
              if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
                tree_view->priv->rubber_band_shift = TRUE;
+
            }
         }
 
@@ -2549,10 +2704,10 @@ prelight_or_select (PsppSheetView *tree_view,
                    gint         x,
                    gint         y)
 {
-  GtkSelectionMode mode = pspp_sheet_selection_get_mode 
(tree_view->priv->selection);
+  PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode 
(tree_view->priv->selection);
   
   if (tree_view->priv->hover_selection &&
-      (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
+      (mode == PSPP_SHEET_SELECTION_SINGLE || mode == 
PSPP_SHEET_SELECTION_BROWSE) &&
       !(tree_view->priv->edited_column &&
        tree_view->priv->edited_column->editable_widget))
     {
@@ -2573,7 +2728,7 @@ prelight_or_select (PsppSheetView *tree_view,
            }
        }
 
-      else if (mode == GTK_SELECTION_SINGLE)
+      else if (mode == PSPP_SHEET_SELECTION_SINGLE)
        pspp_sheet_selection_unselect_all (tree_view->priv->selection);
     }
 
@@ -3265,6 +3420,7 @@ pspp_sheet_view_update_rubber_band (PsppSheetView 
*tree_view)
   GdkRectangle new_area;
   GdkRectangle common;
   GdkRegion *invalid_region;
+  PsppSheetViewColumn *column;
 
   old_area.x = MIN (tree_view->priv->press_start_x, 
tree_view->priv->rubber_band_x);
   old_area.y = MIN (tree_view->priv->press_start_y, 
tree_view->priv->rubber_band_y) - tree_view->priv->dy;
@@ -3307,6 +3463,14 @@ pspp_sheet_view_update_rubber_band (PsppSheetView 
*tree_view)
 
   tree_view->priv->rubber_band_x = x;
   tree_view->priv->rubber_band_y = y;
+  pspp_sheet_view_get_path_at_pos (tree_view, x, y, NULL, &column, NULL, NULL);
+
+  pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
+  pspp_sheet_selection_select_column_range (tree_view->priv->selection,
+                                            tree_view->priv->anchor_column,
+                                            column);
+
+  gtk_widget_queue_draw (GTK_WIDGET (tree_view));
 
   pspp_sheet_view_update_rubber_band_selection (tree_view);
 }
@@ -3319,6 +3483,7 @@ pspp_sheet_view_paint_rubber_band (PsppSheetView  
*tree_view,
   GdkRectangle rect;
   GdkRectangle rubber_rect;
 
+  return;
   rubber_rect.x = MIN (tree_view->priv->press_start_x, 
tree_view->priv->rubber_band_x);
   rubber_rect.y = MIN (tree_view->priv->press_start_y, 
tree_view->priv->rubber_band_y) - tree_view->priv->dy;
   rubber_rect.width = ABS (tree_view->priv->press_start_x - 
tree_view->priv->rubber_band_x) + 1;
@@ -3657,6 +3822,7 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
       gboolean is_first = FALSE;
       gboolean is_last = FALSE;
       gboolean done = FALSE;
+      gboolean selected;
 
       max_height = ROW_HEIGHT (tree_view);
 
@@ -3670,8 +3836,7 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
       if (node == tree_view->priv->prelight_node)
        flags |= GTK_CELL_RENDERER_PRELIT;
 
-      if (pspp_sheet_view_node_is_selected (tree_view, node))
-        flags |= GTK_CELL_RENDERER_SELECTED;
+      selected = pspp_sheet_view_node_is_selected (tree_view, node);
 
       parity = node % 2;
 
@@ -3697,11 +3862,17 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
        {
          PsppSheetViewColumn *column = list->data;
          const gchar *detail = NULL;
+          gboolean selected_column;
          GtkStateType state;
 
          if (!column->visible)
             continue;
 
+          if (tree_view->priv->selection->type == 
PSPP_SHEET_SELECTION_RECTANGLE)
+            selected_column = column->selected && column->selectable;
+          else
+            selected_column = TRUE;
+
          if (cell_offset > event->area.x + event->area.width ||
              cell_offset + column->width < event->area.x)
            {
@@ -3709,6 +3880,11 @@ pspp_sheet_view_bin_expose (GtkWidget      *widget,
              continue;
            }
 
+          if (selected && selected_column)
+            flags |= GTK_CELL_RENDERER_SELECTED;
+          else
+            flags &= ~GTK_CELL_RENDERER_SELECTED;
+
           if (column->show_sort_indicator)
            flags |= GTK_CELL_RENDERER_SORTED;
           else
@@ -5486,6 +5662,7 @@ scroll_row_timeout (gpointer data)
 {
   PsppSheetView *tree_view = data;
 
+  pspp_sheet_view_horizontal_autoscroll (tree_view);
   pspp_sheet_view_vertical_autoscroll (tree_view);
 
   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
@@ -6401,6 +6578,7 @@ pspp_sheet_view_header_focus (PsppSheetView      
*tree_view,
 
 /* This function returns in 'path' the first focusable path, if the given path
  * is already focusable, it's the returned one.
+ *
  */
 static gboolean
 search_first_focusable_path (PsppSheetView  *tree_view,
@@ -6408,6 +6586,8 @@ search_first_focusable_path (PsppSheetView  *tree_view,
                             gboolean      search_forward,
                             int *new_node)
 {
+  /* XXX this function is trivial given that the sheetview doesn't support
+     separator rows */
   int node = -1;
 
   if (!path || !*path)
@@ -7389,8 +7569,8 @@ pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view)
 
   if (cursor_path == NULL)
     {
-      /* Consult the selection before defaulting to the
-       * first focusable element
+      /* There's no cursor.  Move the cursor to the first selected row, if any
+       * are selected, otherwise to the first row in the sheetview.
        */
       GList *selected_rows;
       GtkTreeModel *model;
@@ -7401,6 +7581,7 @@ pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view)
 
       if (selected_rows)
        {
+          /* XXX we could avoid doing O(n) work to get this result */
           cursor_path = gtk_tree_path_copy((const GtkTreePath 
*)(selected_rows->data));
          g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
          g_list_free (selected_rows);
@@ -7417,7 +7598,8 @@ pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view)
 
       if (cursor_path)
        {
-         if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+         if (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE 
||
+              tree_view->priv->selection->type == 
PSPP_SHEET_SELECTION_RECTANGLE)
            pspp_sheet_view_real_set_cursor (tree_view, cursor_path, FALSE, 
FALSE);
          else
            pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, 
FALSE);
@@ -7426,6 +7608,7 @@ pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view)
 
   if (cursor_path)
     {
+      /* Now find a column for the cursor. */
       PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
 
       pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL);
@@ -7439,9 +7622,12 @@ pspp_sheet_view_focus_to_cursor (PsppSheetView 
*tree_view)
              if (PSPP_SHEET_VIEW_COLUMN (list->data)->visible)
                {
                  tree_view->priv->focus_column = PSPP_SHEET_VIEW_COLUMN 
(list->data);
+                  pspp_sheet_selection_unselect_all_columns 
(tree_view->priv->selection);
+                  pspp_sheet_selection_select_column 
(tree_view->priv->selection, tree_view->priv->focus_column);
                  break;
                }
            }
+
        }
     }
 }
@@ -7474,7 +7660,7 @@ pspp_sheet_view_move_cursor_up_down (PsppSheetView 
*tree_view,
   selection_count = pspp_sheet_selection_count_selected_rows 
(tree_view->priv->selection);
 
   if (selection_count == 0
-      && tree_view->priv->selection->type != GTK_SELECTION_NONE
+      && tree_view->priv->selection->type != PSPP_SHEET_SELECTION_NONE
       && !tree_view->priv->ctrl_pressed)
     {
       /* Don't move the cursor, but just select the current node */
@@ -7506,7 +7692,8 @@ pspp_sheet_view_move_cursor_up_down (PsppSheetView 
*tree_view,
    * If the list has only one item and multi-selection is set then select
    * the row (if not yet selected).
    */
-  if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
+  if ((tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
+       tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE) &&
       new_cursor_node < 0)
     {
       if (count == -1)
@@ -7802,7 +7989,8 @@ pspp_sheet_view_real_select_all (PsppSheetView *tree_view)
   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
     return FALSE;
 
-  if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
+  if (tree_view->priv->selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
+      tree_view->priv->selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
     return FALSE;
 
   pspp_sheet_selection_select_all (tree_view->priv->selection);
@@ -7816,7 +8004,8 @@ pspp_sheet_view_real_unselect_all (PsppSheetView 
*tree_view)
   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
     return FALSE;
 
-  if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
+  if (tree_view->priv->selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
+      tree_view->priv->selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
     return FALSE;
 
   pspp_sheet_selection_unselect_all (tree_view->priv->selection);
@@ -9402,6 +9591,11 @@ pspp_sheet_view_set_reorderable (PsppSheetView 
*tree_view,
   g_object_notify (G_OBJECT (tree_view), "reorderable");
 }
 
+/* If CLEAR_AND_SELECT is true, then the row will be selected and, unless Shift
+   is pressed, other rows will be unselected.
+
+   If CLAMP_NODE is true, then the sheetview will scroll to make the row
+   visible. */
 static void
 pspp_sheet_view_real_set_cursor (PsppSheetView     *tree_view,
                               GtkTreePath     *path,
@@ -9596,6 +9790,10 @@ pspp_sheet_view_set_cursor_on_cell (PsppSheetView       
*tree_view,
        pspp_sheet_view_column_focus_cell (focus_column, focus_cell);
       if (start_editing)
        pspp_sheet_view_start_editing (tree_view, path);
+
+      pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
+      pspp_sheet_selection_select_column (tree_view->priv->selection, 
focus_column);
+
     }
 }
 
@@ -11509,6 +11707,12 @@ pspp_sheet_view_remove_widget (GtkCellEditable 
*cell_editable,
   g_signal_handlers_disconnect_by_func (cell_editable,
                                        pspp_sheet_view_remove_widget,
                                        tree_view);
+  g_signal_handlers_disconnect_by_func (cell_editable,
+                                       
pspp_sheet_view_editable_button_press_event,
+                                       tree_view);
+  g_signal_handlers_disconnect_by_func (cell_editable,
+                                       pspp_sheet_view_editable_clicked,
+                                       tree_view);
 
   gtk_container_remove (GTK_CONTAINER (tree_view),
                        GTK_WIDGET (cell_editable));  
@@ -11591,6 +11795,29 @@ pspp_sheet_view_start_editing (PsppSheetView 
*tree_view,
   return retval;
 }
 
+static gboolean
+pspp_sheet_view_editable_button_press_event (GtkWidget *widget,
+                                             GdkEventButton *event,
+                                             PsppSheetView *sheet_view)
+{
+  gint node;
+
+  node = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
+                                             "pspp-sheet-view-node"));
+  return pspp_sheet_view_row_head_clicked (sheet_view,
+                                           node,
+                                           sheet_view->priv->edited_column,
+                                           event);
+}
+
+static void
+pspp_sheet_view_editable_clicked (GtkButton *button,
+                                  PsppSheetView *sheet_view)
+{
+  pspp_sheet_view_editable_button_press_event (GTK_WIDGET (button), NULL,
+                                               sheet_view);
+}
+
 static void
 pspp_sheet_view_real_start_editing (PsppSheetView       *tree_view,
                                  PsppSheetViewColumn *column,
@@ -11600,6 +11827,7 @@ pspp_sheet_view_real_start_editing (PsppSheetView       
*tree_view,
                                  GdkEvent          *event,
                                  guint              flags)
 {
+  PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode 
(tree_view->priv->selection);
   gint pre_val = tree_view->priv->vadjustment->value;
   GtkRequisition requisition;
 
@@ -11609,6 +11837,10 @@ pspp_sheet_view_real_start_editing (PsppSheetView      
 *tree_view,
   pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE);
   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
 
+  pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
+  pspp_sheet_selection_select_column (tree_view->priv->selection, column);
+  tree_view->priv->anchor_column = column;
+
   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
 
   PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
@@ -11635,6 +11867,18 @@ pspp_sheet_view_real_start_editing (PsppSheetView      
 *tree_view,
   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
   g_signal_connect (cell_editable, "remove-widget",
                    G_CALLBACK (pspp_sheet_view_remove_widget), tree_view);
+  if (mode == PSPP_SHEET_SELECTION_RECTANGLE && column->row_head &&
+      GTK_IS_BUTTON (cell_editable))
+    {
+      g_signal_connect (cell_editable, "button-press-event",
+                        G_CALLBACK 
(pspp_sheet_view_editable_button_press_event),
+                        tree_view);
+      g_object_set_data (G_OBJECT (cell_editable), "pspp-sheet-view-node",
+                         GINT_TO_POINTER (gtk_tree_path_get_indices 
(path)[0]));
+      g_signal_connect (cell_editable, "clicked",
+                        G_CALLBACK (pspp_sheet_view_editable_clicked),
+                        tree_view);
+    }
 }
 
 static void
@@ -11680,7 +11924,7 @@ pspp_sheet_view_stop_editing (PsppSheetView *tree_view,
  * Enables of disables the hover selection mode of @tree_view.
  * Hover selection makes the selected row follow the pointer.
  * Currently, this works only for the selection modes 
- * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
+ * %PSPP_SHEET_SELECTION_SINGLE and %PSPP_SHEET_SELECTION_BROWSE.
  * 
  * Since: 2.6
  **/
@@ -11719,9 +11963,9 @@ pspp_sheet_view_get_hover_selection (PsppSheetView 
*tree_view)
  * @tree_view: a #PsppSheetView
  * @enable: %TRUE to enable rubber banding
  *
- * Enables or disables rubber banding in @tree_view.  If the selection mode
- * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
- * multiple rows by dragging the mouse.
+ * Enables or disables rubber banding in @tree_view.  If the selection mode is
+ * #PSPP_SHEET_SELECTION_MULTIPLE or #PSPP_SHEET_SELECTION_RECTANGLE, rubber
+ * banding will allow the user to select multiple rows by dragging the mouse.
  * 
  * Since: 2.10
  **/
@@ -11744,8 +11988,9 @@ pspp_sheet_view_set_rubber_banding (PsppSheetView 
*tree_view,
  * @tree_view: a #PsppSheetView
  * 
  * Returns whether rubber banding is turned on for @tree_view.  If the
- * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
- * user to select multiple rows by dragging the mouse.
+ * selection mode is #PSPP_SHEET_SELECTION_MULTIPLE or
+ * #PSPP_SHEET_SELECTION_RECTANGLE, rubber banding will allow the user to
+ * select multiple rows by dragging the mouse.
  * 
  * Return value: %TRUE if rubber banding in @tree_view is enabled.
  *
-- 
1.7.2.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]