BOOLEAN:BOOLEAN
BOOLEAN:BOOLEAN,BOOLEAN,BOOLEAN
+BOOLEAN:BOXED
BOOLEAN:ENUM
BOOLEAN:ENUM,INT
BOOLEAN:BOXED,BOXED
gint n_columns;
GList *columns;
gint header_height;
+ gint n_selected_columns;
PsppSheetViewColumnDropFunc column_drop_func;
gpointer column_drop_func_data;
int rubber_band_end_node;
+ /* Rectangular selection. */
+ PsppSheetViewColumn *anchor_column; /* XXX needs to be a weak pointer? */
+
/* fixed height */
gint fixed_height;
static void
pspp_sheet_selection_init (PsppSheetSelection *selection)
{
- selection->type = GTK_SELECTION_SINGLE;
+ selection->type = PSPP_SHEET_SELECTION_SINGLE;
}
static void
* @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;
gtk_tree_path_free (anchor_path);
}
+ /* XXX unselect all columns when switching to/from rectangular selection? */
+
selection->type = type;
}
*
* 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;
}
* @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.
**/
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 */
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;
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;
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))
{
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,
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);
* 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)
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);
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;
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);
* 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)
* @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,
{
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))
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)
}
}
}
- 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))
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));
+ }
+}
#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,
/*< private >*/
PsppSheetView *GSEAL (tree_view);
- GtkSelectionMode GSEAL (type);
+ PsppSheetSelectionMode GSEAL (type);
};
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,
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);
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
#include <string.h>
#include "ui/gui/psppire-marshal.h"
+#include "ui/gui/pspp-sheet-selection.h"
#define P_(STRING) STRING
#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
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
};
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,
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;
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 ("popup-menu",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
G_TYPE_BOOLEAN, 1,
GTK_TYPE_TOOLTIP);
+ tree_column_signals[BUTTON_PRESS_EVENT] =
+ g_signal_new ("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",
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
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;
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;
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;
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
*/
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);
{
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:
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
}
+/**
+ * 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
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))
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);
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);
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,
* 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.
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;
}
\f
return node > 0 ? node - 1 : -1;
}
+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)
gboolean row_double_click = FALSE;
gboolean rtl;
gboolean node_selected;
+ guint modifiers;
/* Empty tree? */
if (tree_view->priv->row_count == 0)
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;
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;
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);
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;
}
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
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;
}
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;
tree_view->priv->rubber_band_ctrl = TRUE;
if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
tree_view->priv->rubber_band_shift = TRUE;
+
}
}
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))
{
}
}
- else if (mode == GTK_SELECTION_SINGLE)
+ else if (mode == PSPP_SHEET_SELECTION_SINGLE)
pspp_sheet_selection_unselect_all (tree_view->priv->selection);
}
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;
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);
}
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;
gboolean is_first = FALSE;
gboolean is_last = FALSE;
gboolean done = FALSE;
+ gboolean selected;
max_height = ROW_HEIGHT (tree_view);
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;
{
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)
{
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
{
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)
/* 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,
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)
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;
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);
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);
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);
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;
}
}
+
}
}
}
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 */
* 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)
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);
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);
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,
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);
+
}
}
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));
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,
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;
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);
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
* 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
**/
* @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
**/
* @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.
*