X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fpspp-sheet-view.c;h=c569d20403c201d967cbe7832349f71452141901;hb=848fb8f85491d13e21cd3352d14460110428032e;hp=9b84dac31e9cd1ed21f17046be0824054928917e;hpb=d64431ef201b3031adaca5643e35274c0cee2fa5;p=pspp diff --git a/src/ui/gui/pspp-sheet-view.c b/src/ui/gui/pspp-sheet-view.c index 9b84dac31e..c569d20403 100644 --- a/src/ui/gui/pspp-sheet-view.c +++ b/src/ui/gui/pspp-sheet-view.c @@ -64,7 +64,6 @@ #define SCROLL_EDGE_SIZE 15 #define EXPANDER_EXTRA_PADDING 4 #define PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT 5000 -#define AUTO_EXPAND_TIMEOUT 500 /* The "background" areas of all rows/cells add up to cover the entire tree. * The background includes all inter-row and inter-cell spacing. @@ -72,8 +71,8 @@ * i.e. just the cells, no spacing. */ -#define BACKGROUND_HEIGHT(node) (PSPP_RBNODE_GET_HEIGHT (node)) -#define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator)) +#define BACKGROUND_HEIGHT(tree_view) (tree_view->priv->fixed_height) +#define CELL_HEIGHT(tree_view, separator) ((BACKGROUND_HEIGHT (tree_view)) - (separator)) /* Translate from bin_window coordinates to rbtree (tree coordinates) and * vice versa. @@ -82,11 +81,11 @@ #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy) /* This is in bin_window coordinates */ -#define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _pspp_rbtree_node_find_offset ((tree), (node)))) -#define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2) +#define BACKGROUND_FIRST_PIXEL(tree_view,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, pspp_sheet_view_node_find_offset (tree_view, (node)))) +#define CELL_FIRST_PIXEL(tree_view,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,node) + separator/2) -#define ROW_HEIGHT(tree_view,height) \ - ((height > 0) ? (height) : (tree_view)->priv->expander_size) +#define ROW_HEIGHT(tree_view) \ + ((tree_view->priv->fixed_height > 0) ? (tree_view->priv->fixed_height) : (tree_view)->priv->expander_size) typedef struct _PsppSheetViewChild PsppSheetViewChild; @@ -118,10 +117,6 @@ struct _TreeViewDragInfo enum { ROW_ACTIVATED, - TEST_EXPAND_ROW, - TEST_COLLAPSE_ROW, - ROW_EXPANDED, - ROW_COLLAPSED, COLUMNS_CHANGED, CURSOR_CHANGED, MOVE_CURSOR, @@ -129,8 +124,6 @@ enum UNSELECT_ALL, SELECT_CURSOR_ROW, TOGGLE_CURSOR_ROW, - EXPAND_COLLAPSE_CURSOR_ROW, - SELECT_CURSOR_PARENT, START_INTERACTIVE_SEARCH, LAST_SIGNAL }; @@ -143,20 +136,17 @@ enum { PROP_VADJUSTMENT, PROP_HEADERS_VISIBLE, PROP_HEADERS_CLICKABLE, - PROP_EXPANDER_COLUMN, PROP_REORDERABLE, PROP_RULES_HINT, PROP_ENABLE_SEARCH, PROP_SEARCH_COLUMN, - PROP_FIXED_HEIGHT_MODE, PROP_HOVER_SELECTION, - PROP_HOVER_EXPAND, - PROP_SHOW_EXPANDERS, - PROP_LEVEL_INDENTATION, PROP_RUBBER_BANDING, PROP_ENABLE_GRID_LINES, - PROP_ENABLE_TREE_LINES, - PROP_TOOLTIP_COLUMN + PROP_TOOLTIP_COLUMN, + PROP_SPECIAL_CELLS, + PROP_FIXED_HEIGHT, + PROP_FIXED_HEIGHT_SET }; /* object signals */ @@ -170,8 +160,7 @@ static void pspp_sheet_view_get_property (GObject *object, GValue *value, GParamSpec *pspec); -/* gtkobject signals */ -static void pspp_sheet_view_destroy (GtkObject *object); +static void pspp_sheet_view_dispose (GObject *object); /* gtkwidget signals */ static void pspp_sheet_view_realize (GtkWidget *widget); @@ -199,10 +188,6 @@ static gboolean pspp_sheet_view_button_release (GtkWidget *widget, GdkEventButton *event); static gboolean pspp_sheet_view_grab_broken (GtkWidget *widget, GdkEventGrabBroken *event); -#if 0 -static gboolean pspp_sheet_view_configure (GtkWidget *widget, - GdkEventConfigure *event); -#endif static void pspp_sheet_view_set_focus_child (GtkContainer *container, GtkWidget *child); @@ -273,11 +258,6 @@ static gboolean pspp_sheet_view_real_unselect_all (PsppSheetView * static gboolean pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, gboolean start_editing); static gboolean pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view); -static gboolean pspp_sheet_view_real_expand_collapse_cursor_row (PsppSheetView *tree_view, - gboolean logical, - gboolean expand, - gboolean open_all); -static gboolean pspp_sheet_view_real_select_cursor_parent (PsppSheetView *tree_view); static void pspp_sheet_view_row_changed (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, @@ -286,10 +266,6 @@ static void pspp_sheet_view_row_inserted (GtkTreeModel *mo GtkTreePath *path, GtkTreeIter *iter, gpointer data); -static void pspp_sheet_view_row_has_child_toggled (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data); static void pspp_sheet_view_row_deleted (GtkTreeModel *model, GtkTreePath *path, gpointer data); @@ -300,16 +276,12 @@ static void pspp_sheet_view_rows_reordered (GtkTreeModel *mo gpointer data); /* Incremental reflow */ -static gboolean validate_row (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, +static gint validate_row (PsppSheetView *tree_view, + int node, GtkTreeIter *iter, GtkTreePath *path); static void validate_visible_area (PsppSheetView *tree_view); static gboolean validate_rows_handler (PsppSheetView *tree_view); -static gboolean do_validate_rows (PsppSheetView *tree_view, - gboolean size_request); -static gboolean validate_rows (PsppSheetView *tree_view); static gboolean presize_handler_callback (gpointer data); static void install_presize_handler (PsppSheetView *tree_view); static void install_scroll_sync_handler (PsppSheetView *tree_view); @@ -321,45 +293,22 @@ static void pspp_sheet_view_top_row_to_dy (PsppSheetView *tree_view); static void invalidate_empty_focus (PsppSheetView *tree_view); /* Internal functions */ -static gboolean pspp_sheet_view_is_expander_column (PsppSheetView *tree_view, - PsppSheetViewColumn *column); static void pspp_sheet_view_add_move_binding (GtkBindingSet *binding_set, guint keyval, guint modmask, gboolean add_shifted_binding, GtkMovementStep step, gint count); -static gint pspp_sheet_view_unref_and_check_selection_tree (PsppSheetView *tree_view, - GtkRBTree *tree); static void pspp_sheet_view_queue_draw_path (PsppSheetView *tree_view, GtkTreePath *path, const GdkRectangle *clip_rect); -static void pspp_sheet_view_queue_draw_arrow (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, - const GdkRectangle *clip_rect); -static void pspp_sheet_view_draw_arrow (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, - gint x, - gint y); -static void pspp_sheet_view_get_arrow_xrange (PsppSheetView *tree_view, - GtkRBTree *tree, - gint *x1, - gint *x2); static gint pspp_sheet_view_new_column_width (PsppSheetView *tree_view, gint i, gint *x); static void pspp_sheet_view_adjustment_changed (GtkAdjustment *adjustment, PsppSheetView *tree_view); -static void pspp_sheet_view_build_tree (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkTreeIter *iter, - gint depth, - gboolean recurse); static void pspp_sheet_view_clamp_node_visible (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node); + int node); static void pspp_sheet_view_clamp_column_visible (PsppSheetView *tree_view, PsppSheetViewColumn *column, gboolean focus_to_cell); @@ -374,37 +323,16 @@ static void pspp_sheet_view_move_cursor_left_right (PsppSheetView gint count); static void pspp_sheet_view_move_cursor_start_end (PsppSheetView *tree_view, gint count); -static gboolean pspp_sheet_view_real_collapse_row (PsppSheetView *tree_view, - GtkTreePath *path, - GtkRBTree *tree, - GtkRBNode *node, - gboolean animate); -static gboolean pspp_sheet_view_real_expand_row (PsppSheetView *tree_view, - GtkTreePath *path, - GtkRBTree *tree, - GtkRBNode *node, - gboolean open_all, - gboolean animate); static void pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view, GtkTreePath *path, gboolean clear_and_select, gboolean clamp_node); static gboolean pspp_sheet_view_has_special_cell (PsppSheetView *tree_view); -static void column_sizing_notify (GObject *object, - GParamSpec *pspec, - gpointer data); -static gboolean expand_collapse_timeout (gpointer data); -static void add_expand_collapse_timeout (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, - gboolean expand); -static void remove_expand_collapse_timeout (PsppSheetView *tree_view); -static void cancel_arrow_animation (PsppSheetView *tree_view); -static gboolean do_expand_collapse (PsppSheetView *tree_view); static void pspp_sheet_view_stop_rubber_band (PsppSheetView *tree_view); static void update_prelight (PsppSheetView *tree_view, int x, int y); +static void initialize_fixed_height_mode (PsppSheetView *tree_view); /* interactive search */ static void pspp_sheet_view_ensure_interactive_directory (PsppSheetView *tree_view); @@ -459,6 +387,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, @@ -466,14 +398,21 @@ static void pspp_sheet_view_real_start_editing (PsppSheetView *tree_view, GdkRectangle *cell_area, GdkEvent *event, guint flags); -static void pspp_sheet_view_stop_editing (PsppSheetView *tree_view, - gboolean cancel_editing); static gboolean pspp_sheet_view_real_start_interactive_search (PsppSheetView *tree_view, gboolean keybinding); static gboolean pspp_sheet_view_start_interactive_search (PsppSheetView *tree_view); static PsppSheetViewColumn *pspp_sheet_view_get_drop_column (PsppSheetView *tree_view, PsppSheetViewColumn *column, gint drop_position); +static void +pspp_sheet_view_adjust_cell_area (PsppSheetView *tree_view, + PsppSheetViewColumn *column, + const GdkRectangle *background_area, + gboolean subtract_focus_rect, + GdkRectangle *cell_area); +static gint pspp_sheet_view_find_offset (PsppSheetView *tree_view, + gint height, + int *new_node); /* GtkBuildable */ static void pspp_sheet_view_buildable_add_child (GtkBuildable *tree_view, @@ -489,6 +428,8 @@ static void remove_scroll_timeout (PsppSheetView *tree_view); static guint tree_view_signals [LAST_SIGNAL] = { 0 }; +static GtkBindingSet *edit_bindings; + /* GType Methods @@ -502,15 +443,17 @@ static void pspp_sheet_view_class_init (PsppSheetViewClass *class) { GObjectClass *o_class; - GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; - GtkBindingSet *binding_set; + GtkBindingSet *binding_set[2]; + int i; - binding_set = gtk_binding_set_by_class (class); + binding_set[0] = gtk_binding_set_by_class (class); + + binding_set[1] = gtk_binding_set_new ("PsppSheetViewEditing"); + edit_bindings = binding_set[1]; o_class = (GObjectClass *) class; - object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; container_class = (GtkContainerClass *) class; @@ -518,9 +461,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) o_class->set_property = pspp_sheet_view_set_property; o_class->get_property = pspp_sheet_view_get_property; o_class->finalize = pspp_sheet_view_finalize; - - /* GtkObject signals */ - object_class->destroy = pspp_sheet_view_destroy; + o_class->dispose = pspp_sheet_view_dispose; /* GtkWidget signals */ widget_class->map = pspp_sheet_view_map; @@ -564,8 +505,6 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) class->unselect_all = pspp_sheet_view_real_unselect_all; class->select_cursor_row = pspp_sheet_view_real_select_cursor_row; class->toggle_cursor_row = pspp_sheet_view_real_toggle_cursor_row; - class->expand_collapse_cursor_row = pspp_sheet_view_real_expand_collapse_cursor_row; - class->select_cursor_parent = pspp_sheet_view_real_select_cursor_parent; class->start_interactive_search = pspp_sheet_view_start_interactive_search; /* Properties */ @@ -610,14 +549,6 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) TRUE, GTK_PARAM_READWRITE)); - g_object_class_install_property (o_class, - PROP_EXPANDER_COLUMN, - g_param_spec_object ("expander-column", - P_("Expander Column"), - P_("Set the column for the expander column"), - PSPP_TYPE_SHEET_VIEW_COLUMN, - GTK_PARAM_READWRITE)); - g_object_class_install_property (o_class, PROP_REORDERABLE, g_param_spec_boolean ("reorderable", @@ -652,32 +583,13 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) -1, GTK_PARAM_READWRITE)); - /** - * PsppSheetView:fixed-height-mode: - * - * Setting the ::fixed-height-mode property to %TRUE speeds up - * #PsppSheetView by assuming that all rows have the same height. - * Only enable this option if all rows are the same height. - * Please see pspp_sheet_view_set_fixed_height_mode() for more - * information on this option. - * - * Since: 2.4 - **/ - g_object_class_install_property (o_class, - PROP_FIXED_HEIGHT_MODE, - g_param_spec_boolean ("fixed-height-mode", - P_("Fixed Height Mode"), - P_("Speeds up PsppSheetView by assuming that all rows have the same height"), - FALSE, - GTK_PARAM_READWRITE)); - /** * PsppSheetView:hover-selection: * * 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. @@ -692,58 +604,6 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) FALSE, GTK_PARAM_READWRITE)); - /** - * PsppSheetView:hover-expand: - * - * Enables of disables the hover expansion mode of @tree_view. - * Hover expansion makes rows expand or collapse if the pointer moves - * over them. - * - * This mode is primarily intended for treeviews in popups, e.g. - * in #GtkComboBox or #GtkEntryCompletion. - * - * Since: 2.6 - */ - g_object_class_install_property (o_class, - PROP_HOVER_EXPAND, - g_param_spec_boolean ("hover-expand", - P_("Hover Expand"), - P_("Whether rows should be expanded/collapsed when the pointer moves over them"), - FALSE, - GTK_PARAM_READWRITE)); - - /** - * PsppSheetView:show-expanders: - * - * %TRUE if the view has expanders. - * - * Since: 2.12 - */ - g_object_class_install_property (o_class, - PROP_SHOW_EXPANDERS, - g_param_spec_boolean ("show-expanders", - P_("Show Expanders"), - P_("View has expanders"), - TRUE, - GTK_PARAM_READWRITE)); - - /** - * PsppSheetView:level-indentation: - * - * Extra indentation for each level. - * - * Since: 2.12 - */ - g_object_class_install_property (o_class, - PROP_LEVEL_INDENTATION, - g_param_spec_int ("level-indentation", - P_("Level Indentation"), - P_("Extra indentation for each level"), - 0, - G_MAXINT, - 0, - GTK_PARAM_READWRITE)); - g_object_class_install_property (o_class, PROP_RUBBER_BANDING, g_param_spec_boolean ("rubber-banding", @@ -761,14 +621,6 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) PSPP_SHEET_VIEW_GRID_LINES_NONE, GTK_PARAM_READWRITE)); - g_object_class_install_property (o_class, - PROP_ENABLE_TREE_LINES, - g_param_spec_boolean ("enable-tree-lines", - P_("Enable Tree Lines"), - P_("Whether tree lines should be drawn in the tree view"), - FALSE, - GTK_PARAM_READWRITE)); - g_object_class_install_property (o_class, PROP_TOOLTIP_COLUMN, g_param_spec_int ("tooltip-column", @@ -779,6 +631,33 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) -1, GTK_PARAM_READWRITE)); + g_object_class_install_property (o_class, + PROP_SPECIAL_CELLS, + g_param_spec_enum ("special-cells", + P_("Special Cells"), + P_("Whether rows have special cells."), + PSPP_TYPE_SHEET_VIEW_SPECIAL_CELLS, + PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT, + GTK_PARAM_READWRITE)); + + g_object_class_install_property (o_class, + PROP_FIXED_HEIGHT, + g_param_spec_int ("fixed-height", + P_("Fixed Height"), + P_("Height of a single row. Normally the height of a row is determined automatically. Writing this property sets fixed-height-set to true, preventing this property's value from changing."), + -1, + G_MAXINT, + -1, + GTK_PARAM_READWRITE)); + + g_object_class_install_property (o_class, + PROP_FIXED_HEIGHT_SET, + g_param_spec_boolean ("fixed-height-set", + P_("Fixed Height Set"), + P_("Whether fixed-height was set externally."), + FALSE, + GTK_PARAM_READWRITE)); + /* Style properties */ #define _TREE_VIEW_EXPANDER_SIZE 12 #define _TREE_VIEW_VERTICAL_SEPARATOR 2 @@ -818,13 +697,6 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) TRUE, GTK_PARAM_READABLE)); - gtk_widget_class_install_style_property (widget_class, - g_param_spec_boolean ("indent-expanders", - P_("Indent Expanders"), - P_("Make the expanders indented"), - TRUE, - GTK_PARAM_READABLE)); - gtk_widget_class_install_style_property (widget_class, g_param_spec_boxed ("even-row-color", P_("Even Row Color"), @@ -860,13 +732,6 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) 0, G_MAXINT, 1, GTK_PARAM_READABLE)); - gtk_widget_class_install_style_property (widget_class, - g_param_spec_string ("grid-line-pattern", - P_("Grid line pattern"), - P_("Dash pattern used to draw the tree view grid lines"), - "\1\1", - GTK_PARAM_READABLE)); - gtk_widget_class_install_style_property (widget_class, g_param_spec_string ("tree-line-pattern", P_("Tree line pattern"), @@ -921,88 +786,6 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) GTK_TYPE_TREE_PATH, PSPP_TYPE_SHEET_VIEW_COLUMN); - /** - * PsppSheetView::test-expand-row: - * @tree_view: the object on which the signal is emitted - * @iter: the tree iter of the row to expand - * @path: a tree path that points to the row - * - * The given row is about to be expanded (show its children nodes). Use this - * signal if you need to control the expandability of individual rows. - * - * Returns: %FALSE to allow expansion, %TRUE to reject - */ - tree_view_signals[TEST_EXPAND_ROW] = - g_signal_new ("test-expand-row", - G_TYPE_FROM_CLASS (o_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (PsppSheetViewClass, test_expand_row), - _gtk_boolean_handled_accumulator, NULL, - psppire_marshal_BOOLEAN__BOXED_BOXED, - G_TYPE_BOOLEAN, 2, - GTK_TYPE_TREE_ITER, - GTK_TYPE_TREE_PATH); - - /** - * PsppSheetView::test-collapse-row: - * @tree_view: the object on which the signal is emitted - * @iter: the tree iter of the row to collapse - * @path: a tree path that points to the row - * - * The given row is about to be collapsed (hide its children nodes). Use this - * signal if you need to control the collapsibility of individual rows. - * - * Returns: %FALSE to allow collapsing, %TRUE to reject - */ - tree_view_signals[TEST_COLLAPSE_ROW] = - g_signal_new ("test-collapse-row", - G_TYPE_FROM_CLASS (o_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (PsppSheetViewClass, test_collapse_row), - _gtk_boolean_handled_accumulator, NULL, - psppire_marshal_BOOLEAN__BOXED_BOXED, - G_TYPE_BOOLEAN, 2, - GTK_TYPE_TREE_ITER, - GTK_TYPE_TREE_PATH); - - /** - * PsppSheetView::row-expanded: - * @tree_view: the object on which the signal is emitted - * @iter: the tree iter of the expanded row - * @path: a tree path that points to the row - * - * The given row has been expanded (child nodes are shown). - */ - tree_view_signals[ROW_EXPANDED] = - g_signal_new ("row-expanded", - G_TYPE_FROM_CLASS (o_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (PsppSheetViewClass, row_expanded), - NULL, NULL, - psppire_marshal_VOID__BOXED_BOXED, - G_TYPE_NONE, 2, - GTK_TYPE_TREE_ITER, - GTK_TYPE_TREE_PATH); - - /** - * PsppSheetView::row-collapsed: - * @tree_view: the object on which the signal is emitted - * @iter: the tree iter of the collapsed row - * @path: a tree path that points to the row - * - * The given row has been collapsed (child nodes are hidden). - */ - tree_view_signals[ROW_COLLAPSED] = - g_signal_new ("row-collapsed", - G_TYPE_FROM_CLASS (o_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (PsppSheetViewClass, row_collapsed), - NULL, NULL, - psppire_marshal_VOID__BOXED_BOXED, - G_TYPE_NONE, 2, - GTK_TYPE_TREE_ITER, - GTK_TYPE_TREE_PATH); - /** * PsppSheetView::columns-changed: * @tree_view: the object on which the signal is emitted @@ -1035,7 +818,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) tree_view_signals[MOVE_CURSOR] = g_signal_new ("move-cursor", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, move_cursor), NULL, NULL, @@ -1046,7 +829,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) tree_view_signals[SELECT_ALL] = g_signal_new ("select-all", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, select_all), NULL, NULL, @@ -1055,7 +838,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) tree_view_signals[UNSELECT_ALL] = g_signal_new ("unselect-all", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, unselect_all), NULL, NULL, @@ -1064,7 +847,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) tree_view_signals[SELECT_CURSOR_ROW] = g_signal_new ("select-cursor-row", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, select_cursor_row), NULL, NULL, @@ -1074,37 +857,16 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) tree_view_signals[TOGGLE_CURSOR_ROW] = g_signal_new ("toggle-cursor-row", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, toggle_cursor_row), NULL, NULL, psppire_marshal_BOOLEAN__VOID, G_TYPE_BOOLEAN, 0); - tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] = - g_signal_new ("expand-collapse-cursor-row", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (PsppSheetViewClass, expand_collapse_cursor_row), - NULL, NULL, - psppire_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN, - G_TYPE_BOOLEAN, 3, - G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN); - - tree_view_signals[SELECT_CURSOR_PARENT] = - g_signal_new ("select-cursor-parent", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (PsppSheetViewClass, select_cursor_parent), - NULL, NULL, - psppire_marshal_BOOLEAN__VOID, - G_TYPE_BOOLEAN, 0); - tree_view_signals[START_INTERACTIVE_SEARCH] = g_signal_new ("start-interactive-search", - G_TYPE_FROM_CLASS (object_class), + G_TYPE_FROM_CLASS (o_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (PsppSheetViewClass, start_interactive_search), NULL, NULL, @@ -1112,217 +874,113 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) G_TYPE_BOOLEAN, 0); /* Key bindings */ - pspp_sheet_view_add_move_binding (binding_set, GDK_Up, 0, TRUE, - GTK_MOVEMENT_DISPLAY_LINES, -1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE, - GTK_MOVEMENT_DISPLAY_LINES, -1); + for (i = 0; i < 2; i++) + { + pspp_sheet_view_add_move_binding (binding_set[i], GDK_Up, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINES, -1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Up, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINES, -1); - pspp_sheet_view_add_move_binding (binding_set, GDK_Down, 0, TRUE, - GTK_MOVEMENT_DISPLAY_LINES, 1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE, - GTK_MOVEMENT_DISPLAY_LINES, 1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_Down, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINES, 1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Down, 0, TRUE, + GTK_MOVEMENT_DISPLAY_LINES, 1); - pspp_sheet_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE, - GTK_MOVEMENT_DISPLAY_LINES, -1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_p, GDK_CONTROL_MASK, FALSE, + GTK_MOVEMENT_DISPLAY_LINES, -1); - pspp_sheet_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE, - GTK_MOVEMENT_DISPLAY_LINES, 1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_n, GDK_CONTROL_MASK, FALSE, + GTK_MOVEMENT_DISPLAY_LINES, 1); - pspp_sheet_view_add_move_binding (binding_set, GDK_Home, 0, TRUE, - GTK_MOVEMENT_BUFFER_ENDS, -1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE, - GTK_MOVEMENT_BUFFER_ENDS, -1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_Home, 0, TRUE, + GTK_MOVEMENT_BUFFER_ENDS, -1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Home, 0, TRUE, + GTK_MOVEMENT_BUFFER_ENDS, -1); - pspp_sheet_view_add_move_binding (binding_set, GDK_End, 0, TRUE, - GTK_MOVEMENT_BUFFER_ENDS, 1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE, - GTK_MOVEMENT_BUFFER_ENDS, 1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_End, 0, TRUE, + GTK_MOVEMENT_BUFFER_ENDS, 1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_End, 0, TRUE, + GTK_MOVEMENT_BUFFER_ENDS, 1); - pspp_sheet_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE, - GTK_MOVEMENT_PAGES, -1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE, - GTK_MOVEMENT_PAGES, -1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_Page_Up, 0, TRUE, + GTK_MOVEMENT_PAGES, -1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Page_Up, 0, TRUE, + GTK_MOVEMENT_PAGES, -1); - pspp_sheet_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE, - GTK_MOVEMENT_PAGES, 1); - pspp_sheet_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE, - GTK_MOVEMENT_PAGES, 1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_Page_Down, 0, TRUE, + GTK_MOVEMENT_PAGES, 1); + pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Page_Down, 0, TRUE, + GTK_MOVEMENT_PAGES, 1); - gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, 1); + gtk_binding_entry_add_signal (binding_set[i], GDK_Right, 0, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, 1); - gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, -1); + gtk_binding_entry_add_signal (binding_set[i], GDK_Left, 0, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, -1); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, 1); + gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Right, 0, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, 1); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, -1); + gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Left, 0, "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, -1); - gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK, - "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, 1); + gtk_binding_entry_add_signal (binding_set[i], GDK_Right, GDK_CONTROL_MASK, + "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, 1); - gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK, - "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, -1); + gtk_binding_entry_add_signal (binding_set[i], GDK_Left, GDK_CONTROL_MASK, + "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, -1); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK, - "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, 1); + gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Right, GDK_CONTROL_MASK, + "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, 1); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK, - "move-cursor", 2, - G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, - G_TYPE_INT, -1); + gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Left, GDK_CONTROL_MASK, + "move-cursor", 2, + G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS, + G_TYPE_INT, -1); - gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0); + gtk_binding_entry_add_signal (binding_set[i], GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0); - gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select-all", 0); - gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select-all", 0); + gtk_binding_entry_add_signal (binding_set[i], GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0); + } - gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0); - gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0); - gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set[0], GDK_a, GDK_CONTROL_MASK, "select-all", 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_slash, GDK_CONTROL_MASK, "select-all", 0); - gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select-cursor-row", 1, - G_TYPE_BOOLEAN, TRUE); + gtk_binding_entry_add_signal (binding_set[0], GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0); - /* expand and collapse rows */ - gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, FALSE); - - gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE); - - gtk_binding_entry_add_signal (binding_set, GDK_slash, 0, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, FALSE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, FALSE); - - /* Not doable on US keyboards */ - gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, FALSE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_Right, - GDK_CONTROL_MASK | GDK_SHIFT_MASK, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, TRUE, + gtk_binding_entry_add_signal (binding_set[0], GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1, G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, - GDK_CONTROL_MASK | GDK_SHIFT_MASK, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, TRUE, + gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1, G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, FALSE); - gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, FALSE, + gtk_binding_entry_add_signal (binding_set[0], GDK_space, 0, "select-cursor-row", 1, G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, FALSE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, TRUE, - G_TYPE_BOOLEAN, FALSE, + gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, 0, "select-cursor-row", 1, G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, FALSE, + gtk_binding_entry_add_signal (binding_set[0], GDK_Return, 0, "select-cursor-row", 1, G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, FALSE, + gtk_binding_entry_add_signal (binding_set[0], GDK_ISO_Enter, 0, "select-cursor-row", 1, G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_Left, - GDK_CONTROL_MASK | GDK_SHIFT_MASK, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, FALSE, + gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Enter, 0, "select-cursor-row", 1, G_TYPE_BOOLEAN, TRUE); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, - GDK_CONTROL_MASK | GDK_SHIFT_MASK, - "expand-collapse-cursor-row", 3, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, FALSE, - G_TYPE_BOOLEAN, TRUE); - - gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select-cursor-parent", 0); - gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0); - gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0); - - gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_BackSpace, 0, "select-cursor-parent", 0); + gtk_binding_entry_add_signal (binding_set[0], GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0); g_type_class_add_private (o_class, sizeof (PsppSheetViewPrivate)); } @@ -1341,11 +999,11 @@ pspp_sheet_view_init (PsppSheetView *tree_view) gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE); gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE); - tree_view->priv->flags = PSPP_SHEET_VIEW_SHOW_EXPANDERS - | PSPP_SHEET_VIEW_DRAW_KEYFOCUS + tree_view->priv->flags = PSPP_SHEET_VIEW_DRAW_KEYFOCUS | PSPP_SHEET_VIEW_HEADERS_VISIBLE; /* We need some padding */ + tree_view->priv->selected = range_tower_create (); tree_view->priv->dy = 0; tree_view->priv->cursor_offset = 0; tree_view->priv->n_columns = 0; @@ -1360,8 +1018,7 @@ pspp_sheet_view_init (PsppSheetView *tree_view) tree_view->priv->presize_handler_timer = 0; tree_view->priv->scroll_sync_timer = 0; tree_view->priv->fixed_height = -1; - tree_view->priv->fixed_height_mode = FALSE; - tree_view->priv->fixed_height_check = 0; + tree_view->priv->fixed_height_set = FALSE; pspp_sheet_view_set_adjustments (tree_view, NULL, NULL); tree_view->priv->selection = _pspp_sheet_selection_new_with_tree_view (tree_view); tree_view->priv->enable_search = TRUE; @@ -1374,17 +1031,15 @@ pspp_sheet_view_init (PsppSheetView *tree_view) tree_view->priv->width = 0; tree_view->priv->hover_selection = FALSE; - tree_view->priv->hover_expand = FALSE; - - tree_view->priv->level_indentation = 0; tree_view->priv->rubber_banding_enable = FALSE; tree_view->priv->grid_lines = PSPP_SHEET_VIEW_GRID_LINES_NONE; - tree_view->priv->tree_lines_enabled = FALSE; tree_view->priv->tooltip_column = -1; + tree_view->priv->special_cells = PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT; + tree_view->priv->post_validation_flag = FALSE; tree_view->priv->last_button_x = -1; @@ -1392,6 +1047,16 @@ pspp_sheet_view_init (PsppSheetView *tree_view) tree_view->priv->event_last_x = -10000; tree_view->priv->event_last_y = -10000; + + 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; + + tree_view->priv->button_style = NULL; + + tree_view->dispose_has_run = FALSE; } @@ -1426,9 +1091,6 @@ pspp_sheet_view_set_property (GObject *object, case PROP_HEADERS_CLICKABLE: pspp_sheet_view_set_headers_clickable (tree_view, g_value_get_boolean (value)); break; - case PROP_EXPANDER_COLUMN: - pspp_sheet_view_set_expander_column (tree_view, g_value_get_object (value)); - break; case PROP_REORDERABLE: pspp_sheet_view_set_reorderable (tree_view, g_value_get_boolean (value)); break; @@ -1441,33 +1103,44 @@ pspp_sheet_view_set_property (GObject *object, case PROP_SEARCH_COLUMN: pspp_sheet_view_set_search_column (tree_view, g_value_get_int (value)); break; - case PROP_FIXED_HEIGHT_MODE: - pspp_sheet_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value)); - break; case PROP_HOVER_SELECTION: tree_view->priv->hover_selection = g_value_get_boolean (value); break; - case PROP_HOVER_EXPAND: - tree_view->priv->hover_expand = g_value_get_boolean (value); - break; - case PROP_SHOW_EXPANDERS: - pspp_sheet_view_set_show_expanders (tree_view, g_value_get_boolean (value)); - break; - case PROP_LEVEL_INDENTATION: - tree_view->priv->level_indentation = g_value_get_int (value); - break; case PROP_RUBBER_BANDING: tree_view->priv->rubber_banding_enable = g_value_get_boolean (value); break; case PROP_ENABLE_GRID_LINES: pspp_sheet_view_set_grid_lines (tree_view, g_value_get_enum (value)); break; - case PROP_ENABLE_TREE_LINES: - pspp_sheet_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value)); - break; case PROP_TOOLTIP_COLUMN: pspp_sheet_view_set_tooltip_column (tree_view, g_value_get_int (value)); break; + case PROP_SPECIAL_CELLS: + pspp_sheet_view_set_special_cells (tree_view, g_value_get_enum (value)); + break; + case PROP_FIXED_HEIGHT: + pspp_sheet_view_set_fixed_height (tree_view, g_value_get_int (value)); + break; + case PROP_FIXED_HEIGHT_SET: + if (g_value_get_boolean (value)) + { + if (!tree_view->priv->fixed_height_set + && tree_view->priv->fixed_height >= 0) + { + tree_view->priv->fixed_height_set = true; + g_object_notify (G_OBJECT (tree_view), "fixed-height-set"); + } + } + else + { + if (tree_view->priv->fixed_height_set) + { + tree_view->priv->fixed_height_set = false; + g_object_notify (G_OBJECT (tree_view), "fixed-height-set"); + install_presize_handler (tree_view); + } + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1501,9 +1174,6 @@ pspp_sheet_view_get_property (GObject *object, case PROP_HEADERS_CLICKABLE: g_value_set_boolean (value, pspp_sheet_view_get_headers_clickable (tree_view)); break; - case PROP_EXPANDER_COLUMN: - g_value_set_object (value, tree_view->priv->expander_column); - break; case PROP_REORDERABLE: g_value_set_boolean (value, tree_view->priv->reorderable); break; @@ -1516,33 +1186,27 @@ pspp_sheet_view_get_property (GObject *object, case PROP_SEARCH_COLUMN: g_value_set_int (value, tree_view->priv->search_column); break; - case PROP_FIXED_HEIGHT_MODE: - g_value_set_boolean (value, tree_view->priv->fixed_height_mode); - break; case PROP_HOVER_SELECTION: g_value_set_boolean (value, tree_view->priv->hover_selection); break; - case PROP_HOVER_EXPAND: - g_value_set_boolean (value, tree_view->priv->hover_expand); - break; - case PROP_SHOW_EXPANDERS: - g_value_set_boolean (value, PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_SHOW_EXPANDERS)); - break; - case PROP_LEVEL_INDENTATION: - g_value_set_int (value, tree_view->priv->level_indentation); - break; case PROP_RUBBER_BANDING: g_value_set_boolean (value, tree_view->priv->rubber_banding_enable); break; case PROP_ENABLE_GRID_LINES: g_value_set_enum (value, tree_view->priv->grid_lines); break; - case PROP_ENABLE_TREE_LINES: - g_value_set_boolean (value, tree_view->priv->tree_lines_enabled); - break; case PROP_TOOLTIP_COLUMN: g_value_set_int (value, tree_view->priv->tooltip_column); break; + case PROP_SPECIAL_CELLS: + g_value_set_enum (value, tree_view->priv->special_cells); + break; + case PROP_FIXED_HEIGHT: + g_value_set_int (value, pspp_sheet_view_get_fixed_height (tree_view)); + break; + case PROP_FIXED_HEIGHT_SET: + g_value_set_boolean (value, tree_view->priv->fixed_height_set); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1550,9 +1214,41 @@ pspp_sheet_view_get_property (GObject *object, } static void -pspp_sheet_view_finalize (GObject *object) +pspp_sheet_view_dispose (GObject *object) { - G_OBJECT_CLASS (pspp_sheet_view_parent_class)->finalize (object); + PsppSheetView *tree_view = PSPP_SHEET_VIEW (object); + + if (tree_view->dispose_has_run) + return; + + tree_view->dispose_has_run = TRUE; + + if (tree_view->priv->selection != NULL) + { + _pspp_sheet_selection_set_tree_view (tree_view->priv->selection, NULL); + g_object_unref (tree_view->priv->selection); + tree_view->priv->selection = NULL; + } + + if (tree_view->priv->hadjustment) + { + g_object_unref (tree_view->priv->hadjustment); + tree_view->priv->hadjustment = NULL; + } + if (tree_view->priv->vadjustment) + { + g_object_unref (tree_view->priv->vadjustment); + tree_view->priv->vadjustment = NULL; + } + + if (tree_view->priv->button_style) + { + g_object_unref (tree_view->priv->button_style); + tree_view->priv->button_style = NULL; + } + + + G_OBJECT_CLASS (pspp_sheet_view_parent_class)->dispose (object); } @@ -1566,57 +1262,22 @@ pspp_sheet_view_buildable_add_child (GtkBuildable *tree_view, pspp_sheet_view_append_column (PSPP_SHEET_VIEW (tree_view), PSPP_SHEET_VIEW_COLUMN (child)); } -/* GtkObject Methods - */ - -static void -pspp_sheet_view_free_rbtree (PsppSheetView *tree_view) -{ - _pspp_rbtree_free (tree_view->priv->tree); - - tree_view->priv->tree = NULL; - tree_view->priv->button_pressed_node = NULL; - tree_view->priv->button_pressed_tree = NULL; - tree_view->priv->prelight_tree = NULL; - tree_view->priv->prelight_node = NULL; - tree_view->priv->expanded_collapsed_node = NULL; - tree_view->priv->expanded_collapsed_tree = NULL; -} - static void -pspp_sheet_view_destroy (GtkObject *object) +pspp_sheet_view_finalize (GObject *object) { PsppSheetView *tree_view = PSPP_SHEET_VIEW (object); - GList *list; pspp_sheet_view_stop_editing (tree_view, TRUE); - if (tree_view->priv->columns != NULL) + if (tree_view->priv->selected != NULL) { - list = tree_view->priv->columns; - while (list) - { - PsppSheetViewColumn *column; - column = PSPP_SHEET_VIEW_COLUMN (list->data); - list = list->next; - pspp_sheet_view_remove_column (tree_view, column); - } - tree_view->priv->columns = NULL; + range_tower_destroy (tree_view->priv->selected); + tree_view->priv->selected = NULL; } - if (tree_view->priv->tree != NULL) - { - pspp_sheet_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree); - pspp_sheet_view_free_rbtree (tree_view); - } + tree_view->priv->prelight_node = -1; - if (tree_view->priv->selection != NULL) - { - _pspp_sheet_selection_set_tree_view (tree_view->priv->selection, NULL); - g_object_unref (tree_view->priv->selection); - tree_view->priv->selection = NULL; - } if (tree_view->priv->scroll_to_path != NULL) { @@ -1681,26 +1342,10 @@ pspp_sheet_view_destroy (GtkObject *object) tree_view->priv->search_position_user_data = NULL; } - if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data) - { - tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data); - tree_view->priv->row_separator_data = NULL; - } - pspp_sheet_view_set_model (tree_view, NULL); - if (tree_view->priv->hadjustment) - { - g_object_unref (tree_view->priv->hadjustment); - tree_view->priv->hadjustment = NULL; - } - if (tree_view->priv->vadjustment) - { - g_object_unref (tree_view->priv->vadjustment); - tree_view->priv->vadjustment = NULL; - } - GTK_OBJECT_CLASS (pspp_sheet_view_parent_class)->destroy (object); + G_OBJECT_CLASS (pspp_sheet_view_parent_class)->finalize (object); } @@ -1723,14 +1368,15 @@ pspp_sheet_view_map_buttons (PsppSheetView *tree_view) for (list = tree_view->priv->columns; list; list = list->next) { column = list->data; - if (gtk_widget_get_visible (column->button) && + if (column->button != NULL && + gtk_widget_get_visible (column->button) && !gtk_widget_get_mapped (column->button)) gtk_widget_map (column->button); } for (list = tree_view->priv->columns; list; list = list->next) { column = list->data; - if (column->visible == FALSE) + if (column->visible == FALSE || column->window == NULL) continue; if (column->resizable) { @@ -1774,6 +1420,7 @@ pspp_sheet_view_map (GtkWidget *widget) static void pspp_sheet_view_realize (GtkWidget *widget) { + gint i; PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget); GList *tmp_list; GdkWindowAttr attributes; @@ -1853,38 +1500,38 @@ pspp_sheet_view_realize (GtkWidget *widget) /* Need to call those here, since they create GCs */ pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines); - pspp_sheet_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled); install_presize_handler (tree_view); + + for (i = 0; i < 5; ++i) + { + tree_view->priv->grid_line_gc[i] = gdk_gc_new (widget->window); + gdk_gc_copy (tree_view->priv->grid_line_gc[i], widget->style->text_aa_gc[i]); + } } static void pspp_sheet_view_unrealize (GtkWidget *widget) { + gint x; PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget); PsppSheetViewPrivate *priv = tree_view->priv; GList *list; - if (priv->scroll_timeout != 0) + GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->unrealize (widget); + + if (priv->scroll_timeout != 0) { g_source_remove (priv->scroll_timeout); priv->scroll_timeout = 0; } - if (priv->auto_expand_timeout != 0) - { - g_source_remove (priv->auto_expand_timeout); - priv->auto_expand_timeout = 0; - } - if (priv->open_dest_timeout != 0) { g_source_remove (priv->open_dest_timeout); priv->open_dest_timeout = 0; } - remove_expand_collapse_timeout (tree_view); - if (priv->presize_handler_timer != 0) { g_source_remove (priv->presize_handler_timer); @@ -1934,19 +1581,21 @@ pspp_sheet_view_unrealize (GtkWidget *widget) priv->drag_highlight_window = NULL; } - if (priv->tree_line_gc) - { - g_object_unref (priv->tree_line_gc); - priv->tree_line_gc = NULL; - } + for (x = 0 ; x < 5 ; ++x) + g_object_unref (priv->grid_line_gc[x]); - if (priv->grid_line_gc) + if (tree_view->priv->columns != NULL) { - g_object_unref (priv->grid_line_gc); - priv->grid_line_gc = NULL; + list = tree_view->priv->columns; + while (list) + { + PsppSheetViewColumn *column; + column = PSPP_SHEET_VIEW_COLUMN (list->data); + list = list->next; + pspp_sheet_view_remove_column (tree_view, column); + } + tree_view->priv->columns = NULL; } - - GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->unrealize (widget); } /* GtkWidget::size_request helper */ @@ -1964,12 +1613,7 @@ pspp_sheet_view_size_request_columns (PsppSheetView *tree_view) GtkRequisition requisition; PsppSheetViewColumn *column = list->data; - if (column->button == NULL) - continue; - - column = list->data; - - gtk_widget_size_request (column->button, &requisition); + pspp_sheet_view_column_size_request (column, &requisition); column->button_request = requisition.width; tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height); } @@ -2008,17 +1652,9 @@ pspp_sheet_view_update_size (PsppSheetView *tree_view) { real_requested_width = column->resized_width; } - else if (column->column_type == PSPP_SHEET_VIEW_COLUMN_FIXED) - { - real_requested_width = column->fixed_width; - } - else if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE)) - { - real_requested_width = MAX (column->requested_width, column->button_request); - } else { - real_requested_width = column->requested_width; + real_requested_width = column->fixed_width; } if (column->min_width != -1) @@ -2029,10 +1665,7 @@ pspp_sheet_view_update_size (PsppSheetView *tree_view) tree_view->priv->width += real_requested_width; } - if (tree_view->priv->tree == NULL) - tree_view->priv->height = 0; - else - tree_view->priv->height = tree_view->priv->tree->root->offset; + tree_view->priv->height = tree_view->priv->fixed_height * tree_view->priv->row_count; } static void @@ -2045,7 +1678,7 @@ pspp_sheet_view_size_request (GtkWidget *widget, /* we validate some rows initially just to make sure we have some size. * In practice, with a lot of static lists, this should get a good width. */ - do_validate_rows (tree_view, FALSE); + initialize_fixed_height_mode (tree_view); pspp_sheet_view_size_request_columns (tree_view); pspp_sheet_view_update_size (PSPP_SHEET_VIEW (widget)); @@ -2066,26 +1699,6 @@ pspp_sheet_view_size_request (GtkWidget *widget, } } -static int -pspp_sheet_view_calculate_width_before_expander (PsppSheetView *tree_view) -{ - int width = 0; - GList *list; - gboolean rtl; - - rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL); - for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns)); - list->data != tree_view->priv->expander_column; - list = (rtl ? list->prev : list->next)) - { - PsppSheetViewColumn *column = list->data; - - width += column->width; - } - - return width; -} - static void invalidate_column (PsppSheetView *tree_view, PsppSheetViewColumn *column) @@ -2151,19 +1764,9 @@ pspp_sheet_view_get_real_requested_width_from_column (PsppSheetView *tree_ { real_requested_width = column->resized_width; } - else if (column->column_type == PSPP_SHEET_VIEW_COLUMN_FIXED) - { - real_requested_width = column->fixed_width; - } - else if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE)) - { - real_requested_width = MAX (column->requested_width, column->button_request); - } else { - real_requested_width = column->requested_width; - if (real_requested_width < 0) - real_requested_width = 0; + real_requested_width = column->fixed_width; } if (column->min_width != -1) @@ -2174,6 +1777,15 @@ pspp_sheet_view_get_real_requested_width_from_column (PsppSheetView *tree_ return real_requested_width; } +static gboolean +span_intersects (int a0, int a_width, + int b0, int b_width) +{ + int a1 = a0 + a_width; + int b1 = b0 + b_width; + return (a0 >= b0 && a0 < b1) || (b0 >= a0 && b0 < a1); +} + /* GtkWidget::size_allocate helper */ static void pspp_sheet_view_size_allocate_columns (GtkWidget *widget, @@ -2184,13 +1796,12 @@ pspp_sheet_view_size_allocate_columns (GtkWidget *widget, PsppSheetViewColumn *column; GtkAllocation allocation; gint width = 0; - gint extra, extra_per_column, extra_for_last; + gint extra, extra_per_column; gint full_requested_width = 0; gint number_of_expand_columns = 0; gboolean column_changed = FALSE; gboolean rtl; - gboolean update_expand; - + tree_view = PSPP_SHEET_VIEW (widget); for (last_column = g_list_last (tree_view->priv->columns); @@ -2224,42 +1835,12 @@ pspp_sheet_view_size_allocate_columns (GtkWidget *widget, number_of_expand_columns++; } - /* Only update the expand value if the width of the widget has changed, - * or the number of expand columns has changed, or if there are no expand - * columns, or if we didn't have an size-allocation yet after the - * last validated node. - */ - update_expand = (width_changed && *width_changed == TRUE) - || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns - || number_of_expand_columns == 0 - || tree_view->priv->post_validation_flag == TRUE; - - tree_view->priv->post_validation_flag = FALSE; - - if (!update_expand) - { - extra = tree_view->priv->last_extra_space; - extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0); - } - else - { - extra = MAX (widget->allocation.width - full_requested_width, 0); - extra_for_last = 0; - - tree_view->priv->last_extra_space = extra; - } - + extra = MAX (widget->allocation.width - full_requested_width, 0); if (number_of_expand_columns > 0) extra_per_column = extra/number_of_expand_columns; else extra_per_column = 0; - if (update_expand) - { - tree_view->priv->last_extra_space_per_column = extra_per_column; - tree_view->priv->last_number_of_expand_columns = number_of_expand_columns; - } - for (list = (rtl ? last_column : first_column); list != (rtl ? first_column->prev : last_column->next); list = (rtl ? list->prev : list->next)) @@ -2283,8 +1864,8 @@ pspp_sheet_view_size_allocate_columns (GtkWidget *widget, &(drag_allocation.height)); drag_allocation.x = 0; drag_allocation.y = 0; - gtk_widget_size_allocate (tree_view->priv->drag_column->button, - &drag_allocation); + pspp_sheet_view_column_size_allocate (tree_view->priv->drag_column, + &drag_allocation); width += drag_allocation.width; continue; } @@ -2309,19 +1890,9 @@ pspp_sheet_view_size_allocate_columns (GtkWidget *widget, number_of_expand_columns --; } } - else if (number_of_expand_columns == 0 && - list == last_column) - { - column->width += extra; - } - - /* In addition to expand, the last column can get even more - * extra space so all available space is filled up. - */ - if (extra_for_last > 0 && list == last_column) - column->width += extra_for_last; - g_object_notify (G_OBJECT (column), "width"); + if (column->width != old_width) + g_object_notify (G_OBJECT (column), "width"); allocation.width = column->width; width += column->width; @@ -2329,7 +1900,13 @@ pspp_sheet_view_size_allocate_columns (GtkWidget *widget, if (column->width > old_width) column_changed = TRUE; - gtk_widget_size_allocate (column->button, &allocation); + pspp_sheet_view_column_size_allocate (column, &allocation); + + if (span_intersects (allocation.x, allocation.width, + tree_view->priv->hadjustment->value, + widget->allocation.width) + && gtk_widget_get_realized (widget)) + pspp_sheet_view_column_set_need_button (column, TRUE); if (column->window) gdk_window_move_resize (column->window, @@ -2456,7 +2033,7 @@ pspp_sheet_view_size_allocate (GtkWidget *widget, allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view)); } - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) invalidate_empty_focus (tree_view); if (gtk_widget_get_realized (widget)) @@ -2471,27 +2048,6 @@ pspp_sheet_view_size_allocate (GtkWidget *widget, } } - if (width_changed && tree_view->priv->expander_column) - { - /* Might seem awkward, but is the best heuristic I could come up - * with. Only if the width of the columns before the expander - * changes, we will update the prelight status. It is this - * width that makes the expander move vertically. Always updating - * prelight status causes trouble with hover selections. - */ - gint width_before_expander; - - width_before_expander = pspp_sheet_view_calculate_width_before_expander (tree_view); - - if (tree_view->priv->prev_width_before_expander - != width_before_expander) - update_prelight (tree_view, - tree_view->priv->event_last_x, - tree_view->priv->event_last_y); - - tree_view->priv->prev_width_before_expander = width_before_expander; - } - /* This little hack only works if we have an LTR locale, and no column has the */ if (width_changed) { @@ -2515,28 +2071,225 @@ grab_focus_and_unset_draw_keyfocus (PsppSheetView *tree_view) PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS); } -static inline gboolean -row_is_separator (PsppSheetView *tree_view, - GtkTreeIter *iter, - GtkTreePath *path) +gboolean +pspp_sheet_view_node_is_selected (PsppSheetView *tree_view, + int node) +{ + return node >= 0 && range_tower_contains (tree_view->priv->selected, node); +} + +void +pspp_sheet_view_node_select (PsppSheetView *tree_view, + int node) +{ + range_tower_set1 (tree_view->priv->selected, node, 1); +} + +void +pspp_sheet_view_node_unselect (PsppSheetView *tree_view, + int node) +{ + range_tower_set0 (tree_view->priv->selected, node, 1); +} + +gint +pspp_sheet_view_node_next (PsppSheetView *tree_view, + gint node) +{ + return node + 1 < tree_view->priv->row_count ? node + 1 : -1; +} + +gint +pspp_sheet_view_node_prev (PsppSheetView *tree_view, + gint node) +{ + 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) { - gboolean is_separator = FALSE; + 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 (tree_view->priv->row_separator_func) + 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) { - GtkTreeIter tmpiter; + GtkTreeRowReference *anchor = tree_view->priv->anchor; + GtkTreePath *anchor_path; - if (iter) - tmpiter = *iter; + 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 - gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path); + { + 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 +find_click (PsppSheetView *tree_view, + gint x, gint y, + gint *node, + PsppSheetViewColumn **column, + GdkRectangle *background_area, + GdkRectangle *cell_area) +{ + gint y_offset; + gboolean rtl; + GList *list; + gint new_y; + + /* find the node that was clicked */ + new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, y); + if (new_y < 0) + new_y = 0; + y_offset = -pspp_sheet_view_find_offset (tree_view, new_y, node); + + if (*node < 0) + return FALSE; + + background_area->y = y_offset + y; + background_area->height = ROW_HEIGHT (tree_view); + background_area->x = 0; + + /* Let the column have a chance at selecting it. */ + rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL); + for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns)); + list; list = (rtl ? list->prev : list->next)) + { + PsppSheetViewColumn *candidate = list->data; + + if (!candidate->visible) + continue; + + background_area->width = candidate->width; + if ((background_area->x > x) || + (background_area->x + background_area->width <= x)) + { + background_area->x += background_area->width; + continue; + } + + /* we found the focus column */ - is_separator = tree_view->priv->row_separator_func (tree_view->priv->model, - &tmpiter, - tree_view->priv->row_separator_data); + pspp_sheet_view_adjust_cell_area (tree_view, candidate, background_area, + TRUE, cell_area); + *column = candidate; + return TRUE; } - return is_separator; + return FALSE; } static gboolean @@ -2549,17 +2302,10 @@ pspp_sheet_view_button_press (GtkWidget *widget, gint i; GdkRectangle background_area; GdkRectangle cell_area; - gint vertical_separator; - gint horizontal_separator; - gboolean path_is_selectable; gboolean rtl; rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL); pspp_sheet_view_stop_editing (tree_view, FALSE); - gtk_widget_style_get (widget, - "vertical-separator", &vertical_separator, - "horizontal-separator", &horizontal_separator, - NULL); /* Because grab_focus can cause reentrancy, we delay grab_focus until after @@ -2568,236 +2314,83 @@ pspp_sheet_view_button_press (GtkWidget *widget, if (event->window == tree_view->priv->bin_window) { - GtkRBNode *node; - GtkRBTree *tree; + int node; GtkTreePath *path; - gchar *path_string; - gint depth; - gint new_y; - gint y_offset; gint dval; gint pre_val, aft_val; PsppSheetViewColumn *column = NULL; GtkCellRenderer *focus_cell = NULL; - gint column_handled_click = FALSE; gboolean row_double_click = FALSE; - gboolean rtl; gboolean node_selected; /* Empty tree? */ - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) { grab_focus_and_unset_draw_keyfocus (tree_view); return TRUE; } - /* are we in an arrow? */ - if (tree_view->priv->prelight_node && - PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_ARROW_PRELIT) && - TREE_VIEW_DRAW_EXPANDERS (tree_view)) - { - if (event->button == 1) - { - gtk_grab_add (widget); - tree_view->priv->button_pressed_node = tree_view->priv->prelight_node; - tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree; - pspp_sheet_view_draw_arrow (PSPP_SHEET_VIEW (widget), - tree_view->priv->prelight_tree, - tree_view->priv->prelight_node, - event->x, - event->y); - } - + if (!find_click (tree_view, event->x, event->y, &node, &column, + &background_area, &cell_area)) + { grab_focus_and_unset_draw_keyfocus (tree_view); - return TRUE; - } + return FALSE; + } - /* find the node that was clicked */ - new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y); - if (new_y < 0) - new_y = 0; - y_offset = -_pspp_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node); + tree_view->priv->focus_column = column; - if (node == NULL) - { - /* We clicked in dead space */ - grab_focus_and_unset_draw_keyfocus (tree_view); - return TRUE; - } + if (pspp_sheet_view_row_head_clicked (tree_view, node, column, event)) + return TRUE; - /* Get the path and the node */ - path = _pspp_sheet_view_find_path (tree_view, tree, node); - path_is_selectable = !row_is_separator (tree_view, NULL, path); + /* select */ + node_selected = pspp_sheet_view_node_is_selected (tree_view, node); + pre_val = tree_view->priv->vadjustment->value; - if (!path_is_selectable) - { - gtk_tree_path_free (path); - grab_focus_and_unset_draw_keyfocus (tree_view); - return TRUE; - } + path = _pspp_sheet_view_find_path (tree_view, node); - depth = gtk_tree_path_get_depth (path); - background_area.y = y_offset + event->y; - background_area.height = ROW_HEIGHT (tree_view, PSPP_RBNODE_GET_HEIGHT (node)); - background_area.x = 0; + /* we only handle selection modifications on the first button press + */ + if (event->type == GDK_BUTTON_PRESS) + { + if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) + tree_view->priv->ctrl_pressed = TRUE; + if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) + tree_view->priv->shift_pressed = TRUE; + focus_cell = _pspp_sheet_view_column_get_cell_at_pos (column, event->x - background_area.x); + if (focus_cell) + pspp_sheet_view_column_focus_cell (column, focus_cell); - /* Let the column have a chance at selecting it. */ - rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL); - for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns)); - list; list = (rtl ? list->prev : list->next)) - { - PsppSheetViewColumn *candidate = list->data; + if (event->state & GDK_CONTROL_MASK) + { + pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE); + pspp_sheet_view_real_toggle_cursor_row (tree_view); + } + else if (event->state & GDK_SHIFT_MASK) + { + 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 (!candidate->visible) - continue; + 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); - background_area.width = candidate->width; - if ((background_area.x > (gint) event->x) || - (background_area.x + background_area.width <= (gint) event->x)) - { - background_area.x += background_area.width; - continue; - } + tree_view->priv->ctrl_pressed = FALSE; + tree_view->priv->shift_pressed = FALSE; + } - /* we found the focus column */ - column = candidate; - cell_area = background_area; - cell_area.width -= horizontal_separator; - cell_area.height -= vertical_separator; - cell_area.x += horizontal_separator/2; - cell_area.y += vertical_separator/2; - if (pspp_sheet_view_is_expander_column (tree_view, column)) - { - if (!rtl) - cell_area.x += (depth - 1) * tree_view->priv->level_indentation; - cell_area.width -= (depth - 1) * tree_view->priv->level_indentation; - - if (TREE_VIEW_DRAW_EXPANDERS (tree_view)) - { - if (!rtl) - cell_area.x += depth * tree_view->priv->expander_size; - cell_area.width -= depth * tree_view->priv->expander_size; - } - } - break; - } - - if (column == NULL) - { - gtk_tree_path_free (path); - grab_focus_and_unset_draw_keyfocus (tree_view); - return FALSE; - } - - 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 ())) - { - GtkTreePath *anchor; - GtkTreeIter iter; - - gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - pspp_sheet_view_column_cell_set_cell_data (column, - tree_view->priv->model, - &iter, - PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_PARENT), - node->children?TRUE:FALSE); - - if (tree_view->priv->anchor) - anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor); - else - anchor = NULL; - - if ((anchor && !gtk_tree_path_compare (anchor, path)) - || !_pspp_sheet_view_column_has_editable_cell (column)) - { - GtkCellEditable *cell_editable = NULL; - - /* FIXME: get the right flags */ - guint flags = 0; - - path_string = gtk_tree_path_to_string (path); - - if (_pspp_sheet_view_column_cell_event (column, - &cell_editable, - (GdkEvent *)event, - path_string, - &background_area, - &cell_area, flags)) - { - if (cell_editable != NULL) - { - gint left, right; - GdkRectangle area; - - area = cell_area; - _pspp_sheet_view_column_get_neighbor_sizes (column, _pspp_sheet_view_column_get_edited_cell (column), &left, &right); - - area.x += left; - area.width -= right + left; - - pspp_sheet_view_real_start_editing (tree_view, - column, - path, - cell_editable, - &area, - (GdkEvent *)event, - flags); - g_free (path_string); - gtk_tree_path_free (path); - gtk_tree_path_free (anchor); - return TRUE; - } - column_handled_click = TRUE; - } - g_free (path_string); - } - if (anchor) - gtk_tree_path_free (anchor); - } - - /* select */ - node_selected = PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SELECTED); - pre_val = tree_view->priv->vadjustment->value; - - /* we only handle selection modifications on the first button press - */ - if (event->type == GDK_BUTTON_PRESS) - { - if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) - tree_view->priv->ctrl_pressed = TRUE; - if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) - tree_view->priv->shift_pressed = TRUE; - - focus_cell = _pspp_sheet_view_column_get_cell_at_pos (column, event->x - background_area.x); - if (focus_cell) - pspp_sheet_view_column_focus_cell (column, focus_cell); - - if (event->state & GDK_CONTROL_MASK) - { - pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE); - pspp_sheet_view_real_toggle_cursor_row (tree_view); - } - else if (event->state & GDK_SHIFT_MASK) - { - pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE); - pspp_sheet_view_real_select_cursor_row (tree_view, FALSE); - } - else - { - pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE); - } - - tree_view->priv->ctrl_pressed = FALSE; - tree_view->priv->shift_pressed = FALSE; - } - - /* the treeview may have been scrolled because of _set_cursor, - * correct here - */ + /* the treeview may have been scrolled because of _set_cursor, + * correct here + */ aft_val = tree_view->priv->vadjustment->value; dval = pre_val - aft_val; @@ -2807,17 +2400,18 @@ pspp_sheet_view_button_press (GtkWidget *widget, /* Save press to possibly begin a drag */ - if (!column_handled_click && - !tree_view->priv->in_grab && + if (!tree_view->priv->in_grab && tree_view->priv->pressed_button < 0) { tree_view->priv->pressed_button = event->button; tree_view->priv->press_start_x = event->x; tree_view->priv->press_start_y = event->y; + tree_view->priv->press_start_node = node; 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; @@ -2828,6 +2422,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; + } } @@ -2898,14 +2493,6 @@ pspp_sheet_view_button_press (GtkWidget *widget, { gpointer drag_data; - if (event->type == GDK_2BUTTON_PRESS && - pspp_sheet_view_column_get_sizing (column) != PSPP_SHEET_VIEW_COLUMN_AUTOSIZE) - { - column->use_resized_width = FALSE; - _pspp_sheet_view_column_autosize (tree_view, column); - return TRUE; - } - if (gdk_pointer_grab (column->window, FALSE, GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | @@ -2915,7 +2502,7 @@ pspp_sheet_view_button_press (GtkWidget *widget, gtk_grab_add (widget); PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE); - column->resized_width = column->width - tree_view->priv->last_extra_space_per_column; + column->resized_width = column->width; /* block attached dnd signal handler */ drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data"); @@ -2926,7 +2513,7 @@ pspp_sheet_view_button_press (GtkWidget *widget, drag_data); tree_view->priv->drag_pos = i; - tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width); + tree_view->priv->x_drag = column->allocation.x + (rtl ? 0 : column->allocation.width); if (!gtk_widget_has_focus (widget)) gtk_widget_grab_focus (widget); @@ -2953,6 +2540,8 @@ pspp_sheet_view_button_release_drag_column (GtkWidget *widget, gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME); /* Move the button back */ + g_return_val_if_fail (tree_view->priv->drag_column->button, FALSE); + g_object_ref (tree_view->priv->drag_column->button); gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button); gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window); @@ -3029,12 +2618,99 @@ pspp_sheet_view_button_release_column_resize (GtkWidget *widget, return TRUE; } +static gboolean +pspp_sheet_view_button_release_edit (PsppSheetView *tree_view, + GdkEventButton *event) +{ + GtkCellEditable *cell_editable; + gchar *path_string; + GtkTreePath *path; + gint left, right; + GtkTreeIter iter; + PsppSheetViewColumn *column; + GdkRectangle background_area; + GdkRectangle cell_area; + GdkRectangle area; + guint modifiers; + guint flags; + int node; + + if (event->window != tree_view->priv->bin_window) + return FALSE; + + if (!find_click (tree_view, event->x, event->y, &node, &column, &background_area, + &cell_area)) + return FALSE; + + /* decide if we edit */ + path = _pspp_sheet_view_find_path (tree_view, node); + modifiers = event->state & gtk_accelerator_get_default_mod_mask (); + if (event->button != 1 || modifiers) + return FALSE; + + gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); + pspp_sheet_view_column_cell_set_cell_data (column, + tree_view->priv->model, + &iter); + + if (!pspp_sheet_view_column_get_quick_edit (column) + && _pspp_sheet_view_column_has_editable_cell (column)) + return FALSE; + + flags = 0; /* FIXME: get the right flags */ + path_string = gtk_tree_path_to_string (path); + + if (!_pspp_sheet_view_column_cell_event (column, + &cell_editable, + (GdkEvent *)event, + path_string, + &background_area, + &cell_area, flags)) + return FALSE; + + if (cell_editable == NULL) + return FALSE; + + 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); + + area.x += left; + area.width -= right + left; + + pspp_sheet_view_real_start_editing (tree_view, + column, + path, + cell_editable, + &area, + (GdkEvent *)event, + flags); + g_free (path_string); + gtk_tree_path_free (path); + return TRUE; +} + static gboolean pspp_sheet_view_button_release (GtkWidget *widget, GdkEventButton *event) { PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget); + pspp_sheet_view_stop_editing (tree_view, FALSE); + if (tree_view->priv->rubber_band_status != RUBBER_BAND_ACTIVE + && pspp_sheet_view_button_release_edit (tree_view, event)) + { + if (tree_view->priv->pressed_button == event->button) + tree_view->priv->pressed_button = -1; + + tree_view->priv->rubber_band_status = RUBBER_BAND_OFF; + return TRUE; + } + if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG)) return pspp_sheet_view_button_release_drag_column (widget, event); @@ -3047,38 +2723,7 @@ pspp_sheet_view_button_release (GtkWidget *widget, if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE)) return pspp_sheet_view_button_release_column_resize (widget, event); - if (tree_view->priv->button_pressed_node == NULL) - return FALSE; - - if (event->button == 1) - { - gtk_grab_remove (widget); - if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node && - PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_ARROW_PRELIT)) - { - GtkTreePath *path = NULL; - - path = _pspp_sheet_view_find_path (tree_view, - tree_view->priv->button_pressed_tree, - tree_view->priv->button_pressed_node); - /* Actually activate the node */ - if (tree_view->priv->button_pressed_node->children == NULL) - pspp_sheet_view_real_expand_row (tree_view, path, - tree_view->priv->button_pressed_tree, - tree_view->priv->button_pressed_node, - FALSE, TRUE); - else - pspp_sheet_view_real_collapse_row (PSPP_SHEET_VIEW (widget), path, - tree_view->priv->button_pressed_tree, - tree_view->priv->button_pressed_node, TRUE); - gtk_tree_path_free (path); - } - - tree_view->priv->button_pressed_tree = NULL; - tree_view->priv->button_pressed_node = NULL; - } - - return TRUE; + return FALSE; } static gboolean @@ -3096,209 +2741,53 @@ pspp_sheet_view_grab_broken (GtkWidget *widget, return TRUE; } -#if 0 -static gboolean -pspp_sheet_view_configure (GtkWidget *widget, - GdkEventConfigure *event) -{ - PsppSheetView *tree_view; - - tree_view = PSPP_SHEET_VIEW (widget); - tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window); - - return FALSE; -} -#endif - /* GtkWidget::motion_event function set. */ -static gboolean -coords_are_over_arrow (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, - /* these are in bin window coords */ - gint x, - gint y) -{ - GdkRectangle arrow; - gint x2; - - if (!gtk_widget_get_realized (GTK_WIDGET (tree_view))) - return FALSE; - - if ((node->flags & PSPP_RBNODE_IS_PARENT) == 0) - return FALSE; - - arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); - - arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)); - - pspp_sheet_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2); - - arrow.width = x2 - arrow.x; - - return (x >= arrow.x && - x < (arrow.x + arrow.width) && - y >= arrow.y && - y < (arrow.y + arrow.height)); -} - -static gboolean -auto_expand_timeout (gpointer data) -{ - PsppSheetView *tree_view = PSPP_SHEET_VIEW (data); - GtkTreePath *path; - - if (tree_view->priv->prelight_node) - { - path = _pspp_sheet_view_find_path (tree_view, - tree_view->priv->prelight_tree, - tree_view->priv->prelight_node); - - if (tree_view->priv->prelight_node->children) - pspp_sheet_view_collapse_row (tree_view, path); - else - pspp_sheet_view_expand_row (tree_view, path, FALSE); - - gtk_tree_path_free (path); - } - - tree_view->priv->auto_expand_timeout = 0; - - return FALSE; -} - -static void -remove_auto_expand_timeout (PsppSheetView *tree_view) -{ - if (tree_view->priv->auto_expand_timeout != 0) - { - g_source_remove (tree_view->priv->auto_expand_timeout); - tree_view->priv->auto_expand_timeout = 0; - } -} - static void do_prelight (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, + int node, /* these are in bin_window coords */ gint x, gint y) { - if (tree_view->priv->prelight_tree == tree && - tree_view->priv->prelight_node == node) - { - /* We are still on the same node, - but we might need to take care of the arrow */ - - if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view)) - { - gboolean over_arrow; - gboolean flag_set; - - over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y); - flag_set = PSPP_SHEET_VIEW_FLAG_SET (tree_view, - PSPP_SHEET_VIEW_ARROW_PRELIT); - - if (over_arrow != flag_set) - { - if (over_arrow) - PSPP_SHEET_VIEW_SET_FLAG (tree_view, - PSPP_SHEET_VIEW_ARROW_PRELIT); - else - PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, - PSPP_SHEET_VIEW_ARROW_PRELIT); - - pspp_sheet_view_draw_arrow (tree_view, tree, node, x, y); - } - } - - return; - } - - if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node) - { - /* Unprelight the old node and arrow */ - - PSPP_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, - PSPP_RBNODE_IS_PRELIT); - - if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_ARROW_PRELIT) - && TREE_VIEW_DRAW_EXPANDERS (tree_view)) - { - PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_ARROW_PRELIT); - - pspp_sheet_view_draw_arrow (tree_view, - tree_view->priv->prelight_tree, - tree_view->priv->prelight_node, - x, - y); - } - - _pspp_sheet_view_queue_draw_node (tree_view, - tree_view->priv->prelight_tree, - tree_view->priv->prelight_node, - NULL); - } - - - if (tree_view->priv->hover_expand) - remove_auto_expand_timeout (tree_view); - - /* Set the new prelight values */ - tree_view->priv->prelight_node = node; - tree_view->priv->prelight_tree = tree; - - if (!node || !tree) - return; - - /* Prelight the new node and arrow */ + int prev_node = tree_view->priv->prelight_node; - if (TREE_VIEW_DRAW_EXPANDERS (tree_view) - && coords_are_over_arrow (tree_view, tree, node, x, y)) + if (prev_node != node) { - PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_ARROW_PRELIT); - - pspp_sheet_view_draw_arrow (tree_view, tree, node, x, y); - } + tree_view->priv->prelight_node = node; - PSPP_RBNODE_SET_FLAG (node, PSPP_RBNODE_IS_PRELIT); + if (prev_node >= 0) + _pspp_sheet_view_queue_draw_node (tree_view, prev_node, NULL); - _pspp_sheet_view_queue_draw_node (tree_view, tree, node, NULL); - - if (tree_view->priv->hover_expand) - { - tree_view->priv->auto_expand_timeout = - gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view); + if (node >= 0) + _pspp_sheet_view_queue_draw_node (tree_view, node, NULL); } } static void prelight_or_select (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, + int node, /* these are in bin_window coords */ 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)) { - if (node) + if (node >= 0) { - if (!PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SELECTED)) + if (!pspp_sheet_view_node_is_selected (tree_view, node)) { GtkTreePath *path; - path = _pspp_sheet_view_find_path (tree_view, tree, node); + path = _pspp_sheet_view_find_path (tree_view, node); pspp_sheet_selection_select_path (tree_view->priv->selection, path); - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SELECTED)) + if (pspp_sheet_view_node_is_selected (tree_view, node)) { PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS); pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, FALSE); @@ -3307,21 +2796,21 @@ 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); } - do_prelight (tree_view, tree, node, x, y); + do_prelight (tree_view, node, x, y); } static void ensure_unprelighted (PsppSheetView *tree_view) { do_prelight (tree_view, - NULL, NULL, + -1, -1000, -1000); /* coords not possibly over an arrow */ - g_assert (tree_view->priv->prelight_node == NULL); + g_assert (tree_view->priv->prelight_node < 0); } static void @@ -3330,10 +2819,9 @@ update_prelight (PsppSheetView *tree_view, gint y) { int new_y; - GtkRBTree *tree; - GtkRBNode *node; + int node; - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) return; if (x == -10000) @@ -3346,11 +2834,10 @@ update_prelight (PsppSheetView *tree_view, if (new_y < 0) new_y = 0; - _pspp_rbtree_find_offset (tree_view->priv->tree, - new_y, &tree, &node); + pspp_sheet_view_find_offset (tree_view, new_y, &node); - if (node) - prelight_or_select (tree_view, tree, node, x, y); + if (node >= 0) + prelight_or_select (tree_view, node, x, y); } @@ -3402,9 +2889,9 @@ pspp_sheet_view_motion_draw_column_motion_arrow (PsppSheetView *tree_view) GdkRectangle visible_rect; pspp_sheet_view_get_visible_rect (tree_view, &visible_rect); if (reorder->left_column) - x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width; + x = reorder->left_column->allocation.x + reorder->left_column->allocation.width; else - x = reorder->right_column->button->allocation.x; + x = reorder->right_column->allocation.x; if (x < visible_rect.x) arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT; @@ -3433,8 +2920,8 @@ pspp_sheet_view_motion_draw_column_motion_arrow (PsppSheetView *tree_view) attributes.wclass = GDK_INPUT_OUTPUT; attributes.x = tree_view->priv->drag_column_x; attributes.y = 0; - width = attributes.width = tree_view->priv->drag_column->button->allocation.width; - height = attributes.height = tree_view->priv->drag_column->button->allocation.height; + width = attributes.width = tree_view->priv->drag_column->allocation.width; + height = attributes.height = tree_view->priv->drag_column->allocation.height; attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view)); attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view)); attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK; @@ -3470,13 +2957,13 @@ pspp_sheet_view_motion_draw_column_motion_arrow (PsppSheetView *tree_view) gdk_window_get_origin (tree_view->priv->header_window, &x, &y); if (reorder->left_column) { - x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2; - height = reorder->left_column->button->allocation.height; + x += reorder->left_column->allocation.x + reorder->left_column->allocation.width - width/2; + height = reorder->left_column->allocation.height; } else { - x += reorder->right_column->button->allocation.x - width/2; - height = reorder->right_column->button->allocation.height; + x += reorder->right_column->allocation.x - width/2; + height = reorder->right_column->allocation.height; } y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */ height += tree_view->priv->expander_size; @@ -3549,9 +3036,9 @@ pspp_sheet_view_motion_draw_column_motion_arrow (PsppSheetView *tree_view) x += widget->allocation.width - width; if (reorder->left_column) - height = reorder->left_column->button->allocation.height; + height = reorder->left_column->allocation.height; else - height = reorder->right_column->button->allocation.height; + height = reorder->right_column->allocation.height; y -= tree_view->priv->expander_size; height += 2*tree_view->priv->expander_size; @@ -3648,8 +3135,10 @@ pspp_sheet_view_motion_resize_column (GtkWidget *widget, { column->use_resized_width = TRUE; column->resized_width = new_width; +#if 0 if (column->expand) column->resized_width -= tree_view->priv->last_extra_space_per_column; +#endif gtk_widget_queue_resize (widget); } @@ -3753,7 +3242,7 @@ pspp_sheet_view_motion_drag_column (GtkWidget *widget, /* Handle moving the header */ gdk_window_get_position (tree_view->priv->drag_window, &x, &y); x = CLAMP (x + (gint)event->x - column->drag_x, 0, - MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width); + MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->allocation.width); gdk_window_move (tree_view->priv->drag_window, x, y); /* autoscroll, if needed */ @@ -3778,7 +3267,6 @@ pspp_sheet_view_stop_rubber_band (PsppSheetView *tree_view) /* The anchor path should be set to the start path */ tmp_path = _pspp_sheet_view_find_path (tree_view, - tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node); if (tree_view->priv->anchor) @@ -3793,7 +3281,6 @@ pspp_sheet_view_stop_rubber_band (PsppSheetView *tree_view) /* ... and the cursor to the end path */ tmp_path = _pspp_sheet_view_find_path (tree_view, - tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node); pspp_sheet_view_real_set_cursor (PSPP_SHEET_VIEW (tree_view), tmp_path, FALSE, FALSE); gtk_tree_path_free (tmp_path); @@ -3806,18 +3293,14 @@ pspp_sheet_view_stop_rubber_band (PsppSheetView *tree_view) tree_view->priv->rubber_band_shift = 0; tree_view->priv->rubber_band_ctrl = 0; - tree_view->priv->rubber_band_start_node = NULL; - tree_view->priv->rubber_band_start_tree = NULL; - tree_view->priv->rubber_band_end_node = NULL; - tree_view->priv->rubber_band_end_tree = NULL; + tree_view->priv->rubber_band_start_node = -1; + tree_view->priv->rubber_band_end_node = -1; } static void pspp_sheet_view_update_rubber_band_selection_range (PsppSheetView *tree_view, - GtkRBTree *start_tree, - GtkRBNode *start_node, - GtkRBTree *end_tree, - GtkRBNode *end_node, + int start_node, + int end_node, gboolean select, gboolean skip_start, gboolean skip_end) @@ -3834,74 +3317,50 @@ pspp_sheet_view_update_rubber_band_selection_range (PsppSheetView *tree_view, /* Small optimization by assuming insensitive nodes are never * selected. */ - if (!PSPP_RBNODE_FLAG_SET (start_node, PSPP_RBNODE_IS_SELECTED)) - { - GtkTreePath *path; - gboolean selectable; - - path = _pspp_sheet_view_find_path (tree_view, start_tree, start_node); - selectable = _pspp_sheet_selection_row_is_selectable (tree_view->priv->selection, start_node, path); - gtk_tree_path_free (path); - - if (!selectable) - goto node_not_selectable; - } - if (select) { if (tree_view->priv->rubber_band_shift) - PSPP_RBNODE_SET_FLAG (start_node, PSPP_RBNODE_IS_SELECTED); + pspp_sheet_view_node_select (tree_view, start_node); else if (tree_view->priv->rubber_band_ctrl) { /* Toggle the selection state */ - if (PSPP_RBNODE_FLAG_SET (start_node, PSPP_RBNODE_IS_SELECTED)) - PSPP_RBNODE_UNSET_FLAG (start_node, PSPP_RBNODE_IS_SELECTED); + if (pspp_sheet_view_node_is_selected (tree_view, start_node)) + pspp_sheet_view_node_unselect (tree_view, start_node); else - PSPP_RBNODE_SET_FLAG (start_node, PSPP_RBNODE_IS_SELECTED); + pspp_sheet_view_node_select (tree_view, start_node); } else - PSPP_RBNODE_SET_FLAG (start_node, PSPP_RBNODE_IS_SELECTED); + pspp_sheet_view_node_select (tree_view, start_node); } else { /* Mirror the above */ if (tree_view->priv->rubber_band_shift) - PSPP_RBNODE_UNSET_FLAG (start_node, PSPP_RBNODE_IS_SELECTED); + pspp_sheet_view_node_unselect (tree_view, start_node); else if (tree_view->priv->rubber_band_ctrl) { /* Toggle the selection state */ - if (PSPP_RBNODE_FLAG_SET (start_node, PSPP_RBNODE_IS_SELECTED)) - PSPP_RBNODE_UNSET_FLAG (start_node, PSPP_RBNODE_IS_SELECTED); + if (pspp_sheet_view_node_is_selected (tree_view, start_node)) + pspp_sheet_view_node_unselect (tree_view, start_node); else - PSPP_RBNODE_SET_FLAG (start_node, PSPP_RBNODE_IS_SELECTED); + pspp_sheet_view_node_select (tree_view, start_node); } else - PSPP_RBNODE_UNSET_FLAG (start_node, PSPP_RBNODE_IS_SELECTED); + pspp_sheet_view_node_unselect (tree_view, start_node); } - _pspp_sheet_view_queue_draw_node (tree_view, start_tree, start_node, NULL); + _pspp_sheet_view_queue_draw_node (tree_view, start_node, NULL); -node_not_selectable: if (start_node == end_node) break; skip_first: - if (start_node->children) - { - start_tree = start_node->children; - start_node = start_tree->root; - while (start_node->left != start_tree->nil) - start_node = start_node->left; - } - else - { - _pspp_rbtree_next_full (start_tree, start_node, &start_tree, &start_node); + start_node = pspp_sheet_view_node_next (tree_view, start_node); - if (!start_tree) - /* Ran out of tree */ - break; - } + if (start_node < 0) + /* Ran out of tree */ + break; if (skip_end && start_node == end_node) break; @@ -3909,108 +3368,117 @@ skip_first: while (TRUE); } +static gint +pspp_sheet_view_node_find_offset (PsppSheetView *tree_view, + int node) +{ + return node * tree_view->priv->fixed_height; +} + +static gint +pspp_sheet_view_find_offset (PsppSheetView *tree_view, + gint height, + int *new_node) +{ + int fixed_height = tree_view->priv->fixed_height; + if (fixed_height <= 0 + || height < 0 + || height >= tree_view->priv->row_count * fixed_height) + { + *new_node = -1; + return 0; + } + else + { + *new_node = height / fixed_height; + return height % fixed_height; + } +} + static void pspp_sheet_view_update_rubber_band_selection (PsppSheetView *tree_view) { - GtkRBTree *start_tree, *end_tree; - GtkRBNode *start_node, *end_node; + int start_node; + int end_node; - _pspp_rbtree_find_offset (tree_view->priv->tree, MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &start_tree, &start_node); - _pspp_rbtree_find_offset (tree_view->priv->tree, MAX (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &end_tree, &end_node); + pspp_sheet_view_find_offset (tree_view, MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &start_node); + pspp_sheet_view_find_offset (tree_view, MAX (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &end_node); /* Handle the start area first */ - if (!tree_view->priv->rubber_band_start_node) + if (tree_view->priv->rubber_band_start_node < 0) { pspp_sheet_view_update_rubber_band_selection_range (tree_view, - start_tree, start_node, - end_tree, end_node, TRUE, FALSE, FALSE); } - else if (_pspp_rbtree_node_find_offset (start_tree, start_node) < - _pspp_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node)) + else if (start_node < tree_view->priv->rubber_band_start_node) { /* New node is above the old one; selection became bigger */ pspp_sheet_view_update_rubber_band_selection_range (tree_view, - start_tree, start_node, - tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node, TRUE, FALSE, TRUE); } - else if (_pspp_rbtree_node_find_offset (start_tree, start_node) > - _pspp_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node)) + else if (start_node > tree_view->priv->rubber_band_start_node) { /* New node is below the old one; selection became smaller */ pspp_sheet_view_update_rubber_band_selection_range (tree_view, - tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node, - start_tree, start_node, FALSE, FALSE, TRUE); } - tree_view->priv->rubber_band_start_tree = start_tree; tree_view->priv->rubber_band_start_node = start_node; /* Next, handle the end area */ - if (!tree_view->priv->rubber_band_end_node) + if (tree_view->priv->rubber_band_end_node < 0) { - /* In the event this happens, start_node was also NULL; this case is + /* In the event this happens, start_node was also -1; this case is * handled above. */ } - else if (!end_node) + else if (end_node < 0) { /* Find the last node in the tree */ - _pspp_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1, - &end_tree, &end_node); + pspp_sheet_view_find_offset (tree_view, tree_view->priv->height - 1, + &end_node); /* Selection reached end of the tree */ pspp_sheet_view_update_rubber_band_selection_range (tree_view, - tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node, - end_tree, end_node, TRUE, TRUE, FALSE); } - else if (_pspp_rbtree_node_find_offset (end_tree, end_node) > - _pspp_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node)) + else if (end_node > tree_view->priv->rubber_band_end_node) { /* New node is below the old one; selection became bigger */ pspp_sheet_view_update_rubber_band_selection_range (tree_view, - tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node, - end_tree, end_node, TRUE, TRUE, FALSE); } - else if (_pspp_rbtree_node_find_offset (end_tree, end_node) < - _pspp_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node)) + else if (end_node < tree_view->priv->rubber_band_end_node) { /* New node is above the old one; selection became smaller */ pspp_sheet_view_update_rubber_band_selection_range (tree_view, - end_tree, end_node, - tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node, FALSE, TRUE, FALSE); } - tree_view->priv->rubber_band_end_tree = end_tree; tree_view->priv->rubber_band_end_node = end_node; } @@ -4022,6 +3490,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; @@ -4064,6 +3533,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); } @@ -4076,6 +3553,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; @@ -4115,17 +3593,25 @@ pspp_sheet_view_motion_bin_window (GtkWidget *widget, GdkEventMotion *event) { PsppSheetView *tree_view; - GtkRBTree *tree; - GtkRBNode *node; + int node; gint new_y; tree_view = (PsppSheetView *) widget; - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) return FALSE; if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START) { + GdkRectangle background_area, cell_area; + PsppSheetViewColumn *column; + + if (find_click (tree_view, event->x, event->y, &node, &column, + &background_area, &cell_area) + && tree_view->priv->focus_column == column + && tree_view->priv->press_start_node == node) + return FALSE; + gtk_grab_add (GTK_WIDGET (tree_view)); pspp_sheet_view_update_rubber_band (tree_view); @@ -4147,17 +3633,12 @@ pspp_sheet_view_motion_bin_window (GtkWidget *widget, if (new_y < 0) new_y = 0; - _pspp_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node); - - /* If we are currently pressing down a button, we don't want to prelight anything else. */ - if ((tree_view->priv->button_pressed_node != NULL) && - (tree_view->priv->button_pressed_node != node)) - node = NULL; + pspp_sheet_view_find_offset (tree_view, new_y, &node); tree_view->priv->event_last_x = event->x; tree_view->priv->event_last_y = event->y; - prelight_or_select (tree_view, tree, node, event->x, event->y); + prelight_or_select (tree_view, node, event->x, event->y); return TRUE; } @@ -4232,16 +3713,21 @@ draw_empty_focus (PsppSheetView *tree_view, GdkRectangle *clip_area) static void pspp_sheet_view_draw_grid_lines (PsppSheetView *tree_view, GdkEventExpose *event, - gint n_visible_columns) + gint n_visible_columns, + gint min_y, + gint max_y) { GList *list = tree_view->priv->columns; gint i = 0; gint current_x = 0; + gint height; if (tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_VERTICAL && tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_BOTH) return; + gdk_drawable_get_size (event->window, NULL, &height); + /* Only draw the lines for visible rows and columns */ for (list = tree_view->priv->columns; list; list = list->next, i++) { @@ -4256,10 +3742,12 @@ pspp_sheet_view_draw_grid_lines (PsppSheetView *tree_view, current_x += column->width; - gdk_draw_line (event->window, - tree_view->priv->grid_line_gc, - current_x - 1, 0, - current_x - 1, tree_view->priv->height); + if (current_x - 1 >= event->area.x + && current_x - 1 < event->area.x + event->area.width) + gdk_draw_line (event->window, + tree_view->priv->grid_line_gc[GTK_WIDGET(tree_view)->state], + current_x - 1, min_y, + current_x - 1, max_y - min_y); } } @@ -4275,13 +3763,10 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, { PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget); GtkTreePath *path; - GtkRBTree *tree; GList *list; - GtkRBNode *node; - GtkRBNode *cursor = NULL; - GtkRBTree *cursor_tree = NULL; - GtkRBNode *drag_highlight = NULL; - GtkRBTree *drag_highlight_tree = NULL; + int node; + int cursor = -1; + int drag_highlight = -1; GtkTreeIter iter; gint new_y; gint y_offset, cell_offset; @@ -4290,8 +3775,6 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, GdkRectangle background_area; GdkRectangle cell_area; guint flags; - gint highlight_x; - gint expander_cell_width; gint bin_window_width; gint bin_window_height; GtkTreePath *cursor_path; @@ -4304,11 +3787,10 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, gboolean has_special_cell; gboolean rtl; gint n_visible_columns; - gint pointer_x, pointer_y; gint grid_line_width; - gboolean got_pointer = FALSE; gboolean row_ending_details; gboolean draw_vgrid_lines, draw_hgrid_lines; + gint min_y, max_y; rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL); @@ -4320,7 +3802,7 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, "row-ending-details", &row_ending_details, NULL); - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) { draw_empty_focus (tree_view, &event->area); return TRUE; @@ -4336,7 +3818,7 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, if (new_y < 0) new_y = 0; - y_offset = -_pspp_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node); + y_offset = -pspp_sheet_view_find_offset (tree_view, new_y, &node); gdk_drawable_get_size (tree_view->priv->bin_window, &bin_window_width, &bin_window_height); @@ -4354,13 +3836,11 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, bin_window_height - tree_view->priv->height); } - if (node == NULL) + if (node < 0) return TRUE; /* find the path for the node */ - path = _pspp_sheet_view_find_path ((PsppSheetView *)widget, - tree, - node); + path = _pspp_sheet_view_find_path ((PsppSheetView *)widget, node); gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); @@ -4374,15 +3854,14 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); if (cursor_path) - _pspp_sheet_view_find_node (tree_view, cursor_path, - &cursor_tree, &cursor); + _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor); if (tree_view->priv->drag_dest_row) drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row); if (drag_dest_path) _pspp_sheet_view_find_node (tree_view, drag_dest_path, - &drag_highlight_tree, &drag_highlight); + &drag_highlight); draw_vgrid_lines = tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_VERTICAL @@ -4419,51 +3898,52 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, * order, drawing each successive node. */ + min_y = y_offset; do { gboolean parity; - gboolean is_separator = FALSE; gboolean is_first = FALSE; gboolean is_last = FALSE; - - is_separator = row_is_separator (tree_view, &iter, NULL); + gboolean done = FALSE; + gboolean selected; - max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)); + max_height = ROW_HEIGHT (tree_view); cell_offset = 0; - highlight_x = 0; /* should match x coord of first cell */ - expander_cell_width = 0; background_area.y = y_offset + event->area.y; background_area.height = max_height; + max_y = background_area.y + max_height; flags = 0; - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_PRELIT)) + if (node == tree_view->priv->prelight_node) flags |= GTK_CELL_RENDERER_PRELIT; - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SELECTED)) - flags |= GTK_CELL_RENDERER_SELECTED; + selected = pspp_sheet_view_node_is_selected (tree_view, node); - parity = _pspp_rbtree_node_find_parity (tree, node); - - /* we *need* to set cell data on all cells before the call - * to _has_special_cell, else _has_special_cell() does not - * return a correct value. - */ - for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns)); - list; - list = (rtl ? list->prev : list->next)) - { - PsppSheetViewColumn *column = list->data; - pspp_sheet_view_column_cell_set_cell_data (column, - tree_view->priv->model, - &iter, - PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_PARENT), - node->children?TRUE:FALSE); - } - - has_special_cell = pspp_sheet_view_has_special_cell (tree_view); + parity = node % 2; + + if (tree_view->priv->special_cells == PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT) + { + /* we *need* to set cell data on all cells before the call + * to _has_special_cell, else _has_special_cell() does not + * return a correct value. + */ + for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns)); + list; + list = (rtl ? list->prev : list->next)) + { + PsppSheetViewColumn *column = list->data; + pspp_sheet_view_column_cell_set_cell_data (column, + tree_view->priv->model, + &iter); + } + + has_special_cell = pspp_sheet_view_has_special_cell (tree_view); + } + else + has_special_cell = tree_view->priv->special_cells == PSPP_SHEET_VIEW_SPECIAL_CELLS_YES; for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns)); list; @@ -4471,11 +3951,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) { @@ -4483,6 +3969,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 @@ -4533,10 +4024,8 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, } pspp_sheet_view_column_cell_set_cell_data (column, - tree_view->priv->model, - &iter, - PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_PARENT), - node->children?TRUE:FALSE); + tree_view->priv->model, + &iter); /* Select the detail for drawing the cell. relevant * factors are parity, sortedness, and whether to @@ -4639,166 +4128,27 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, { if (background_area.y > 0) gdk_draw_line (event->window, - tree_view->priv->grid_line_gc, + tree_view->priv->grid_line_gc[widget->state], background_area.x, background_area.y, background_area.x + background_area.width, background_area.y); if (y_offset + max_height >= event->area.height) gdk_draw_line (event->window, - tree_view->priv->grid_line_gc, + tree_view->priv->grid_line_gc[widget->state], background_area.x, background_area.y + max_height, background_area.x + background_area.width, background_area.y + max_height); } - if (pspp_sheet_view_is_expander_column (tree_view, column)) - { - if (!rtl) - cell_area.x += (depth - 1) * tree_view->priv->level_indentation; - cell_area.width -= (depth - 1) * tree_view->priv->level_indentation; - - if (TREE_VIEW_DRAW_EXPANDERS(tree_view)) - { - if (!rtl) - cell_area.x += depth * tree_view->priv->expander_size; - cell_area.width -= depth * tree_view->priv->expander_size; - } - - /* If we have an expander column, the highlight underline - * starts with that column, so that it indicates which - * level of the tree we're dropping at. - */ - highlight_x = cell_area.x; - expander_cell_width = cell_area.width; - - if (is_separator) - gtk_paint_hline (widget->style, - event->window, - state, - &cell_area, - widget, - NULL, - cell_area.x, - cell_area.x + cell_area.width, - cell_area.y + cell_area.height / 2); - else - _pspp_sheet_view_column_cell_render (column, - event->window, - &background_area, - &cell_area, - &event->area, - flags); - if (TREE_VIEW_DRAW_EXPANDERS(tree_view) - && (node->flags & PSPP_RBNODE_IS_PARENT) == PSPP_RBNODE_IS_PARENT) - { - if (!got_pointer) - { - gdk_window_get_pointer (tree_view->priv->bin_window, - &pointer_x, &pointer_y, NULL); - got_pointer = TRUE; - } - - pspp_sheet_view_draw_arrow (PSPP_SHEET_VIEW (widget), - tree, - node, - pointer_x, pointer_y); - } - } - else - { - if (is_separator) - gtk_paint_hline (widget->style, - event->window, - state, - &cell_area, - widget, - NULL, - cell_area.x, - cell_area.x + cell_area.width, - cell_area.y + cell_area.height / 2); - else - _pspp_sheet_view_column_cell_render (column, - event->window, - &background_area, - &cell_area, - &event->area, - flags); - } - - if (pspp_sheet_view_is_expander_column (tree_view, column) && - tree_view->priv->tree_lines_enabled) - { - gint x = background_area.x; - gint mult = rtl ? -1 : 1; - gint y0 = background_area.y; - gint y1 = background_area.y + background_area.height/2; - gint y2 = background_area.y + background_area.height; - - if (rtl) - x += background_area.width - 1; - - if ((node->flags & PSPP_RBNODE_IS_PARENT) == PSPP_RBNODE_IS_PARENT - && depth > 1) - { - gdk_draw_line (event->window, - tree_view->priv->tree_line_gc, - x + tree_view->priv->expander_size * (depth - 1.5) * mult, - y1, - x + tree_view->priv->expander_size * (depth - 1.1) * mult, - y1); - } - else if (depth > 1) - { - gdk_draw_line (event->window, - tree_view->priv->tree_line_gc, - x + tree_view->priv->expander_size * (depth - 1.5) * mult, - y1, - x + tree_view->priv->expander_size * (depth - 0.5) * mult, - y1); - } - - if (depth > 1) - { - gint i; - GtkRBNode *tmp_node; - GtkRBTree *tmp_tree; - - if (!_pspp_rbtree_next (tree, node)) - gdk_draw_line (event->window, - tree_view->priv->tree_line_gc, - x + tree_view->priv->expander_size * (depth - 1.5) * mult, - y0, - x + tree_view->priv->expander_size * (depth - 1.5) * mult, - y1); - else - gdk_draw_line (event->window, - tree_view->priv->tree_line_gc, - x + tree_view->priv->expander_size * (depth - 1.5) * mult, - y0, - x + tree_view->priv->expander_size * (depth - 1.5) * mult, - y2); - - tmp_node = tree->parent_node; - tmp_tree = tree->parent_tree; - - for (i = depth - 2; i > 0; i--) - { - if (_pspp_rbtree_next (tmp_tree, tmp_node)) - gdk_draw_line (event->window, - tree_view->priv->tree_line_gc, - x + tree_view->priv->expander_size * (i - 0.5) * mult, - y0, - x + tree_view->priv->expander_size * (i - 0.5) * mult, - y2); - - tmp_node = tmp_tree->parent_node; - tmp_tree = tmp_tree->parent_tree; - } - } - } + _pspp_sheet_view_column_cell_render (column, + event->window, + &background_area, + &cell_area, + &event->area, + flags); - if (node == cursor && has_special_cell && + if (node == cursor && has_special_cell && ((column == tree_view->priv->focus_column && PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS) && gtk_widget_has_focus (widget)) || @@ -4815,13 +4165,27 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, cell_offset += column->width; } + if (cell_offset < event->area.x) + { + gtk_paint_flat_box (widget->style, + event->window, + GTK_STATE_NORMAL, + GTK_SHADOW_NONE, + &event->area, + widget, + "base", + cell_offset, + background_area.y, + event->area.x - cell_offset, + background_area.height); + } + if (node == drag_highlight) { /* Draw indicator for the drop */ gint highlight_y = -1; - GtkRBTree *tree = NULL; - GtkRBNode *node = NULL; + int node = -1; gint width; switch (tree_view->priv->drag_dest_pos) @@ -4838,9 +4202,9 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, case PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE: case PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER: - _pspp_sheet_view_find_node (tree_view, drag_dest_path, &tree, &node); + _pspp_sheet_view_find_node (tree_view, drag_dest_path, &node); - if (tree == NULL) + if (node < 0) break; gdk_drawable_get_size (tree_view->priv->bin_window, &width, NULL); @@ -4854,9 +4218,9 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, (is_first ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" ) : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )), - 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + 0, BACKGROUND_FIRST_PIXEL (tree_view, node) - focus_line_width / 2, - width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) + width, ROW_HEIGHT (tree_view) - focus_line_width + 1); else gtk_paint_focus (widget->style, @@ -4865,9 +4229,9 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, &event->area, widget, "treeview-drop-indicator", - 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + 0, BACKGROUND_FIRST_PIXEL (tree_view, node) - focus_line_width / 2, - width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) + width, ROW_HEIGHT (tree_view) - focus_line_width + 1); break; } @@ -4876,7 +4240,7 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, { gdk_draw_line (event->window, widget->style->fg_gc[gtk_widget_get_state (widget)], - rtl ? highlight_x + expander_cell_width : highlight_x, + 0, highlight_y, rtl ? 0 : bin_window_width, highlight_y); @@ -4903,13 +4267,13 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, if (draw_hgrid_lines) { - tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2; - tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width; + tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, node) + grid_line_width / 2; + tmp_height = ROW_HEIGHT (tree_view) - grid_line_width; } else { - tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); - tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)); + tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, node); + tmp_height = ROW_HEIGHT (tree_view); } if (row_ending_details) @@ -4935,67 +4299,28 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, } y_offset += max_height; - if (node->children) - { - GtkTreeIter parent = iter; - gboolean has_child; - tree = node->children; - node = tree->root; - - g_assert (node != tree->nil); - - while (node->left != tree->nil) - node = node->left; - has_child = gtk_tree_model_iter_children (tree_view->priv->model, - &iter, - &parent); - depth++; - - /* Sanity Check! */ - TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE); - } - else - { - gboolean done = FALSE; - - do - { - node = _pspp_rbtree_next (tree, node); - if (node != NULL) - { - gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter); - done = TRUE; + do + { + node = pspp_sheet_view_node_next (tree_view, node); + if (node >= 0) + { + gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter); + done = TRUE; - /* Sanity Check! */ - TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE); - } - else - { - GtkTreeIter parent_iter = iter; - gboolean has_parent; - - node = tree->parent_node; - tree = tree->parent_tree; - if (tree == NULL) - /* we should go to done to free some memory */ - goto done; - has_parent = gtk_tree_model_iter_parent (tree_view->priv->model, - &iter, - &parent_iter); - depth--; - - /* Sanity check */ - TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE); - } - } - while (!done); - } + /* Sanity Check! */ + TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE); + } + else + goto done; + } + while (!done); } while (y_offset < event->area.height); done: - pspp_sheet_view_draw_grid_lines (tree_view, event, n_visible_columns); + pspp_sheet_view_draw_grid_lines (tree_view, event, n_visible_columns, + min_y, max_y); if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE) { @@ -5023,7 +4348,7 @@ done: static gboolean pspp_sheet_view_expose (GtkWidget *widget, - GdkEventExpose *event) + GdkEventExpose *event) { PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget); @@ -5052,20 +4377,47 @@ pspp_sheet_view_expose (GtkWidget *widget, else if (event->window == tree_view->priv->header_window) { + gint n_visible_columns; GList *list; - + + gtk_paint_flat_box (widget->style, + event->window, + GTK_STATE_NORMAL, + GTK_SHADOW_NONE, + &event->area, + widget, + "cell_odd", + event->area.x, + event->area.y, + event->area.width, + event->area.height); + for (list = tree_view->priv->columns; list != NULL; list = list->next) { PsppSheetViewColumn *column = list->data; - if (column == tree_view->priv->drag_column) + if (column == tree_view->priv->drag_column || !column->visible) continue; - if (column->visible) - gtk_container_propagate_expose (GTK_CONTAINER (tree_view), - column->button, - event); + if (span_intersects (column->allocation.x, column->allocation.width, + event->area.x, event->area.width) + && column->button != NULL) + gtk_container_propagate_expose (GTK_CONTAINER (tree_view), + column->button, event); } + + n_visible_columns = 0; + for (list = tree_view->priv->columns; list; list = list->next) + { + if (! PSPP_SHEET_VIEW_COLUMN (list->data)->visible) + continue; + n_visible_columns ++; + } + pspp_sheet_view_draw_grid_lines (tree_view, + event, + n_visible_columns, + event->area.y, + event->area.height); } else if (event->window == tree_view->priv->drag_window) { @@ -5323,7 +4675,7 @@ pspp_sheet_view_key_press (GtkWidget *widget, { PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (focus_column->data); - if (gtk_widget_has_focus (column->button)) + if (column->button && gtk_widget_has_focus (column->button)) break; } @@ -5352,7 +4704,7 @@ pspp_sheet_view_key_press (GtkWidget *widget, column->resized_width = 0; if (column->min_width == -1) - column->resized_width = MAX (column->button->requisition.width, + column->resized_width = MAX (column->button_request, column->resized_width); else column->resized_width = MAX (column->min_width, @@ -5544,15 +4896,14 @@ pspp_sheet_view_enter_notify (GtkWidget *widget, GdkEventCrossing *event) { PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget); - GtkRBTree *tree; - GtkRBNode *node; + int node; gint new_y; /* Sanity check it */ if (event->window != tree_view->priv->bin_window) return FALSE; - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) return FALSE; if (event->mode == GDK_CROSSING_GRAB || @@ -5565,14 +4916,12 @@ pspp_sheet_view_enter_notify (GtkWidget *widget, new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y); if (new_y < 0) new_y = 0; - _pspp_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node); + pspp_sheet_view_find_offset (tree_view, new_y, &node); tree_view->priv->event_last_x = event->x; tree_view->priv->event_last_y = event->y; - if ((tree_view->priv->button_pressed_node == NULL) || - (tree_view->priv->button_pressed_node == node)) - prelight_or_select (tree_view, tree, node, event->x, event->y); + prelight_or_select (tree_view, node, event->x, event->y); return TRUE; } @@ -5588,9 +4937,8 @@ pspp_sheet_view_leave_notify (GtkWidget *widget, tree_view = PSPP_SHEET_VIEW (widget); - if (tree_view->priv->prelight_node) + if (tree_view->priv->prelight_node >= 0) _pspp_sheet_view_queue_draw_node (tree_view, - tree_view->priv->prelight_tree, tree_view->priv->prelight_node, NULL); @@ -5598,7 +4946,7 @@ pspp_sheet_view_leave_notify (GtkWidget *widget, tree_view->priv->event_last_y = -10000; prelight_or_select (tree_view, - NULL, NULL, + -1, -1000, -1000); /* coords not possibly over an arrow */ return TRUE; @@ -5628,31 +4976,29 @@ pspp_sheet_view_focus_out (GtkWidget *widget, static void pspp_sheet_view_node_queue_redraw (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node) + int node) { gint y; - y = _pspp_rbtree_node_find_offset (tree, node) + y = pspp_sheet_view_node_find_offset (tree_view, node) - tree_view->priv->vadjustment->value + TREE_VIEW_HEADER_HEIGHT (tree_view); gtk_widget_queue_draw_area (GTK_WIDGET (tree_view), 0, y, GTK_WIDGET (tree_view)->allocation.width, - PSPP_RBNODE_GET_HEIGHT (node)); + tree_view->priv->fixed_height); } static gboolean node_is_visible (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node) + int node) { int y; int height; - y = _pspp_rbtree_node_find_offset (tree, node); - height = ROW_HEIGHT (tree_view, PSPP_RBNODE_GET_HEIGHT (node)); + y = pspp_sheet_view_node_find_offset (tree_view, node); + height = ROW_HEIGHT (tree_view); if (y >= tree_view->priv->vadjustment->value && y + height <= (tree_view->priv->vadjustment->value @@ -5662,12 +5008,10 @@ node_is_visible (PsppSheetView *tree_view, return FALSE; } -/* Returns TRUE if it updated the size - */ -static gboolean +/* Returns the row height. */ +static gint validate_row (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, + int node, GtkTreeIter *iter, GtkTreePath *path) { @@ -5677,22 +5021,13 @@ validate_row (PsppSheetView *tree_view, gint horizontal_separator; gint vertical_separator; gint focus_line_width; - gint depth = gtk_tree_path_get_depth (path); gboolean retval = FALSE; - gboolean is_separator = FALSE; gboolean draw_vgrid_lines, draw_hgrid_lines; gint focus_pad; gint grid_line_width; gboolean wide_separators; gint separator_height; - /* double check the row needs validating */ - if (! PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_INVALID) && - ! PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_COLUMN_INVALID)) - return FALSE; - - is_separator = row_is_separator (tree_view, iter, NULL); - gtk_widget_style_get (GTK_WIDGET (tree_view), "focus-padding", &focus_pad, "focus-line-width", &focus_line_width, @@ -5730,39 +5065,15 @@ validate_row (PsppSheetView *tree_view, if (! column->visible) continue; - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_COLUMN_INVALID) && !column->dirty) - continue; - - pspp_sheet_view_column_cell_set_cell_data (column, tree_view->priv->model, iter, - PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_PARENT), - node->children?TRUE:FALSE); + pspp_sheet_view_column_cell_set_cell_data (column, tree_view->priv->model, iter); pspp_sheet_view_column_cell_get_size (column, NULL, NULL, NULL, &tmp_width, &tmp_height); - if (!is_separator) - { - tmp_height += vertical_separator; - height = MAX (height, tmp_height); - height = MAX (height, tree_view->priv->expander_size); - } - else - { - if (wide_separators) - height = separator_height + 2 * focus_pad; - else - height = 2 + 2 * focus_pad; - } - - if (pspp_sheet_view_is_expander_column (tree_view, column)) - { - tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation; + tmp_height += vertical_separator; + height = MAX (height, tmp_height); - if (TREE_VIEW_DRAW_EXPANDERS (tree_view)) - tmp_width += depth * tree_view->priv->expander_size; - } - else - tmp_width = tmp_width + horizontal_separator; + tmp_width = tmp_width + horizontal_separator; if (draw_vgrid_lines) { @@ -5782,15 +5093,8 @@ validate_row (PsppSheetView *tree_view, if (draw_hgrid_lines) height += grid_line_width; - if (height != PSPP_RBNODE_GET_HEIGHT (node)) - { - retval = TRUE; - _pspp_rbtree_node_set_height (tree, node, height); - } - _pspp_rbtree_node_mark_valid (tree, node); tree_view->priv->post_validation_flag = TRUE; - - return retval; + return height; } @@ -5800,19 +5104,16 @@ validate_visible_area (PsppSheetView *tree_view) GtkTreePath *path = NULL; GtkTreePath *above_path = NULL; GtkTreeIter iter; - GtkRBTree *tree = NULL; - GtkRBNode *node = NULL; - gboolean need_redraw = FALSE; + int node = -1; gboolean size_changed = FALSE; gint total_height; gint area_above = 0; gint area_below = 0; - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) return; - if (! PSPP_RBNODE_FLAG_SET (tree_view->priv->tree->root, PSPP_RBNODE_DESCENDANTS_INVALID) && - tree_view->priv->scroll_to_path == NULL) + if (tree_view->priv->scroll_to_path == NULL) return; total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view); @@ -5820,248 +5121,120 @@ validate_visible_area (PsppSheetView *tree_view) if (total_height == 0) return; - /* First, we check to see if we need to scroll anywhere - */ - if (tree_view->priv->scroll_to_path) + path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path); + if (path) { - path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path); - if (path && !_pspp_sheet_view_find_node (tree_view, path, &tree, &node)) - { - /* we are going to scroll, and will update dy */ - gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_INVALID) || - PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_COLUMN_INVALID)) - { - _pspp_sheet_view_queue_draw_node (tree_view, tree, node, NULL); - if (validate_row (tree_view, tree, node, &iter, path)) - size_changed = TRUE; - } + /* we are going to scroll, and will update dy */ + _pspp_sheet_view_find_node (tree_view, path, &node); + gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - if (tree_view->priv->scroll_to_use_align) - { - gint height = ROW_HEIGHT (tree_view, PSPP_RBNODE_GET_HEIGHT (node)); - area_above = (total_height - height) * - tree_view->priv->scroll_to_row_align; - area_below = total_height - area_above - height; - area_above = MAX (area_above, 0); - area_below = MAX (area_below, 0); - } - else - { - /* two cases: - * 1) row not visible - * 2) row visible - */ - gint dy; - gint height = ROW_HEIGHT (tree_view, PSPP_RBNODE_GET_HEIGHT (node)); + if (tree_view->priv->scroll_to_use_align) + { + gint height = ROW_HEIGHT (tree_view); + area_above = (total_height - height) * + tree_view->priv->scroll_to_row_align; + area_below = total_height - area_above - height; + area_above = MAX (area_above, 0); + area_below = MAX (area_below, 0); + } + else + { + /* two cases: + * 1) row not visible + * 2) row visible + */ + gint dy; + gint height = ROW_HEIGHT (tree_view); - dy = _pspp_rbtree_node_find_offset (tree, node); + dy = pspp_sheet_view_node_find_offset (tree_view, node); - if (dy >= tree_view->priv->vadjustment->value && - dy + height <= (tree_view->priv->vadjustment->value - + tree_view->priv->vadjustment->page_size)) - { - /* row visible: keep the row at the same position */ - area_above = dy - tree_view->priv->vadjustment->value; - area_below = (tree_view->priv->vadjustment->value + - tree_view->priv->vadjustment->page_size) - - dy - height; - } - else - { - /* row not visible */ - if (dy >= 0 - && dy + height <= tree_view->priv->vadjustment->page_size) - { - /* row at the beginning -- fixed */ - area_above = dy; - area_below = tree_view->priv->vadjustment->page_size - - area_above - height; - } - else if (dy >= (tree_view->priv->vadjustment->upper - - tree_view->priv->vadjustment->page_size)) - { - /* row at the end -- fixed */ - area_above = dy - (tree_view->priv->vadjustment->upper - - tree_view->priv->vadjustment->page_size); - area_below = tree_view->priv->vadjustment->page_size - - area_above - height; - - if (area_below < 0) - { - area_above = tree_view->priv->vadjustment->page_size - height; - area_below = 0; - } - } - else - { - /* row somewhere in the middle, bring it to the top - * of the view - */ - area_above = 0; - area_below = total_height - height; - } - } - } - } - else - /* the scroll to isn't valid; ignore it. - */ - { - if (tree_view->priv->scroll_to_path && !path) - { - gtk_tree_row_reference_free (tree_view->priv->scroll_to_path); - tree_view->priv->scroll_to_path = NULL; - } - if (path) - gtk_tree_path_free (path); - path = NULL; - } + if (dy >= tree_view->priv->vadjustment->value && + dy + height <= (tree_view->priv->vadjustment->value + + tree_view->priv->vadjustment->page_size)) + { + /* row visible: keep the row at the same position */ + area_above = dy - tree_view->priv->vadjustment->value; + area_below = (tree_view->priv->vadjustment->value + + tree_view->priv->vadjustment->page_size) + - dy - height; + } + else + { + /* row not visible */ + if (dy >= 0 + && dy + height <= tree_view->priv->vadjustment->page_size) + { + /* row at the beginning -- fixed */ + area_above = dy; + area_below = tree_view->priv->vadjustment->page_size + - area_above - height; + } + else if (dy >= (tree_view->priv->vadjustment->upper - + tree_view->priv->vadjustment->page_size)) + { + /* row at the end -- fixed */ + area_above = dy - (tree_view->priv->vadjustment->upper - + tree_view->priv->vadjustment->page_size); + area_below = tree_view->priv->vadjustment->page_size - + area_above - height; + + if (area_below < 0) + { + area_above = tree_view->priv->vadjustment->page_size - height; + area_below = 0; + } + } + else + { + /* row somewhere in the middle, bring it to the top + * of the view + */ + area_above = 0; + area_below = total_height - height; + } + } + } } - - /* We didn't have a scroll_to set, so we just handle things normally - */ - if (path == NULL) + else + /* the scroll to isn't valid; ignore it. + */ { - gint offset; - - offset = _pspp_rbtree_find_offset (tree_view->priv->tree, - TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0), - &tree, &node); - if (node == NULL) - { - /* In this case, nothing has been validated */ - path = gtk_tree_path_new_first (); - _pspp_sheet_view_find_node (tree_view, path, &tree, &node); - } - else - { - path = _pspp_sheet_view_find_path (tree_view, tree, node); - total_height += offset; - } - - gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_INVALID) || - PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_COLUMN_INVALID)) - { - _pspp_sheet_view_queue_draw_node (tree_view, tree, node, NULL); - if (validate_row (tree_view, tree, node, &iter, path)) - size_changed = TRUE; - } - area_above = 0; - area_below = total_height - ROW_HEIGHT (tree_view, PSPP_RBNODE_GET_HEIGHT (node)); + gtk_tree_row_reference_free (tree_view->priv->scroll_to_path); + tree_view->priv->scroll_to_path = NULL; + return; } above_path = gtk_tree_path_copy (path); - /* if we do not validate any row above the new top_row, we will make sure - * that the row immediately above top_row has been validated. (if we do not - * do this, _pspp_rbtree_find_offset will find the row above top_row, because - * when invalidated that row's height will be zero. and this will mess up - * scrolling). - */ - if (area_above == 0) - { - GtkRBTree *tmptree; - GtkRBNode *tmpnode; - - _pspp_sheet_view_find_node (tree_view, above_path, &tmptree, &tmpnode); - _pspp_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode); - - if (tmpnode) - { - GtkTreePath *tmppath; - GtkTreeIter tmpiter; - - tmppath = _pspp_sheet_view_find_path (tree_view, tmptree, tmpnode); - gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath); - - if (PSPP_RBNODE_FLAG_SET (tmpnode, PSPP_RBNODE_INVALID) || - PSPP_RBNODE_FLAG_SET (tmpnode, PSPP_RBNODE_COLUMN_INVALID)) - { - _pspp_sheet_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL); - if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath)) - size_changed = TRUE; - } - - gtk_tree_path_free (tmppath); - } - } - /* Now, we walk forwards and backwards, measuring rows. Unfortunately, * backwards is much slower then forward, as there is no iter_prev function. * We go forwards first in case we run out of tree. Then we go backwards to * fill out the top. */ - while (node && area_below > 0) + while (node >= 0 && area_below > 0) { - if (node->children) - { - GtkTreeIter parent = iter; - gboolean has_child; - - tree = node->children; - node = tree->root; - - g_assert (node != tree->nil); - - while (node->left != tree->nil) - node = node->left; - has_child = gtk_tree_model_iter_children (tree_view->priv->model, - &iter, - &parent); - TREE_VIEW_INTERNAL_ASSERT_VOID (has_child); - gtk_tree_path_down (path); - } - else - { - gboolean done = FALSE; - do - { - node = _pspp_rbtree_next (tree, node); - if (node != NULL) - { - gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter); - done = TRUE; - gtk_tree_path_next (path); + gboolean done = FALSE; + do + { + node = pspp_sheet_view_node_next (tree_view, node); + if (node >= 0) + { + gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter); + done = TRUE; + gtk_tree_path_next (path); - /* Sanity Check! */ - TREE_VIEW_INTERNAL_ASSERT_VOID (has_next); - } - else - { - GtkTreeIter parent_iter = iter; - gboolean has_parent; - - node = tree->parent_node; - tree = tree->parent_tree; - if (tree == NULL) - break; - has_parent = gtk_tree_model_iter_parent (tree_view->priv->model, - &iter, - &parent_iter); - gtk_tree_path_up (path); - - /* Sanity check */ - TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent); - } - } - while (!done); - } + /* Sanity Check! */ + TREE_VIEW_INTERNAL_ASSERT_VOID (has_next); + } + else + break; + } + while (!done); - if (!node) + if (node < 0) break; - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_INVALID) || - PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_COLUMN_INVALID)) - { - _pspp_sheet_view_queue_draw_node (tree_view, tree, node, NULL); - if (validate_row (tree_view, tree, node, &iter, path)) - size_changed = TRUE; - } - - area_below -= ROW_HEIGHT (tree_view, PSPP_RBNODE_GET_HEIGHT (node)); + area_below -= ROW_HEIGHT (tree_view); } gtk_tree_path_free (path); @@ -6070,12 +5243,12 @@ validate_visible_area (PsppSheetView *tree_view) if (area_below > 0) area_above += area_below; - _pspp_sheet_view_find_node (tree_view, above_path, &tree, &node); + _pspp_sheet_view_find_node (tree_view, above_path, &node); /* We walk backwards */ while (area_above > 0) { - _pspp_rbtree_prev_full (tree, node, &tree, &node); + node = pspp_sheet_view_node_prev (tree_view, node); /* Always find the new path in the tree. We cannot just assume * a gtk_tree_path_prev() is enough here, as there might be children @@ -6086,49 +5259,22 @@ validate_visible_area (PsppSheetView *tree_view) * iter_prev). */ - if (node == NULL) + if (node < 0) break; gtk_tree_path_free (above_path); - above_path = _pspp_sheet_view_find_path (tree_view, tree, node); + above_path = _pspp_sheet_view_find_path (tree_view, node); gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path); - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_INVALID) || - PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_COLUMN_INVALID)) - { - _pspp_sheet_view_queue_draw_node (tree_view, tree, node, NULL); - if (validate_row (tree_view, tree, node, &iter, above_path)) - size_changed = TRUE; - } - area_above -= ROW_HEIGHT (tree_view, PSPP_RBNODE_GET_HEIGHT (node)); + area_above -= ROW_HEIGHT (tree_view); } - /* if we scrolled to a path, we need to set the dy here, + /* set the dy here to scroll to the path, * and sync the top row accordingly */ - if (tree_view->priv->scroll_to_path) - { - pspp_sheet_view_set_top_row (tree_view, above_path, -area_above); - pspp_sheet_view_top_row_to_dy (tree_view); - - need_redraw = TRUE; - } - else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size) - { - /* when we are not scrolling, we should never set dy to something - * else than zero. we update top_row to be in sync with dy = 0. - */ - gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0); - pspp_sheet_view_dy_to_top_row (tree_view); - } - else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height) - { - gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size); - pspp_sheet_view_dy_to_top_row (tree_view); - } - else - pspp_sheet_view_top_row_to_dy (tree_view); + pspp_sheet_view_set_top_row (tree_view, above_path, -area_above); + pspp_sheet_view_top_row_to_dy (tree_view); /* update width/height and queue a resize */ if (size_changed) @@ -6147,11 +5293,8 @@ validate_visible_area (PsppSheetView *tree_view) gtk_widget_queue_resize (GTK_WIDGET (tree_view)); } - if (tree_view->priv->scroll_to_path) - { - gtk_tree_row_reference_free (tree_view->priv->scroll_to_path); - tree_view->priv->scroll_to_path = NULL; - } + gtk_tree_row_reference_free (tree_view->priv->scroll_to_path); + tree_view->priv->scroll_to_path = NULL; if (above_path) gtk_tree_path_free (above_path); @@ -6160,14 +5303,16 @@ validate_visible_area (PsppSheetView *tree_view) { tree_view->priv->scroll_to_column = NULL; } - if (need_redraw) - gtk_widget_queue_draw (GTK_WIDGET (tree_view)); + gtk_widget_queue_draw (GTK_WIDGET (tree_view)); } static void initialize_fixed_height_mode (PsppSheetView *tree_view) { - if (!tree_view->priv->tree) + if (!tree_view->priv->row_count) + return; + + if (tree_view->priv->fixed_height_set) return; if (tree_view->priv->fixed_height < 0) @@ -6175,24 +5320,17 @@ initialize_fixed_height_mode (PsppSheetView *tree_view) GtkTreeIter iter; GtkTreePath *path; - GtkRBTree *tree = NULL; - GtkRBNode *node = NULL; - - tree = tree_view->priv->tree; - node = tree->root; + int node = 0; - path = _pspp_sheet_view_find_path (tree_view, tree, node); + path = _pspp_sheet_view_find_path (tree_view, node); gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - validate_row (tree_view, tree, node, &iter, path); + tree_view->priv->fixed_height = validate_row (tree_view, node, &iter, path); gtk_tree_path_free (path); - tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, PSPP_RBNODE_GET_HEIGHT (node)); + g_object_notify (G_OBJECT (tree_view), "fixed-height"); } - - _pspp_rbtree_set_fixed_height (tree_view->priv->tree, - tree_view->priv->fixed_height, TRUE); } /* Our strategy for finding nodes to validate is a little convoluted. We find @@ -6202,202 +5340,36 @@ initialize_fixed_height_mode (PsppSheetView *tree_view) */ static gboolean -do_validate_rows (PsppSheetView *tree_view, gboolean queue_resize) +validate_rows_handler (PsppSheetView *tree_view) { - GtkRBTree *tree = NULL; - GtkRBNode *node = NULL; - gboolean validated_area = FALSE; - gint retval = TRUE; - GtkTreePath *path = NULL; - GtkTreeIter iter; - GTimer *timer; - gint i = 0; - - gint prev_height = -1; - gboolean fixed_height = TRUE; - - g_assert (tree_view); - - if (tree_view->priv->tree == NULL) - return FALSE; - - if (tree_view->priv->fixed_height_mode) + initialize_fixed_height_mode (tree_view); + if (tree_view->priv->validate_rows_timer) { - if (tree_view->priv->fixed_height < 0) - initialize_fixed_height_mode (tree_view); - - return FALSE; + g_source_remove (tree_view->priv->validate_rows_timer); + tree_view->priv->validate_rows_timer = 0; } - timer = g_timer_new (); - g_timer_start (timer); - - do - { - if (! PSPP_RBNODE_FLAG_SET (tree_view->priv->tree->root, PSPP_RBNODE_DESCENDANTS_INVALID)) - { - retval = FALSE; - goto done; - } - - if (path != NULL) - { - node = _pspp_rbtree_next (tree, node); - if (node != NULL) - { - TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE); - gtk_tree_path_next (path); - } - else - { - gtk_tree_path_free (path); - path = NULL; - } - } - - if (path == NULL) - { - tree = tree_view->priv->tree; - node = tree_view->priv->tree->root; - - g_assert (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_DESCENDANTS_INVALID)); - - do - { - if (node->left != tree->nil && - PSPP_RBNODE_FLAG_SET (node->left, PSPP_RBNODE_DESCENDANTS_INVALID)) - { - node = node->left; - } - else if (node->right != tree->nil && - PSPP_RBNODE_FLAG_SET (node->right, PSPP_RBNODE_DESCENDANTS_INVALID)) - { - node = node->right; - } - else if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_INVALID) || - PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_COLUMN_INVALID)) - { - break; - } - else if (node->children != NULL) - { - tree = node->children; - node = tree->root; - } - else - /* RBTree corruption! All bad */ - g_assert_not_reached (); - } - while (TRUE); - path = _pspp_sheet_view_find_path (tree_view, tree, node); - gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - } - - validated_area = validate_row (tree_view, tree, node, &iter, path) || - validated_area; - - if (!tree_view->priv->fixed_height_check) - { - gint height; - - height = ROW_HEIGHT (tree_view, PSPP_RBNODE_GET_HEIGHT (node)); - if (prev_height < 0) - prev_height = height; - else if (prev_height != height) - fixed_height = FALSE; - } - - i++; - } - while (g_timer_elapsed (timer, NULL) < PSPP_SHEET_VIEW_TIME_MS_PER_IDLE / 1000.); - - if (!tree_view->priv->fixed_height_check) - { - if (fixed_height) - _pspp_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE); - - tree_view->priv->fixed_height_check = 1; - } - - done: - if (validated_area) - { - GtkRequisition requisition; - /* We temporarily guess a size, under the assumption that it will be the - * same when we get our next size_allocate. If we don't do this, we'll be - * in an inconsistent state when we call top_row_to_dy. */ - - gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition); - tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width); - tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height); - gtk_adjustment_changed (tree_view->priv->hadjustment); - gtk_adjustment_changed (tree_view->priv->vadjustment); - - if (queue_resize) - gtk_widget_queue_resize (GTK_WIDGET (tree_view)); - } - - if (path) gtk_tree_path_free (path); - g_timer_destroy (timer); - - return retval; -} - -static gboolean -validate_rows (PsppSheetView *tree_view) -{ - gboolean retval; - - retval = do_validate_rows (tree_view, TRUE); - - if (! retval && tree_view->priv->validate_rows_timer) - { - g_source_remove (tree_view->priv->validate_rows_timer); - tree_view->priv->validate_rows_timer = 0; - } - - return retval; -} - -static gboolean -validate_rows_handler (PsppSheetView *tree_view) -{ - gboolean retval; - - retval = do_validate_rows (tree_view, TRUE); - if (! retval && tree_view->priv->validate_rows_timer) - { - g_source_remove (tree_view->priv->validate_rows_timer); - tree_view->priv->validate_rows_timer = 0; - } - - return retval; -} + return FALSE; +} static gboolean do_presize_handler (PsppSheetView *tree_view) { - if (tree_view->priv->mark_rows_col_dirty) - { - if (tree_view->priv->tree) - _pspp_rbtree_column_invalid (tree_view->priv->tree); - tree_view->priv->mark_rows_col_dirty = FALSE; - } + GtkRequisition requisition; + validate_visible_area (tree_view); tree_view->priv->presize_handler_timer = 0; - if (tree_view->priv->fixed_height_mode) - { - GtkRequisition requisition; + if (! gtk_widget_get_realized (GTK_WIDGET (tree_view))) + return FALSE; - gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition); + gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition); - tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width); - tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height); - gtk_adjustment_changed (tree_view->priv->hadjustment); - gtk_adjustment_changed (tree_view->priv->vadjustment); - gtk_widget_queue_resize (GTK_WIDGET (tree_view)); - } + tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width); + tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height); + gtk_adjustment_changed (tree_view->priv->hadjustment); + gtk_adjustment_changed (tree_view->priv->vadjustment); + gtk_widget_queue_resize (GTK_WIDGET (tree_view)); return FALSE; } @@ -6483,26 +5455,25 @@ pspp_sheet_view_dy_to_top_row (PsppSheetView *tree_view) { gint offset; GtkTreePath *path; - GtkRBTree *tree; - GtkRBNode *node; + int node; - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) { pspp_sheet_view_set_top_row (tree_view, NULL, 0); } else { - offset = _pspp_rbtree_find_offset (tree_view->priv->tree, - tree_view->priv->dy, - &tree, &node); + offset = pspp_sheet_view_find_offset (tree_view, + tree_view->priv->dy, + &node); - if (tree == NULL) + if (node < 0) { pspp_sheet_view_set_top_row (tree_view, NULL, 0); } else { - path = _pspp_sheet_view_find_path (tree_view, tree, node); + path = _pspp_sheet_view_find_path (tree_view, node); pspp_sheet_view_set_top_row (tree_view, path, offset); gtk_tree_path_free (path); } @@ -6513,8 +5484,7 @@ static void pspp_sheet_view_top_row_to_dy (PsppSheetView *tree_view) { GtkTreePath *path; - GtkRBTree *tree; - GtkRBNode *node; + int node; int new_dy; /* Avoid recursive calls */ @@ -6527,14 +5497,14 @@ pspp_sheet_view_top_row_to_dy (PsppSheetView *tree_view) path = NULL; if (!path) - tree = NULL; + node = -1; else - _pspp_sheet_view_find_node (tree_view, path, &tree, &node); + _pspp_sheet_view_find_node (tree_view, path, &node); if (path) gtk_tree_path_free (path); - if (tree == NULL) + if (node < 0) { /* keep dy and set new toprow */ gtk_tree_row_reference_free (tree_view->priv->top_row); @@ -6545,15 +5515,14 @@ pspp_sheet_view_top_row_to_dy (PsppSheetView *tree_view) return; } - if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - < tree_view->priv->top_row_dy) + if (ROW_HEIGHT (tree_view) < tree_view->priv->top_row_dy) { /* new top row -- do NOT install the idle handler */ pspp_sheet_view_dy_to_top_row (tree_view); return; } - new_dy = _pspp_rbtree_node_find_offset (tree, node); + new_dy = pspp_sheet_view_node_find_offset (tree_view, node); new_dy += tree_view->priv->top_row_dy; if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height) @@ -6570,33 +5539,9 @@ pspp_sheet_view_top_row_to_dy (PsppSheetView *tree_view) void _pspp_sheet_view_install_mark_rows_col_dirty (PsppSheetView *tree_view) { - tree_view->priv->mark_rows_col_dirty = TRUE; - install_presize_handler (tree_view); } -/* - * This function works synchronously (due to the while (validate_rows...) - * loop). - * - * There was a check for column_type != PSPP_SHEET_VIEW_COLUMN_AUTOSIZE - * here. You now need to check that yourself. - */ -void -_pspp_sheet_view_column_autosize (PsppSheetView *tree_view, - PsppSheetViewColumn *column) -{ - g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); - g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column)); - - _pspp_sheet_view_column_cell_set_dirty (column, FALSE); - - do_presize_handler (tree_view); - while (validate_rows (tree_view)); - - gtk_widget_queue_resize (GTK_WIDGET (tree_view)); -} - /* Drag-and-drop */ static void @@ -6852,54 +5797,12 @@ check_model_dnd (GtkTreeModel *model, return TRUE; } -static void -remove_open_timeout (PsppSheetView *tree_view) -{ - if (tree_view->priv->open_dest_timeout != 0) - { - g_source_remove (tree_view->priv->open_dest_timeout); - tree_view->priv->open_dest_timeout = 0; - } -} - - -static gint -open_row_timeout (gpointer data) -{ - PsppSheetView *tree_view = data; - GtkTreePath *dest_path = NULL; - PsppSheetViewDropPosition pos; - gboolean result = FALSE; - - pspp_sheet_view_get_drag_dest_row (tree_view, - &dest_path, - &pos); - - if (dest_path && - (pos == PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER || - pos == PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE)) - { - pspp_sheet_view_expand_row (tree_view, dest_path, FALSE); - tree_view->priv->open_dest_timeout = 0; - - gtk_tree_path_free (dest_path); - } - else - { - if (dest_path) - gtk_tree_path_free (dest_path); - - result = TRUE; - } - - return result; -} - static gboolean 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) @@ -6944,7 +5847,6 @@ set_destination_row (PsppSheetView *tree_view, PSPP_SHEET_VIEW_DROP_BEFORE); remove_scroll_timeout (PSPP_SHEET_VIEW (widget)); - remove_open_timeout (PSPP_SHEET_VIEW (widget)); return FALSE; /* no longer a drop site */ } @@ -6964,8 +5866,6 @@ set_destination_row (PsppSheetView *tree_view, gint n_children; GtkTreeModel *model; - remove_open_timeout (tree_view); - /* the row got dropped on empty space, let's setup a special case */ @@ -7000,12 +5900,6 @@ set_destination_row (PsppSheetView *tree_view, &old_dest_path, &old_pos); - if (old_dest_path && - (gtk_tree_path_compare (path, old_dest_path) != 0 || - !(pos == PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER || - pos == PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE))) - remove_open_timeout (tree_view); - if (old_dest_path) gtk_tree_path_free (old_dest_path); @@ -7037,8 +5931,6 @@ out: else { /* can't drop here */ - remove_open_timeout (tree_view); - pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget), NULL, PSPP_SHEET_VIEW_DROP_BEFORE); @@ -7317,7 +6209,6 @@ pspp_sheet_view_drag_leave (GtkWidget *widget, PSPP_SHEET_VIEW_DROP_BEFORE); remove_scroll_timeout (PSPP_SHEET_VIEW (widget)); - remove_open_timeout (PSPP_SHEET_VIEW (widget)); } @@ -7357,8 +6248,7 @@ pspp_sheet_view_drag_motion (GtkWidget *widget, (pos == PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER || pos == PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE)) { - tree_view->priv->open_dest_timeout = - gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view); + /* Nothing. */ } else { @@ -7409,7 +6299,6 @@ pspp_sheet_view_drag_drop (GtkWidget *widget, model = pspp_sheet_view_get_model (tree_view); remove_scroll_timeout (PSPP_SHEET_VIEW (widget)); - remove_open_timeout (PSPP_SHEET_VIEW (widget)); di = get_info (tree_view); @@ -7664,6 +6553,9 @@ pspp_sheet_view_has_special_cell (PsppSheetView *tree_view) { GList *list; + if (tree_view->priv->special_cells != PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT) + return tree_view->priv->special_cells = PSPP_SHEET_VIEW_SPECIAL_CELLS_YES; + for (list = tree_view->priv->columns; list; list = list->next) { if (!((PsppSheetViewColumn *)list->data)->visible) @@ -7676,88 +6568,24 @@ pspp_sheet_view_has_special_cell (PsppSheetView *tree_view) } static void -column_sizing_notify (GObject *object, - GParamSpec *pspec, - gpointer data) -{ - PsppSheetViewColumn *c = PSPP_SHEET_VIEW_COLUMN (object); - - if (pspp_sheet_view_column_get_sizing (c) != PSPP_SHEET_VIEW_COLUMN_FIXED) - /* disable fixed height mode */ - g_object_set (data, "fixed-height-mode", FALSE, NULL); -} - -/** - * pspp_sheet_view_set_fixed_height_mode: - * @tree_view: a #PsppSheetView - * @enable: %TRUE to enable fixed height mode - * - * Enables or disables the fixed height mode of @tree_view. - * Fixed height mode speeds up #PsppSheetView by assuming that all - * rows have the same height. - * Only enable this option if all rows are the same height and all - * columns are of type %PSPP_SHEET_VIEW_COLUMN_FIXED. - * - * Since: 2.6 - **/ -void -pspp_sheet_view_set_fixed_height_mode (PsppSheetView *tree_view, - gboolean enable) +pspp_sheet_view_focus_column (PsppSheetView *tree_view, + PsppSheetViewColumn *focus_column, + gboolean clamp_column_visible) { - GList *l; - - enable = enable != FALSE; - - if (enable == tree_view->priv->fixed_height_mode) - return; - - if (!enable) - { - tree_view->priv->fixed_height_mode = 0; - tree_view->priv->fixed_height = -1; + g_return_if_fail (focus_column != NULL); - /* force a revalidation */ - install_presize_handler (tree_view); - } - else + tree_view->priv->focus_column = focus_column; + if (!focus_column->button) { - /* make sure all columns are of type FIXED */ - for (l = tree_view->priv->columns; l; l = l->next) - { - PsppSheetViewColumn *c = l->data; - - g_return_if_fail (pspp_sheet_view_column_get_sizing (c) == PSPP_SHEET_VIEW_COLUMN_FIXED); - } - - /* yes, we really have to do this is in a separate loop */ - for (l = tree_view->priv->columns; l; l = l->next) - g_signal_connect (l->data, "notify::sizing", - G_CALLBACK (column_sizing_notify), tree_view); - - tree_view->priv->fixed_height_mode = 1; - tree_view->priv->fixed_height = -1; - - if (tree_view->priv->tree) - initialize_fixed_height_mode (tree_view); + pspp_sheet_view_column_set_need_button (focus_column, TRUE); + g_return_if_fail (focus_column->button != NULL); } - g_object_notify (G_OBJECT (tree_view), "fixed-height-mode"); -} + if (GTK_CONTAINER (tree_view)->focus_child != focus_column->button) + gtk_widget_grab_focus (focus_column->button); -/** - * pspp_sheet_view_get_fixed_height_mode: - * @tree_view: a #PsppSheetView - * - * Returns whether fixed height mode is turned on for @tree_view. - * - * Return value: %TRUE if @tree_view is in fixed height mode - * - * Since: 2.6 - **/ -gboolean -pspp_sheet_view_get_fixed_height_mode (PsppSheetView *tree_view) -{ - return tree_view->priv->fixed_height_mode; + if (clamp_column_visible) + pspp_sheet_view_clamp_column_visible (tree_view, focus_column, FALSE); } /* Returns TRUE if the focus is within the headers, after the focus operation is @@ -7769,7 +6597,7 @@ pspp_sheet_view_header_focus (PsppSheetView *tree_view, gboolean clamp_column_visible) { GtkWidget *focus_child; - + PsppSheetViewColumn *focus_column; GList *last_column, *first_column; GList *tmp_list; gboolean rtl; @@ -7782,10 +6610,9 @@ pspp_sheet_view_header_focus (PsppSheetView *tree_view, first_column = tree_view->priv->columns; while (first_column) { - if (gtk_widget_get_can_focus (PSPP_SHEET_VIEW_COLUMN (first_column->data)->button) && - PSPP_SHEET_VIEW_COLUMN (first_column->data)->visible && - (PSPP_SHEET_VIEW_COLUMN (first_column->data)->clickable || - PSPP_SHEET_VIEW_COLUMN (first_column->data)->reorderable)) + PsppSheetViewColumn *c = PSPP_SHEET_VIEW_COLUMN (first_column->data); + + if (pspp_sheet_view_column_can_focus (c) && c->visible) break; first_column = first_column->next; } @@ -7798,10 +6625,9 @@ pspp_sheet_view_header_focus (PsppSheetView *tree_view, last_column = g_list_last (tree_view->priv->columns); while (last_column) { - if (gtk_widget_get_can_focus (PSPP_SHEET_VIEW_COLUMN (last_column->data)->button) && - PSPP_SHEET_VIEW_COLUMN (last_column->data)->visible && - (PSPP_SHEET_VIEW_COLUMN (last_column->data)->clickable || - PSPP_SHEET_VIEW_COLUMN (last_column->data)->reorderable)) + PsppSheetViewColumn *c = PSPP_SHEET_VIEW_COLUMN (last_column->data); + + if (pspp_sheet_view_column_can_focus (c) && c->visible) break; last_column = last_column->prev; } @@ -7818,12 +6644,13 @@ pspp_sheet_view_header_focus (PsppSheetView *tree_view, if (focus_child == NULL) { if (tree_view->priv->focus_column != NULL && - gtk_widget_get_can_focus (tree_view->priv->focus_column->button)) - focus_child = tree_view->priv->focus_column->button; + pspp_sheet_view_column_can_focus (tree_view->priv->focus_column)) + focus_column = tree_view->priv->focus_column; else - focus_child = PSPP_SHEET_VIEW_COLUMN (first_column->data)->button; - gtk_widget_grab_focus (focus_child); - break; + focus_column = first_column->data; + pspp_sheet_view_focus_column (tree_view, focus_column, + clamp_column_visible); + return TRUE; } return FALSE; @@ -7832,20 +6659,25 @@ pspp_sheet_view_header_focus (PsppSheetView *tree_view, if (focus_child == NULL) { if (tree_view->priv->focus_column != NULL) - focus_child = tree_view->priv->focus_column->button; + focus_column = tree_view->priv->focus_column; else if (dir == GTK_DIR_LEFT) - focus_child = PSPP_SHEET_VIEW_COLUMN (last_column->data)->button; + focus_column = last_column->data; else - focus_child = PSPP_SHEET_VIEW_COLUMN (first_column->data)->button; - gtk_widget_grab_focus (focus_child); - break; + focus_column = first_column->data; + pspp_sheet_view_focus_column (tree_view, focus_column, + clamp_column_visible); + return TRUE; } if (gtk_widget_child_focus (focus_child, dir)) { /* The focus moves inside the button. */ /* This is probably a great example of bad UI */ - break; + if (clamp_column_visible) + pspp_sheet_view_clamp_column_visible (tree_view, + tree_view->priv->focus_column, + FALSE); + return TRUE; } /* We need to move the focus among the row of buttons. */ @@ -7857,7 +6689,7 @@ pspp_sheet_view_header_focus (PsppSheetView *tree_view, || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))) { gtk_widget_error_bell (GTK_WIDGET (tree_view)); - break; + return TRUE; } while (tmp_list) @@ -7877,81 +6709,45 @@ pspp_sheet_view_header_focus (PsppSheetView *tree_view, column = tmp_list->data; if (column->button && column->visible && - gtk_widget_get_can_focus (column->button)) + pspp_sheet_view_column_can_focus (column)) { - focus_child = column->button; - gtk_widget_grab_focus (column->button); - break; + pspp_sheet_view_focus_column (tree_view, column, + clamp_column_visible); + return TRUE; } } - break; + return FALSE; + default: g_assert_not_reached (); break; } - /* if focus child is non-null, we assume it's been set to the current focus child - */ - if (focus_child) - { - for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next) - if (PSPP_SHEET_VIEW_COLUMN (tmp_list->data)->button == focus_child) - { - tree_view->priv->focus_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data); - break; - } - - if (clamp_column_visible) - { - pspp_sheet_view_clamp_column_visible (tree_view, - tree_view->priv->focus_column, - FALSE); - } - } - - return (focus_child != NULL); + return FALSE; } /* 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, GtkTreePath **path, gboolean search_forward, - GtkRBTree **new_tree, - GtkRBNode **new_node) + int *new_node) { - GtkRBTree *tree = NULL; - GtkRBNode *node = NULL; + /* XXX this function is trivial given that the sheetview doesn't support + separator rows */ + int node = -1; if (!path || !*path) return FALSE; - _pspp_sheet_view_find_node (tree_view, *path, &tree, &node); + _pspp_sheet_view_find_node (tree_view, *path, &node); - if (!tree || !node) + if (node < 0) return FALSE; - while (node && row_is_separator (tree_view, NULL, *path)) - { - if (search_forward) - _pspp_rbtree_next_full (tree, node, &tree, &node); - else - _pspp_rbtree_prev_full (tree, node, &tree, &node); - - if (*path) - gtk_tree_path_free (*path); - - if (node) - *path = _pspp_sheet_view_find_path (tree_view, tree, node); - else - *path = NULL; - } - - if (new_tree) - *new_tree = tree; - if (new_node) *new_node = node; @@ -8031,12 +6827,20 @@ pspp_sheet_view_style_set (GtkWidget *widget, if (gtk_widget_get_realized (widget)) { + gint i; + PsppSheetViewPrivate *priv = PSPP_SHEET_VIEW (widget)->priv; + gdk_window_set_back_pixmap (widget->window, NULL, FALSE); gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]); gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL); + for (i = 0; i < 5 ; ++i) + { + g_object_unref (priv->grid_line_gc[i]); + priv->grid_line_gc[i] = gdk_gc_new (widget->window); + gdk_gc_copy (priv->grid_line_gc[i], widget->style->text_aa_gc[i]); + } pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines); - pspp_sheet_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled); } gtk_widget_style_get (widget, @@ -8047,11 +6851,17 @@ pspp_sheet_view_style_set (GtkWidget *widget, for (list = tree_view->priv->columns; list; list = list->next) { column = list->data; - _pspp_sheet_view_column_cell_set_dirty (column, TRUE); + _pspp_sheet_view_column_cell_set_dirty (column); } tree_view->priv->fixed_height = -1; - _pspp_rbtree_mark_invalid (tree_view->priv->tree); + + /* Invalidate cached button style. */ + if (tree_view->priv->button_style) + { + g_object_unref (tree_view->priv->button_style); + tree_view->priv->button_style = NULL; + } gtk_widget_queue_resize (widget); } @@ -8151,7 +6961,7 @@ pspp_sheet_view_real_move_cursor (PsppSheetView *tree_view, step == GTK_MOVEMENT_PAGES || step == GTK_MOVEMENT_BUFFER_ENDS, FALSE); - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) return FALSE; if (!gtk_widget_has_focus (GTK_WIDGET (tree_view))) return FALSE; @@ -8272,10 +7082,8 @@ pspp_sheet_view_row_changed (GtkTreeModel *model, gpointer data) { PsppSheetView *tree_view = (PsppSheetView *)data; - GtkRBTree *tree; - GtkRBNode *node; + int node; gboolean free_path = FALSE; - GList *list; GtkTreePath *cursor_path; g_return_if_fail (path != NULL || iter != NULL); @@ -8300,45 +7108,16 @@ pspp_sheet_view_row_changed (GtkTreeModel *model, else if (iter == NULL) gtk_tree_model_get_iter (model, iter, path); - if (_pspp_sheet_view_find_node (tree_view, - path, - &tree, - &node)) - /* We aren't actually showing the node */ - goto done; - - if (tree == NULL) - goto done; + _pspp_sheet_view_find_node (tree_view, + path, + &node); - if (tree_view->priv->fixed_height_mode - && tree_view->priv->fixed_height >= 0) + if (node >= 0) { - _pspp_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height); if (gtk_widget_get_realized (GTK_WIDGET (tree_view))) - pspp_sheet_view_node_queue_redraw (tree_view, tree, node); - } - else - { - _pspp_rbtree_node_mark_invalid (tree, node); - for (list = tree_view->priv->columns; list; list = list->next) - { - PsppSheetViewColumn *column; - - column = list->data; - if (! column->visible) - continue; - - if (column->column_type == PSPP_SHEET_VIEW_COLUMN_AUTOSIZE) - { - _pspp_sheet_view_column_cell_set_dirty (column, TRUE); - } - } + pspp_sheet_view_node_queue_redraw (tree_view, node); } - - done: - if (!tree_view->priv->fixed_height_mode && - gtk_widget_get_realized (GTK_WIDGET (tree_view))) - install_presize_handler (tree_view); + if (free_path) gtk_tree_path_free (path); } @@ -8351,22 +7130,13 @@ pspp_sheet_view_row_inserted (GtkTreeModel *model, { PsppSheetView *tree_view = (PsppSheetView *) data; gint *indices; - GtkRBTree *tmptree, *tree; - GtkRBNode *tmpnode = NULL; - gint depth; - gint i = 0; - gint height; + int tmpnode = -1; + gint height = tree_view->priv->fixed_height; gboolean free_path = FALSE; gboolean node_visible = TRUE; g_return_if_fail (path != NULL || iter != NULL); - if (tree_view->priv->fixed_height_mode - && tree_view->priv->fixed_height >= 0) - height = tree_view->priv->fixed_height; - else - height = 0; - if (path == NULL) { path = gtk_tree_model_get_path (model, iter); @@ -8375,79 +7145,18 @@ pspp_sheet_view_row_inserted (GtkTreeModel *model, else if (iter == NULL) gtk_tree_model_get_iter (model, iter, path); - if (tree_view->priv->tree == NULL) - tree_view->priv->tree = _pspp_rbtree_new (); - - tmptree = tree = tree_view->priv->tree; + tree_view->priv->row_count = gtk_tree_model_iter_n_children (model, NULL); /* Update all row-references */ gtk_tree_row_reference_inserted (G_OBJECT (data), path); - depth = gtk_tree_path_get_depth (path); indices = gtk_tree_path_get_indices (path); + tmpnode = indices[0]; - /* First, find the parent tree */ - while (i < depth - 1) - { - if (tmptree == NULL) - { - /* We aren't showing the node */ - node_visible = FALSE; - goto done; - } - - tmpnode = _pspp_rbtree_find_count (tmptree, indices[i] + 1); - if (tmpnode == NULL) - { - g_warning ("A node was inserted with a parent that's not in the tree.\n" \ - "This possibly means that a GtkTreeModel inserted a child node\n" \ - "before the parent was inserted."); - goto done; - } - else if (!PSPP_RBNODE_FLAG_SET (tmpnode, PSPP_RBNODE_IS_PARENT)) - { - /* FIXME enforce correct behavior on model, probably */ - /* In theory, the model should have emitted has_child_toggled here. We - * try to catch it anyway, just to be safe, in case the model hasn't. - */ - GtkTreePath *tmppath = _pspp_sheet_view_find_path (tree_view, - tree, - tmpnode); - pspp_sheet_view_row_has_child_toggled (model, tmppath, NULL, data); - gtk_tree_path_free (tmppath); - goto done; - } - - tmptree = tmpnode->children; - tree = tmptree; - i++; - } - - if (tree == NULL) - { - node_visible = FALSE; - goto done; - } - - /* ref the node */ - gtk_tree_model_ref_node (tree_view->priv->model, iter); - if (indices[depth - 1] == 0) - { - tmpnode = _pspp_rbtree_find_count (tree, 1); - tmpnode = _pspp_rbtree_insert_before (tree, tmpnode, height, FALSE); - } - else - { - tmpnode = _pspp_rbtree_find_count (tree, indices[depth - 1]); - tmpnode = _pspp_rbtree_insert_after (tree, tmpnode, height, FALSE); - } + range_tower_insert0 (tree_view->priv->selected, tmpnode, 1); - done: if (height > 0) { - if (tree) - _pspp_rbtree_node_mark_valid (tree, tmpnode); - - if (node_visible && node_is_visible (tree_view, tree, tmpnode)) + if (node_visible && node_is_visible (tree_view, tmpnode)) gtk_widget_queue_resize (GTK_WIDGET (tree_view)); else gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view)); @@ -8458,132 +7167,24 @@ pspp_sheet_view_row_inserted (GtkTreeModel *model, gtk_tree_path_free (path); } -static void -pspp_sheet_view_row_has_child_toggled (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data) -{ - PsppSheetView *tree_view = (PsppSheetView *)data; - GtkTreeIter real_iter; - gboolean has_child; - GtkRBTree *tree; - GtkRBNode *node; - gboolean free_path = FALSE; - - g_return_if_fail (path != NULL || iter != NULL); - - if (iter) - real_iter = *iter; - - if (path == NULL) - { - path = gtk_tree_model_get_path (model, iter); - free_path = TRUE; - } - else if (iter == NULL) - gtk_tree_model_get_iter (model, &real_iter, path); - - if (_pspp_sheet_view_find_node (tree_view, - path, - &tree, - &node)) - /* We aren't actually showing the node */ - goto done; - - if (tree == NULL) - goto done; - - has_child = gtk_tree_model_iter_has_child (model, &real_iter); - /* Sanity check. - */ - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_PARENT) == has_child) - goto done; - - if (has_child) - PSPP_RBNODE_SET_FLAG (node, PSPP_RBNODE_IS_PARENT); - else - PSPP_RBNODE_UNSET_FLAG (node, PSPP_RBNODE_IS_PARENT); - - if (has_child && PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IS_LIST)) - { - PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_IS_LIST); - if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_SHOW_EXPANDERS)) - { - GList *list; - - for (list = tree_view->priv->columns; list; list = list->next) - if (PSPP_SHEET_VIEW_COLUMN (list->data)->visible) - { - PSPP_SHEET_VIEW_COLUMN (list->data)->dirty = TRUE; - _pspp_sheet_view_column_cell_set_dirty (PSPP_SHEET_VIEW_COLUMN (list->data), TRUE); - break; - } - } - gtk_widget_queue_resize (GTK_WIDGET (tree_view)); - } - else - { - _pspp_sheet_view_queue_draw_node (tree_view, tree, node, NULL); - } - - done: - if (free_path) - gtk_tree_path_free (path); -} - -static void -count_children_helper (GtkRBTree *tree, - GtkRBNode *node, - gpointer data) -{ - if (node->children) - _pspp_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data); - (*((gint *)data))++; -} - -static void -check_selection_helper (GtkRBTree *tree, - GtkRBNode *node, - gpointer data) -{ - gint *value = (gint *)data; - - *value = PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SELECTED); - - if (node->children && !*value) - _pspp_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data); -} - static void pspp_sheet_view_row_deleted (GtkTreeModel *model, GtkTreePath *path, gpointer data) { PsppSheetView *tree_view = (PsppSheetView *)data; - GtkRBTree *tree; - GtkRBNode *node; - GList *list; - gint selection_changed = FALSE; + int node; g_return_if_fail (path != NULL); gtk_tree_row_reference_deleted (G_OBJECT (data), path); - if (_pspp_sheet_view_find_node (tree_view, path, &tree, &node)) - return; + _pspp_sheet_view_find_node (tree_view, path, &node); - if (tree == NULL) + if (node < 0) return; - /* check if the selection has been changed */ - _pspp_rbtree_traverse (tree, node, G_POST_ORDER, - check_selection_helper, &selection_changed); - - for (list = tree_view->priv->columns; list; list = list->next) - if (((PsppSheetViewColumn *)list->data)->visible && - ((PsppSheetViewColumn *)list->data)->column_type == PSPP_SHEET_VIEW_COLUMN_AUTOSIZE) - _pspp_sheet_view_column_cell_set_dirty ((PsppSheetViewColumn *)list->data, TRUE); + range_tower_delete (tree_view->priv->selected, node, 1); /* Ensure we don't have a dangling pointer to a dead node */ ensure_unprelighted (tree_view); @@ -8591,28 +7192,13 @@ pspp_sheet_view_row_deleted (GtkTreeModel *model, /* Cancel editting if we've started */ pspp_sheet_view_stop_editing (tree_view, TRUE); - /* If we have a node expanded/collapsed timeout, remove it */ - remove_expand_collapse_timeout (tree_view); - if (tree_view->priv->destroy_count_func) { gint child_count = 0; - if (node->children) - _pspp_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count); tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data); } - if (tree->root->count == 1) - { - if (tree_view->priv->tree == tree) - tree_view->priv->tree = NULL; - - _pspp_rbtree_remove (tree); - } - else - { - _pspp_rbtree_remove_node (tree, node); - } + tree_view->priv->row_count = gtk_tree_model_iter_n_children (model, NULL); if (! gtk_tree_row_reference_valid (tree_view->priv->top_row)) { @@ -8624,8 +7210,10 @@ pspp_sheet_view_row_deleted (GtkTreeModel *model, gtk_widget_queue_resize (GTK_WIDGET (tree_view)); - if (selection_changed) +#if 0 + if (helper_data.changed) g_signal_emit_by_name (tree_view->priv->selection, "changed"); +#endif } static void @@ -8636,10 +7224,9 @@ pspp_sheet_view_rows_reordered (GtkTreeModel *model, gpointer data) { PsppSheetView *tree_view = PSPP_SHEET_VIEW (data); - GtkRBTree *tree; - GtkRBNode *node; gint len; + /* XXX need to adjust selection */ len = gtk_tree_model_iter_n_children (model, iter); if (len < 2) @@ -8650,19 +7237,7 @@ pspp_sheet_view_rows_reordered (GtkTreeModel *model, iter, new_order); - if (_pspp_sheet_view_find_node (tree_view, - parent, - &tree, - &node)) - return; - - /* We need to special case the parent path */ - if (tree == NULL) - tree = tree_view->priv->tree; - else - tree = node->children; - - if (tree == NULL) + if (gtk_tree_path_get_depth (parent) != 0) return; if (tree_view->priv->edited_column) @@ -8671,11 +7246,6 @@ pspp_sheet_view_rows_reordered (GtkTreeModel *model, /* we need to be unprelighted */ ensure_unprelighted (tree_view); - /* clear the timeout */ - cancel_arrow_animation (tree_view); - - _pspp_rbtree_reorder (tree, new_order, len); - gtk_widget_queue_draw (GTK_WIDGET (tree_view)); pspp_sheet_view_dy_to_top_row (tree_view); @@ -8688,7 +7258,6 @@ pspp_sheet_view_rows_reordered (GtkTreeModel *model, static void pspp_sheet_view_get_background_xrange (PsppSheetView *tree_view, - GtkRBTree *tree, PsppSheetViewColumn *column, gint *x1, gint *x2) @@ -8737,133 +7306,11 @@ pspp_sheet_view_get_background_xrange (PsppSheetView *tree_view, *x2 = total_width; /* width of 0 */ } } -static void -pspp_sheet_view_get_arrow_xrange (PsppSheetView *tree_view, - GtkRBTree *tree, - gint *x1, - gint *x2) -{ - gint x_offset = 0; - GList *list; - PsppSheetViewColumn *tmp_column = NULL; - gint total_width; - gboolean indent_expanders; - gboolean rtl; - - rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL); - - total_width = 0; - for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns)); - list; - list = (rtl ? list->prev : list->next)) - { - tmp_column = list->data; - - if (pspp_sheet_view_is_expander_column (tree_view, tmp_column)) - { - if (rtl) - x_offset = total_width + tmp_column->width - tree_view->priv->expander_size; - else - x_offset = total_width; - break; - } - - if (tmp_column->visible) - total_width += tmp_column->width; - } - - gtk_widget_style_get (GTK_WIDGET (tree_view), - "indent-expanders", &indent_expanders, - NULL); - - if (indent_expanders) - { - if (rtl) - x_offset -= tree_view->priv->expander_size * _pspp_rbtree_get_depth (tree); - else - x_offset += tree_view->priv->expander_size * _pspp_rbtree_get_depth (tree); - } - - *x1 = x_offset; - - if (tmp_column && tmp_column->visible) - /* +1 because x2 isn't included in the range. */ - *x2 = *x1 + tree_view->priv->expander_size + 1; - else - *x2 = *x1; -} - -static void -pspp_sheet_view_build_tree (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkTreeIter *iter, - gint depth, - gboolean recurse) -{ - GtkRBNode *temp = NULL; - GtkTreePath *path = NULL; - gboolean is_list = PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IS_LIST); - - do - { - gtk_tree_model_ref_node (tree_view->priv->model, iter); - temp = _pspp_rbtree_insert_after (tree, temp, 0, FALSE); - - if (tree_view->priv->fixed_height > 0) - { - if (PSPP_RBNODE_FLAG_SET (temp, PSPP_RBNODE_INVALID)) - { - _pspp_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height); - _pspp_rbtree_node_mark_valid (tree, temp); - } - } - - if (is_list) - continue; - - if (recurse) - { - GtkTreeIter child; - - if (!path) - path = gtk_tree_model_get_path (tree_view->priv->model, iter); - else - gtk_tree_path_next (path); - - if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter)) - { - gboolean expand; - - g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand); - - if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter) - && !expand) - { - temp->children = _pspp_rbtree_new (); - temp->children->parent_tree = tree; - temp->children->parent_node = temp; - pspp_sheet_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse); - } - } - } - - if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)) - { - if ((temp->flags&PSPP_RBNODE_IS_PARENT) != PSPP_RBNODE_IS_PARENT) - temp->flags ^= PSPP_RBNODE_IS_PARENT; - } - } - while (gtk_tree_model_iter_next (tree_view->priv->model, iter)); - - if (path) - gtk_tree_path_free (path); -} /* Make sure the node is visible vertically */ static void pspp_sheet_view_clamp_node_visible (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node) + int node) { gint node_dy, height; GtkTreePath *path = NULL; @@ -8872,15 +7319,14 @@ pspp_sheet_view_clamp_node_visible (PsppSheetView *tree_view, return; /* just return if the node is visible, avoiding a costly expose */ - node_dy = _pspp_rbtree_node_find_offset (tree, node); - height = ROW_HEIGHT (tree_view, PSPP_RBNODE_GET_HEIGHT (node)); - if (! PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_INVALID) - && node_dy >= tree_view->priv->vadjustment->value + node_dy = pspp_sheet_view_node_find_offset (tree_view, node); + height = ROW_HEIGHT (tree_view); + if (node_dy >= tree_view->priv->vadjustment->value && node_dy + height <= (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)) return; - path = _pspp_sheet_view_find_path (tree_view, tree, node); + path = _pspp_sheet_view_find_path (tree_view, node); if (path) { /* We process updates because we want to clear old selected items when we scroll. @@ -8901,8 +7347,8 @@ pspp_sheet_view_clamp_column_visible (PsppSheetView *tree_view, if (column == NULL) return; - x = column->button->allocation.x; - width = column->button->allocation.width; + x = column->allocation.x; + width = column->allocation.width; if (width > tree_view->priv->hadjustment->page_size) { @@ -8965,121 +7411,30 @@ pspp_sheet_view_clamp_column_visible (PsppSheetView *tree_view, } } -/* This function could be more efficient. I'll optimize it if profiling seems - * to imply that it is important */ GtkTreePath * _pspp_sheet_view_find_path (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node) + int node) { GtkTreePath *path; - GtkRBTree *tmp_tree; - GtkRBNode *tmp_node, *last; - gint count; path = gtk_tree_path_new (); - - g_return_val_if_fail (node != NULL, path); - g_return_val_if_fail (node != tree->nil, path); - - count = 1 + node->left->count; - - last = node; - tmp_node = node->parent; - tmp_tree = tree; - while (tmp_tree) - { - while (tmp_node != tmp_tree->nil) - { - if (tmp_node->right == last) - count += 1 + tmp_node->left->count; - last = tmp_node; - tmp_node = tmp_node->parent; - } - gtk_tree_path_prepend_index (path, count - 1); - last = tmp_tree->parent_node; - tmp_tree = tmp_tree->parent_tree; - if (last) - { - count = 1 + last->left->count; - tmp_node = last->parent; - } - } + if (node >= 0) + gtk_tree_path_append_index (path, node); return path; } -/* Returns TRUE if we ran out of tree before finding the path. If the path is - * invalid (ie. points to a node that's not in the tree), *tree and *node are - * both set to NULL. - */ -gboolean +void _pspp_sheet_view_find_node (PsppSheetView *tree_view, GtkTreePath *path, - GtkRBTree **tree, - GtkRBNode **node) + int *node) { - GtkRBNode *tmpnode = NULL; - GtkRBTree *tmptree = tree_view->priv->tree; gint *indices = gtk_tree_path_get_indices (path); gint depth = gtk_tree_path_get_depth (path); - gint i = 0; - - *node = NULL; - *tree = NULL; - - if (depth == 0 || tmptree == NULL) - return FALSE; - do - { - tmpnode = _pspp_rbtree_find_count (tmptree, indices[i] + 1); - ++i; - if (tmpnode == NULL) - { - *tree = NULL; - *node = NULL; - return FALSE; - } - if (i >= depth) - { - *tree = tmptree; - *node = tmpnode; - return FALSE; - } - *tree = tmptree; - *node = tmpnode; - tmptree = tmpnode->children; - if (tmptree == NULL) - return TRUE; - } - while (1); -} - -static gboolean -pspp_sheet_view_is_expander_column (PsppSheetView *tree_view, - PsppSheetViewColumn *column) -{ - GList *list; - - if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IS_LIST)) - return FALSE; - if (tree_view->priv->expander_column != NULL) - { - if (tree_view->priv->expander_column == column) - return TRUE; - return FALSE; - } - else - { - for (list = tree_view->priv->columns; - list; - list = list->next) - if (((PsppSheetViewColumn *)list->data)->visible) - break; - if (list && list->data == column) - return TRUE; - } - return FALSE; + *node = -1; + if (depth == 0 || indices[0] < 0 || indices[0] >= tree_view->priv->row_count) + return; + *node = indices[0]; } static void @@ -9116,71 +7471,6 @@ pspp_sheet_view_add_move_binding (GtkBindingSet *binding_set, G_TYPE_INT, count); } -static gint -pspp_sheet_view_unref_tree_helper (GtkTreeModel *model, - GtkTreeIter *iter, - GtkRBTree *tree, - GtkRBNode *node) -{ - gint retval = FALSE; - do - { - g_return_val_if_fail (node != NULL, FALSE); - - if (node->children) - { - GtkTreeIter child; - GtkRBTree *new_tree; - GtkRBNode *new_node; - - new_tree = node->children; - new_node = new_tree->root; - - while (new_node && new_node->left != new_tree->nil) - new_node = new_node->left; - - if (!gtk_tree_model_iter_children (model, &child, iter)) - return FALSE; - - retval = retval || pspp_sheet_view_unref_tree_helper (model, &child, new_tree, new_node); - } - - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SELECTED)) - retval = TRUE; - gtk_tree_model_unref_node (model, iter); - node = _pspp_rbtree_next (tree, node); - } - while (gtk_tree_model_iter_next (model, iter)); - - return retval; -} - -static gint -pspp_sheet_view_unref_and_check_selection_tree (PsppSheetView *tree_view, - GtkRBTree *tree) -{ - GtkTreeIter iter; - GtkTreePath *path; - GtkRBNode *node; - gint retval; - - if (!tree) - return FALSE; - - node = tree->root; - while (node && node->left != tree->nil) - node = node->left; - - g_return_val_if_fail (node != NULL, FALSE); - path = _pspp_sheet_view_find_path (tree_view, tree, node); - gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model), - &iter, path); - retval = pspp_sheet_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node); - gtk_tree_path_free (path); - - return retval; -} - static void pspp_sheet_view_set_column_drag_info (PsppSheetView *tree_view, PsppSheetViewColumn *column) @@ -9268,9 +7558,9 @@ pspp_sheet_view_set_column_drag_info (PsppSheetView *tree_view, if (tmp_list->next != NULL) { g_assert (tmp_list->next->data); - left = reorder->right_align = (reorder->right_column->button->allocation.x + - reorder->right_column->button->allocation.width + - ((PsppSheetViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2; + left = reorder->right_align = (reorder->right_column->allocation.x + + reorder->right_column->allocation.width + + ((PsppSheetViewColumnReorder *)tmp_list->next->data)->left_column->allocation.x)/2; } else { @@ -9294,6 +7584,7 @@ _pspp_sheet_view_column_start_drag (PsppSheetView *tree_view, g_return_if_fail (tree_view->priv->column_drag_info == NULL); g_return_if_fail (tree_view->priv->cur_reorder == NULL); + g_return_if_fail (column->button); pspp_sheet_view_set_column_drag_info (tree_view, column); @@ -9307,10 +7598,10 @@ _pspp_sheet_view_column_start_drag (PsppSheetView *tree_view, attributes.window_type = GDK_WINDOW_CHILD; attributes.wclass = GDK_INPUT_OUTPUT; - attributes.x = column->button->allocation.x; + attributes.x = column->allocation.x; attributes.y = 0; - attributes.width = column->button->allocation.width; - attributes.height = column->button->allocation.height; + attributes.width = column->allocation.width; + attributes.height = column->allocation.height; attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view)); attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view)); attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK; @@ -9360,8 +7651,8 @@ _pspp_sheet_view_column_start_drag (PsppSheetView *tree_view, gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view)); g_object_unref (column->button); - tree_view->priv->drag_column_x = column->button->allocation.x; - allocation = column->button->allocation; + tree_view->priv->drag_column_x = column->allocation.x; + allocation = column->allocation; allocation.x = 0; gtk_widget_size_allocate (column->button, &allocation); gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window); @@ -9386,10 +7677,9 @@ _pspp_sheet_view_column_start_drag (PsppSheetView *tree_view, GDK_CURRENT_TIME); } -static void -pspp_sheet_view_queue_draw_arrow (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, +void +_pspp_sheet_view_queue_draw_node (PsppSheetView *tree_view, + int node, const GdkRectangle *clip_rect) { GdkRectangle rect; @@ -9398,10 +7688,10 @@ pspp_sheet_view_queue_draw_arrow (PsppSheetView *tree_view, return; rect.x = 0; - rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width)); + rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width); - rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); - rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)); + rect.y = BACKGROUND_FIRST_PIXEL (tree_view, node); + rect.height = ROW_HEIGHT (tree_view); if (clip_rect) { @@ -9417,126 +7707,17 @@ pspp_sheet_view_queue_draw_arrow (PsppSheetView *tree_view, } } -void -_pspp_sheet_view_queue_draw_node (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, - const GdkRectangle *clip_rect) +static void +pspp_sheet_view_queue_draw_path (PsppSheetView *tree_view, + GtkTreePath *path, + const GdkRectangle *clip_rect) { - GdkRectangle rect; - - if (!gtk_widget_get_realized (GTK_WIDGET (tree_view))) - return; - - rect.x = 0; - rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width); - - rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); - rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)); - - if (clip_rect) - { - GdkRectangle new_rect; - - gdk_rectangle_intersect (clip_rect, &rect, &new_rect); - - gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE); - } - else - { - gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE); - } -} - -static void -pspp_sheet_view_queue_draw_path (PsppSheetView *tree_view, - GtkTreePath *path, - const GdkRectangle *clip_rect) -{ - GtkRBTree *tree = NULL; - GtkRBNode *node = NULL; - - _pspp_sheet_view_find_node (tree_view, path, &tree, &node); - - if (tree) - _pspp_sheet_view_queue_draw_node (tree_view, tree, node, clip_rect); -} - -/* x and y are the mouse position - */ -static void -pspp_sheet_view_draw_arrow (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, - /* in bin_window coordinates */ - gint x, - gint y) -{ - GdkRectangle area; - GtkStateType state; - GtkWidget *widget; - gint x_offset = 0; - gint x2; - gint vertical_separator; - gint expander_size; - GtkExpanderStyle expander_style; - - widget = GTK_WIDGET (tree_view); - - gtk_widget_style_get (widget, - "vertical-separator", &vertical_separator, - NULL); - expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING; - - if (! PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_PARENT)) - return; - - pspp_sheet_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2); - - area.x = x_offset; - area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator); - area.width = expander_size + 2; - area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator)); + int node = -1; - if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE) - { - state = GTK_STATE_INSENSITIVE; - } - else if (node == tree_view->priv->button_pressed_node) - { - if (x >= area.x && x <= (area.x + area.width) && - y >= area.y && y <= (area.y + area.height)) - state = GTK_STATE_ACTIVE; - else - state = GTK_STATE_NORMAL; - } - else - { - if (node == tree_view->priv->prelight_node && - PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_ARROW_PRELIT)) - state = GTK_STATE_PRELIGHT; - else - state = GTK_STATE_NORMAL; - } - - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SEMI_EXPANDED)) - expander_style = GTK_EXPANDER_SEMI_EXPANDED; - else if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SEMI_COLLAPSED)) - expander_style = GTK_EXPANDER_SEMI_COLLAPSED; - else if (node->children != NULL) - expander_style = GTK_EXPANDER_EXPANDED; - else - expander_style = GTK_EXPANDER_COLLAPSED; + _pspp_sheet_view_find_node (tree_view, path, &node); - gtk_paint_expander (widget->style, - tree_view->priv->bin_window, - state, - &area, - widget, - "treeview", - area.x + area.width / 2, - area.y + area.height / 2, - expander_style); + if (node) + _pspp_sheet_view_queue_draw_node (tree_view, node, clip_rect); } static void @@ -9545,7 +7726,7 @@ pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view) { GtkTreePath *cursor_path; - if ((tree_view->priv->tree == NULL) || + if ((tree_view->priv->row_count == 0) || (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))) return; @@ -9555,8 +7736,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; @@ -9567,6 +7748,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); @@ -9575,7 +7757,7 @@ pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view) { cursor_path = gtk_tree_path_new_first (); search_first_focusable_path (tree_view, &cursor_path, - TRUE, NULL, NULL); + TRUE, NULL); } gtk_tree_row_reference_free (tree_view->priv->cursor); @@ -9583,7 +7765,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); @@ -9592,6 +7775,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); @@ -9605,9 +7789,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; } } + } } } @@ -9617,13 +7804,10 @@ pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, gint count) { gint selection_count; - GtkRBTree *cursor_tree = NULL; - GtkRBNode *cursor_node = NULL; - GtkRBTree *new_cursor_tree = NULL; - GtkRBNode *new_cursor_node = NULL; + int cursor_node = -1; + int new_cursor_node = -1; GtkTreePath *cursor_path = NULL; gboolean grab_focus = TRUE; - gboolean selectable; if (! gtk_widget_has_focus (GTK_WIDGET (tree_view))) return; @@ -9634,47 +7818,37 @@ pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, return; cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); - _pspp_sheet_view_find_node (tree_view, cursor_path, - &cursor_tree, &cursor_node); + _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node); - if (cursor_tree == NULL) + if (cursor_node < 0) /* FIXME: we lost the cursor; should we get the first? */ return; selection_count = pspp_sheet_selection_count_selected_rows (tree_view->priv->selection); - selectable = _pspp_sheet_selection_row_is_selectable (tree_view->priv->selection, - cursor_node, - cursor_path); if (selection_count == 0 - && tree_view->priv->selection->type != GTK_SELECTION_NONE - && !tree_view->priv->ctrl_pressed - && selectable) + && 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 */ - new_cursor_tree = cursor_tree; new_cursor_node = cursor_node; } else { if (count == -1) - _pspp_rbtree_prev_full (cursor_tree, cursor_node, - &new_cursor_tree, &new_cursor_node); + new_cursor_node = pspp_sheet_view_node_prev (tree_view, cursor_node); else - _pspp_rbtree_next_full (cursor_tree, cursor_node, - &new_cursor_tree, &new_cursor_node); + new_cursor_node = pspp_sheet_view_node_next (tree_view, cursor_node); } gtk_tree_path_free (cursor_path); if (new_cursor_node) { - cursor_path = _pspp_sheet_view_find_path (tree_view, - new_cursor_tree, new_cursor_node); + cursor_path = _pspp_sheet_view_find_path (tree_view, new_cursor_node); search_first_focusable_path (tree_view, &cursor_path, (count != -1), - &new_cursor_tree, &new_cursor_node); if (cursor_path) @@ -9685,37 +7859,35 @@ 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 && - new_cursor_node == NULL) + 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) - _pspp_rbtree_next_full (cursor_tree, cursor_node, - &new_cursor_tree, &new_cursor_node); + new_cursor_node = pspp_sheet_view_node_next (tree_view, cursor_node); else - _pspp_rbtree_prev_full (cursor_tree, cursor_node, - &new_cursor_tree, &new_cursor_node); + new_cursor_node = pspp_sheet_view_node_prev (tree_view, cursor_node); - if (new_cursor_node == NULL - && !PSPP_RBNODE_FLAG_SET (cursor_node, PSPP_RBNODE_IS_SELECTED)) + if (new_cursor_node < 0 + && !pspp_sheet_view_node_is_selected (tree_view, cursor_node)) { new_cursor_node = cursor_node; - new_cursor_tree = cursor_tree; } else { - new_cursor_node = NULL; + new_cursor_node = -1; } } - if (new_cursor_node) + if (new_cursor_node >= 0) { - cursor_path = _pspp_sheet_view_find_path (tree_view, new_cursor_tree, new_cursor_node); + cursor_path = _pspp_sheet_view_find_path (tree_view, new_cursor_node); pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE); gtk_tree_path_free (cursor_path); } else { - pspp_sheet_view_clamp_node_visible (tree_view, cursor_tree, cursor_node); + pspp_sheet_view_clamp_node_visible (tree_view, cursor_node); if (!tree_view->priv->shift_pressed) { @@ -9748,12 +7920,10 @@ static void pspp_sheet_view_move_cursor_page_up_down (PsppSheetView *tree_view, gint count) { - GtkRBTree *cursor_tree = NULL; - GtkRBNode *cursor_node = NULL; + int cursor_node = -1; GtkTreePath *old_cursor_path = NULL; GtkTreePath *cursor_path = NULL; - GtkRBTree *start_cursor_tree = NULL; - GtkRBNode *start_cursor_node = NULL; + int start_cursor_node = -1; gint y; gint window_y; gint vertical_separator; @@ -9768,18 +7938,16 @@ pspp_sheet_view_move_cursor_page_up_down (PsppSheetView *tree_view, return; gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL); - _pspp_sheet_view_find_node (tree_view, old_cursor_path, - &cursor_tree, &cursor_node); + _pspp_sheet_view_find_node (tree_view, old_cursor_path, &cursor_node); - if (cursor_tree == NULL) + if (cursor_node < 0) { /* FIXME: we lost the cursor. Should we try to get one? */ gtk_tree_path_free (old_cursor_path); return; } - g_return_if_fail (cursor_node != NULL); - y = _pspp_rbtree_node_find_offset (cursor_tree, cursor_node); + y = pspp_sheet_view_node_find_offset (tree_view, cursor_node); window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y); y += tree_view->priv->cursor_offset; y += count * (int)tree_view->priv->vadjustment->page_increment; @@ -9789,51 +7957,47 @@ pspp_sheet_view_move_cursor_page_up_down (PsppSheetView *tree_view, y = tree_view->priv->height - 1; tree_view->priv->cursor_offset = - _pspp_rbtree_find_offset (tree_view->priv->tree, y, - &cursor_tree, &cursor_node); + pspp_sheet_view_find_offset (tree_view, y, &cursor_node); - if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node)) + if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (tree_view)) { - _pspp_rbtree_next_full (cursor_tree, cursor_node, - &cursor_tree, &cursor_node); - tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node); + cursor_node = pspp_sheet_view_node_next (tree_view, cursor_node); + tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (tree_view); } y -= tree_view->priv->cursor_offset; - cursor_path = _pspp_sheet_view_find_path (tree_view, cursor_tree, cursor_node); + cursor_path = _pspp_sheet_view_find_path (tree_view, cursor_node); - start_cursor_tree = cursor_tree; start_cursor_node = cursor_node; if (! search_first_focusable_path (tree_view, &cursor_path, (count != -1), - &cursor_tree, &cursor_node)) + &cursor_node)) { /* It looks like we reached the end of the view without finding * a focusable row. We will step backwards to find the last * focusable row. */ - cursor_tree = start_cursor_tree; cursor_node = start_cursor_node; - cursor_path = _pspp_sheet_view_find_path (tree_view, cursor_tree, cursor_node); + cursor_path = _pspp_sheet_view_find_path (tree_view, cursor_node); search_first_focusable_path (tree_view, &cursor_path, (count == -1), - &cursor_tree, &cursor_node); + &cursor_node); } if (!cursor_path) goto cleanup; /* update y */ - y = _pspp_rbtree_node_find_offset (cursor_tree, cursor_node); + y = pspp_sheet_view_node_find_offset (tree_view, cursor_node); pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE); y -= window_y; pspp_sheet_view_scroll_to_point (tree_view, -1, y); - pspp_sheet_view_clamp_node_visible (tree_view, cursor_tree, cursor_node); - _pspp_sheet_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL); + pspp_sheet_view_clamp_node_visible (tree_view, cursor_node); + _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL); if (!gtk_tree_path_compare (old_cursor_path, cursor_path)) gtk_widget_error_bell (GTK_WIDGET (tree_view)); @@ -9849,8 +8013,7 @@ static void pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view, gint count) { - GtkRBTree *cursor_tree = NULL; - GtkRBNode *cursor_node = NULL; + int cursor_node = -1; GtkTreePath *cursor_path = NULL; PsppSheetViewColumn *column; GtkTreeIter iter; @@ -9868,8 +8031,8 @@ pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view, else return; - _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node); - if (cursor_tree == NULL) + _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node); + if (cursor_node < 0) return; if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE) { @@ -9893,14 +8056,12 @@ pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view, gboolean left, right; column = list->data; - if (column->visible == FALSE) + if (column->visible == FALSE || column->row_head) goto loop_end; pspp_sheet_view_column_cell_set_cell_data (column, tree_view->priv->model, - &iter, - PSPP_RBNODE_FLAG_SET (cursor_node, PSPP_RBNODE_IS_PARENT), - cursor_node->children?TRUE:FALSE); + &iter); if (rtl) { @@ -9928,11 +8089,7 @@ pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view, if (found_column) { - if (!pspp_sheet_view_has_special_cell (tree_view)) - _pspp_sheet_view_queue_draw_node (tree_view, - cursor_tree, - cursor_node, - NULL); + _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL); g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0); gtk_widget_grab_focus (GTK_WIDGET (tree_view)); } @@ -9949,49 +8106,30 @@ static void pspp_sheet_view_move_cursor_start_end (PsppSheetView *tree_view, gint count) { - GtkRBTree *cursor_tree; - GtkRBNode *cursor_node; + int cursor_node; GtkTreePath *path; GtkTreePath *old_path; if (!gtk_widget_has_focus (GTK_WIDGET (tree_view))) return; - g_return_if_fail (tree_view->priv->tree != NULL); + g_return_if_fail (tree_view->priv->row_count > 0); pspp_sheet_view_get_cursor (tree_view, &old_path, NULL); - cursor_tree = tree_view->priv->tree; - cursor_node = cursor_tree->root; - if (count == -1) { - while (cursor_node && cursor_node->left != cursor_tree->nil) - cursor_node = cursor_node->left; - /* Now go forward to find the first focusable row. */ - path = _pspp_sheet_view_find_path (tree_view, cursor_tree, cursor_node); + path = _pspp_sheet_view_find_path (tree_view, 0); search_first_focusable_path (tree_view, &path, - TRUE, &cursor_tree, &cursor_node); + TRUE, &cursor_node); } else { - do - { - while (cursor_node && cursor_node->right != cursor_tree->nil) - cursor_node = cursor_node->right; - if (cursor_node->children == NULL) - break; - - cursor_tree = cursor_node->children; - cursor_node = cursor_tree->root; - } - while (1); - /* Now go backwards to find last focusable row. */ - path = _pspp_sheet_view_find_path (tree_view, cursor_tree, cursor_node); + path = _pspp_sheet_view_find_path (tree_view, tree_view->priv->row_count - 1); search_first_focusable_path (tree_view, &path, - FALSE, &cursor_tree, &cursor_node); + FALSE, &cursor_node); } if (!path) @@ -10018,7 +8156,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); @@ -10032,7 +8171,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); @@ -10044,10 +8184,8 @@ static gboolean pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, gboolean start_editing) { - GtkRBTree *new_tree = NULL; - GtkRBNode *new_node = NULL; - GtkRBTree *cursor_tree = NULL; - GtkRBNode *cursor_node = NULL; + int new_node = -1; + int cursor_node = -1; GtkTreePath *cursor_path = NULL; GtkTreeSelectMode mode = 0; @@ -10061,9 +8199,9 @@ pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, return FALSE; _pspp_sheet_view_find_node (tree_view, cursor_path, - &cursor_tree, &cursor_node); + &cursor_node); - if (cursor_tree == NULL) + if (cursor_node < 0) { gtk_tree_path_free (cursor_path); return FALSE; @@ -10086,7 +8224,6 @@ pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, _pspp_sheet_selection_internal_select_node (tree_view->priv->selection, cursor_node, - cursor_tree, cursor_path, mode, FALSE); @@ -10095,15 +8232,15 @@ pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, * handling the selection-changed callback. We do return TRUE because * the key press has been handled at this point. */ - _pspp_sheet_view_find_node (tree_view, cursor_path, &new_tree, &new_node); + _pspp_sheet_view_find_node (tree_view, cursor_path, &new_node); - if (cursor_tree != new_tree || cursor_node != new_node) + if (cursor_node != new_node) return FALSE; - pspp_sheet_view_clamp_node_visible (tree_view, cursor_tree, cursor_node); + pspp_sheet_view_clamp_node_visible (tree_view, cursor_node); gtk_widget_grab_focus (GTK_WIDGET (tree_view)); - _pspp_sheet_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL); + _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL); if (!tree_view->priv->shift_pressed) pspp_sheet_view_row_activated (tree_view, cursor_path, @@ -10117,10 +8254,8 @@ pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view, static gboolean pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view) { - GtkRBTree *new_tree = NULL; - GtkRBNode *new_node = NULL; - GtkRBTree *cursor_tree = NULL; - GtkRBNode *cursor_node = NULL; + int new_node = -1; + int cursor_node = -1; GtkTreePath *cursor_path = NULL; if (!gtk_widget_has_focus (GTK_WIDGET (tree_view))) @@ -10133,9 +8268,8 @@ pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view) if (cursor_path == NULL) return FALSE; - _pspp_sheet_view_find_node (tree_view, cursor_path, - &cursor_tree, &cursor_node); - if (cursor_tree == NULL) + _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node); + if (cursor_node < 0) { gtk_tree_path_free (cursor_path); return FALSE; @@ -10143,7 +8277,6 @@ pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view) _pspp_sheet_selection_internal_select_node (tree_view->priv->selection, cursor_node, - cursor_tree, cursor_path, GTK_TREE_SELECT_MODE_TOGGLE, FALSE); @@ -10152,12 +8285,12 @@ pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view) * handling the selection-changed callback. We do return TRUE because * the key press has been handled at this point. */ - _pspp_sheet_view_find_node (tree_view, cursor_path, &new_tree, &new_node); + _pspp_sheet_view_find_node (tree_view, cursor_path, &new_node); - if (cursor_tree != new_tree || cursor_node != new_node) + if (cursor_node != new_node) return FALSE; - pspp_sheet_view_clamp_node_visible (tree_view, cursor_tree, cursor_node); + pspp_sheet_view_clamp_node_visible (tree_view, cursor_node); gtk_widget_grab_focus (GTK_WIDGET (tree_view)); pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL); @@ -10166,105 +8299,6 @@ pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view) return TRUE; } -static gboolean -pspp_sheet_view_real_expand_collapse_cursor_row (PsppSheetView *tree_view, - gboolean logical, - gboolean expand, - gboolean open_all) -{ - GtkTreePath *cursor_path = NULL; - GtkRBTree *tree; - GtkRBNode *node; - - if (!gtk_widget_has_focus (GTK_WIDGET (tree_view))) - return FALSE; - - cursor_path = NULL; - if (tree_view->priv->cursor) - cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); - - if (cursor_path == NULL) - return FALSE; - - if (_pspp_sheet_view_find_node (tree_view, cursor_path, &tree, &node)) - return FALSE; - - /* Don't handle the event if we aren't an expander */ - if (!((node->flags & PSPP_RBNODE_IS_PARENT) == PSPP_RBNODE_IS_PARENT)) - return FALSE; - - if (!logical - && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL) - expand = !expand; - - if (expand) - pspp_sheet_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE); - else - pspp_sheet_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE); - - gtk_tree_path_free (cursor_path); - - return TRUE; -} - -static gboolean -pspp_sheet_view_real_select_cursor_parent (PsppSheetView *tree_view) -{ - GtkRBTree *cursor_tree = NULL; - GtkRBNode *cursor_node = NULL; - GtkTreePath *cursor_path = NULL; - GdkModifierType state; - - if (!gtk_widget_has_focus (GTK_WIDGET (tree_view))) - goto out; - - cursor_path = NULL; - if (tree_view->priv->cursor) - cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); - - if (cursor_path == NULL) - goto out; - - _pspp_sheet_view_find_node (tree_view, cursor_path, - &cursor_tree, &cursor_node); - if (cursor_tree == NULL) - { - gtk_tree_path_free (cursor_path); - goto out; - } - - if (cursor_tree->parent_node) - { - pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL); - cursor_node = cursor_tree->parent_node; - cursor_tree = cursor_tree->parent_tree; - - gtk_tree_path_up (cursor_path); - - if (gtk_get_current_event_state (&state)) - { - if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) - tree_view->priv->ctrl_pressed = TRUE; - } - - pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE); - pspp_sheet_view_clamp_node_visible (tree_view, cursor_tree, cursor_node); - - gtk_widget_grab_focus (GTK_WIDGET (tree_view)); - pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL); - gtk_tree_path_free (cursor_path); - - tree_view->priv->ctrl_pressed = FALSE; - - return TRUE; - } - - out: - - tree_view->priv->search_entry_avoid_unhandled_binding = TRUE; - return FALSE; -} - static gboolean pspp_sheet_view_search_entry_flush_timeout (PsppSheetView *tree_view) { @@ -10409,7 +8443,7 @@ pspp_sheet_view_real_start_interactive_search (PsppSheetView *tree_view, if (! column->visible) continue; - if (gtk_widget_has_focus (column->button)) + if (column->button && gtk_widget_has_focus (column->button)) { found_focus = TRUE; break; @@ -10485,19 +8519,17 @@ pspp_sheet_view_new_column_width (PsppSheetView *tree_view, */ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL); column = g_list_nth (tree_view->priv->columns, i)->data; - width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x); + width = rtl ? (column->allocation.x + column->allocation.width - *x) : (*x - column->allocation.x); /* Clamp down the value */ if (column->min_width == -1) - width = MAX (column->button->requisition.width, - width); + width = MAX (column->button_request, width); else - width = MAX (column->min_width, - width); + width = MAX (column->min_width, width); if (column->max_width != -1) width = MIN (width, column->max_width); - *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width); + *x = rtl ? (column->allocation.x + column->allocation.width - width) : (column->allocation.x + width); return width; } @@ -10574,6 +8606,9 @@ adjust_allocation (GtkWidget *widget, adjust_allocation_recurse (widget, &scroll_data); } +void +pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column); + /* Callbacks */ static void pspp_sheet_view_adjustment_changed (GtkAdjustment *adjustment, @@ -10581,6 +8616,7 @@ pspp_sheet_view_adjustment_changed (GtkAdjustment *adjustment, { if (gtk_widget_get_realized (GTK_WIDGET (tree_view))) { + GList *list; gint dy; gdk_window_move (tree_view->priv->bin_window, @@ -10628,8 +8664,20 @@ pspp_sheet_view_adjustment_changed (GtkAdjustment *adjustment, pspp_sheet_view_dy_to_top_row (tree_view); } - gdk_window_process_updates (tree_view->priv->header_window, TRUE); - gdk_window_process_updates (tree_view->priv->bin_window, TRUE); + for (list = tree_view->priv->columns; list; list = list->next) + { + PsppSheetViewColumn *column = list->data; + GtkAllocation *allocation = &column->allocation; + + if (span_intersects (allocation->x, allocation->width, + tree_view->priv->hadjustment->value, + GTK_WIDGET (tree_view)->allocation.width)) + { + pspp_sheet_view_column_set_need_button (column, TRUE); + if (!column->button) + pspp_sheet_view_column_update_button (column); + } + } } } @@ -10714,20 +8762,16 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, { GList *tmplist = tree_view->priv->columns; - pspp_sheet_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree); + if (tree_view->priv->selected) + range_tower_set0 (tree_view->priv->selected, 0, ULONG_MAX); pspp_sheet_view_stop_editing (tree_view, TRUE); - remove_expand_collapse_timeout (tree_view); - g_signal_handlers_disconnect_by_func (tree_view->priv->model, pspp_sheet_view_row_changed, tree_view); g_signal_handlers_disconnect_by_func (tree_view->priv->model, pspp_sheet_view_row_inserted, tree_view); - g_signal_handlers_disconnect_by_func (tree_view->priv->model, - pspp_sheet_view_row_has_child_toggled, - tree_view); g_signal_handlers_disconnect_by_func (tree_view->priv->model, pspp_sheet_view_row_deleted, tree_view); @@ -10739,8 +8783,7 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, _pspp_sheet_view_column_unset_model (tmplist->data, tree_view->priv->model); - if (tree_view->priv->tree) - pspp_sheet_view_free_rbtree (tree_view); + tree_view->priv->prelight_node = -1; gtk_tree_row_reference_free (tree_view->priv->drag_dest_row); tree_view->priv->drag_dest_row = NULL; @@ -10758,7 +8801,6 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, g_object_unref (tree_view->priv->model); tree_view->priv->search_column = -1; - tree_view->priv->fixed_height_check = 0; tree_view->priv->fixed_height = -1; tree_view->priv->dy = tree_view->priv->top_row_dy = 0; tree_view->priv->last_button_x = -1; @@ -10770,8 +8812,6 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, if (tree_view->priv->model) { gint i; - GtkTreePath *path; - GtkTreeIter iter; GtkTreeModelFlags flags; if (tree_view->priv->search_column == -1) @@ -10797,10 +8837,6 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, "row-inserted", G_CALLBACK (pspp_sheet_view_row_inserted), tree_view); - g_signal_connect (tree_view->priv->model, - "row-has-child-toggled", - G_CALLBACK (pspp_sheet_view_row_has_child_toggled), - tree_view); g_signal_connect (tree_view->priv->model, "row-deleted", G_CALLBACK (pspp_sheet_view_row_deleted), @@ -10811,18 +8847,8 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, tree_view); flags = gtk_tree_model_get_flags (tree_view->priv->model); - if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY) - PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_IS_LIST); - else - PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_IS_LIST); - path = gtk_tree_path_new_first (); - if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path)) - { - tree_view->priv->tree = _pspp_rbtree_new (); - pspp_sheet_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE); - } - gtk_tree_path_free (path); + tree_view->priv->row_count = gtk_tree_model_iter_n_children (tree_view->priv->model, NULL); /* FIXME: do I need to do this? pspp_sheet_view_create_buttons (tree_view); */ install_presize_handler (tree_view); @@ -10831,7 +8857,7 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, g_object_notify (G_OBJECT (tree_view), "model"); if (tree_view->priv->selection) - _pspp_sheet_selection_emit_changed (tree_view->priv->selection); + _pspp_sheet_selection_emit_changed (tree_view->priv->selection); if (gtk_widget_get_realized (GTK_WIDGET (tree_view))) gtk_widget_queue_resize (GTK_WIDGET (tree_view)); @@ -10995,7 +9021,8 @@ pspp_sheet_view_set_headers_visible (PsppSheetView *tree_view, for (list = tree_view->priv->columns; list; list = list->next) { column = list->data; - gtk_widget_unmap (column->button); + if (column->button) + gtk_widget_unmap (column->button); } gdk_window_hide (tree_view->priv->header_window); } @@ -11031,9 +9058,7 @@ pspp_sheet_view_columns_autosize (PsppSheetView *tree_view) for (list = tree_view->priv->columns; list; list = list->next) { column = list->data; - if (column->column_type == PSPP_SHEET_VIEW_COLUMN_AUTOSIZE) - continue; - _pspp_sheet_view_column_cell_set_dirty (column, TRUE); + _pspp_sheet_view_column_cell_set_dirty (column); dirty = TRUE; } @@ -11147,9 +9172,7 @@ pspp_sheet_view_get_rules_hint (PsppSheetView *tree_view) * @tree_view: A #PsppSheetView. * @column: The #PsppSheetViewColumn to add. * - * Appends @column to the list of columns. If @tree_view has "fixed_height" - * mode enabled, then @column must have its "sizing" property set to be - * PSPP_SHEET_VIEW_COLUMN_FIXED. + * Appends @column to the list of columns. * * Return value: The number of columns in @tree_view after appending. **/ @@ -11193,13 +9216,6 @@ pspp_sheet_view_remove_column (PsppSheetView *tree_view, tree_view->priv->edited_column = NULL; } - if (tree_view->priv->expander_column == column) - tree_view->priv->expander_column = NULL; - - g_signal_handlers_disconnect_by_func (column, - G_CALLBACK (column_sizing_notify), - tree_view); - _pspp_sheet_view_column_unset_tree_view (column); tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column); @@ -11216,11 +9232,12 @@ pspp_sheet_view_remove_column (PsppSheetView *tree_view, tmp_column = PSPP_SHEET_VIEW_COLUMN (list->data); if (tmp_column->visible) - _pspp_sheet_view_column_cell_set_dirty (tmp_column, TRUE); + _pspp_sheet_view_column_cell_set_dirty (tmp_column); } if (tree_view->priv->n_columns == 0 && - pspp_sheet_view_get_headers_visible (tree_view)) + pspp_sheet_view_get_headers_visible (tree_view) && + tree_view->priv->header_window) gdk_window_hide (tree_view->priv->header_window); gtk_widget_queue_resize (GTK_WIDGET (tree_view)); @@ -11239,9 +9256,7 @@ pspp_sheet_view_remove_column (PsppSheetView *tree_view, * @position: The position to insert @column in. * * This inserts the @column into the @tree_view at @position. If @position is - * -1, then the column is inserted at the end. If @tree_view has - * "fixed_height" mode enabled, then @column must have its "sizing" property - * set to be PSPP_SHEET_VIEW_COLUMN_FIXED. + * -1, then the column is inserted at the end. * * Return value: The number of columns in @tree_view after insertion. **/ @@ -11254,10 +9269,6 @@ pspp_sheet_view_insert_column (PsppSheetView *tree_view, g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), -1); g_return_val_if_fail (column->tree_view == NULL, -1); - if (tree_view->priv->fixed_height_mode) - g_return_val_if_fail (pspp_sheet_view_column_get_sizing (column) - == PSPP_SHEET_VIEW_COLUMN_FIXED, -1); - g_object_ref_sink (column); if (tree_view->priv->n_columns == 0 && @@ -11267,9 +9278,6 @@ pspp_sheet_view_insert_column (PsppSheetView *tree_view, gdk_window_show (tree_view->priv->header_window); } - g_signal_connect (column, "notify::sizing", - G_CALLBACK (column_sizing_notify), tree_view); - tree_view->priv->columns = g_list_insert (tree_view->priv->columns, column, position); tree_view->priv->n_columns++; @@ -11286,7 +9294,7 @@ pspp_sheet_view_insert_column (PsppSheetView *tree_view, { column = PSPP_SHEET_VIEW_COLUMN (list->data); if (column->visible) - _pspp_sheet_view_column_cell_set_dirty (column, TRUE); + _pspp_sheet_view_column_cell_set_dirty (column); } gtk_widget_queue_resize (GTK_WIDGET (tree_view)); } @@ -11306,9 +9314,7 @@ pspp_sheet_view_insert_column (PsppSheetView *tree_view, * * Creates a new #PsppSheetViewColumn and inserts it into the @tree_view at * @position. If @position is -1, then the newly created column is inserted at - * the end. The column is initialized with the attributes given. If @tree_view - * has "fixed_height" mode enabled, then the new column will have its sizing - * property set to be PSPP_SHEET_VIEW_COLUMN_FIXED. + * the end. The column is initialized with the attributes given. * * Return value: The number of columns in @tree_view after insertion. **/ @@ -11327,9 +9333,6 @@ pspp_sheet_view_insert_column_with_attributes (PsppSheetView *tree_view, g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1); column = pspp_sheet_view_column_new (); - if (tree_view->priv->fixed_height_mode) - pspp_sheet_view_column_set_sizing (column, PSPP_SHEET_VIEW_COLUMN_FIXED); - pspp_sheet_view_column_set_title (column, title); pspp_sheet_view_column_pack_start (column, cell, TRUE); @@ -11365,8 +9368,6 @@ pspp_sheet_view_insert_column_with_attributes (PsppSheetView *tree_view, * with the given cell renderer and a #GtkCellDataFunc to set cell renderer * attributes (normally using data from the model). See also * pspp_sheet_view_column_set_cell_data_func(), pspp_sheet_view_column_pack_start(). - * If @tree_view has "fixed_height" mode enabled, then the new column will have its - * "sizing" property set to be PSPP_SHEET_VIEW_COLUMN_FIXED. * * Return value: number of columns in the tree view post-insert **/ @@ -11384,9 +9385,6 @@ pspp_sheet_view_insert_column_with_data_func (PsppSheetView *tree g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1); column = pspp_sheet_view_column_new (); - if (tree_view->priv->fixed_height_mode) - pspp_sheet_view_column_set_sizing (column, PSPP_SHEET_VIEW_COLUMN_FIXED); - pspp_sheet_view_column_set_title (column, title); pspp_sheet_view_column_pack_start (column, cell, TRUE); pspp_sheet_view_column_set_cell_data_func (column, cell, func, data, dnotify); @@ -11495,66 +9493,6 @@ pspp_sheet_view_move_column_after (PsppSheetView *tree_view, g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0); } -/** - * pspp_sheet_view_set_expander_column: - * @tree_view: A #PsppSheetView - * @column: %NULL, or the column to draw the expander arrow at. - * - * Sets the column to draw the expander arrow at. It must be in @tree_view. - * If @column is %NULL, then the expander arrow is always at the first - * visible column. - * - * If you do not want expander arrow to appear in your tree, set the - * expander column to a hidden column. - **/ -void -pspp_sheet_view_set_expander_column (PsppSheetView *tree_view, - PsppSheetViewColumn *column) -{ - g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); - g_return_if_fail (column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (column)); - - if (tree_view->priv->expander_column != column) - { - GList *list; - - if (column) - { - /* Confirm that column is in tree_view */ - for (list = tree_view->priv->columns; list; list = list->next) - if (list->data == column) - break; - g_return_if_fail (list != NULL); - } - - tree_view->priv->expander_column = column; - g_object_notify (G_OBJECT (tree_view), "expander-column"); - } -} - -/** - * pspp_sheet_view_get_expander_column: - * @tree_view: A #PsppSheetView - * - * Returns the column that is the current expander column. This - * column has the expander arrow drawn next to it. - * - * Return value: The expander column. - **/ -PsppSheetViewColumn * -pspp_sheet_view_get_expander_column (PsppSheetView *tree_view) -{ - GList *list; - - g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL); - - for (list = tree_view->priv->columns; list; list = list->next) - if (pspp_sheet_view_is_expander_column (tree_view, PSPP_SHEET_VIEW_COLUMN (list->data))) - return (PsppSheetViewColumn *) list->data; - return NULL; -} - - /** * pspp_sheet_view_set_column_drag_function: * @tree_view: A #PsppSheetView. @@ -11658,775 +9596,109 @@ pspp_sheet_view_scroll_to_cell (PsppSheetView *tree_view, { g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); g_return_if_fail (tree_view->priv->model != NULL); - g_return_if_fail (tree_view->priv->tree != NULL); - g_return_if_fail (row_align >= 0.0 && row_align <= 1.0); - g_return_if_fail (col_align >= 0.0 && col_align <= 1.0); - g_return_if_fail (path != NULL || column != NULL); - -#if 0 - g_print ("pspp_sheet_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n", - gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align); -#endif - row_align = CLAMP (row_align, 0.0, 1.0); - col_align = CLAMP (col_align, 0.0, 1.0); - - - /* Note: Despite the benefits that come from having one code path for the - * scrolling code, we short-circuit validate_visible_area's immplementation as - * it is much slower than just going to the point. - */ - if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) || - !gtk_widget_get_realized (GTK_WIDGET (tree_view)) || - /* XXX GTK_WIDGET_ALLOC_NEEDED (tree_view) || */ - PSPP_RBNODE_FLAG_SET (tree_view->priv->tree->root, PSPP_RBNODE_DESCENDANTS_INVALID)) - { - if (tree_view->priv->scroll_to_path) - gtk_tree_row_reference_free (tree_view->priv->scroll_to_path); - - tree_view->priv->scroll_to_path = NULL; - tree_view->priv->scroll_to_column = NULL; - - if (path) - tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path); - if (column) - tree_view->priv->scroll_to_column = column; - tree_view->priv->scroll_to_use_align = use_align; - tree_view->priv->scroll_to_row_align = row_align; - tree_view->priv->scroll_to_col_align = col_align; - - install_presize_handler (tree_view); - } - else - { - GdkRectangle cell_rect; - GdkRectangle vis_rect; - gint dest_x, dest_y; - - pspp_sheet_view_get_background_area (tree_view, path, column, &cell_rect); - pspp_sheet_view_get_visible_rect (tree_view, &vis_rect); - - cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y); - - dest_x = vis_rect.x; - dest_y = vis_rect.y; - - if (column) - { - if (use_align) - { - dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align); - } - else - { - if (cell_rect.x < vis_rect.x) - dest_x = cell_rect.x; - if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width) - dest_x = cell_rect.x + cell_rect.width - vis_rect.width; - } - } - - if (path) - { - if (use_align) - { - dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align); - dest_y = MAX (dest_y, 0); - } - else - { - if (cell_rect.y < vis_rect.y) - dest_y = cell_rect.y; - if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height) - dest_y = cell_rect.y + cell_rect.height - vis_rect.height; - } - } - - pspp_sheet_view_scroll_to_point (tree_view, dest_x, dest_y); - } -} - -/** - * pspp_sheet_view_row_activated: - * @tree_view: A #PsppSheetView - * @path: The #GtkTreePath to be activated. - * @column: The #PsppSheetViewColumn to be activated. - * - * Activates the cell determined by @path and @column. - **/ -void -pspp_sheet_view_row_activated (PsppSheetView *tree_view, - GtkTreePath *path, - PsppSheetViewColumn *column) -{ - g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); - - g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column); -} - - -static void -pspp_sheet_view_expand_all_emission_helper (GtkRBTree *tree, - GtkRBNode *node, - gpointer data) -{ - PsppSheetView *tree_view = data; - - if ((node->flags & PSPP_RBNODE_IS_PARENT) == PSPP_RBNODE_IS_PARENT && - node->children) - { - GtkTreePath *path; - GtkTreeIter iter; - - path = _pspp_sheet_view_find_path (tree_view, tree, node); - gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - - g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path); - - gtk_tree_path_free (path); - } - - if (node->children) - _pspp_rbtree_traverse (node->children, - node->children->root, - G_PRE_ORDER, - pspp_sheet_view_expand_all_emission_helper, - tree_view); -} - -/** - * pspp_sheet_view_expand_all: - * @tree_view: A #PsppSheetView. - * - * Recursively expands all nodes in the @tree_view. - **/ -void -pspp_sheet_view_expand_all (PsppSheetView *tree_view) -{ - GtkTreePath *path; - GtkRBTree *tree; - GtkRBNode *node; - - g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); - - if (tree_view->priv->tree == NULL) - return; - - path = gtk_tree_path_new_first (); - _pspp_sheet_view_find_node (tree_view, path, &tree, &node); - - while (node) - { - pspp_sheet_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE); - node = _pspp_rbtree_next (tree, node); - gtk_tree_path_next (path); - } - - gtk_tree_path_free (path); -} - -/* Timeout to animate the expander during expands and collapses */ -static gboolean -expand_collapse_timeout (gpointer data) -{ - return do_expand_collapse (data); -} - -static void -add_expand_collapse_timeout (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkRBNode *node, - gboolean expand) -{ - if (tree_view->priv->expand_collapse_timeout != 0) - return; - - tree_view->priv->expand_collapse_timeout = - gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view); - tree_view->priv->expanded_collapsed_tree = tree; - tree_view->priv->expanded_collapsed_node = node; - - if (expand) - PSPP_RBNODE_SET_FLAG (node, PSPP_RBNODE_IS_SEMI_COLLAPSED); - else - PSPP_RBNODE_SET_FLAG (node, PSPP_RBNODE_IS_SEMI_EXPANDED); -} - -static void -remove_expand_collapse_timeout (PsppSheetView *tree_view) -{ - if (tree_view->priv->expand_collapse_timeout) - { - g_source_remove (tree_view->priv->expand_collapse_timeout); - tree_view->priv->expand_collapse_timeout = 0; - } - - if (tree_view->priv->expanded_collapsed_node != NULL) - { - PSPP_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, PSPP_RBNODE_IS_SEMI_EXPANDED); - PSPP_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, PSPP_RBNODE_IS_SEMI_COLLAPSED); - - tree_view->priv->expanded_collapsed_node = NULL; - } -} - -static void -cancel_arrow_animation (PsppSheetView *tree_view) -{ - if (tree_view->priv->expand_collapse_timeout) - { - while (do_expand_collapse (tree_view)); - - remove_expand_collapse_timeout (tree_view); - } -} - -static gboolean -do_expand_collapse (PsppSheetView *tree_view) -{ - GtkRBNode *node; - GtkRBTree *tree; - gboolean expanding; - gboolean redraw; - - redraw = FALSE; - expanding = TRUE; - - node = tree_view->priv->expanded_collapsed_node; - tree = tree_view->priv->expanded_collapsed_tree; - - if (node->children == NULL) - expanding = FALSE; - - if (expanding) - { - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SEMI_COLLAPSED)) - { - PSPP_RBNODE_UNSET_FLAG (node, PSPP_RBNODE_IS_SEMI_COLLAPSED); - PSPP_RBNODE_SET_FLAG (node, PSPP_RBNODE_IS_SEMI_EXPANDED); - - redraw = TRUE; - - } - else if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SEMI_EXPANDED)) - { - PSPP_RBNODE_UNSET_FLAG (node, PSPP_RBNODE_IS_SEMI_EXPANDED); - - redraw = TRUE; - } - } - else - { - if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SEMI_EXPANDED)) - { - PSPP_RBNODE_UNSET_FLAG (node, PSPP_RBNODE_IS_SEMI_EXPANDED); - PSPP_RBNODE_SET_FLAG (node, PSPP_RBNODE_IS_SEMI_COLLAPSED); - - redraw = TRUE; - } - else if (PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SEMI_COLLAPSED)) - { - PSPP_RBNODE_UNSET_FLAG (node, PSPP_RBNODE_IS_SEMI_COLLAPSED); - - redraw = TRUE; - - } - } - - if (redraw) - { - pspp_sheet_view_queue_draw_arrow (tree_view, tree, node, NULL); - - return TRUE; - } - - return FALSE; -} - -/** - * pspp_sheet_view_collapse_all: - * @tree_view: A #PsppSheetView. - * - * Recursively collapses all visible, expanded nodes in @tree_view. - **/ -void -pspp_sheet_view_collapse_all (PsppSheetView *tree_view) -{ - GtkRBTree *tree; - GtkRBNode *node; - GtkTreePath *path; - gint *indices; - - g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); - - if (tree_view->priv->tree == NULL) - return; - - path = gtk_tree_path_new (); - gtk_tree_path_down (path); - indices = gtk_tree_path_get_indices (path); - - tree = tree_view->priv->tree; - node = tree->root; - while (node && node->left != tree->nil) - node = node->left; - - while (node) - { - if (node->children) - pspp_sheet_view_real_collapse_row (tree_view, path, tree, node, FALSE); - indices[0]++; - node = _pspp_rbtree_next (tree, node); - } - - gtk_tree_path_free (path); -} - -/** - * pspp_sheet_view_expand_to_path: - * @tree_view: A #PsppSheetView. - * @path: path to a row. - * - * Expands the row at @path. This will also expand all parent rows of - * @path as necessary. - * - * Since: 2.2 - **/ -void -pspp_sheet_view_expand_to_path (PsppSheetView *tree_view, - GtkTreePath *path) -{ - gint i, depth; - gint *indices; - GtkTreePath *tmp; - - g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); - g_return_if_fail (path != NULL); - - depth = gtk_tree_path_get_depth (path); - indices = gtk_tree_path_get_indices (path); - - tmp = gtk_tree_path_new (); - g_return_if_fail (tmp != NULL); - - for (i = 0; i < depth; i++) - { - gtk_tree_path_append_index (tmp, indices[i]); - pspp_sheet_view_expand_row (tree_view, tmp, FALSE); - } - - gtk_tree_path_free (tmp); -} - -/* FIXME the bool return values for expand_row and collapse_row are - * not analagous; they should be TRUE if the row had children and - * was not already in the requested state. - */ - - -static gboolean -pspp_sheet_view_real_expand_row (PsppSheetView *tree_view, - GtkTreePath *path, - GtkRBTree *tree, - GtkRBNode *node, - gboolean open_all, - gboolean animate) -{ - GtkTreeIter iter; - GtkTreeIter temp; - gboolean expand; - - if (animate) - g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)), - "gtk-enable-animations", &animate, - NULL); - - remove_auto_expand_timeout (tree_view); - - if (node->children && !open_all) - return FALSE; - - if (! PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_PARENT)) - return FALSE; - - gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter)) - return FALSE; - - - if (node->children && open_all) - { - gboolean retval = FALSE; - GtkTreePath *tmp_path = gtk_tree_path_copy (path); - - gtk_tree_path_append_index (tmp_path, 0); - tree = node->children; - node = tree->root; - while (node->left != tree->nil) - node = node->left; - /* try to expand the children */ - do - { - gboolean t; - t = pspp_sheet_view_real_expand_row (tree_view, tmp_path, tree, node, - TRUE, animate); - if (t) - retval = TRUE; - - gtk_tree_path_next (tmp_path); - node = _pspp_rbtree_next (tree, node); - } - while (node != NULL); - - gtk_tree_path_free (tmp_path); - - return retval; - } - - g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand); - - if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter)) - return FALSE; - - if (expand) - return FALSE; - - node->children = _pspp_rbtree_new (); - node->children->parent_tree = tree; - node->children->parent_node = node; - - gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter); - - pspp_sheet_view_build_tree (tree_view, - node->children, - &temp, - gtk_tree_path_get_depth (path) + 1, - open_all); - - remove_expand_collapse_timeout (tree_view); - - if (animate) - add_expand_collapse_timeout (tree_view, tree, node, TRUE); - - install_presize_handler (tree_view); - - g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path); - if (open_all && node->children) - { - _pspp_rbtree_traverse (node->children, - node->children->root, - G_PRE_ORDER, - pspp_sheet_view_expand_all_emission_helper, - tree_view); - } - return TRUE; -} - - -/** - * pspp_sheet_view_expand_row: - * @tree_view: a #PsppSheetView - * @path: path to a row - * @open_all: whether to recursively expand, or just expand immediate children - * - * Opens the row so its children are visible. - * - * Return value: %TRUE if the row existed and had children - **/ -gboolean -pspp_sheet_view_expand_row (PsppSheetView *tree_view, - GtkTreePath *path, - gboolean open_all) -{ - GtkRBTree *tree; - GtkRBNode *node; - - g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE); - g_return_val_if_fail (tree_view->priv->model != NULL, FALSE); - g_return_val_if_fail (path != NULL, FALSE); - - if (_pspp_sheet_view_find_node (tree_view, - path, - &tree, - &node)) - return FALSE; - - if (tree != NULL) - return pspp_sheet_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE); - else - return FALSE; -} - -static gboolean -pspp_sheet_view_real_collapse_row (PsppSheetView *tree_view, - GtkTreePath *path, - GtkRBTree *tree, - GtkRBNode *node, - gboolean animate) -{ - GtkTreeIter iter; - GtkTreeIter children; - gboolean collapse; - gint x, y; - GList *list; - GdkWindow *child, *parent; - - if (animate) - g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)), - "gtk-enable-animations", &animate, - NULL); - - remove_auto_expand_timeout (tree_view); - - if (node->children == NULL) - return FALSE; - - gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - - g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse); - - if (collapse) - return FALSE; - - /* if the prelighted node is a child of us, we want to unprelight it. We have - * a chance to prelight the correct node below */ - - if (tree_view->priv->prelight_tree) - { - GtkRBTree *parent_tree; - GtkRBNode *parent_node; - - parent_tree = tree_view->priv->prelight_tree->parent_tree; - parent_node = tree_view->priv->prelight_tree->parent_node; - while (parent_tree) - { - if (parent_tree == tree && parent_node == node) - { - ensure_unprelighted (tree_view); - break; - } - parent_node = parent_tree->parent_node; - parent_tree = parent_tree->parent_tree; - } - } - - TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE); - - for (list = tree_view->priv->columns; list; list = list->next) - { - PsppSheetViewColumn *column = list->data; - - if (column->visible == FALSE) - continue; - if (pspp_sheet_view_column_get_sizing (column) == PSPP_SHEET_VIEW_COLUMN_AUTOSIZE) - _pspp_sheet_view_column_cell_set_dirty (column, TRUE); - } - - if (tree_view->priv->destroy_count_func) - { - GtkTreePath *child_path; - gint child_count = 0; - child_path = gtk_tree_path_copy (path); - gtk_tree_path_down (child_path); - if (node->children) - _pspp_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count); - tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data); - gtk_tree_path_free (child_path); - } + g_return_if_fail (row_align >= 0.0 && row_align <= 1.0); + g_return_if_fail (col_align >= 0.0 && col_align <= 1.0); + g_return_if_fail (path != NULL || column != NULL); - if (gtk_tree_row_reference_valid (tree_view->priv->cursor)) - { - GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); +#if 0 + g_print ("pspp_sheet_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n", + gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align); +#endif + row_align = CLAMP (row_align, 0.0, 1.0); + col_align = CLAMP (col_align, 0.0, 1.0); - if (gtk_tree_path_is_ancestor (path, cursor_path)) - { - gtk_tree_row_reference_free (tree_view->priv->cursor); - tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), - tree_view->priv->model, - path); - } - gtk_tree_path_free (cursor_path); - } - if (gtk_tree_row_reference_valid (tree_view->priv->anchor)) + /* Note: Despite the benefits that come from having one code path for the + * scrolling code, we short-circuit validate_visible_area's immplementation as + * it is much slower than just going to the point. + */ + if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) || + !gtk_widget_get_realized (GTK_WIDGET (tree_view)) + /* XXX || GTK_WIDGET_ALLOC_NEEDED (tree_view) */) { - GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor); - if (gtk_tree_path_is_ancestor (path, anchor_path)) - { - gtk_tree_row_reference_free (tree_view->priv->anchor); - tree_view->priv->anchor = NULL; - } - gtk_tree_path_free (anchor_path); - } + if (tree_view->priv->scroll_to_path) + gtk_tree_row_reference_free (tree_view->priv->scroll_to_path); - /* Stop a pending double click */ - tree_view->priv->last_button_x = -1; - tree_view->priv->last_button_y = -1; + tree_view->priv->scroll_to_path = NULL; + tree_view->priv->scroll_to_column = NULL; - remove_expand_collapse_timeout (tree_view); + if (path) + tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path); + if (column) + tree_view->priv->scroll_to_column = column; + tree_view->priv->scroll_to_use_align = use_align; + tree_view->priv->scroll_to_row_align = row_align; + tree_view->priv->scroll_to_col_align = col_align; - if (pspp_sheet_view_unref_and_check_selection_tree (tree_view, node->children)) - { - _pspp_rbtree_remove (node->children); - g_signal_emit_by_name (tree_view->priv->selection, "changed"); + install_presize_handler (tree_view); } else - _pspp_rbtree_remove (node->children); - - if (animate) - add_expand_collapse_timeout (tree_view, tree, node, FALSE); - - if (gtk_widget_get_mapped (GTK_WIDGET (tree_view))) { - gtk_widget_queue_resize (GTK_WIDGET (tree_view)); - } + GdkRectangle cell_rect; + GdkRectangle vis_rect; + gint dest_x, dest_y; - g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path); + pspp_sheet_view_get_background_area (tree_view, path, column, &cell_rect); + pspp_sheet_view_get_visible_rect (tree_view, &vis_rect); - if (gtk_widget_get_mapped (GTK_WIDGET (tree_view))) - { - /* now that we've collapsed all rows, we want to try to set the prelight - * again. To do this, we fake a motion event and send it to ourselves. */ + cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y); - child = tree_view->priv->bin_window; - parent = gdk_window_get_parent (child); + dest_x = vis_rect.x; + dest_y = vis_rect.y; - if (gdk_window_get_pointer (parent, &x, &y, NULL) == child) + if (column) { - GdkEventMotion event; - gint child_x, child_y; - - gdk_window_get_position (child, &child_x, &child_y); - - event.window = tree_view->priv->bin_window; - event.x = x - child_x; - event.y = y - child_y; - - /* despite the fact this isn't a real event, I'm almost positive it will - * never trigger a drag event. maybe_drag is the only function that uses - * more than just event.x and event.y. */ - pspp_sheet_view_motion_bin_window (GTK_WIDGET (tree_view), &event); + if (use_align) + { + dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align); + } + else + { + if (cell_rect.x < vis_rect.x) + dest_x = cell_rect.x; + if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width) + dest_x = cell_rect.x + cell_rect.width - vis_rect.width; + } } - } - - return TRUE; -} - -/** - * pspp_sheet_view_collapse_row: - * @tree_view: a #PsppSheetView - * @path: path to a row in the @tree_view - * - * Collapses a row (hides its child rows, if they exist). - * - * Return value: %TRUE if the row was collapsed. - **/ -gboolean -pspp_sheet_view_collapse_row (PsppSheetView *tree_view, - GtkTreePath *path) -{ - GtkRBTree *tree; - GtkRBNode *node; - - g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE); - g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE); - g_return_val_if_fail (path != NULL, FALSE); - - if (_pspp_sheet_view_find_node (tree_view, - path, - &tree, - &node)) - return FALSE; - - if (tree == NULL || node->children == NULL) - return FALSE; - - return pspp_sheet_view_real_collapse_row (tree_view, path, tree, node, FALSE); -} - -static void -pspp_sheet_view_map_expanded_rows_helper (PsppSheetView *tree_view, - GtkRBTree *tree, - GtkTreePath *path, - PsppSheetViewMappingFunc func, - gpointer user_data) -{ - GtkRBNode *node; - - if (tree == NULL || tree->root == NULL) - return; - node = tree->root; - - while (node && node->left != tree->nil) - node = node->left; - - while (node) - { - if (node->children) + if (path) { - (* func) (tree_view, path, user_data); - gtk_tree_path_down (path); - pspp_sheet_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data); - gtk_tree_path_up (path); + if (use_align) + { + dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align); + dest_y = MAX (dest_y, 0); + } + else + { + if (cell_rect.y < vis_rect.y) + dest_y = cell_rect.y; + if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height) + dest_y = cell_rect.y + cell_rect.height - vis_rect.height; + } } - gtk_tree_path_next (path); - node = _pspp_rbtree_next (tree, node); + + pspp_sheet_view_scroll_to_point (tree_view, dest_x, dest_y); } } /** - * pspp_sheet_view_map_expanded_rows: + * pspp_sheet_view_row_activated: * @tree_view: A #PsppSheetView - * @func: A function to be called - * @data: User data to be passed to the function. + * @path: The #GtkTreePath to be activated. + * @column: The #PsppSheetViewColumn to be activated. * - * Calls @func on all expanded rows. + * Activates the cell determined by @path and @column. **/ void -pspp_sheet_view_map_expanded_rows (PsppSheetView *tree_view, - PsppSheetViewMappingFunc func, - gpointer user_data) +pspp_sheet_view_row_activated (PsppSheetView *tree_view, + GtkTreePath *path, + PsppSheetViewColumn *column) { - GtkTreePath *path; - g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); - g_return_if_fail (func != NULL); - - path = gtk_tree_path_new_first (); - pspp_sheet_view_map_expanded_rows_helper (tree_view, - tree_view->priv->tree, - path, func, user_data); - - gtk_tree_path_free (path); + g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column); } -/** - * pspp_sheet_view_row_expanded: - * @tree_view: A #PsppSheetView. - * @path: A #GtkTreePath to test expansion state. - * - * Returns %TRUE if the node pointed to by @path is expanded in @tree_view. - * - * Return value: %TRUE if #path is expanded. - **/ -gboolean -pspp_sheet_view_row_expanded (PsppSheetView *tree_view, - GtkTreePath *path) -{ - GtkRBTree *tree; - GtkRBNode *node; - - g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE); - g_return_val_if_fail (path != NULL, FALSE); - - _pspp_sheet_view_find_node (tree_view, path, &tree, &node); - - if (node == NULL) - return FALSE; - - return (node->children != NULL); -} /** * pspp_sheet_view_get_reorderable: @@ -12502,14 +9774,18 @@ 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, gboolean clear_and_select, gboolean clamp_node) { - GtkRBTree *tree = NULL; - GtkRBNode *node = NULL; + int node = -1; if (gtk_tree_row_reference_valid (tree_view->priv->cursor)) { @@ -12522,30 +9798,15 @@ pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view, gtk_tree_row_reference_free (tree_view->priv->cursor); tree_view->priv->cursor = NULL; - /* One cannot set the cursor on a separator. Also, if - * _pspp_sheet_view_find_node returns TRUE, it ran out of tree - * before finding the tree and node belonging to path. The - * path maps to a non-existing path and we will silently bail out. - * We unset tree and node to avoid further processing. - */ - if (!row_is_separator (tree_view, NULL, path) - && _pspp_sheet_view_find_node (tree_view, path, &tree, &node) == FALSE) - { - tree_view->priv->cursor = - gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), - tree_view->priv->model, - path); - } - else - { - tree = NULL; - node = NULL; - } + _pspp_sheet_view_find_node (tree_view, path, &node); + tree_view->priv->cursor = + gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), + tree_view->priv->model, + path); - if (tree != NULL) + if (tree_view->priv->row_count > 0) { - GtkRBTree *new_tree = NULL; - GtkRBNode *new_node = NULL; + int new_node = -1; if (clear_and_select && !tree_view->priv->ctrl_pressed) { @@ -12557,7 +9818,7 @@ pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view, mode |= GTK_TREE_SELECT_MODE_EXTEND; _pspp_sheet_selection_internal_select_node (tree_view->priv->selection, - node, tree, path, mode, + node, path, mode, FALSE); } @@ -12565,15 +9826,15 @@ pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view, * cleared the node or the whole tree in the PsppSheetSelection::changed * callback. If the nodes differ we bail out here. */ - _pspp_sheet_view_find_node (tree_view, path, &new_tree, &new_node); + _pspp_sheet_view_find_node (tree_view, path, &new_node); - if (tree != new_tree || node != new_node) + if (node != new_node) return; if (clamp_node) { - pspp_sheet_view_clamp_node_visible (tree_view, tree, node); - _pspp_sheet_view_queue_draw_node (tree_view, tree, node, NULL); + pspp_sheet_view_clamp_node_visible (tree_view, node); + _pspp_sheet_view_queue_draw_node (tree_view, node, NULL); } } @@ -12712,6 +9973,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); + } } @@ -12772,8 +10037,7 @@ pspp_sheet_view_get_path_at_pos (PsppSheetView *tree_view, gint *cell_x, gint *cell_y) { - GtkRBTree *tree; - GtkRBNode *node; + int node; gint y_offset; g_return_val_if_fail (tree_view != NULL, FALSE); @@ -12786,7 +10050,7 @@ pspp_sheet_view_get_path_at_pos (PsppSheetView *tree_view, if (tree_view->priv->bin_window == NULL) return FALSE; - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) return FALSE; if (x > tree_view->priv->hadjustment->upper) @@ -12850,22 +10114,137 @@ pspp_sheet_view_get_path_at_pos (PsppSheetView *tree_view, } } - y_offset = _pspp_rbtree_find_offset (tree_view->priv->tree, - TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y), - &tree, &node); + y_offset = pspp_sheet_view_find_offset (tree_view, + TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y), + &node); - if (tree == NULL) + if (node < 0) return FALSE; if (cell_y) *cell_y = y_offset; if (path) - *path = _pspp_sheet_view_find_path (tree_view, tree, node); + *path = _pspp_sheet_view_find_path (tree_view, node); return TRUE; } +/* Computes 'cell_area' from 'background_area', which must be the background + area for a cell. Set 'subtract_focus_rect' to TRUE to compute the cell area + as passed to a GtkCellRenderer's "render" function, or to FALSE to compute + the cell area as passed to _pspp_sheet_view_column_cell_render(). + + 'column' is required to properly adjust 'cell_area->x' and + 'cell_area->width'. It may be set to NULL if these values are not of + interest. In this case 'cell_area->x' and 'cell_area->width' will be + returned as 0. */ +static void +pspp_sheet_view_adjust_cell_area (PsppSheetView *tree_view, + PsppSheetViewColumn *column, + const GdkRectangle *background_area, + gboolean subtract_focus_rect, + GdkRectangle *cell_area) +{ + gint vertical_separator; + gint horizontal_separator; + + *cell_area = *background_area; + + gtk_widget_style_get (GTK_WIDGET (tree_view), + "vertical-separator", &vertical_separator, + "horizontal-separator", &horizontal_separator, + NULL); + cell_area->x += horizontal_separator / 2; + cell_area->y += vertical_separator / 2; + cell_area->width -= horizontal_separator; + cell_area->height -= vertical_separator; + + if (subtract_focus_rect) + { + int focus_line_width; + + gtk_widget_style_get (GTK_WIDGET (tree_view), + "focus-line-width", &focus_line_width, + NULL); + cell_area->x += focus_line_width; + cell_area->y += focus_line_width; + cell_area->width -= 2 * focus_line_width; + cell_area->height -= 2 * focus_line_width; + } + + if (tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_NONE) + { + gint grid_line_width; + gtk_widget_style_get (GTK_WIDGET (tree_view), + "grid-line-width", &grid_line_width, + NULL); + + if ((tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_VERTICAL + || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH) + && column != NULL) + { + PsppSheetViewColumn *first_column, *last_column; + GList *list; + + /* Find the last visible column. */ + last_column = NULL; + for (list = g_list_last (tree_view->priv->columns); + list; + list = list->prev) + { + PsppSheetViewColumn *c = list->data; + if (c->visible) + { + last_column = c; + break; + } + } + + /* Find the first visible column. */ + first_column = NULL; + for (list = g_list_first (tree_view->priv->columns); + list; + list = list->next) + { + PsppSheetViewColumn *c = list->data; + if (c->visible) + { + first_column = c; + break; + } + } + + if (column == first_column) + { + cell_area->width -= grid_line_width / 2; + } + else if (column == last_column) + { + cell_area->x += grid_line_width / 2; + cell_area->width -= grid_line_width / 2; + } + else + { + cell_area->x += grid_line_width / 2; + cell_area->width -= grid_line_width; + } + } + + if (tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL + || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH) + { + cell_area->y += grid_line_width / 2; + cell_area->height -= grid_line_width; + } + } + + if (column == NULL) + { + cell_area->x = 0; + cell_area->width = 0; + } +} /** * pspp_sheet_view_get_cell_area: @@ -12890,10 +10269,7 @@ pspp_sheet_view_get_cell_area (PsppSheetView *tree_view, PsppSheetViewColumn *column, GdkRectangle *rect) { - GtkRBTree *tree = NULL; - GtkRBNode *node = NULL; - gint vertical_separator; - gint horizontal_separator; + GdkRectangle background_area; g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); g_return_if_fail (column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (column)); @@ -12901,55 +10277,10 @@ pspp_sheet_view_get_cell_area (PsppSheetView *tree_view, g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view); g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view))); - gtk_widget_style_get (GTK_WIDGET (tree_view), - "vertical-separator", &vertical_separator, - "horizontal-separator", &horizontal_separator, - NULL); - - rect->x = 0; - rect->y = 0; - rect->width = 0; - rect->height = 0; - - if (column) - { - rect->x = column->button->allocation.x + horizontal_separator/2; - rect->width = column->button->allocation.width - horizontal_separator; - } - - if (path) - { - gboolean ret = _pspp_sheet_view_find_node (tree_view, path, &tree, &node); - - /* Get vertical coords */ - if ((!ret && tree == NULL) || ret) - return; - - rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator); - rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator); - - if (column && - pspp_sheet_view_is_expander_column (tree_view, column)) - { - gint depth = gtk_tree_path_get_depth (path); - gboolean rtl; - - rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL; - - if (!rtl) - rect->x += (depth - 1) * tree_view->priv->level_indentation; - rect->width -= (depth - 1) * tree_view->priv->level_indentation; - - if (TREE_VIEW_DRAW_EXPANDERS (tree_view)) - { - if (!rtl) - rect->x += depth * tree_view->priv->expander_size; - rect->width -= depth * tree_view->priv->expander_size; - } - - rect->width = MAX (rect->width, 0); - } - } + pspp_sheet_view_get_background_area (tree_view, path, column, + &background_area); + pspp_sheet_view_adjust_cell_area (tree_view, column, &background_area, + FALSE, rect); } /** @@ -12967,7 +10298,7 @@ pspp_sheet_view_get_cell_area (PsppSheetView *tree_view, * @background_area passed to gtk_cell_renderer_render(). These background * areas tile to cover the entire bin window. Contrast with the @cell_area, * returned by pspp_sheet_view_get_cell_area(), which returns only the cell - * itself, excluding surrounding borders and the tree expander area. + * itself, excluding surrounding borders. * **/ void @@ -12976,8 +10307,7 @@ pspp_sheet_view_get_background_area (PsppSheetView *tree_view, PsppSheetViewColumn *column, GdkRectangle *rect) { - GtkRBTree *tree = NULL; - GtkRBNode *node = NULL; + int node = -1; g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); g_return_if_fail (column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (column)); @@ -12992,20 +10322,20 @@ pspp_sheet_view_get_background_area (PsppSheetView *tree_view, { /* Get vertical coords */ - if (!_pspp_sheet_view_find_node (tree_view, path, &tree, &node) && - tree == NULL) + _pspp_sheet_view_find_node (tree_view, path, &node); + if (node < 0) return; - rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); + rect->y = BACKGROUND_FIRST_PIXEL (tree_view, node); - rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)); + rect->height = ROW_HEIGHT (tree_view); } if (column) { gint x2 = 0; - pspp_sheet_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2); + pspp_sheet_view_get_background_xrange (tree_view, column, &rect->x, &x2); rect->width = x2 - rect->x; } } @@ -13303,24 +10633,23 @@ pspp_sheet_view_get_visible_range (PsppSheetView *tree_view, GtkTreePath **start_path, GtkTreePath **end_path) { - GtkRBTree *tree; - GtkRBNode *node; + int node; gboolean retval; g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE); - if (!tree_view->priv->tree) + if (!tree_view->priv->row_count) return FALSE; retval = TRUE; if (start_path) { - _pspp_rbtree_find_offset (tree_view->priv->tree, - TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0), - &tree, &node); - if (node) - *start_path = _pspp_sheet_view_find_path (tree_view, tree, node); + pspp_sheet_view_find_offset (tree_view, + TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0), + &node); + if (node >= 0) + *start_path = _pspp_sheet_view_find_path (tree_view, node); else retval = FALSE; } @@ -13334,9 +10663,9 @@ pspp_sheet_view_get_visible_range (PsppSheetView *tree_view, else y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1; - _pspp_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node); - if (node) - *end_path = _pspp_sheet_view_find_path (tree_view, tree, node); + pspp_sheet_view_find_offset (tree_view, y, &node); + if (node >= 0) + *end_path = _pspp_sheet_view_find_path (tree_view, node); else retval = FALSE; } @@ -13547,21 +10876,20 @@ pspp_sheet_view_set_drag_dest_row (PsppSheetView *tree_view, if (current_dest) { - GtkRBTree *tree, *new_tree; - GtkRBNode *node, *new_node; + int node, new_node; - _pspp_sheet_view_find_node (tree_view, current_dest, &tree, &node); - _pspp_sheet_view_queue_draw_node (tree_view, tree, node, NULL); + _pspp_sheet_view_find_node (tree_view, current_dest, &node); + _pspp_sheet_view_queue_draw_node (tree_view, node, NULL); - if (tree && node) + if (node >= 0) { - _pspp_rbtree_next_full (tree, node, &new_tree, &new_node); - if (new_tree && new_node) - _pspp_sheet_view_queue_draw_node (tree_view, new_tree, new_node, NULL); + new_node = pspp_sheet_view_node_next (tree_view, node); + if (new_node >= 0) + _pspp_sheet_view_queue_draw_node (tree_view, new_node, NULL); - _pspp_rbtree_prev_full (tree, node, &new_tree, &new_node); - if (new_tree && new_node) - _pspp_sheet_view_queue_draw_node (tree_view, new_tree, new_node, NULL); + new_node = pspp_sheet_view_node_prev (tree_view, node); + if (new_node >= 0) + _pspp_sheet_view_queue_draw_node (tree_view, new_node, NULL); } gtk_tree_path_free (current_dest); } @@ -13644,7 +10972,7 @@ pspp_sheet_view_get_dest_row_at_pos (PsppSheetView *tree_view, if (tree_view->priv->bin_window == NULL) return FALSE; - if (tree_view->priv->tree == NULL) + if (tree_view->priv->row_count == 0) return FALSE; /* If in the top third of a row, we drop before that row; if @@ -13718,8 +11046,7 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, GtkTreePath *path) { GtkTreeIter iter; - GtkRBTree *tree; - GtkRBNode *node; + int node; gint cell_offset; GList *list; GdkRectangle background_area; @@ -13730,7 +11057,6 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, gint x = 1, y = 1; GdkDrawable *drawable; gint bin_window_width; - gboolean is_separator = FALSE; gboolean rtl; g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL); @@ -13745,10 +11071,9 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, _pspp_sheet_view_find_node (tree_view, path, - &tree, &node); - if (tree == NULL) + if (node < 0) return NULL; if (!gtk_tree_model_get_iter (tree_view->priv->model, @@ -13756,12 +11081,10 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, path)) return NULL; - is_separator = row_is_separator (tree_view, &iter, NULL); - cell_offset = x; background_area.y = y; - background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)); + background_area.height = ROW_HEIGHT (tree_view); gdk_drawable_get_size (tree_view->priv->bin_window, &bin_window_width, NULL); @@ -13796,9 +11119,7 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, if (!column->visible) continue; - pspp_sheet_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter, - PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_PARENT), - node->children?TRUE:FALSE); + pspp_sheet_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter); background_area.x = cell_offset; background_area.width = column->width; @@ -13812,40 +11133,13 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, cell_area.y += vertical_separator / 2; cell_area.height -= vertical_separator; - if (pspp_sheet_view_is_expander_column (tree_view, column)) - { - if (!rtl) - cell_area.x += (depth - 1) * tree_view->priv->level_indentation; - cell_area.width -= (depth - 1) * tree_view->priv->level_indentation; - - if (TREE_VIEW_DRAW_EXPANDERS(tree_view)) - { - if (!rtl) - cell_area.x += depth * tree_view->priv->expander_size; - cell_area.width -= depth * tree_view->priv->expander_size; - } - } - if (pspp_sheet_view_column_cell_is_visible (column)) - { - if (is_separator) - gtk_paint_hline (widget->style, - drawable, - GTK_STATE_NORMAL, - &cell_area, - widget, - NULL, - cell_area.x, - cell_area.x + cell_area.width, - cell_area.y + cell_area.height / 2); - else - _pspp_sheet_view_column_cell_render (column, - drawable, - &background_area, - &cell_area, - &expose_area, - 0); - } + _pspp_sheet_view_column_cell_render (column, + drawable, + &background_area, + &cell_area, + &expose_area, + 0); cell_offset += column->width; } @@ -13868,8 +11162,7 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, * @destroy: (allow-none): Destroy notifier for @data, or %NULL * * This function should almost never be used. It is meant for private use by - * ATK for determining the number of visible children that are removed when the - * user collapses a row, or a row is deleted. + * ATK for determining the number of visible children that are removed when a row is deleted. **/ void pspp_sheet_view_set_destroy_count_func (PsppSheetView *tree_view, @@ -14274,8 +11567,7 @@ pspp_sheet_view_search_activate (GtkEntry *entry, PsppSheetView *tree_view) { GtkTreePath *path; - GtkRBNode *node; - GtkRBTree *tree; + int node; pspp_sheet_view_search_dialog_hide (tree_view->priv->search_window, tree_view); @@ -14286,9 +11578,9 @@ pspp_sheet_view_search_activate (GtkEntry *entry, { path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); - _pspp_sheet_view_find_node (tree_view, path, &tree, &node); + _pspp_sheet_view_find_node (tree_view, path, &node); - if (node && PSPP_RBNODE_FLAG_SET (node, PSPP_RBNODE_IS_SELECTED)) + if (node >= 0 && pspp_sheet_view_node_is_selected (tree_view, node)) pspp_sheet_view_row_activated (tree_view, path, tree_view->priv->focus_column); gtk_tree_path_free (path); @@ -14559,30 +11851,31 @@ pspp_sheet_view_search_equal_func (GtkTreeModel *model, static gboolean pspp_sheet_view_search_iter (GtkTreeModel *model, - PsppSheetSelection *selection, - GtkTreeIter *iter, - const gchar *text, - gint *count, - gint n) -{ - GtkRBTree *tree = NULL; - GtkRBNode *node = NULL; + PsppSheetSelection *selection, + GtkTreeIter *iter, + const gchar *text, + gint *count, + gint n) +{ + int node = -1; GtkTreePath *path; PsppSheetView *tree_view = pspp_sheet_selection_get_tree_view (selection); path = gtk_tree_model_get_path (model, iter); - _pspp_sheet_view_find_node (tree_view, path, &tree, &node); + _pspp_sheet_view_find_node (tree_view, path, &node); do { + gboolean done = FALSE; + if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data)) { (*count)++; if (*count == n) { pspp_sheet_view_scroll_to_cell (tree_view, path, NULL, - TRUE, 0.5, 0.0); + TRUE, 0.5, 0.0); pspp_sheet_selection_select_iter (selection, iter); pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE); @@ -14593,72 +11886,33 @@ pspp_sheet_view_search_iter (GtkTreeModel *model, } } - if (node->children) - { - gboolean has_child; - GtkTreeIter tmp; - - tree = node->children; - node = tree->root; - - while (node->left != tree->nil) - node = node->left; - - tmp = *iter; - has_child = gtk_tree_model_iter_children (model, iter, &tmp); - gtk_tree_path_down (path); - - /* sanity check */ - TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE); - } - else - { - gboolean done = FALSE; - - do - { - node = _pspp_rbtree_next (tree, node); - - if (node) - { - gboolean has_next; - - has_next = gtk_tree_model_iter_next (model, iter); - - done = TRUE; - gtk_tree_path_next (path); - - /* sanity check */ - TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE); - } - else - { - gboolean has_parent; - GtkTreeIter tmp_iter = *iter; - node = tree->parent_node; - tree = tree->parent_tree; + do + { + node = pspp_sheet_view_node_next (tree_view, node); - if (!tree) - { - if (path) - gtk_tree_path_free (path); + if (node >= 0) + { + gboolean has_next; - /* we've run out of tree, done with this func */ - return FALSE; - } + has_next = gtk_tree_model_iter_next (model, iter); - has_parent = gtk_tree_model_iter_parent (model, - iter, - &tmp_iter); - gtk_tree_path_up (path); + done = TRUE; + gtk_tree_path_next (path); - /* sanity check */ - TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE); - } - } - while (!done); - } + /* sanity check */ + TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE); + } + else + { + if (path) + gtk_tree_path_free (path); + + /* we've run out of tree, done with this func */ + return FALSE; + } + } + while (!done); } while (1); @@ -14726,6 +11980,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)); @@ -14745,28 +12005,23 @@ pspp_sheet_view_start_editing (PsppSheetView *tree_view, gchar *path_string; guint flags = 0; /* can be 0, as the flags are primarily for rendering */ gint retval = FALSE; - GtkRBTree *cursor_tree; - GtkRBNode *cursor_node; + int cursor_node; g_assert (tree_view->priv->focus_column); if (!gtk_widget_get_realized (GTK_WIDGET (tree_view))) return FALSE; - if (_pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) || - cursor_node == NULL) + _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node); + if (cursor_node < 0) return FALSE; path_string = gtk_tree_path_to_string (cursor_path); gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path); - validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path); - pspp_sheet_view_column_cell_set_cell_data (tree_view->priv->focus_column, tree_view->priv->model, - &iter, - PSPP_RBNODE_FLAG_SET (cursor_node, PSPP_RBNODE_IS_PARENT), - cursor_node->children?TRUE:FALSE); + &iter); pspp_sheet_view_get_background_area (tree_view, cursor_path, tree_view->priv->focus_column, @@ -14813,6 +12068,177 @@ 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 gboolean +is_all_selected (GtkWidget *widget) +{ + GtkEntryBuffer *buffer; + gint start_pos, end_pos; + + if (!GTK_IS_ENTRY (widget)) + return FALSE; + + buffer = gtk_entry_get_buffer (GTK_ENTRY (widget)); + return (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), + &start_pos, &end_pos) + && start_pos == 0 + && end_pos == gtk_entry_buffer_get_length (buffer)); +} + +static gboolean +is_at_left (GtkWidget *widget) +{ + return (GTK_IS_ENTRY (widget) + && gtk_editable_get_position (GTK_EDITABLE (widget)) == 0); +} + +static gboolean +is_at_right (GtkWidget *widget) +{ + GtkEntryBuffer *buffer; + gint length; + + if (!GTK_IS_ENTRY (widget)) + return FALSE; + + buffer = gtk_entry_get_buffer (GTK_ENTRY (widget)); + length = gtk_entry_buffer_get_length (buffer); + return gtk_editable_get_position (GTK_EDITABLE (widget)) == length; +} + +static gboolean +pspp_sheet_view_event (GtkWidget *widget, + GdkEventKey *event, + PsppSheetView *tree_view) +{ + PsppSheetViewColumn *column; + GtkTreePath *path; + gboolean handled; + gboolean cancel; + guint keyval; + guint state; + gint row; + + /* Intercept only key press events. + It would make sense to use "key-press-event" instead of "event", but + GtkEntry attaches its own signal handler to "key-press-event" that runs + before ours and overrides our desired behavior for GDK_Up and GDK_Down. + */ + if (event->type != GDK_KEY_PRESS) + return FALSE; + + if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK)) + { + /* Pass through most keys that include modifiers. */ + if ((event->keyval == GDK_Tab || event->keyval == GDK_ISO_Left_Tab) + && !(event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))) + { + /* Special case for Shift-Tab. */ + } + else + return FALSE; + } + + keyval = event->keyval; + state = event->state & ~(GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK); + cancel = FALSE; + switch (event->keyval) + { + case GDK_Left: case GDK_KP_Left: + if (!is_all_selected (widget) && !is_at_left (widget)) + return FALSE; + break; + + case GDK_Right: case GDK_KP_Right: + if (!is_all_selected (widget) && !is_at_right (widget)) + return FALSE; + break; + + case GDK_Up: case GDK_KP_Up: + case GDK_Down: case GDK_KP_Down: + break; + + case GDK_Page_Up: case GDK_KP_Page_Up: + case GDK_Page_Down: case GDK_KP_Page_Down: + break; + + case GDK_Escape: + cancel = TRUE; + break; + + case GDK_Return: + keyval = GDK_Down; + break; + + case GDK_Tab: + case GDK_ISO_Left_Tab: + keyval = event->state & GDK_SHIFT_MASK ? GDK_Left : GDK_Right; + break; + + default: + return FALSE; + } + + row = tree_view->priv->edited_row; + column = tree_view->priv->edited_column; + path = gtk_tree_path_new_from_indices (row, -1); + + pspp_sheet_view_stop_editing (tree_view, cancel); + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + + pspp_sheet_view_set_cursor (tree_view, path, column, FALSE); + gtk_tree_path_free (path); + + handled = gtk_binding_set_activate (edit_bindings, keyval, state, + GTK_OBJECT (tree_view)); + if (handled) + g_signal_stop_emission_by_name (widget, "event"); + + pspp_sheet_view_get_cursor (tree_view, &path, NULL); + pspp_sheet_view_start_editing (tree_view, path); + gtk_tree_path_free (path); + + return handled; +} + +static void +pspp_sheet_view_override_cell_keypresses (GtkWidget *widget, + gpointer data) +{ + PsppSheetView *sheet_view = data; + + g_signal_connect (widget, "event", + G_CALLBACK (pspp_sheet_view_event), + sheet_view); + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + pspp_sheet_view_override_cell_keypresses, + data); +} + static void pspp_sheet_view_real_start_editing (PsppSheetView *tree_view, PsppSheetViewColumn *column, @@ -14822,15 +12248,25 @@ 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; + gint row; + + g_return_if_fail (gtk_tree_path_get_depth (path) == 1); tree_view->priv->edited_column = column; _pspp_sheet_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable)); + row = gtk_tree_path_get_indices (path)[0]; + tree_view->priv->edited_row = row; 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); @@ -14857,11 +12293,26 @@ 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 (row)); + g_signal_connect (cell_editable, "clicked", + G_CALLBACK (pspp_sheet_view_editable_clicked), + tree_view); + } + + pspp_sheet_view_override_cell_keypresses (GTK_WIDGET (cell_editable), + tree_view); } -static void +void pspp_sheet_view_stop_editing (PsppSheetView *tree_view, - gboolean cancel_editing) + gboolean cancel_editing) { PsppSheetViewColumn *column; GtkCellRenderer *cell; @@ -14902,7 +12353,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 **/ @@ -14936,55 +12387,14 @@ pspp_sheet_view_get_hover_selection (PsppSheetView *tree_view) return tree_view->priv->hover_selection; } -/** - * pspp_sheet_view_set_hover_expand: - * @tree_view: a #PsppSheetView - * @expand: %TRUE to enable hover selection mode - * - * Enables of disables the hover expansion mode of @tree_view. - * Hover expansion makes rows expand or collapse if the pointer - * moves over them. - * - * Since: 2.6 - **/ -void -pspp_sheet_view_set_hover_expand (PsppSheetView *tree_view, - gboolean expand) -{ - expand = expand != FALSE; - - if (expand != tree_view->priv->hover_expand) - { - tree_view->priv->hover_expand = expand; - - g_object_notify (G_OBJECT (tree_view), "hover-expand"); - } -} - -/** - * pspp_sheet_view_get_hover_expand: - * @tree_view: a #PsppSheetView - * - * Returns whether hover expansion mode is turned on for @tree_view. - * - * Return value: %TRUE if @tree_view is in hover expansion mode - * - * Since: 2.6 - **/ -gboolean -pspp_sheet_view_get_hover_expand (PsppSheetView *tree_view) -{ - return tree_view->priv->hover_expand; -} - /** * pspp_sheet_view_set_rubber_banding: * @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 **/ @@ -15007,8 +12417,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. * @@ -15044,58 +12455,6 @@ pspp_sheet_view_is_rubber_banding_active (PsppSheetView *tree_view) return FALSE; } -/** - * pspp_sheet_view_get_row_separator_func: - * @tree_view: a #PsppSheetView - * - * Returns the current row separator function. - * - * Return value: the current row separator function. - * - * Since: 2.6 - **/ -PsppSheetViewRowSeparatorFunc -pspp_sheet_view_get_row_separator_func (PsppSheetView *tree_view) -{ - g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL); - - return tree_view->priv->row_separator_func; -} - -/** - * pspp_sheet_view_set_row_separator_func: - * @tree_view: a #PsppSheetView - * @func: a #PsppSheetViewRowSeparatorFunc - * @data: (allow-none): user data to pass to @func, or %NULL - * @destroy: (allow-none): destroy notifier for @data, or %NULL - * - * Sets the row separator function, which is used to determine - * whether a row should be drawn as a separator. If the row separator - * function is %NULL, no separators are drawn. This is the default value. - * - * Since: 2.6 - **/ -void -pspp_sheet_view_set_row_separator_func (PsppSheetView *tree_view, - PsppSheetViewRowSeparatorFunc func, - gpointer data, - GDestroyNotify destroy) -{ - g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); - - if (tree_view->priv->row_separator_destroy) - tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data); - - tree_view->priv->row_separator_func = func; - tree_view->priv->row_separator_data = data; - tree_view->priv->row_separator_destroy = destroy; - - /* Have the tree recalculate heights */ - _pspp_rbtree_mark_invalid (tree_view->priv->tree); - gtk_widget_queue_resize (GTK_WIDGET (tree_view)); -} - - static void pspp_sheet_view_grab_notify (GtkWidget *widget, gboolean was_grabbed) @@ -15173,38 +12532,6 @@ pspp_sheet_view_set_grid_lines (PsppSheetView *tree_view, old_grid_lines = priv->grid_lines; priv->grid_lines = grid_lines; - if (gtk_widget_get_realized (widget)) - { - if (grid_lines == PSPP_SHEET_VIEW_GRID_LINES_NONE && - priv->grid_line_gc) - { - g_object_unref (priv->grid_line_gc); - priv->grid_line_gc = NULL; - } - - if (grid_lines != PSPP_SHEET_VIEW_GRID_LINES_NONE && - !priv->grid_line_gc) - { - gint line_width; - gint8 *dash_list; - - gtk_widget_style_get (widget, - "grid-line-width", &line_width, - "grid-line-pattern", (gchar *)&dash_list, - NULL); - - priv->grid_line_gc = gdk_gc_new (widget->window); - gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc); - - gdk_gc_set_line_attributes (priv->grid_line_gc, line_width, - GDK_LINE_ON_OFF_DASH, - GDK_CAP_BUTT, GDK_JOIN_MITER); - gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2); - - g_free (dash_list); - } - } - if (old_grid_lines != grid_lines) { gtk_widget_queue_draw (GTK_WIDGET (tree_view)); @@ -15214,185 +12541,74 @@ pspp_sheet_view_set_grid_lines (PsppSheetView *tree_view, } /** - * pspp_sheet_view_get_enable_tree_lines: - * @tree_view: a #PsppSheetView. - * - * Returns whether or not tree lines are drawn in @tree_view. + * pspp_sheet_view_get_special_cells: + * @tree_view: a #PsppSheetView * - * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE - * otherwise. + * Returns which grid lines are enabled in @tree_view. * - * Since: 2.10 + * Return value: a #PsppSheetViewSpecialCells value indicating whether rows in + * the sheet view contain special cells. */ -gboolean -pspp_sheet_view_get_enable_tree_lines (PsppSheetView *tree_view) +PsppSheetViewSpecialCells +pspp_sheet_view_get_special_cells (PsppSheetView *tree_view) { - g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE); + g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), 0); - return tree_view->priv->tree_lines_enabled; + return tree_view->priv->special_cells; } /** - * pspp_sheet_view_set_enable_tree_lines: + * pspp_sheet_view_set_special_cells: * @tree_view: a #PsppSheetView - * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise. + * @special_cells: a #PsppSheetViewSpecialCells value indicating whether rows in + * the sheet view contain special cells. * - * Sets whether to draw lines interconnecting the expanders in @tree_view. - * This does not have any visible effects for lists. - * - * Since: 2.10 + * Sets whether rows in the sheet view contain special cells, controlling the + * rendering of row selections. */ void -pspp_sheet_view_set_enable_tree_lines (PsppSheetView *tree_view, - gboolean enabled) +pspp_sheet_view_set_special_cells (PsppSheetView *tree_view, + PsppSheetViewSpecialCells special_cells) { PsppSheetViewPrivate *priv; GtkWidget *widget; - gboolean was_enabled; g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); - enabled = enabled != FALSE; - priv = tree_view->priv; widget = GTK_WIDGET (tree_view); - was_enabled = priv->tree_lines_enabled; - - priv->tree_lines_enabled = enabled; - - if (gtk_widget_get_realized (widget)) - { - if (!enabled && priv->tree_line_gc) - { - g_object_unref (priv->tree_line_gc); - priv->tree_line_gc = NULL; - } - - if (enabled && !priv->tree_line_gc) - { - gint line_width; - gint8 *dash_list; - gtk_widget_style_get (widget, - "tree-line-width", &line_width, - "tree-line-pattern", (gchar *)&dash_list, - NULL); - - priv->tree_line_gc = gdk_gc_new (widget->window); - gdk_gc_copy (priv->tree_line_gc, widget->style->black_gc); - - gdk_gc_set_line_attributes (priv->tree_line_gc, line_width, - GDK_LINE_ON_OFF_DASH, - GDK_CAP_BUTT, GDK_JOIN_MITER); - gdk_gc_set_dashes (priv->tree_line_gc, 0, dash_list, 2); - - g_free (dash_list); - } - } - - if (was_enabled != enabled) + if (priv->special_cells != special_cells) { + priv->special_cells = special_cells; gtk_widget_queue_draw (GTK_WIDGET (tree_view)); - - g_object_notify (G_OBJECT (tree_view), "enable-tree-lines"); + g_object_notify (G_OBJECT (tree_view), "special-cells"); } } - -/** - * pspp_sheet_view_set_show_expanders: - * @tree_view: a #PsppSheetView - * @enabled: %TRUE to enable expander drawing, %FALSE otherwise. - * - * Sets whether to draw and enable expanders and indent child rows in - * @tree_view. When disabled there will be no expanders visible in trees - * and there will be no way to expand and collapse rows by default. Also - * note that hiding the expanders will disable the default indentation. You - * can set a custom indentation in this case using - * pspp_sheet_view_set_level_indentation(). - * This does not have any visible effects for lists. - * - * Since: 2.12 - */ -void -pspp_sheet_view_set_show_expanders (PsppSheetView *tree_view, - gboolean enabled) -{ - gboolean was_enabled; - - g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); - - enabled = enabled != FALSE; - was_enabled = PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_SHOW_EXPANDERS); - - if (enabled) - PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_SHOW_EXPANDERS); - else - PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_SHOW_EXPANDERS); - - if (enabled != was_enabled) - gtk_widget_queue_draw (GTK_WIDGET (tree_view)); -} - -/** - * pspp_sheet_view_get_show_expanders: - * @tree_view: a #PsppSheetView. - * - * Returns whether or not expanders are drawn in @tree_view. - * - * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE - * otherwise. - * - * Since: 2.12 - */ -gboolean -pspp_sheet_view_get_show_expanders (PsppSheetView *tree_view) +int +pspp_sheet_view_get_fixed_height (const PsppSheetView *tree_view) { - g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE); - - return PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_SHOW_EXPANDERS); + /* XXX (re)calculate fixed_height if necessary */ + return tree_view->priv->fixed_height; } -/** - * pspp_sheet_view_set_level_indentation: - * @tree_view: a #PsppSheetView - * @indentation: the amount, in pixels, of extra indentation in @tree_view. - * - * Sets the amount of extra indentation for child levels to use in @tree_view - * in addition to the default indentation. The value should be specified in - * pixels, a value of 0 disables this feature and in this case only the default - * indentation will be used. - * This does not have any visible effects for lists. - * - * Since: 2.12 - */ void -pspp_sheet_view_set_level_indentation (PsppSheetView *tree_view, - gint indentation) -{ - tree_view->priv->level_indentation = indentation; - - gtk_widget_queue_draw (GTK_WIDGET (tree_view)); -} - -/** - * pspp_sheet_view_get_level_indentation: - * @tree_view: a #PsppSheetView. - * - * Returns the amount, in pixels, of extra indentation for child levels - * in @tree_view. - * - * Return value: the amount of extra indentation for child levels in - * @tree_view. A return value of 0 means that this feature is disabled. - * - * Since: 2.12 - */ -gint -pspp_sheet_view_get_level_indentation (PsppSheetView *tree_view) +pspp_sheet_view_set_fixed_height (PsppSheetView *tree_view, + int fixed_height) { - g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), 0); + g_return_if_fail (fixed_height > 0); - return tree_view->priv->level_indentation; + if (tree_view->priv->fixed_height != fixed_height) + { + tree_view->priv->fixed_height = fixed_height; + g_object_notify (G_OBJECT (tree_view), "fixed-height"); + } + if (!tree_view->priv->fixed_height_set) + { + tree_view->priv->fixed_height_set = TRUE; + g_object_notify (G_OBJECT (tree_view), "fixed-height-set"); + } } /** @@ -15431,11 +12647,6 @@ pspp_sheet_view_set_tooltip_row (PsppSheetView *tree_view, * area will be set to the full area covered by @column. See also * gtk_tooltip_set_tip_area(). * - * Note that if @path is not specified and @cell is set and part of a column - * containing the expander, the tooltip might not show and hide at the correct - * position. In such cases @path must be set to the current node under the - * mouse cursor for this function to operate correctly. - * * See also pspp_sheet_view_set_tooltip_column() for a simpler alternative. * * Since: 2.12 @@ -15460,13 +12671,6 @@ pspp_sheet_view_set_tooltip_cell (PsppSheetView *tree_view, GdkRectangle tmp; gint start, width; - /* We always pass in path here, whether it is NULL or not. - * For cells in expander columns path must be specified so that - * we can correctly account for the indentation. This also means - * that the tooltip is constrained vertically by the "Determine y - * values" code below; this is not a real problem since cells actually - * don't stretch vertically in constrast to columns. - */ pspp_sheet_view_get_cell_area (tree_view, path, column, &tmp); pspp_sheet_view_column_cell_get_position (column, cell, &start, &width); @@ -15737,3 +12941,19 @@ pspp_sheet_view_grid_lines_get_type (void) } return etype; } + +GType +pspp_sheet_view_special_cells_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY(etype == 0)) { + static const GEnumValue values[] = { + { PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT, "PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT", "detect" }, + { PSPP_SHEET_VIEW_SPECIAL_CELLS_YES, "PSPP_SHEET_VIEW_SPECIAL_CELLS_YES", "yes" }, + { PSPP_SHEET_VIEW_SPECIAL_CELLS_NO, "PSPP_SHEET_VIEW_SPECIAL_CELLS_NO", "no" }, + { 0, NULL, NULL } + }; + etype = g_enum_register_static (g_intern_static_string ("PsppSheetViewSpecialCells"), values); + } + return etype; +}