[Top][All Lists]
[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
- Re: [PATCH 06/17] pspp-sheet-view-column: Add support for tooltips on columns., (continued)
- [PATCH 07/17] pspp-sheet-view: Edit cells on the first click by default., Ben Pfaff, 2012/04/22
- [PATCH 09/17] pspp-sheet-view: Start editing upon button release, not press., Ben Pfaff, 2012/04/22
- [PATCH 10/17] pspp-sheet-view: Add "special-cells" property to speed drawing many columns., Ben Pfaff, 2012/04/22
- [PATCH 13/17] pspp-sheet-view: Improve look of sheet when there are few columns., Ben Pfaff, 2012/04/22
- [PATCH 11/17] pspp-widget-facade: New code to measure and render some GTK+ widgets., Ben Pfaff, 2012/04/22
- [PATCH 14/17] pspp-sheet-view: Make pspp_sheet_view_stop_editing() public., Ben Pfaff, 2012/04/22
- [PATCH 08/17] pspp-sheet-view: Support rectangular selection, column popup menus.,
Ben Pfaff <=
- [PATCH 12/17] pspp-sheet-view: Optimize by making column header widgets lazy., Ben Pfaff, 2012/04/22
- [PATCH 15/17] pspp-sheet-view: Add "fixed-height" and "fixed-height-set" properties., Ben Pfaff, 2012/04/22
- [PATCH 17/17] psppire-cell-renderer-button: Add "slash" property., Ben Pfaff, 2012/04/22
- [PATCH 16/17] psppire-cell-renderer-button: New cell renderer for GtkButton., Ben Pfaff, 2012/04/22
- [PATCH 02/17] pspp-sheet-view: Reduce time and memory cost to O(1) in number of rows., Ben Pfaff, 2012/04/22
- [PATCH 01/17] Import GtkTreeView from GTK+ 2.0-2.20.1 renamed as PsppSheetView., Ben Pfaff, 2012/04/22