X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fpspp-sheet-view.c;h=c4eec5637c9e2664d4b3cee3c39840f20b9e59b0;hb=6e29a48cd6e626fb2542d5babcbdcc7f67c071d3;hp=b836e3655354ec092e95f348c6117a5723592938;hpb=7ecdf4e88e39024da846a25c98caa2887f0dac59;p=pspp diff --git a/src/ui/gui/pspp-sheet-view.c b/src/ui/gui/pspp-sheet-view.c index b836e36553..c4eec5637c 100644 --- a/src/ui/gui/pspp-sheet-view.c +++ b/src/ui/gui/pspp-sheet-view.c @@ -143,7 +143,10 @@ enum { PROP_HOVER_SELECTION, PROP_RUBBER_BANDING, PROP_ENABLE_GRID_LINES, - PROP_TOOLTIP_COLUMN + PROP_TOOLTIP_COLUMN, + PROP_SPECIAL_CELLS, + PROP_FIXED_HEIGHT, + PROP_FIXED_HEIGHT_SET }; /* object signals */ @@ -186,10 +189,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); @@ -389,6 +388,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, @@ -396,14 +399,18 @@ 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); @@ -581,7 +588,7 @@ pspp_sheet_view_class_init (PsppSheetViewClass *class) * Enables of disables the hover selection mode of @tree_view. * Hover selection makes the selected row follow the pointer. * Currently, this works only for the selection modes - * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE. + * %PSPP_SHEET_SELECTION_SINGLE and %PSPP_SHEET_SELECTION_BROWSE. * * This mode is primarily intended for treeviews in popups, e.g. * in #GtkComboBox or #GtkEntryCompletion. @@ -623,6 +630,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 @@ -697,13 +731,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"), @@ -987,6 +1014,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_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; @@ -1006,6 +1034,8 @@ pspp_sheet_view_init (PsppSheetView *tree_view) 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; @@ -1017,6 +1047,10 @@ pspp_sheet_view_init (PsppSheetView *tree_view) tree_view->priv->prelight_node = -1; tree_view->priv->rubber_band_start_node = -1; tree_view->priv->rubber_band_end_node = -1; + + tree_view->priv->anchor_column = NULL; + + tree_view->priv->button_style = NULL; } @@ -1075,6 +1109,32 @@ pspp_sheet_view_set_property (GObject *object, 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; @@ -1132,6 +1192,15 @@ pspp_sheet_view_get_property (GObject *object, 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; @@ -1270,6 +1339,12 @@ pspp_sheet_view_destroy (GtkObject *object) 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; + } + GTK_OBJECT_CLASS (pspp_sheet_view_parent_class)->destroy (object); } @@ -1293,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) { @@ -1519,12 +1595,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); } @@ -1688,6 +1759,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, @@ -1698,13 +1778,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); @@ -1738,42 +1817,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)) @@ -1797,8 +1846,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; } @@ -1823,19 +1872,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; @@ -1843,7 +1882,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, @@ -2043,6 +2088,192 @@ pspp_sheet_view_node_prev (PsppSheetView *tree_view, return node > 0 ? node - 1 : -1; } +static gboolean +all_columns_selected (PsppSheetView *tree_view) +{ + GList *list; + + for (list = tree_view->priv->columns; list; list = list->next) + { + PsppSheetViewColumn *column = list->data; + if (column->selectable && !column->selected) + return FALSE; + } + + return TRUE; +} + +static gboolean +pspp_sheet_view_row_head_clicked (PsppSheetView *tree_view, + gint node, + PsppSheetViewColumn *column, + GdkEventButton *event) +{ + PsppSheetSelection *selection; + PsppSheetSelectionMode mode; + GtkTreePath *path; + gboolean update_anchor; + gboolean handled; + guint modifiers; + + g_return_val_if_fail (tree_view != NULL, FALSE); + g_return_val_if_fail (column != NULL, FALSE); + + selection = tree_view->priv->selection; + mode = pspp_sheet_selection_get_mode (selection); + if (mode != PSPP_SHEET_SELECTION_RECTANGLE) + return FALSE; + + if (!column->row_head) + return FALSE; + + if (event) + { + modifiers = event->state & gtk_accelerator_get_default_mod_mask (); + if (event->type != GDK_BUTTON_PRESS + || (modifiers != GDK_CONTROL_MASK && modifiers != GDK_SHIFT_MASK)) + return FALSE; + } + else + modifiers = 0; + + path = gtk_tree_path_new_from_indices (node, -1); + if (event == NULL) + { + pspp_sheet_selection_unselect_all (selection); + pspp_sheet_selection_select_path (selection, path); + pspp_sheet_selection_select_all_columns (selection); + update_anchor = TRUE; + handled = TRUE; + } + else if (event->type == GDK_BUTTON_PRESS && event->button == 3) + { + if (pspp_sheet_selection_count_selected_rows (selection) <= 1 + || !all_columns_selected (tree_view)) + { + pspp_sheet_selection_unselect_all (selection); + pspp_sheet_selection_select_path (selection, path); + pspp_sheet_selection_select_all_columns (selection); + update_anchor = TRUE; + handled = FALSE; + } + else + update_anchor = handled = FALSE; + } + else if (event->type == GDK_BUTTON_PRESS && event->button == 1 + && modifiers == GDK_CONTROL_MASK) + { + if (!all_columns_selected (tree_view)) + { + pspp_sheet_selection_unselect_all (selection); + pspp_sheet_selection_select_all_columns (selection); + } + + if (pspp_sheet_selection_path_is_selected (selection, path)) + pspp_sheet_selection_unselect_path (selection, path); + else + pspp_sheet_selection_select_path (selection, path); + update_anchor = TRUE; + handled = TRUE; + } + else if (event->type == GDK_BUTTON_PRESS && event->button == 1 + && modifiers == GDK_SHIFT_MASK) + { + GtkTreeRowReference *anchor = tree_view->priv->anchor; + GtkTreePath *anchor_path; + + if (all_columns_selected (tree_view) + && gtk_tree_row_reference_valid (anchor)) + { + update_anchor = FALSE; + anchor_path = gtk_tree_row_reference_get_path (anchor); + } + else + { + update_anchor = TRUE; + anchor_path = gtk_tree_path_copy (path); + } + + pspp_sheet_selection_unselect_all (selection); + pspp_sheet_selection_select_range (selection, anchor_path, path); + pspp_sheet_selection_select_all_columns (selection); + + gtk_tree_path_free (anchor_path); + + handled = TRUE; + } + else + update_anchor = handled = FALSE; + + if (update_anchor) + { + if (tree_view->priv->anchor) + gtk_tree_row_reference_free (tree_view->priv->anchor); + tree_view->priv->anchor = + gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), + tree_view->priv->model, + path); + } + + gtk_tree_path_free (path); + return handled; +} + +static gboolean +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 */ + + pspp_sheet_view_adjust_cell_area (tree_view, candidate, background_area, + TRUE, cell_area); + *column = candidate; + return TRUE; + } + + return FALSE; +} + static gboolean pspp_sheet_view_button_press (GtkWidget *widget, GdkEventButton *event) @@ -2053,16 +2284,10 @@ pspp_sheet_view_button_press (GtkWidget *widget, gint i; GdkRectangle background_area; GdkRectangle cell_area; - gint vertical_separator; - gint horizontal_separator; 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 @@ -2073,18 +2298,11 @@ pspp_sheet_view_button_press (GtkWidget *widget, { 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->row_count == 0) @@ -2093,134 +2311,23 @@ pspp_sheet_view_button_press (GtkWidget *widget, return TRUE; } - /* 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_sheet_view_find_offset (tree_view, new_y, &node); - - if (node < 0) - { - /* We clicked in dead space */ - grab_focus_and_unset_draw_keyfocus (tree_view); - return TRUE; - } - - /* Get the path and the node */ - 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); - 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 > (gint) event->x) || - (background_area.x + background_area.width <= (gint) event->x)) - { - background_area.x += background_area.width; - continue; - } - - /* 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; - break; - } - - if (column == NULL) - { - gtk_tree_path_free (path); + if (!find_click (tree_view, event->x, event->y, &node, &column, + &background_area, &cell_area)) + { grab_focus_and_unset_draw_keyfocus (tree_view); - return FALSE; - } + 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); - - 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); - } + if (pspp_sheet_view_row_head_clicked (tree_view, node, column, event)) + return TRUE; /* select */ - node_selected = pspp_sheet_view_node_is_selected (tree_view, node); pre_val = tree_view->priv->vadjustment->value; + path = _pspp_sheet_view_find_path (tree_view, node); + /* we only handle selection modifications on the first button press */ if (event->type == GDK_BUTTON_PRESS) @@ -2241,7 +2348,7 @@ pspp_sheet_view_button_press (GtkWidget *widget, } else if (event->state & GDK_SHIFT_MASK) { - pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE); + pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE); pspp_sheet_view_real_select_cursor_row (tree_view, FALSE); } else @@ -2249,6 +2356,14 @@ pspp_sheet_view_button_press (GtkWidget *widget, pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE); } + if (tree_view->priv->anchor_column == NULL || + !(event->state & GDK_SHIFT_MASK)) + tree_view->priv->anchor_column = column; + pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection); + pspp_sheet_selection_select_column_range (tree_view->priv->selection, + tree_view->priv->anchor_column, + column); + tree_view->priv->ctrl_pressed = FALSE; tree_view->priv->shift_pressed = FALSE; } @@ -2265,17 +2380,17 @@ 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) + && (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; @@ -2286,6 +2401,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; + } } @@ -2365,7 +2481,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"); @@ -2376,7 +2492,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); @@ -2403,6 +2519,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); @@ -2479,12 +2597,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); @@ -2515,20 +2720,6 @@ 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. */ @@ -2560,10 +2751,10 @@ prelight_or_select (PsppSheetView *tree_view, gint x, gint y) { - GtkSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection); + PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection); if (tree_view->priv->hover_selection && - (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) && + (mode == PSPP_SHEET_SELECTION_SINGLE || mode == PSPP_SHEET_SELECTION_BROWSE) && !(tree_view->priv->edited_column && tree_view->priv->edited_column->editable_widget)) { @@ -2584,7 +2775,7 @@ prelight_or_select (PsppSheetView *tree_view, } } - else if (mode == GTK_SELECTION_SINGLE) + else if (mode == PSPP_SHEET_SELECTION_SINGLE) pspp_sheet_selection_unselect_all (tree_view->priv->selection); } @@ -2677,9 +2868,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; @@ -2708,8 +2899,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; @@ -2745,13 +2936,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; @@ -2824,9 +3015,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; @@ -2923,8 +3114,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); } @@ -3028,7 +3221,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 */ @@ -3276,6 +3469,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; @@ -3318,6 +3512,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); } @@ -3330,6 +3532,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; @@ -3379,6 +3582,15 @@ pspp_sheet_view_motion_bin_window (GtkWidget *widget, 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); @@ -3480,16 +3692,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++) { @@ -3504,10 +3721,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, + current_x - 1, min_y, + current_x - 1, max_y - min_y); } } @@ -3531,7 +3750,6 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, gint new_y; gint y_offset, cell_offset; gint max_height; - gint depth; GdkRectangle background_area; GdkRectangle cell_area; guint flags; @@ -3550,6 +3768,7 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, gint grid_line_width; 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); @@ -3603,7 +3822,6 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); - depth = gtk_tree_path_get_depth (path); gtk_tree_path_free (path); cursor_path = NULL; @@ -3657,12 +3875,14 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, * order, drawing each successive node. */ + min_y = y_offset; do { gboolean parity; gboolean is_first = FALSE; gboolean is_last = FALSE; gboolean done = FALSE; + gboolean selected; max_height = ROW_HEIGHT (tree_view); @@ -3670,32 +3890,37 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, background_area.y = y_offset + event->area.y; background_area.height = max_height; + max_y = background_area.y + max_height; flags = 0; if (node == tree_view->priv->prelight_node) flags |= GTK_CELL_RENDERER_PRELIT; - if (pspp_sheet_view_node_is_selected (tree_view, node)) - flags |= GTK_CELL_RENDERER_SELECTED; + selected = pspp_sheet_view_node_is_selected (tree_view, node); parity = node % 2; - /* 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)) + if (tree_view->priv->special_cells == PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT) { - PsppSheetViewColumn *column = list->data; - pspp_sheet_view_column_cell_set_cell_data (column, - tree_view->priv->model, - &iter); - } + /* 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); + 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; @@ -3703,11 +3928,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) { @@ -3715,6 +3946,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 @@ -3906,6 +4142,21 @@ 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 @@ -4045,7 +4296,8 @@ pspp_sheet_view_bin_expose (GtkWidget *widget, 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) { @@ -4073,7 +4325,7 @@ done: static gboolean pspp_sheet_view_expose (GtkWidget *widget, - GdkEventExpose *event) + GdkEventExpose *event) { PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget); @@ -4102,20 +4354,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) { @@ -4373,7 +4652,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; } @@ -4402,7 +4681,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, @@ -4719,7 +4998,6 @@ validate_row (PsppSheetView *tree_view, gint horizontal_separator; gint vertical_separator; gint focus_line_width; - gboolean retval = FALSE; gboolean draw_vgrid_lines, draw_hgrid_lines; gint focus_pad; gint grid_line_width; @@ -4782,10 +5060,7 @@ validate_row (PsppSheetView *tree_view, } if (tmp_width > column->requested_width) - { - retval = TRUE; - column->requested_width = tmp_width; - } + column->requested_width = tmp_width; } if (draw_hgrid_lines) @@ -5010,6 +5285,9 @@ initialize_fixed_height_mode (PsppSheetView *tree_view) if (!tree_view->priv->row_count) return; + if (tree_view->priv->fixed_height_set) + return; + if (tree_view->priv->fixed_height < 0) { GtkTreeIter iter; @@ -5023,6 +5301,8 @@ initialize_fixed_height_mode (PsppSheetView *tree_view) tree_view->priv->fixed_height = validate_row (tree_view, node, &iter, path); gtk_tree_path_free (path); + + g_object_notify (G_OBJECT (tree_view), "fixed-height"); } } @@ -5492,6 +5772,7 @@ scroll_row_timeout (gpointer data) { PsppSheetView *tree_view = data; + pspp_sheet_view_horizontal_autoscroll (tree_view); pspp_sheet_view_vertical_autoscroll (tree_view); if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE) @@ -6242,6 +6523,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) @@ -6253,6 +6537,27 @@ pspp_sheet_view_has_special_cell (PsppSheetView *tree_view) return FALSE; } +static void +pspp_sheet_view_focus_column (PsppSheetView *tree_view, + PsppSheetViewColumn *focus_column, + gboolean clamp_column_visible) +{ + g_return_if_fail (focus_column != NULL); + + tree_view->priv->focus_column = focus_column; + if (!focus_column->button) + { + pspp_sheet_view_column_set_need_button (focus_column, TRUE); + g_return_if_fail (focus_column->button != NULL); + } + + if (GTK_CONTAINER (tree_view)->focus_child != focus_column->button) + gtk_widget_grab_focus (focus_column->button); + + 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 * done */ @@ -6262,7 +6567,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; @@ -6275,10 +6580,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; } @@ -6291,10 +6595,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; } @@ -6311,12 +6614,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; @@ -6325,20 +6629,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. */ @@ -6350,7 +6659,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) @@ -6370,43 +6679,26 @@ 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, @@ -6414,6 +6706,8 @@ search_first_focusable_path (PsppSheetView *tree_view, gboolean search_forward, int *new_node) { + /* XXX this function is trivial given that the sheetview doesn't support + separator rows */ int node = -1; if (!path || !*path) @@ -6523,6 +6817,13 @@ pspp_sheet_view_style_set (GtkWidget *widget, tree_view->priv->fixed_height = -1; + /* 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); } @@ -7007,8 +7308,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) { @@ -7218,9 +7519,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 { @@ -7244,6 +7545,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); @@ -7257,10 +7559,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; @@ -7310,8 +7612,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); @@ -7395,8 +7697,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; @@ -7407,6 +7709,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); @@ -7423,7 +7726,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); @@ -7432,6 +7736,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); @@ -7445,9 +7750,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; } } + } } } @@ -7480,7 +7788,7 @@ pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, selection_count = pspp_sheet_selection_count_selected_rows (tree_view->priv->selection); if (selection_count == 0 - && tree_view->priv->selection->type != GTK_SELECTION_NONE + && tree_view->priv->selection->type != PSPP_SHEET_SELECTION_NONE && !tree_view->priv->ctrl_pressed) { /* Don't move the cursor, but just select the current node */ @@ -7512,7 +7820,8 @@ pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view, * If the list has only one item and multi-selection is set then select * the row (if not yet selected). */ - if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE && + if ((tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE || + tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE) && new_cursor_node < 0) { if (count == -1) @@ -7741,10 +8050,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_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)); } @@ -7811,7 +8117,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); @@ -7825,7 +8132,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); @@ -8096,7 +8404,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; @@ -8172,19 +8480,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; } @@ -8261,6 +8567,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, @@ -8268,6 +8577,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, @@ -8315,8 +8625,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); + } + } } } @@ -8451,7 +8773,6 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, if (tree_view->priv->model) { gint i; - GtkTreeModelFlags flags; if (tree_view->priv->search_column == -1) { @@ -8485,8 +8806,6 @@ pspp_sheet_view_set_model (PsppSheetView *tree_view, G_CALLBACK (pspp_sheet_view_rows_reordered), tree_view); - flags = gtk_tree_model_get_flags (tree_view->priv->model); - 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); */ @@ -8660,7 +8979,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); } @@ -9411,6 +9731,11 @@ pspp_sheet_view_set_reorderable (PsppSheetView *tree_view, g_object_notify (G_OBJECT (tree_view), "reorderable"); } +/* If CLEAR_AND_SELECT is true, then the row will be selected and, unless Shift + is pressed, other rows will be unselected. + + If CLAMP_NODE is true, then the sheetview will scroll to make the row + visible. */ static void pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view, GtkTreePath *path, @@ -9605,6 +9930,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); + } } @@ -9758,6 +10087,121 @@ pspp_sheet_view_get_path_at_pos (PsppSheetView *tree_view, 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: @@ -9782,9 +10226,7 @@ pspp_sheet_view_get_cell_area (PsppSheetView *tree_view, PsppSheetViewColumn *column, GdkRectangle *rect) { - int node = -1; - 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)); @@ -9792,33 +10234,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) - { - _pspp_sheet_view_find_node (tree_view, path, &node); - - /* Get vertical coords */ - if (node < 0) - return; - - rect->y = CELL_FIRST_PIXEL (tree_view, node, vertical_separator); - rect->height = MAX (CELL_HEIGHT (tree_view, vertical_separator), tree_view->priv->expander_size - vertical_separator); - } + 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); } /** @@ -10590,7 +11009,6 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, GdkRectangle background_area; GdkRectangle expose_area; GtkWidget *widget; - gint depth; /* start drawing inside the black outline */ gint x = 1, y = 1; GdkDrawable *drawable; @@ -10605,8 +11023,6 @@ pspp_sheet_view_create_row_drag_icon (PsppSheetView *tree_view, if (!gtk_widget_get_realized (widget)) return NULL; - depth = gtk_tree_path_get_depth (path); - _pspp_sheet_view_find_node (tree_view, path, &node); @@ -11518,6 +11934,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)); @@ -11600,6 +12022,29 @@ pspp_sheet_view_start_editing (PsppSheetView *tree_view, return retval; } +static gboolean +pspp_sheet_view_editable_button_press_event (GtkWidget *widget, + GdkEventButton *event, + PsppSheetView *sheet_view) +{ + gint node; + + node = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), + "pspp-sheet-view-node")); + return pspp_sheet_view_row_head_clicked (sheet_view, + node, + sheet_view->priv->edited_column, + event); +} + +static void +pspp_sheet_view_editable_clicked (GtkButton *button, + PsppSheetView *sheet_view) +{ + pspp_sheet_view_editable_button_press_event (GTK_WIDGET (button), NULL, + sheet_view); +} + static void pspp_sheet_view_real_start_editing (PsppSheetView *tree_view, PsppSheetViewColumn *column, @@ -11609,6 +12054,7 @@ pspp_sheet_view_real_start_editing (PsppSheetView *tree_view, GdkEvent *event, guint flags) { + PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection); gint pre_val = tree_view->priv->vadjustment->value; GtkRequisition requisition; @@ -11618,6 +12064,10 @@ pspp_sheet_view_real_start_editing (PsppSheetView *tree_view, pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE); cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value; + pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection); + pspp_sheet_selection_select_column (tree_view->priv->selection, column); + tree_view->priv->anchor_column = column; + gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition); PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS); @@ -11644,11 +12094,23 @@ pspp_sheet_view_real_start_editing (PsppSheetView *tree_view, gtk_widget_grab_focus (GTK_WIDGET (cell_editable)); g_signal_connect (cell_editable, "remove-widget", G_CALLBACK (pspp_sheet_view_remove_widget), tree_view); + if (mode == PSPP_SHEET_SELECTION_RECTANGLE && column->row_head && + GTK_IS_BUTTON (cell_editable)) + { + g_signal_connect (cell_editable, "button-press-event", + G_CALLBACK (pspp_sheet_view_editable_button_press_event), + tree_view); + g_object_set_data (G_OBJECT (cell_editable), "pspp-sheet-view-node", + GINT_TO_POINTER (gtk_tree_path_get_indices (path)[0])); + g_signal_connect (cell_editable, "clicked", + G_CALLBACK (pspp_sheet_view_editable_clicked), + tree_view); + } } -static void +void pspp_sheet_view_stop_editing (PsppSheetView *tree_view, - gboolean cancel_editing) + gboolean cancel_editing) { PsppSheetViewColumn *column; GtkCellRenderer *cell; @@ -11689,7 +12151,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 **/ @@ -11728,9 +12190,9 @@ pspp_sheet_view_get_hover_selection (PsppSheetView *tree_view) * @tree_view: a #PsppSheetView * @enable: %TRUE to enable rubber banding * - * Enables or disables rubber banding in @tree_view. If the selection mode - * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select - * multiple rows by dragging the mouse. + * Enables or disables rubber banding in @tree_view. If the selection mode is + * #PSPP_SHEET_SELECTION_MULTIPLE or #PSPP_SHEET_SELECTION_RECTANGLE, rubber + * banding will allow the user to select multiple rows by dragging the mouse. * * Since: 2.10 **/ @@ -11753,8 +12215,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. * @@ -11880,22 +12343,13 @@ pspp_sheet_view_set_grid_lines (PsppSheetView *tree_view, !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); } } @@ -11907,6 +12361,75 @@ pspp_sheet_view_set_grid_lines (PsppSheetView *tree_view, } } +/** + * pspp_sheet_view_get_special_cells: + * @tree_view: a #PsppSheetView + * + * Returns which grid lines are enabled in @tree_view. + * + * Return value: a #PsppSheetViewSpecialCells value indicating whether rows in + * the sheet view contain special cells. + */ +PsppSheetViewSpecialCells +pspp_sheet_view_get_special_cells (PsppSheetView *tree_view) +{ + g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), 0); + + return tree_view->priv->special_cells; +} + +/** + * pspp_sheet_view_set_special_cells: + * @tree_view: a #PsppSheetView + * @special_cells: a #PsppSheetViewSpecialCells value indicating whether rows in + * the sheet view contain special cells. + * + * Sets whether rows in the sheet view contain special cells, controlling the + * rendering of row selections. + */ +void +pspp_sheet_view_set_special_cells (PsppSheetView *tree_view, + PsppSheetViewSpecialCells special_cells) +{ + PsppSheetViewPrivate *priv; + + g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view)); + + priv = tree_view->priv; + + 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), "special-cells"); + } +} + +int +pspp_sheet_view_get_fixed_height (const PsppSheetView *tree_view) +{ + /* XXX (re)calculate fixed_height if necessary */ + return tree_view->priv->fixed_height; +} + +void +pspp_sheet_view_set_fixed_height (PsppSheetView *tree_view, + int fixed_height) +{ + g_return_if_fail (fixed_height > 0); + + 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"); + } +} + /** * pspp_sheet_view_set_tooltip_row: * @tree_view: a #PsppSheetView @@ -12237,3 +12760,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; +}