1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2011, 2012 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* gtktreeviewcolumn.c
18 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Library General Public
22 * License as published by the Free Software Foundation; either
23 * version 2 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Library General Public License for more details.
30 * You should have received a copy of the GNU Library General Public
31 * License along with this library; if not, write to the
32 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
33 * Boston, MA 02111-1307, USA.
38 #include "ui/gui/pspp-sheet-private.h"
45 #include "ui/gui/psppire-marshal.h"
46 #include "ui/gui/pspp-sheet-selection.h"
47 #include "ui/gui/pspp-widget-facade.h"
49 #define P_(STRING) STRING
50 #define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
51 #define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
87 typedef struct _PsppSheetViewColumnCellInfo PsppSheetViewColumnCellInfo;
88 struct _PsppSheetViewColumnCellInfo
90 GtkCellRenderer *cell;
92 PsppSheetCellDataFunc func;
94 GDestroyNotify destroy;
100 guint in_editing_mode : 1;
104 static void pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface);
106 /* GObject methods */
107 static void pspp_sheet_view_column_set_property (GObject *object,
111 static void pspp_sheet_view_column_get_property (GObject *object,
115 static void pspp_sheet_view_column_finalize (GObject *object);
117 /* GtkCellLayout implementation */
118 static void pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
119 GtkCellRenderer *cell,
121 static void pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
122 GtkCellRenderer *cell,
124 static void pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout);
125 static void pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
126 GtkCellRenderer *cell,
127 const gchar *attribute,
129 static void pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
130 GtkCellRenderer *cell,
131 GtkCellLayoutDataFunc func,
133 GDestroyNotify destroy);
134 static void pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
135 GtkCellRenderer *cell);
136 static void pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
137 GtkCellRenderer *cell,
139 static GList *pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
141 /* Button handling code */
142 static void pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column);
143 void pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
145 /* Button signal handlers */
146 static gint pspp_sheet_view_column_button_event (GtkWidget *widget,
149 static void pspp_sheet_view_column_button_clicked (GtkWidget *widget,
151 static void pspp_sheet_view_column_button_popup_menu (GtkWidget *widget,
153 static gboolean pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
154 gboolean group_cycling,
156 static gboolean on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *);
157 static gboolean on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *,
160 /* Property handlers */
161 static void pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
162 PsppSheetViewColumn *tree_column);
164 /* Internal functions */
165 static void pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
167 static void pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column);
168 static void pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
169 GtkCellRenderer *cell_renderer,
171 static PsppSheetViewColumnCellInfo *pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
172 GtkCellRenderer *cell_renderer);
174 /* cell list manipulation */
175 static GList *pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column);
176 static GList *pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column);
177 static GList *pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
179 static GList *pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
181 static void pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
182 PsppSheetViewColumnCellInfo *info);
183 /* GtkBuildable implementation */
184 static void pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface);
186 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
188 G_DEFINE_TYPE_WITH_CODE (PsppSheetViewColumn, pspp_sheet_view_column, GTK_TYPE_OBJECT,
189 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
190 pspp_sheet_view_column_cell_layout_init)
191 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
192 pspp_sheet_view_column_buildable_init))
196 pspp_sheet_view_column_class_init (PsppSheetViewColumnClass *class)
198 GObjectClass *object_class;
200 object_class = (GObjectClass*) class;
202 class->clicked = on_pspp_sheet_view_column_button_clicked;
203 class->button_press_event = on_pspp_sheet_view_column_button_press_event;
205 object_class->finalize = pspp_sheet_view_column_finalize;
206 object_class->set_property = pspp_sheet_view_column_set_property;
207 object_class->get_property = pspp_sheet_view_column_get_property;
209 tree_column_signals[CLICKED] =
210 g_signal_new ("clicked",
211 G_OBJECT_CLASS_TYPE (object_class),
213 G_STRUCT_OFFSET (PsppSheetViewColumnClass, clicked),
214 g_signal_accumulator_true_handled, NULL,
215 psppire_marshal_BOOLEAN__VOID,
218 tree_column_signals[POPUP_MENU] =
219 g_signal_new ("popup-menu",
220 G_OBJECT_CLASS_TYPE (object_class),
224 g_cclosure_marshal_VOID__VOID,
227 tree_column_signals[QUERY_TOOLTIP] =
228 g_signal_new ("query-tooltip",
229 G_OBJECT_CLASS_TYPE (object_class),
232 g_signal_accumulator_true_handled, NULL,
233 psppire_marshal_BOOLEAN__OBJECT,
237 tree_column_signals[BUTTON_PRESS_EVENT] =
238 g_signal_new ("button-press-event",
239 G_OBJECT_CLASS_TYPE (object_class),
240 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
241 G_STRUCT_OFFSET (PsppSheetViewColumnClass, button_press_event),
242 g_signal_accumulator_true_handled, NULL,
243 psppire_marshal_BOOLEAN__BOXED,
245 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
247 g_object_class_install_property (object_class,
249 g_param_spec_boolean ("visible",
251 P_("Whether to display the column"),
253 GTK_PARAM_READWRITE));
255 g_object_class_install_property (object_class,
257 g_param_spec_boolean ("resizable",
259 P_("Column is user-resizable"),
261 GTK_PARAM_READWRITE));
263 g_object_class_install_property (object_class,
265 g_param_spec_int ("width",
267 P_("Current width of the column"),
271 GTK_PARAM_READABLE));
272 g_object_class_install_property (object_class,
274 g_param_spec_int ("spacing",
276 P_("Space which is inserted between cells"),
280 GTK_PARAM_READWRITE));
282 g_object_class_install_property (object_class,
284 g_param_spec_int ("fixed-width",
286 P_("Current fixed width of the column"),
290 GTK_PARAM_READWRITE));
292 g_object_class_install_property (object_class,
294 g_param_spec_int ("min-width",
296 P_("Minimum allowed width of the column"),
300 GTK_PARAM_READWRITE));
302 g_object_class_install_property (object_class,
304 g_param_spec_int ("max-width",
306 P_("Maximum allowed width of the column"),
310 GTK_PARAM_READWRITE));
312 g_object_class_install_property (object_class,
314 g_param_spec_string ("title",
316 P_("Title to appear in column header"),
318 GTK_PARAM_READWRITE));
320 g_object_class_install_property (object_class,
322 g_param_spec_boolean ("expand",
324 P_("Column gets share of extra width allocated to the widget"),
326 GTK_PARAM_READWRITE));
328 g_object_class_install_property (object_class,
330 g_param_spec_boolean ("clickable",
332 P_("Whether the header can be clicked"),
334 GTK_PARAM_READWRITE));
337 g_object_class_install_property (object_class,
339 g_param_spec_object ("widget",
341 P_("Widget to put in column header button instead of column title"),
343 GTK_PARAM_READWRITE));
345 g_object_class_install_property (object_class,
347 g_param_spec_float ("alignment",
349 P_("X Alignment of the column header text or widget"),
353 GTK_PARAM_READWRITE));
355 g_object_class_install_property (object_class,
357 g_param_spec_boolean ("reorderable",
359 P_("Whether the column can be reordered around the headers"),
361 GTK_PARAM_READWRITE));
363 g_object_class_install_property (object_class,
365 g_param_spec_boolean ("sort-indicator",
366 P_("Sort indicator"),
367 P_("Whether to show a sort indicator"),
369 GTK_PARAM_READWRITE));
371 g_object_class_install_property (object_class,
373 g_param_spec_enum ("sort-order",
375 P_("Sort direction the sort indicator should indicate"),
378 GTK_PARAM_READWRITE));
381 * PsppSheetViewColumn:sort-column-id:
383 * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
384 * clickable. Set to %-1 to make the column unsortable.
388 g_object_class_install_property (object_class,
390 g_param_spec_int ("sort-column-id",
391 P_("Sort column ID"),
392 P_("Logical sort column ID this column sorts on when selected for sorting"),
396 GTK_PARAM_READWRITE));
398 g_object_class_install_property (object_class,
400 g_param_spec_boolean ("quick-edit",
402 P_("If true, editing starts upon the first click in the column. If false, the first click selects the column and a second click is needed to begin editing. This has no effect on cells that are not editable."),
404 GTK_PARAM_READWRITE));
406 g_object_class_install_property (object_class,
408 g_param_spec_boolean ("selected",
410 P_("If true, this column is selected as part of a rectangular selection."),
412 GTK_PARAM_READWRITE));
414 g_object_class_install_property (object_class,
416 g_param_spec_boolean ("selectable",
418 P_("If true, this column may be selected as part of a rectangular selection."),
420 GTK_PARAM_READWRITE));
422 g_object_class_install_property (object_class,
424 g_param_spec_boolean ("row-head",
426 P_("If true, this column is a \"row head\", equivalent to a column head. If rectangular selection is enabled, then shift+click and control+click in the column select row ranges and toggle row selection, respectively. The column should ordinarily include a button cell; clicking on the button will select the row (and deselect all other rows)."),
428 GTK_PARAM_READWRITE));
432 pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface)
434 iface->add_child = _gtk_cell_layout_buildable_add_child;
435 iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
436 iface->custom_tag_end = _gtk_cell_layout_buildable_custom_tag_end;
440 pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface)
442 iface->pack_start = pspp_sheet_view_column_cell_layout_pack_start;
443 iface->pack_end = pspp_sheet_view_column_cell_layout_pack_end;
444 iface->clear = pspp_sheet_view_column_cell_layout_clear;
445 iface->add_attribute = pspp_sheet_view_column_cell_layout_add_attribute;
446 iface->set_cell_data_func = pspp_sheet_view_column_cell_layout_set_cell_data_func;
447 iface->clear_attributes = pspp_sheet_view_column_cell_layout_clear_attributes;
448 iface->reorder = pspp_sheet_view_column_cell_layout_reorder;
449 iface->get_cells = pspp_sheet_view_column_cell_layout_get_cells;
453 pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column)
455 tree_column->button = NULL;
456 tree_column->xalign = 0.0;
457 tree_column->width = 0;
458 tree_column->spacing = 0;
459 tree_column->requested_width = -1;
460 tree_column->min_width = -1;
461 tree_column->max_width = -1;
462 tree_column->resized_width = 0;
463 tree_column->visible = TRUE;
464 tree_column->resizable = FALSE;
465 tree_column->expand = FALSE;
466 tree_column->clickable = FALSE;
467 tree_column->dirty = TRUE;
468 tree_column->selected = FALSE;
469 tree_column->selectable = TRUE;
470 tree_column->row_head = FALSE;
471 tree_column->sort_order = GTK_SORT_ASCENDING;
472 tree_column->show_sort_indicator = FALSE;
473 tree_column->property_changed_signal = 0;
474 tree_column->sort_clicked_signal = 0;
475 tree_column->sort_column_changed_signal = 0;
476 tree_column->sort_column_id = -1;
477 tree_column->reorderable = FALSE;
478 tree_column->maybe_reordered = FALSE;
479 tree_column->fixed_width = 1;
480 tree_column->use_resized_width = FALSE;
481 tree_column->title = g_strdup ("");
482 tree_column->quick_edit = TRUE;
483 tree_column->need_button = FALSE;
487 pspp_sheet_view_column_finalize (GObject *object)
489 PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
492 for (list = tree_column->cell_list; list; list = list->next)
494 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
498 GDestroyNotify d = info->destroy;
500 info->destroy = NULL;
503 pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
504 g_object_unref (info->cell);
508 g_free (tree_column->title);
509 g_list_free (tree_column->cell_list);
511 if (tree_column->child)
512 g_object_unref (tree_column->child);
514 G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
518 pspp_sheet_view_column_set_property (GObject *object,
523 PsppSheetViewColumn *tree_column;
525 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
530 pspp_sheet_view_column_set_visible (tree_column,
531 g_value_get_boolean (value));
535 pspp_sheet_view_column_set_resizable (tree_column,
536 g_value_get_boolean (value));
539 case PROP_FIXED_WIDTH:
540 pspp_sheet_view_column_set_fixed_width (tree_column,
541 g_value_get_int (value));
545 pspp_sheet_view_column_set_min_width (tree_column,
546 g_value_get_int (value));
550 pspp_sheet_view_column_set_max_width (tree_column,
551 g_value_get_int (value));
555 pspp_sheet_view_column_set_spacing (tree_column,
556 g_value_get_int (value));
560 pspp_sheet_view_column_set_title (tree_column,
561 g_value_get_string (value));
565 pspp_sheet_view_column_set_expand (tree_column,
566 g_value_get_boolean (value));
570 pspp_sheet_view_column_set_clickable (tree_column,
571 g_value_get_boolean (value));
575 pspp_sheet_view_column_set_widget (tree_column,
576 (GtkWidget*) g_value_get_object (value));
580 pspp_sheet_view_column_set_alignment (tree_column,
581 g_value_get_float (value));
584 case PROP_REORDERABLE:
585 pspp_sheet_view_column_set_reorderable (tree_column,
586 g_value_get_boolean (value));
589 case PROP_SORT_INDICATOR:
590 pspp_sheet_view_column_set_sort_indicator (tree_column,
591 g_value_get_boolean (value));
594 case PROP_SORT_ORDER:
595 pspp_sheet_view_column_set_sort_order (tree_column,
596 g_value_get_enum (value));
599 case PROP_SORT_COLUMN_ID:
600 pspp_sheet_view_column_set_sort_column_id (tree_column,
601 g_value_get_int (value));
604 case PROP_QUICK_EDIT:
605 pspp_sheet_view_column_set_quick_edit (tree_column,
606 g_value_get_boolean (value));
610 pspp_sheet_view_column_set_selected (tree_column,
611 g_value_get_boolean (value));
614 case PROP_SELECTABLE:
615 pspp_sheet_view_column_set_selectable (tree_column,
616 g_value_get_boolean (value));
620 pspp_sheet_view_column_set_row_head (tree_column,
621 g_value_get_boolean (value));
625 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
631 pspp_sheet_view_column_get_property (GObject *object,
636 PsppSheetViewColumn *tree_column;
638 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
643 g_value_set_boolean (value,
644 pspp_sheet_view_column_get_visible (tree_column));
648 g_value_set_boolean (value,
649 pspp_sheet_view_column_get_resizable (tree_column));
653 g_value_set_int (value,
654 pspp_sheet_view_column_get_width (tree_column));
658 g_value_set_int (value,
659 pspp_sheet_view_column_get_spacing (tree_column));
662 case PROP_FIXED_WIDTH:
663 g_value_set_int (value,
664 pspp_sheet_view_column_get_fixed_width (tree_column));
668 g_value_set_int (value,
669 pspp_sheet_view_column_get_min_width (tree_column));
673 g_value_set_int (value,
674 pspp_sheet_view_column_get_max_width (tree_column));
678 g_value_set_string (value,
679 pspp_sheet_view_column_get_title (tree_column));
683 g_value_set_boolean (value,
684 pspp_sheet_view_column_get_expand (tree_column));
688 g_value_set_boolean (value,
689 pspp_sheet_view_column_get_clickable (tree_column));
693 g_value_set_object (value,
694 (GObject*) pspp_sheet_view_column_get_widget (tree_column));
698 g_value_set_float (value,
699 pspp_sheet_view_column_get_alignment (tree_column));
702 case PROP_REORDERABLE:
703 g_value_set_boolean (value,
704 pspp_sheet_view_column_get_reorderable (tree_column));
707 case PROP_SORT_INDICATOR:
708 g_value_set_boolean (value,
709 pspp_sheet_view_column_get_sort_indicator (tree_column));
712 case PROP_SORT_ORDER:
713 g_value_set_enum (value,
714 pspp_sheet_view_column_get_sort_order (tree_column));
717 case PROP_SORT_COLUMN_ID:
718 g_value_set_int (value,
719 pspp_sheet_view_column_get_sort_column_id (tree_column));
722 case PROP_QUICK_EDIT:
723 g_value_set_boolean (value,
724 pspp_sheet_view_column_get_quick_edit (tree_column));
728 g_value_set_boolean (value,
729 pspp_sheet_view_column_get_selected (tree_column));
732 case PROP_SELECTABLE:
733 g_value_set_boolean (value,
734 pspp_sheet_view_column_get_selectable (tree_column));
738 g_value_set_boolean (value,
739 pspp_sheet_view_column_get_row_head (tree_column));
743 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
748 /* Implementation of GtkCellLayout interface
752 pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
753 GtkCellRenderer *cell,
756 PsppSheetViewColumn *column;
757 PsppSheetViewColumnCellInfo *cell_info;
759 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
760 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
761 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
763 g_object_ref_sink (cell);
765 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
766 cell_info->cell = cell;
767 cell_info->expand = expand ? TRUE : FALSE;
768 cell_info->pack = GTK_PACK_START;
769 cell_info->has_focus = 0;
770 cell_info->attributes = NULL;
772 column->cell_list = g_list_append (column->cell_list, cell_info);
776 pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
777 GtkCellRenderer *cell,
780 PsppSheetViewColumn *column;
781 PsppSheetViewColumnCellInfo *cell_info;
783 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
784 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
785 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
787 g_object_ref_sink (cell);
789 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
790 cell_info->cell = cell;
791 cell_info->expand = expand ? TRUE : FALSE;
792 cell_info->pack = GTK_PACK_END;
793 cell_info->has_focus = 0;
794 cell_info->attributes = NULL;
796 column->cell_list = g_list_append (column->cell_list, cell_info);
800 pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
802 PsppSheetViewColumn *column;
804 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
805 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
807 while (column->cell_list)
809 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
811 pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
812 g_object_unref (info->cell);
814 column->cell_list = g_list_delete_link (column->cell_list,
820 pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
821 GtkCellRenderer *cell,
822 const gchar *attribute,
825 PsppSheetViewColumn *tree_column;
826 PsppSheetViewColumnCellInfo *info;
828 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
829 tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
831 info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
832 g_return_if_fail (info != NULL);
834 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
835 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
837 if (tree_column->tree_view)
838 _pspp_sheet_view_column_cell_set_dirty (tree_column);
842 pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
843 GtkCellRenderer *cell,
844 GtkCellLayoutDataFunc func,
846 GDestroyNotify destroy)
848 PsppSheetViewColumn *column;
849 PsppSheetViewColumnCellInfo *info;
851 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
852 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
854 info = pspp_sheet_view_column_get_cell_info (column, cell);
855 g_return_if_fail (info != NULL);
859 GDestroyNotify d = info->destroy;
861 info->destroy = NULL;
865 info->func = (PsppSheetCellDataFunc)func;
866 info->func_data = func_data;
867 info->destroy = destroy;
869 if (column->tree_view)
870 _pspp_sheet_view_column_cell_set_dirty (column);
874 pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
875 GtkCellRenderer *cell_renderer)
877 PsppSheetViewColumn *column;
878 PsppSheetViewColumnCellInfo *info;
880 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
881 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
883 info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
885 pspp_sheet_view_column_clear_attributes_by_info (column, info);
889 pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
890 GtkCellRenderer *cell,
894 PsppSheetViewColumn *column;
895 PsppSheetViewColumnCellInfo *info;
897 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
898 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
900 info = pspp_sheet_view_column_get_cell_info (column, cell);
902 g_return_if_fail (info != NULL);
903 g_return_if_fail (position >= 0);
905 link = g_list_find (column->cell_list, info);
907 g_return_if_fail (link != NULL);
909 column->cell_list = g_list_delete_link (column->cell_list, link);
910 column->cell_list = g_list_insert (column->cell_list, info, position);
912 if (column->tree_view)
913 gtk_widget_queue_draw (column->tree_view);
917 pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
918 PsppSheetViewColumnCellInfo *info)
922 list = info->attributes;
924 while (list && list->next)
927 list = list->next->next;
929 g_slist_free (info->attributes);
930 info->attributes = NULL;
932 if (tree_column->tree_view)
933 _pspp_sheet_view_column_cell_set_dirty (tree_column);
937 on_query_tooltip (GtkWidget *widget,
940 gboolean keyboard_mode,
944 PsppSheetViewColumn *tree_column = user_data;
947 g_signal_emit (tree_column, tree_column_signals[QUERY_TOOLTIP], 0,
953 on_button_pressed (GtkWidget *widget, GdkEventButton *event,
956 PsppSheetViewColumn *tree_column = user_data;
959 /* XXX See "Implement GtkWidget::popup_menu" in GTK+ reference manual. */
960 g_signal_emit (tree_column, tree_column_signals[BUTTON_PRESS_EVENT],
968 /* Button handling code
971 pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
973 PsppSheetView *tree_view;
977 tree_view = (PsppSheetView *) tree_column->tree_view;
979 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
980 g_return_if_fail (tree_column->button == NULL);
982 gtk_widget_push_composite_child ();
983 tree_column->button = gtk_button_new ();
984 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
985 gtk_widget_pop_composite_child ();
987 /* make sure we own a reference to it as well. */
988 if (tree_view->priv->header_window)
989 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
990 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
992 g_signal_connect (tree_column->button, "event",
993 G_CALLBACK (pspp_sheet_view_column_button_event),
995 g_signal_connect (tree_column->button, "clicked",
996 G_CALLBACK (pspp_sheet_view_column_button_clicked),
998 g_signal_connect (tree_column->button, "popup-menu",
999 G_CALLBACK (pspp_sheet_view_column_button_popup_menu),
1001 g_signal_connect (tree_column->button, "button-press-event",
1002 G_CALLBACK (on_button_pressed), tree_column);
1004 g_signal_connect (tree_column->button, "query-tooltip",
1005 G_CALLBACK (on_query_tooltip), tree_column);
1006 g_object_set (tree_column->button, "has-tooltip", TRUE, NULL);
1008 tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
1010 hbox = gtk_hbox_new (FALSE, 2);
1011 tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
1013 if (tree_column->child)
1014 child = tree_column->child;
1017 child = gtk_label_new (tree_column->title);
1018 gtk_widget_show (child);
1021 g_signal_connect (child, "mnemonic-activate",
1022 G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
1025 if (tree_column->xalign <= 0.5)
1026 gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
1028 gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
1030 gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
1032 gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
1033 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
1035 gtk_widget_show (hbox);
1036 gtk_widget_show (tree_column->alignment);
1037 pspp_sheet_view_column_update_button (tree_column);
1041 pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
1043 gint sort_column_id = -1;
1045 GtkWidget *alignment;
1047 GtkWidget *current_child;
1048 GtkArrowType arrow_type = GTK_ARROW_NONE;
1049 GtkTreeModel *model;
1052 if (tree_column->tree_view)
1053 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1057 /* Create a button if necessary */
1058 if (tree_column->need_button &&
1059 tree_column->visible &&
1060 tree_column->button == NULL &&
1061 tree_column->tree_view &&
1062 gtk_widget_get_realized (tree_column->tree_view))
1063 pspp_sheet_view_column_create_button (tree_column);
1065 if (! tree_column->button)
1068 hbox = GTK_BIN (tree_column->button)->child;
1069 alignment = tree_column->alignment;
1070 arrow = tree_column->arrow;
1071 current_child = GTK_BIN (alignment)->child;
1073 /* Set up the actual button */
1074 gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
1077 if (tree_column->child)
1079 if (current_child != tree_column->child)
1081 gtk_container_remove (GTK_CONTAINER (alignment),
1083 gtk_container_add (GTK_CONTAINER (alignment),
1084 tree_column->child);
1089 if (current_child == NULL)
1091 current_child = gtk_label_new (NULL);
1092 gtk_widget_show (current_child);
1093 gtk_container_add (GTK_CONTAINER (alignment),
1097 g_return_if_fail (GTK_IS_LABEL (current_child));
1099 if (tree_column->title)
1100 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1101 tree_column->title);
1103 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1107 if (GTK_IS_TREE_SORTABLE (model))
1108 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1112 if (tree_column->show_sort_indicator)
1114 gboolean alternative;
1116 g_object_get (gtk_widget_get_settings (tree_column->tree_view),
1117 "gtk-alternative-sort-arrows", &alternative,
1120 switch (tree_column->sort_order)
1122 case GTK_SORT_ASCENDING:
1123 arrow_type = alternative ? GTK_ARROW_UP : GTK_ARROW_DOWN;
1126 case GTK_SORT_DESCENDING:
1127 arrow_type = alternative ? GTK_ARROW_DOWN : GTK_ARROW_UP;
1131 g_warning (G_STRLOC": bad sort order");
1136 gtk_arrow_set (GTK_ARROW (arrow),
1140 /* Put arrow on the right if the text is left-or-center justified, and on the
1141 * left otherwise; do this by packing boxes, so flipping text direction will
1144 g_object_ref (arrow);
1145 gtk_container_remove (GTK_CONTAINER (hbox), arrow);
1147 if (tree_column->xalign <= 0.5)
1149 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1153 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1154 /* move it to the front */
1155 gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
1157 g_object_unref (arrow);
1159 if (tree_column->show_sort_indicator
1160 || (GTK_IS_TREE_SORTABLE (model) && tree_column->sort_column_id >= 0))
1161 gtk_widget_show (arrow);
1163 gtk_widget_hide (arrow);
1165 /* It's always safe to hide the button. It isn't always safe to show it, as
1166 * if you show it before it's realized, it'll get the wrong window. */
1167 if (tree_column->button &&
1168 tree_column->tree_view != NULL &&
1169 gtk_widget_get_realized (tree_column->tree_view))
1171 if (tree_column->visible)
1173 gtk_widget_show_now (tree_column->button);
1174 if (tree_column->window)
1176 if (tree_column->resizable)
1178 gdk_window_show (tree_column->window);
1179 gdk_window_raise (tree_column->window);
1183 gdk_window_hide (tree_column->window);
1189 gtk_widget_hide (tree_column->button);
1190 if (tree_column->window)
1191 gdk_window_hide (tree_column->window);
1195 can_focus = pspp_sheet_view_column_can_focus (tree_column);
1196 gtk_widget_set_can_focus (tree_column->button, can_focus);
1197 if (!can_focus && gtk_widget_has_focus (tree_column->button))
1199 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
1200 if (gtk_widget_is_toplevel (toplevel))
1202 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
1206 /* Queue a resize on the assumption that we always want to catch all changes
1207 * and columns don't change all that often.
1209 if (gtk_widget_get_realized (tree_column->tree_view))
1210 gtk_widget_queue_resize (tree_column->tree_view);
1214 /* Button signal handlers
1218 pspp_sheet_view_column_button_event (GtkWidget *widget,
1222 PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
1224 g_return_val_if_fail (event != NULL, FALSE);
1226 if (event->type == GDK_BUTTON_PRESS &&
1227 column->reorderable &&
1228 ((GdkEventButton *)event)->button == 1)
1230 column->maybe_reordered = TRUE;
1231 gdk_window_get_pointer (GTK_BUTTON (widget)->event_window,
1235 gtk_widget_grab_focus (widget);
1238 if (event->type == GDK_BUTTON_RELEASE ||
1239 event->type == GDK_LEAVE_NOTIFY)
1240 column->maybe_reordered = FALSE;
1242 if (event->type == GDK_MOTION_NOTIFY &&
1243 column->maybe_reordered &&
1244 (gtk_drag_check_threshold (widget,
1247 (gint) ((GdkEventMotion *)event)->x,
1248 (gint) ((GdkEventMotion *)event)->y)))
1250 column->maybe_reordered = FALSE;
1251 _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
1254 if (column->clickable == FALSE)
1256 switch (event->type)
1258 case GDK_MOTION_NOTIFY:
1259 case GDK_BUTTON_RELEASE:
1260 case GDK_ENTER_NOTIFY:
1261 case GDK_LEAVE_NOTIFY:
1271 all_rows_selected (PsppSheetView *sheet_view)
1273 PsppSheetSelection *selection = sheet_view->priv->selection;
1274 gint n_rows, n_selected_rows;
1276 n_rows = sheet_view->priv->row_count;
1277 n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
1279 return n_rows > 0 && n_selected_rows >= n_rows;
1283 on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *column,
1284 GdkEventButton *event)
1286 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (column->tree_view);
1287 PsppSheetSelection *selection;
1288 GSignalInvocationHint *hint;
1291 /* We only want to run first, not last, but combining that with return type
1292 `gboolean' makes GObject warn, so just ignore the run_last call. */
1293 hint = g_signal_get_invocation_hint (column);
1294 g_return_val_if_fail (hint != NULL, FALSE);
1295 if (hint->run_type != G_SIGNAL_RUN_FIRST)
1298 g_return_val_if_fail (sheet_view != NULL, FALSE);
1300 selection = sheet_view->priv->selection;
1301 g_return_val_if_fail (selection != NULL, FALSE);
1303 if (pspp_sheet_selection_get_mode (selection) != PSPP_SHEET_SELECTION_RECTANGLE)
1306 modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
1307 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
1309 if (pspp_sheet_selection_count_selected_columns (selection) <= 1
1310 || !all_rows_selected (sheet_view))
1312 pspp_sheet_selection_select_all (selection);
1313 pspp_sheet_selection_unselect_all_columns (selection);
1314 pspp_sheet_selection_select_column (selection, column);
1315 sheet_view->priv->anchor_column = column;
1319 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1320 && modifiers == GDK_CONTROL_MASK)
1322 gboolean is_selected;
1324 if (!all_rows_selected (sheet_view))
1326 pspp_sheet_selection_select_all (selection);
1327 pspp_sheet_selection_unselect_all_columns (selection);
1329 sheet_view->priv->anchor_column = column;
1331 is_selected = pspp_sheet_view_column_get_selected (column);
1332 pspp_sheet_view_column_set_selected (column, !is_selected);
1336 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1337 && modifiers == GDK_SHIFT_MASK)
1339 if (!all_rows_selected (sheet_view))
1341 pspp_sheet_selection_select_all (selection);
1342 pspp_sheet_selection_unselect_all_columns (selection);
1343 sheet_view->priv->anchor_column = column;
1345 else if (sheet_view->priv->anchor_column == NULL)
1346 sheet_view->priv->anchor_column = column;
1348 pspp_sheet_selection_unselect_all_columns (selection);
1349 pspp_sheet_selection_select_column_range (selection,
1350 sheet_view->priv->anchor_column,
1359 on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *column)
1361 PsppSheetSelection *selection;
1362 PsppSheetView *sheet_view;
1364 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (column));
1365 selection = pspp_sheet_view_get_selection (sheet_view);
1366 if (pspp_sheet_selection_get_mode (selection) == PSPP_SHEET_SELECTION_RECTANGLE)
1368 pspp_sheet_selection_select_all (selection);
1369 if (pspp_sheet_view_column_get_row_head (column))
1370 pspp_sheet_selection_select_all_columns (selection);
1373 pspp_sheet_selection_unselect_all_columns (selection);
1374 pspp_sheet_selection_select_column (selection, column);
1376 sheet_view->priv->anchor_column = column;
1383 pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
1385 PsppSheetViewColumn *column = data;
1388 g_signal_emit (column, tree_column_signals[CLICKED], 0, &handled);
1392 pspp_sheet_view_column_button_popup_menu (GtkWidget *widget, gpointer data)
1394 g_signal_emit_by_name (data, "popup-menu");
1398 pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
1399 gboolean group_cycling,
1402 PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
1404 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
1406 PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
1407 if (column->clickable)
1408 gtk_button_clicked (GTK_BUTTON (column->button));
1409 else if (gtk_widget_get_can_focus (column->button))
1410 gtk_widget_grab_focus (column->button);
1412 gtk_widget_grab_focus (column->tree_view);
1418 pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
1419 PsppSheetViewColumn *column)
1421 gint sort_column_id;
1424 if (gtk_tree_sortable_get_sort_column_id (sortable,
1428 if (sort_column_id == column->sort_column_id)
1430 pspp_sheet_view_column_set_sort_indicator (column, TRUE);
1431 pspp_sheet_view_column_set_sort_order (column, order);
1435 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1440 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1445 pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
1448 gint sort_column_id;
1450 gboolean has_sort_column;
1451 gboolean has_default_sort_func;
1453 g_return_if_fail (tree_column->tree_view != NULL);
1456 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1459 has_default_sort_func =
1460 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
1462 if (has_sort_column &&
1463 sort_column_id == tree_column->sort_column_id)
1465 if (order == GTK_SORT_ASCENDING)
1466 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1467 tree_column->sort_column_id,
1468 GTK_SORT_DESCENDING);
1469 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
1470 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1471 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1472 GTK_SORT_ASCENDING);
1474 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1475 tree_column->sort_column_id,
1476 GTK_SORT_ASCENDING);
1480 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1481 tree_column->sort_column_id,
1482 GTK_SORT_ASCENDING);
1488 pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
1490 GtkTreeModel *model;
1492 if (tree_column->tree_view == NULL)
1495 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1500 if (GTK_IS_TREE_SORTABLE (model) &&
1501 tree_column->sort_column_id != -1)
1503 gint real_sort_column_id;
1504 GtkSortType real_order;
1506 if (tree_column->sort_column_changed_signal == 0)
1507 tree_column->sort_column_changed_signal =
1508 g_signal_connect (model, "sort-column-changed",
1509 G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
1512 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1513 &real_sort_column_id,
1515 (real_sort_column_id == tree_column->sort_column_id))
1517 pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
1518 pspp_sheet_view_column_set_sort_order (tree_column, real_order);
1522 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
1528 /* Exported Private Functions.
1529 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1533 _pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
1535 PsppSheetView *tree_view;
1537 guint attributes_mask;
1540 tree_view = (PsppSheetView *)column->tree_view;
1541 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
1543 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1544 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
1545 g_return_if_fail (tree_view->priv->header_window != NULL);
1546 if (!column->need_button || !column->button)
1549 g_return_if_fail (column->button != NULL);
1551 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
1553 if (column->visible)
1554 gtk_widget_show (column->button);
1556 attr.window_type = GDK_WINDOW_CHILD;
1557 attr.wclass = GDK_INPUT_ONLY;
1558 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1559 attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1560 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
1561 (GDK_BUTTON_PRESS_MASK |
1562 GDK_BUTTON_RELEASE_MASK |
1563 GDK_POINTER_MOTION_MASK |
1564 GDK_POINTER_MOTION_HINT_MASK |
1565 GDK_KEY_PRESS_MASK);
1566 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
1567 attr.cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (tree_view->priv->header_window),
1568 GDK_SB_H_DOUBLE_ARROW);
1570 attr.width = TREE_VIEW_DRAG_WIDTH;
1571 attr.height = tree_view->priv->header_height;
1573 attr.x = (column->button->allocation.x + (rtl ? 0 : column->button->allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
1574 column->window = gdk_window_new (tree_view->priv->header_window,
1575 &attr, attributes_mask);
1576 gdk_window_set_user_data (column->window, tree_view);
1578 pspp_sheet_view_column_update_button (column);
1580 gdk_cursor_unref (attr.cursor);
1584 _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
1586 g_return_if_fail (column != NULL);
1587 if (column->window != NULL)
1589 gdk_window_set_user_data (column->window, NULL);
1590 gdk_window_destroy (column->window);
1591 column->window = NULL;
1596 _pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
1597 GtkTreeModel *old_model)
1599 if (column->sort_column_changed_signal)
1601 g_signal_handler_disconnect (old_model,
1602 column->sort_column_changed_signal);
1603 column->sort_column_changed_signal = 0;
1605 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1609 _pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
1610 PsppSheetView *tree_view)
1612 g_assert (column->tree_view == NULL);
1614 column->tree_view = GTK_WIDGET (tree_view);
1615 if (column->need_button)
1616 pspp_sheet_view_column_create_button (column);
1618 column->property_changed_signal =
1619 g_signal_connect_swapped (tree_view,
1621 G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
1624 pspp_sheet_view_column_setup_sort_column_id_callback (column);
1628 _pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
1630 if (column->tree_view && column->button)
1632 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1634 if (column->property_changed_signal)
1636 g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
1637 column->property_changed_signal = 0;
1640 if (column->sort_column_changed_signal)
1642 g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
1643 column->sort_column_changed_signal);
1644 column->sort_column_changed_signal = 0;
1647 column->tree_view = NULL;
1648 column->button = NULL;
1652 _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
1656 for (list = column->cell_list; list; list = list->next)
1657 if (((PsppSheetViewColumnCellInfo *)list->data)->cell->mode ==
1658 GTK_CELL_RENDERER_MODE_EDITABLE)
1664 /* gets cell being edited */
1666 _pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
1670 for (list = column->cell_list; list; list = list->next)
1671 if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
1672 return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
1678 _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
1683 for (list = column->cell_list; list; list = list->next)
1685 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1687 if ((cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1688 cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
1689 cellinfo->cell->visible)
1697 _pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
1703 list = pspp_sheet_view_column_cell_first (column);
1704 for (; list; list = pspp_sheet_view_column_cell_next (column, list))
1706 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1707 if (current_x <= x && x <= current_x + cellinfo->real_width)
1708 return cellinfo->cell;
1709 current_x += cellinfo->real_width;
1715 /* Public Functions */
1719 * pspp_sheet_view_column_new:
1721 * Creates a new #PsppSheetViewColumn.
1723 * Return value: A newly created #PsppSheetViewColumn.
1725 PsppSheetViewColumn *
1726 pspp_sheet_view_column_new (void)
1728 PsppSheetViewColumn *tree_column;
1730 tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
1736 * pspp_sheet_view_column_new_with_attributes:
1737 * @title: The title to set the header to.
1738 * @cell: The #GtkCellRenderer.
1739 * @Varargs: A %NULL-terminated list of attributes.
1741 * Creates a new #PsppSheetViewColumn with a number of default values. This is
1742 * equivalent to calling pspp_sheet_view_column_set_title(),
1743 * pspp_sheet_view_column_pack_start(), and
1744 * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
1746 * Here's a simple example:
1748 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1751 * PsppSheetViewColumn *column;
1752 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
1754 * column = pspp_sheet_view_column_new_with_attributes ("Title",
1756 * "text", TEXT_COLUMN,
1757 * "foreground", COLOR_COLUMN,
1762 * Return value: A newly created #PsppSheetViewColumn.
1764 PsppSheetViewColumn *
1765 pspp_sheet_view_column_new_with_attributes (const gchar *title,
1766 GtkCellRenderer *cell,
1769 PsppSheetViewColumn *retval;
1772 retval = pspp_sheet_view_column_new ();
1774 pspp_sheet_view_column_set_title (retval, title);
1775 pspp_sheet_view_column_pack_start (retval, cell, TRUE);
1777 va_start (args, cell);
1778 pspp_sheet_view_column_set_attributesv (retval, cell, args);
1784 static PsppSheetViewColumnCellInfo *
1785 pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
1786 GtkCellRenderer *cell_renderer)
1789 for (list = tree_column->cell_list; list; list = list->next)
1790 if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
1791 return (PsppSheetViewColumnCellInfo *) list->data;
1797 * pspp_sheet_view_column_pack_start:
1798 * @tree_column: A #PsppSheetViewColumn.
1799 * @cell: The #GtkCellRenderer.
1800 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1802 * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
1803 * the @cell is allocated no more space than it needs. Any unused space is divided
1804 * evenly between cells for which @expand is %TRUE.
1807 pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
1808 GtkCellRenderer *cell,
1811 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
1815 * pspp_sheet_view_column_pack_end:
1816 * @tree_column: A #PsppSheetViewColumn.
1817 * @cell: The #GtkCellRenderer.
1818 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1820 * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
1821 * is allocated no more space than it needs. Any unused space is divided
1822 * evenly between cells for which @expand is %TRUE.
1825 pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
1826 GtkCellRenderer *cell,
1829 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
1833 * pspp_sheet_view_column_clear:
1834 * @tree_column: A #PsppSheetViewColumn
1836 * Unsets all the mappings on all renderers on the @tree_column.
1839 pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
1841 gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
1845 pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
1847 PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
1848 GList *retval = NULL, *list;
1850 g_return_val_if_fail (tree_column != NULL, NULL);
1852 for (list = tree_column->cell_list; list; list = list->next)
1854 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
1856 retval = g_list_append (retval, info->cell);
1863 * pspp_sheet_view_column_get_cell_renderers:
1864 * @tree_column: A #PsppSheetViewColumn
1866 * Returns a newly-allocated #GList of all the cell renderers in the column,
1867 * in no particular order. The list must be freed with g_list_free().
1869 * Return value: A list of #GtkCellRenderers
1871 * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
1874 pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
1876 return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
1880 * pspp_sheet_view_column_add_attribute:
1881 * @tree_column: A #PsppSheetViewColumn.
1882 * @cell_renderer: the #GtkCellRenderer to set attributes on
1883 * @attribute: An attribute on the renderer
1884 * @column: The column position on the model to get the attribute from.
1886 * Adds an attribute mapping to the list in @tree_column. The @column is the
1887 * column of the model to get a value from, and the @attribute is the
1888 * parameter on @cell_renderer to be set from the value. So for example
1889 * if column 2 of the model contains strings, you could have the
1890 * "text" attribute of a #GtkCellRendererText get its values from
1894 pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
1895 GtkCellRenderer *cell_renderer,
1896 const gchar *attribute,
1899 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
1900 cell_renderer, attribute, column);
1904 pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
1905 GtkCellRenderer *cell_renderer,
1911 attribute = va_arg (args, gchar *);
1913 pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
1915 while (attribute != NULL)
1917 column = va_arg (args, gint);
1918 pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1919 attribute = va_arg (args, gchar *);
1924 * pspp_sheet_view_column_set_attributes:
1925 * @tree_column: A #PsppSheetViewColumn.
1926 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1927 * @Varargs: A %NULL-terminated list of attributes.
1929 * Sets the attributes in the list as the attributes of @tree_column.
1930 * The attributes should be in attribute/column order, as in
1931 * pspp_sheet_view_column_add_attribute(). All existing attributes
1932 * are removed, and replaced with the new attributes.
1935 pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
1936 GtkCellRenderer *cell_renderer,
1941 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1942 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1943 g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
1945 va_start (args, cell_renderer);
1946 pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
1952 * pspp_sheet_view_column_set_cell_data_func:
1953 * @tree_column: A #PsppSheetViewColumn
1954 * @cell_renderer: A #GtkCellRenderer
1955 * @func: The #PsppSheetViewColumnFunc to use.
1956 * @func_data: The user data for @func.
1957 * @destroy: The destroy notification for @func_data
1959 * Sets the #PsppSheetViewColumnFunc to use for the column. This
1960 * function is used instead of the standard attributes mapping for
1961 * setting the column value, and should set the value of @tree_column's
1962 * cell renderer as appropriate. @func may be %NULL to remove an
1966 pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
1967 GtkCellRenderer *cell_renderer,
1968 PsppSheetCellDataFunc func,
1970 GDestroyNotify destroy)
1972 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
1974 (GtkCellLayoutDataFunc)func,
1975 func_data, destroy);
1980 * pspp_sheet_view_column_clear_attributes:
1981 * @tree_column: a #PsppSheetViewColumn
1982 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1984 * Clears all existing attributes previously set with
1985 * pspp_sheet_view_column_set_attributes().
1988 pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
1989 GtkCellRenderer *cell_renderer)
1991 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
1996 * pspp_sheet_view_column_set_spacing:
1997 * @tree_column: A #PsppSheetViewColumn.
1998 * @spacing: distance between cell renderers in pixels.
2000 * Sets the spacing field of @tree_column, which is the number of pixels to
2001 * place between cell renderers packed into it.
2004 pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
2007 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2008 g_return_if_fail (spacing >= 0);
2010 if (tree_column->spacing == spacing)
2013 tree_column->spacing = spacing;
2014 if (tree_column->tree_view)
2015 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2019 * pspp_sheet_view_column_get_spacing:
2020 * @tree_column: A #PsppSheetViewColumn.
2022 * Returns the spacing of @tree_column.
2024 * Return value: the spacing of @tree_column.
2027 pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
2029 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2031 return tree_column->spacing;
2034 /* Options for manipulating the columns */
2037 * pspp_sheet_view_column_set_visible:
2038 * @tree_column: A #PsppSheetViewColumn.
2039 * @visible: %TRUE if the @tree_column is visible.
2041 * Sets the visibility of @tree_column.
2044 pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
2047 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2049 visible = !! visible;
2051 if (tree_column->visible == visible)
2054 tree_column->visible = visible;
2056 if (tree_column->visible)
2057 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2059 pspp_sheet_view_column_update_button (tree_column);
2060 g_object_notify (G_OBJECT (tree_column), "visible");
2064 * pspp_sheet_view_column_get_visible:
2065 * @tree_column: A #PsppSheetViewColumn.
2067 * Returns %TRUE if @tree_column is visible.
2069 * Return value: whether the column is visible or not. If it is visible, then
2070 * the tree will show the column.
2073 pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
2075 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2077 return tree_column->visible;
2081 * pspp_sheet_view_column_set_resizable:
2082 * @tree_column: A #PsppSheetViewColumn
2083 * @resizable: %TRUE, if the column can be resized
2085 * If @resizable is %TRUE, then the user can explicitly resize the column by
2086 * grabbing the outer edge of the column button.
2089 pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
2092 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2094 resizable = !! resizable;
2096 if (tree_column->resizable == resizable)
2099 tree_column->resizable = resizable;
2101 pspp_sheet_view_column_update_button (tree_column);
2103 g_object_notify (G_OBJECT (tree_column), "resizable");
2107 * pspp_sheet_view_column_get_resizable:
2108 * @tree_column: A #PsppSheetViewColumn
2110 * Returns %TRUE if the @tree_column can be resized by the end user.
2112 * Return value: %TRUE, if the @tree_column can be resized.
2115 pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
2117 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2119 return tree_column->resizable;
2124 * pspp_sheet_view_column_get_width:
2125 * @tree_column: A #PsppSheetViewColumn.
2127 * Returns the current size of @tree_column in pixels.
2129 * Return value: The current width of @tree_column.
2132 pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
2134 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2136 return tree_column->width;
2140 * pspp_sheet_view_column_set_fixed_width:
2141 * @tree_column: A #PsppSheetViewColumn.
2142 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
2144 * Sets the size of the column in pixels. The size of the column is clamped to
2145 * the min/max width for the column. Please note that the min/max width of the
2146 * column doesn't actually affect the "fixed_width" property of the widget, just
2147 * the actual size when displayed.
2150 pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
2153 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2154 g_return_if_fail (fixed_width > 0);
2156 tree_column->fixed_width = fixed_width;
2157 tree_column->use_resized_width = FALSE;
2159 if (tree_column->tree_view &&
2160 gtk_widget_get_realized (tree_column->tree_view))
2162 gtk_widget_queue_resize (tree_column->tree_view);
2165 g_object_notify (G_OBJECT (tree_column), "fixed-width");
2169 * pspp_sheet_view_column_get_fixed_width:
2170 * @tree_column: a #PsppSheetViewColumn
2172 * Gets the fixed width of the column. This value is only meaning may not be
2173 * the actual width of the column on the screen, just what is requested.
2175 * Return value: the fixed width of the column
2178 pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
2180 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2182 return tree_column->fixed_width;
2186 * pspp_sheet_view_column_set_min_width:
2187 * @tree_column: A #PsppSheetViewColumn.
2188 * @min_width: The minimum width of the column in pixels, or -1.
2190 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
2191 * minimum width is unset.
2194 pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
2197 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2198 g_return_if_fail (min_width >= -1);
2200 if (min_width == tree_column->min_width)
2203 if (tree_column->visible &&
2204 tree_column->tree_view != NULL &&
2205 gtk_widget_get_realized (tree_column->tree_view))
2207 if (min_width > tree_column->width)
2208 gtk_widget_queue_resize (tree_column->tree_view);
2211 tree_column->min_width = min_width;
2212 g_object_freeze_notify (G_OBJECT (tree_column));
2213 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
2215 tree_column->max_width = min_width;
2216 g_object_notify (G_OBJECT (tree_column), "max-width");
2218 g_object_notify (G_OBJECT (tree_column), "min-width");
2219 g_object_thaw_notify (G_OBJECT (tree_column));
2223 * pspp_sheet_view_column_get_min_width:
2224 * @tree_column: A #PsppSheetViewColumn.
2226 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
2229 * Return value: The minimum width of the @tree_column.
2232 pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
2234 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2236 return tree_column->min_width;
2240 * pspp_sheet_view_column_set_max_width:
2241 * @tree_column: A #PsppSheetViewColumn.
2242 * @max_width: The maximum width of the column in pixels, or -1.
2244 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
2245 * maximum width is unset. Note, the column can actually be wider than max
2246 * width if it's the last column in a view. In this case, the column expands to
2247 * fill any extra space.
2250 pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
2253 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2254 g_return_if_fail (max_width >= -1);
2256 if (max_width == tree_column->max_width)
2259 if (tree_column->visible &&
2260 tree_column->tree_view != NULL &&
2261 gtk_widget_get_realized (tree_column->tree_view))
2263 if (max_width != -1 && max_width < tree_column->width)
2264 gtk_widget_queue_resize (tree_column->tree_view);
2267 tree_column->max_width = max_width;
2268 g_object_freeze_notify (G_OBJECT (tree_column));
2269 if (max_width != -1 && max_width < tree_column->min_width)
2271 tree_column->min_width = max_width;
2272 g_object_notify (G_OBJECT (tree_column), "min-width");
2274 g_object_notify (G_OBJECT (tree_column), "max-width");
2275 g_object_thaw_notify (G_OBJECT (tree_column));
2279 * pspp_sheet_view_column_get_max_width:
2280 * @tree_column: A #PsppSheetViewColumn.
2282 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
2285 * Return value: The maximum width of the @tree_column.
2288 pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
2290 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2292 return tree_column->max_width;
2296 * pspp_sheet_view_column_clicked:
2297 * @tree_column: a #PsppSheetViewColumn
2299 * Emits the "clicked" signal on the column. This function will only work if
2300 * @tree_column is clickable.
2303 pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
2305 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2307 if (tree_column->visible &&
2308 tree_column->button &&
2309 tree_column->clickable)
2310 gtk_button_clicked (GTK_BUTTON (tree_column->button));
2314 * pspp_sheet_view_column_set_title:
2315 * @tree_column: A #PsppSheetViewColumn.
2316 * @title: The title of the @tree_column.
2318 * Sets the title of the @tree_column. If a custom widget has been set, then
2319 * this value is ignored.
2322 pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
2327 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2329 new_title = g_strdup (title);
2330 g_free (tree_column->title);
2331 tree_column->title = new_title;
2333 pspp_sheet_view_column_update_button (tree_column);
2334 g_object_notify (G_OBJECT (tree_column), "title");
2338 * pspp_sheet_view_column_get_title:
2339 * @tree_column: A #PsppSheetViewColumn.
2341 * Returns the title of the widget.
2343 * Return value: the title of the column. This string should not be
2344 * modified or freed.
2346 G_CONST_RETURN gchar *
2347 pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
2349 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2351 return tree_column->title;
2355 * pspp_sheet_view_column_set_expand:
2356 * @tree_column: A #PsppSheetViewColumn
2357 * @expand: %TRUE if the column should take available extra space, %FALSE if not
2359 * Sets the column to take available extra space. This space is shared equally
2360 * amongst all columns that have the expand set to %TRUE. If no column has this
2361 * option set, then the last column gets all extra space. By default, every
2362 * column is created with this %FALSE.
2367 pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
2370 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2373 if (tree_column->expand == expand)
2375 tree_column->expand = expand;
2377 if (tree_column->visible &&
2378 tree_column->tree_view != NULL &&
2379 gtk_widget_get_realized (tree_column->tree_view))
2381 /* We want to continue using the original width of the
2382 * column that includes additional space added by the user
2383 * resizing the columns and possibly extra (expanded) space, which
2384 * are not included in the resized width.
2386 tree_column->use_resized_width = FALSE;
2388 gtk_widget_queue_resize (tree_column->tree_view);
2391 g_object_notify (G_OBJECT (tree_column), "expand");
2395 * pspp_sheet_view_column_get_expand:
2396 * @tree_column: a #PsppSheetViewColumn
2398 * Return %TRUE if the column expands to take any available space.
2400 * Return value: %TRUE, if the column expands
2405 pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
2407 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2409 return tree_column->expand;
2413 * pspp_sheet_view_column_set_clickable:
2414 * @tree_column: A #PsppSheetViewColumn.
2415 * @clickable: %TRUE if the header is active.
2417 * Sets the header to be active if @active is %TRUE. When the header is active,
2418 * then it can take keyboard focus, and can be clicked.
2421 pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
2424 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2426 clickable = !! clickable;
2427 if (tree_column->clickable == clickable)
2430 tree_column->clickable = clickable;
2431 pspp_sheet_view_column_update_button (tree_column);
2432 g_object_notify (G_OBJECT (tree_column), "clickable");
2436 * pspp_sheet_view_column_get_clickable:
2437 * @tree_column: a #PsppSheetViewColumn
2439 * Returns %TRUE if the user can click on the header for the column.
2441 * Return value: %TRUE if user can click the column header.
2444 pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
2446 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2448 return tree_column->clickable;
2452 * pspp_sheet_view_column_set_widget:
2453 * @tree_column: A #PsppSheetViewColumn.
2454 * @widget: (allow-none): A child #GtkWidget, or %NULL.
2456 * Sets the widget in the header to be @widget. If widget is %NULL, then the
2457 * header button is set with a #GtkLabel set to the title of @tree_column.
2460 pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
2463 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2464 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
2467 g_object_ref_sink (widget);
2469 if (tree_column->child)
2470 g_object_unref (tree_column->child);
2472 tree_column->child = widget;
2473 pspp_sheet_view_column_update_button (tree_column);
2474 g_object_notify (G_OBJECT (tree_column), "widget");
2478 * pspp_sheet_view_column_get_widget:
2479 * @tree_column: A #PsppSheetViewColumn.
2481 * Returns the #GtkWidget in the button on the column header. If a custom
2482 * widget has not been set then %NULL is returned.
2484 * Return value: The #GtkWidget in the column header, or %NULL
2487 pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
2489 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2491 return tree_column->child;
2495 * pspp_sheet_view_column_set_alignment:
2496 * @tree_column: A #PsppSheetViewColumn.
2497 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2499 * Sets the alignment of the title or custom widget inside the column header.
2500 * The alignment determines its location inside the button -- 0.0 for left, 0.5
2501 * for center, 1.0 for right.
2504 pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
2507 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2509 xalign = CLAMP (xalign, 0.0, 1.0);
2511 if (tree_column->xalign == xalign)
2514 tree_column->xalign = xalign;
2515 pspp_sheet_view_column_update_button (tree_column);
2516 g_object_notify (G_OBJECT (tree_column), "alignment");
2520 * pspp_sheet_view_column_get_alignment:
2521 * @tree_column: A #PsppSheetViewColumn.
2523 * Returns the current x alignment of @tree_column. This value can range
2524 * between 0.0 and 1.0.
2526 * Return value: The current alignent of @tree_column.
2529 pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
2531 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0.5);
2533 return tree_column->xalign;
2537 * pspp_sheet_view_column_set_reorderable:
2538 * @tree_column: A #PsppSheetViewColumn
2539 * @reorderable: %TRUE, if the column can be reordered.
2541 * If @reorderable is %TRUE, then the column can be reordered by the end user
2542 * dragging the header.
2545 pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
2546 gboolean reorderable)
2548 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2551 pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
2553 reorderable = !!reorderable;
2554 if (tree_column->reorderable == reorderable)
2557 tree_column->reorderable = reorderable;
2558 pspp_sheet_view_column_update_button (tree_column);
2559 g_object_notify (G_OBJECT (tree_column), "reorderable");
2563 * pspp_sheet_view_column_get_reorderable:
2564 * @tree_column: A #PsppSheetViewColumn
2566 * Returns %TRUE if the @tree_column can be reordered by the user.
2568 * Return value: %TRUE if the @tree_column can be reordered by the user.
2571 pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
2573 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2575 return tree_column->reorderable;
2579 * pspp_sheet_view_column_set_quick_edit:
2580 * @tree_column: A #PsppSheetViewColumn
2581 * @quick_edit: If true, editing starts upon the first click in the column. If
2582 * false, the first click selects the column and a second click is needed to
2583 * begin editing. This has no effect on cells that are not editable.
2586 pspp_sheet_view_column_set_quick_edit (PsppSheetViewColumn *tree_column,
2587 gboolean quick_edit)
2589 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2591 quick_edit = !!quick_edit;
2592 if (tree_column->quick_edit != quick_edit)
2594 tree_column->quick_edit = quick_edit;
2595 g_object_notify (G_OBJECT (tree_column), "quick-edit");
2600 * pspp_sheet_view_column_get_quick_edit:
2601 * @tree_column: A #PsppSheetViewColumn
2603 * Returns %TRUE if editing starts upon the first click in the column. Returns
2604 * %FALSE, the first click selects the column and a second click is needed to
2605 * begin editing. This is not meaningful for cells that are not editable.
2607 * Return value: %TRUE if editing starts upon the first click.
2610 pspp_sheet_view_column_get_quick_edit (PsppSheetViewColumn *tree_column)
2612 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2614 return tree_column->quick_edit;
2619 * pspp_sheet_view_column_set_selected:
2620 * @tree_column: A #PsppSheetViewColumn
2621 * @selected: If true, the column is selected as part of a rectangular
2625 pspp_sheet_view_column_set_selected (PsppSheetViewColumn *tree_column,
2628 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2630 selected = !!selected;
2631 if (tree_column->selected != selected)
2633 PsppSheetSelection *selection;
2634 PsppSheetView *sheet_view;
2636 if (tree_column->tree_view != NULL)
2637 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2638 tree_column->selected = selected;
2639 g_object_notify (G_OBJECT (tree_column), "selected");
2641 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
2643 selection = pspp_sheet_view_get_selection (sheet_view);
2644 _pspp_sheet_selection_emit_changed (selection);
2649 * pspp_sheet_view_column_get_selected:
2650 * @tree_column: A #PsppSheetViewColumn
2652 * Returns %TRUE if the column is selected as part of a rectangular
2655 * Return value: %TRUE if the column is selected as part of a rectangular
2659 pspp_sheet_view_column_get_selected (PsppSheetViewColumn *tree_column)
2661 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2663 return tree_column->selected;
2667 * pspp_sheet_view_column_set_selectable:
2668 * @tree_column: A #PsppSheetViewColumn
2669 * @selectable: If true, the column may be selected as part of a rectangular
2673 pspp_sheet_view_column_set_selectable (PsppSheetViewColumn *tree_column,
2674 gboolean selectable)
2676 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2678 selectable = !!selectable;
2679 if (tree_column->selectable != selectable)
2681 if (tree_column->tree_view != NULL)
2682 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2683 tree_column->selectable = selectable;
2684 g_object_notify (G_OBJECT (tree_column), "selectable");
2689 * pspp_sheet_view_column_get_selectable:
2690 * @tree_column: A #PsppSheetViewColumn
2692 * Returns %TRUE if the column may be selected as part of a rectangular
2695 * Return value: %TRUE if the column may be selected as part of a rectangular
2699 pspp_sheet_view_column_get_selectable (PsppSheetViewColumn *tree_column)
2701 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2703 return tree_column->selectable;
2708 * pspp_sheet_view_column_set_row_head:
2709 * @tree_column: A #PsppSheetViewColumn
2710 * @row_head: If true, the column is a "row head", analogous to a column head.
2711 * See the description of the row-head property for more information.
2714 pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column,
2717 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2719 row_head = !!row_head;
2720 if (tree_column->row_head != row_head)
2722 tree_column->row_head = row_head;
2723 g_object_notify (G_OBJECT (tree_column), "row_head");
2728 * pspp_sheet_view_column_get_row_head:
2729 * @tree_column: A #PsppSheetViewColumn
2731 * Returns %TRUE if the column is a row head.
2733 * Return value: %TRUE if the column is a row head.
2736 pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column)
2738 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2740 return tree_column->row_head;
2745 * pspp_sheet_view_column_set_sort_column_id:
2746 * @tree_column: a #PsppSheetViewColumn
2747 * @sort_column_id: The @sort_column_id of the model to sort on.
2749 * Sets the logical @sort_column_id that this column sorts on when this column
2750 * is selected for sorting. Doing so makes the column header clickable.
2753 pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
2754 gint sort_column_id)
2756 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2757 g_return_if_fail (sort_column_id >= -1);
2759 if (tree_column->sort_column_id == sort_column_id)
2762 tree_column->sort_column_id = sort_column_id;
2764 /* Handle unsetting the id */
2765 if (sort_column_id == -1)
2767 GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
2769 if (tree_column->sort_clicked_signal)
2771 g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
2772 tree_column->sort_clicked_signal = 0;
2775 if (tree_column->sort_column_changed_signal)
2777 g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
2778 tree_column->sort_column_changed_signal = 0;
2781 pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2782 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
2783 pspp_sheet_view_column_set_clickable (tree_column, FALSE);
2784 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2788 pspp_sheet_view_column_set_clickable (tree_column, TRUE);
2790 if (! tree_column->sort_clicked_signal)
2791 tree_column->sort_clicked_signal = g_signal_connect (tree_column,
2793 G_CALLBACK (pspp_sheet_view_column_sort),
2796 pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
2797 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2801 * pspp_sheet_view_column_get_sort_column_id:
2802 * @tree_column: a #PsppSheetViewColumn
2804 * Gets the logical @sort_column_id that the model sorts on when this
2805 * column is selected for sorting.
2806 * See pspp_sheet_view_column_set_sort_column_id().
2808 * Return value: the current @sort_column_id for this column, or -1 if
2809 * this column can't be used for sorting.
2812 pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
2814 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2816 return tree_column->sort_column_id;
2820 * pspp_sheet_view_column_set_sort_indicator:
2821 * @tree_column: a #PsppSheetViewColumn
2822 * @setting: %TRUE to display an indicator that the column is sorted
2824 * Call this function with a @setting of %TRUE to display an arrow in
2825 * the header button indicating the column is sorted. Call
2826 * pspp_sheet_view_column_set_sort_order() to change the direction of
2831 pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
2834 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2836 setting = setting != FALSE;
2838 if (setting == tree_column->show_sort_indicator)
2841 tree_column->show_sort_indicator = setting;
2842 pspp_sheet_view_column_update_button (tree_column);
2843 g_object_notify (G_OBJECT (tree_column), "sort-indicator");
2847 * pspp_sheet_view_column_get_sort_indicator:
2848 * @tree_column: a #PsppSheetViewColumn
2850 * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
2852 * Return value: whether the sort indicator arrow is displayed
2855 pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column)
2857 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2859 return tree_column->show_sort_indicator;
2863 * pspp_sheet_view_column_set_sort_order:
2864 * @tree_column: a #PsppSheetViewColumn
2865 * @order: sort order that the sort indicator should indicate
2867 * Changes the appearance of the sort indicator.
2869 * This <emphasis>does not</emphasis> actually sort the model. Use
2870 * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
2871 * support. This function is primarily for custom sorting behavior, and should
2872 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2873 * that. For custom models, the mechanism will vary.
2875 * The sort indicator changes direction to indicate normal sort or reverse sort.
2876 * Note that you must have the sort indicator enabled to see anything when
2877 * calling this function; see pspp_sheet_view_column_set_sort_indicator().
2880 pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
2883 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2885 if (order == tree_column->sort_order)
2888 tree_column->sort_order = order;
2889 pspp_sheet_view_column_update_button (tree_column);
2890 g_object_notify (G_OBJECT (tree_column), "sort-order");
2894 * pspp_sheet_view_column_get_sort_order:
2895 * @tree_column: a #PsppSheetViewColumn
2897 * Gets the value set by pspp_sheet_view_column_set_sort_order().
2899 * Return value: the sort order the sort indicator is indicating
2902 pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column)
2904 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2906 return tree_column->sort_order;
2910 * pspp_sheet_view_column_cell_set_cell_data:
2911 * @tree_column: A #PsppSheetViewColumn.
2912 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2913 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2915 * Sets the cell renderer based on the @tree_model and @iter. That is, for
2916 * every attribute mapping in @tree_column, it will get a value from the set
2917 * column on the @iter, and use that value to set the attribute on the cell
2918 * renderer. This is used primarily by the #PsppSheetView.
2921 pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
2922 GtkTreeModel *tree_model,
2926 GValue value = { 0, };
2929 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2931 if (tree_model == NULL)
2934 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2936 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
2937 GObject *cell = (GObject *) info->cell;
2939 list = info->attributes;
2941 g_object_freeze_notify (cell);
2943 while (list && list->next)
2945 gtk_tree_model_get_value (tree_model, iter,
2946 GPOINTER_TO_INT (list->next->data),
2948 g_object_set_property (cell, (gchar *) list->data, &value);
2949 g_value_unset (&value);
2950 list = list->next->next;
2954 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2955 g_object_thaw_notify (G_OBJECT (info->cell));
2961 * pspp_sheet_view_column_cell_get_size:
2962 * @tree_column: A #PsppSheetViewColumn.
2963 * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
2964 * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
2965 * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
2966 * @width: (allow-none): location to return width needed to render a cell, or %NULL
2967 * @height: (allow-none): location to return height needed to render a cell, or %NULL
2969 * Obtains the width and height needed to render the column. This is used
2970 * primarily by the #PsppSheetView.
2973 pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
2974 const GdkRectangle *cell_area,
2981 gboolean first_cell = TRUE;
2982 gint focus_line_width;
2984 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2991 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
2993 for (list = tree_column->cell_list; list; list = list->next)
2995 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2997 gint new_height = 0;
2999 g_object_get (info->cell, "visible", &visible, NULL);
3001 if (visible == FALSE)
3004 if (first_cell == FALSE && width)
3005 *width += tree_column->spacing;
3007 gtk_cell_renderer_get_size (info->cell,
3008 tree_column->tree_view,
3016 * height = MAX (*height, new_height + focus_line_width * 2);
3017 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
3019 * width += info->requested_width;
3024 /* rendering, event handling and rendering focus are somewhat complicated, and
3025 * quite a bit of code. Rather than duplicate them, we put them together to
3026 * keep the code in one place.
3028 * To better understand what's going on, check out
3029 * docs/tree-column-sizing.png
3038 pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn *tree_column,
3040 const GdkRectangle *background_area,
3041 const GdkRectangle *cell_area,
3044 const GdkRectangle *expose_area, /* RENDER */
3045 GdkRectangle *focus_rectangle, /* FOCUS */
3046 GtkCellEditable **editable_widget, /* EVENT */
3047 GdkEvent *event, /* EVENT */
3048 gchar *path_string) /* EVENT */
3051 GdkRectangle real_cell_area;
3052 GdkRectangle real_background_area;
3053 GdkRectangle real_expose_area = *cell_area;
3055 gint expand_cell_count = 0;
3056 gint full_requested_width = 0;
3058 gint min_x, min_y, max_x, max_y;
3059 gint focus_line_width;
3061 gint horizontal_separator;
3062 gboolean cursor_row = FALSE;
3063 gboolean first_cell = TRUE;
3065 /* If we have rtl text, we need to transform our areas */
3066 GdkRectangle rtl_cell_area;
3067 GdkRectangle rtl_background_area;
3074 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
3075 special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
3077 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
3079 PsppSheetViewColumnCellInfo *info = NULL;
3080 gboolean found_has_focus = FALSE;
3082 /* one should have focus */
3083 for (list = tree_column->cell_list; list; list = list->next)
3086 if (info && info->has_focus)
3088 found_has_focus = TRUE;
3093 if (!found_has_focus)
3095 /* give the first one focus */
3096 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3097 info->has_focus = TRUE;
3101 cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
3103 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3104 "focus-line-width", &focus_line_width,
3105 "horizontal-separator", &horizontal_separator,
3108 real_cell_area = *cell_area;
3109 real_background_area = *background_area;
3112 real_cell_area.x += focus_line_width;
3113 real_cell_area.y += focus_line_width;
3114 real_cell_area.height -= 2 * focus_line_width;
3117 depth = real_background_area.width - real_cell_area.width;
3119 depth = real_cell_area.x - real_background_area.x;
3121 /* Find out how much extra space we have to allocate */
3122 for (list = tree_column->cell_list; list; list = list->next)
3124 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
3126 if (! info->cell->visible)
3129 if (info->expand == TRUE)
3130 expand_cell_count ++;
3131 full_requested_width += info->requested_width;
3134 full_requested_width += tree_column->spacing;
3139 extra_space = cell_area->width - full_requested_width;
3140 if (extra_space < 0)
3142 else if (extra_space > 0 && expand_cell_count > 0)
3143 extra_space /= expand_cell_count;
3145 /* iterate list for GTK_PACK_START cells */
3146 for (list = tree_column->cell_list; list; list = list->next)
3148 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3150 if (info->pack == GTK_PACK_END)
3153 if (! info->cell->visible)
3156 if ((info->has_focus || special_cells == 1) && cursor_row)
3157 flags |= GTK_CELL_RENDERER_FOCUSED;
3159 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3161 info->real_width = info->requested_width + (info->expand?extra_space:0);
3163 /* We constrain ourselves to only the width available */
3164 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3166 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3169 if (real_cell_area.x > cell_area->x + cell_area->width)
3172 real_cell_area.width = info->real_width;
3173 real_cell_area.width -= 2 * focus_line_width;
3177 real_background_area.width = info->real_width + depth;
3181 /* fill the rest of background for the last cell */
3182 real_background_area.width = background_area->x + background_area->width - real_background_area.x;
3185 rtl_cell_area = real_cell_area;
3186 rtl_background_area = real_background_area;
3190 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3191 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3195 if (action == CELL_ACTION_RENDER)
3197 gtk_cell_renderer_render (info->cell,
3199 tree_column->tree_view,
3200 &rtl_background_area,
3206 else if (action == CELL_ACTION_FOCUS)
3208 gint x_offset, y_offset, width, height;
3210 gtk_cell_renderer_get_size (info->cell,
3211 tree_column->tree_view,
3213 &x_offset, &y_offset,
3216 if (special_cells > 1)
3218 if (info->has_focus)
3220 min_x = rtl_cell_area.x + x_offset;
3221 max_x = min_x + width;
3222 min_y = rtl_cell_area.y + y_offset;
3223 max_y = min_y + height;
3228 if (min_x > (rtl_cell_area.x + x_offset))
3229 min_x = rtl_cell_area.x + x_offset;
3230 if (max_x < rtl_cell_area.x + x_offset + width)
3231 max_x = rtl_cell_area.x + x_offset + width;
3232 if (min_y > (rtl_cell_area.y + y_offset))
3233 min_y = rtl_cell_area.y + y_offset;
3234 if (max_y < rtl_cell_area.y + y_offset + height)
3235 max_y = rtl_cell_area.y + y_offset + height;
3239 else if (action == CELL_ACTION_EVENT)
3241 gboolean try_event = FALSE;
3245 if (special_cells == 1)
3247 /* only 1 activatable cell -> whole column can activate */
3248 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3249 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3252 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3253 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3254 /* only activate cell if the user clicked on an individual
3259 else if (special_cells > 1 && info->has_focus)
3261 else if (special_cells == 1)
3266 gboolean visible, mode;
3268 g_object_get (info->cell,
3269 "visible", &visible,
3272 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3274 if (gtk_cell_renderer_activate (info->cell,
3276 tree_column->tree_view,
3278 &rtl_background_area,
3282 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3286 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3289 gtk_cell_renderer_start_editing (info->cell,
3291 tree_column->tree_view,
3293 &rtl_background_area,
3297 if (*editable_widget != NULL)
3299 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3300 info->in_editing_mode = TRUE;
3301 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3303 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3311 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3313 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3314 real_background_area.x += real_background_area.width + tree_column->spacing;
3316 /* Only needed for first cell */
3320 /* iterate list for PACK_END cells */
3321 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
3323 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3325 if (info->pack == GTK_PACK_START)
3328 if (! info->cell->visible)
3331 if ((info->has_focus || special_cells == 1) && cursor_row)
3332 flags |= GTK_CELL_RENDERER_FOCUSED;
3334 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3336 info->real_width = info->requested_width + (info->expand?extra_space:0);
3338 /* We constrain ourselves to only the width available */
3339 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3341 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3344 if (real_cell_area.x > cell_area->x + cell_area->width)
3347 real_cell_area.width = info->real_width;
3348 real_cell_area.width -= 2 * focus_line_width;
3349 real_background_area.width = info->real_width + depth;
3351 rtl_cell_area = real_cell_area;
3352 rtl_background_area = real_background_area;
3355 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3356 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3360 if (action == CELL_ACTION_RENDER)
3362 gtk_cell_renderer_render (info->cell,
3364 tree_column->tree_view,
3365 &rtl_background_area,
3371 else if (action == CELL_ACTION_FOCUS)
3373 gint x_offset, y_offset, width, height;
3375 gtk_cell_renderer_get_size (info->cell,
3376 tree_column->tree_view,
3378 &x_offset, &y_offset,
3381 if (special_cells > 1)
3383 if (info->has_focus)
3385 min_x = rtl_cell_area.x + x_offset;
3386 max_x = min_x + width;
3387 min_y = rtl_cell_area.y + y_offset;
3388 max_y = min_y + height;
3393 if (min_x > (rtl_cell_area.x + x_offset))
3394 min_x = rtl_cell_area.x + x_offset;
3395 if (max_x < rtl_cell_area.x + x_offset + width)
3396 max_x = rtl_cell_area.x + x_offset + width;
3397 if (min_y > (rtl_cell_area.y + y_offset))
3398 min_y = rtl_cell_area.y + y_offset;
3399 if (max_y < rtl_cell_area.y + y_offset + height)
3400 max_y = rtl_cell_area.y + y_offset + height;
3404 else if (action == CELL_ACTION_EVENT)
3406 gboolean try_event = FALSE;
3410 if (special_cells == 1)
3412 /* only 1 activatable cell -> whole column can activate */
3413 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3414 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3417 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3418 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3419 /* only activate cell if the user clicked on an individual
3424 else if (special_cells > 1 && info->has_focus)
3426 else if (special_cells == 1)
3431 gboolean visible, mode;
3433 g_object_get (info->cell,
3434 "visible", &visible,
3437 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3439 if (gtk_cell_renderer_activate (info->cell,
3441 tree_column->tree_view,
3443 &rtl_background_area,
3447 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3451 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3454 gtk_cell_renderer_start_editing (info->cell,
3456 tree_column->tree_view,
3458 &rtl_background_area,
3462 if (*editable_widget != NULL)
3464 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3465 info->in_editing_mode = TRUE;
3466 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3468 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3475 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3477 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3478 real_background_area.x += (real_background_area.width + tree_column->spacing);
3480 /* Only needed for first cell */
3484 /* fill focus_rectangle when required */
3485 if (action == CELL_ACTION_FOCUS)
3487 if (min_x >= max_x || min_y >= max_y)
3489 *focus_rectangle = *cell_area;
3490 /* don't change the focus_rectangle, just draw it nicely inside
3495 focus_rectangle->x = min_x - focus_line_width;
3496 focus_rectangle->y = min_y - focus_line_width;
3497 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
3498 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
3506 * pspp_sheet_view_column_cell_render:
3507 * @tree_column: A #PsppSheetViewColumn.
3508 * @window: a #GdkDrawable to draw to
3509 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
3510 * @cell_area: area normally rendered by a cell renderer
3511 * @expose_area: area that actually needs updating
3512 * @flags: flags that affect rendering
3514 * Renders the cell contained by #tree_column. This is used primarily by the
3518 _pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
3520 const GdkRectangle *background_area,
3521 const GdkRectangle *cell_area,
3522 const GdkRectangle *expose_area,
3525 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3526 g_return_if_fail (background_area != NULL);
3527 g_return_if_fail (cell_area != NULL);
3528 g_return_if_fail (expose_area != NULL);
3530 pspp_sheet_view_column_cell_process_action (tree_column,
3537 NULL, NULL, NULL, NULL);
3541 _pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
3542 GtkCellEditable **editable_widget,
3545 const GdkRectangle *background_area,
3546 const GdkRectangle *cell_area,
3549 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3551 return pspp_sheet_view_column_cell_process_action (tree_column,
3564 _pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
3565 const GdkRectangle *background_area,
3566 const GdkRectangle *cell_area,
3567 GdkRectangle *focus_area)
3569 pspp_sheet_view_column_cell_process_action (tree_column,
3581 /* cell list manipulation */
3583 pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
3585 GList *list = tree_column->cell_list;
3587 /* first GTK_PACK_START cell we find */
3588 for ( ; list; list = list->next)
3590 PsppSheetViewColumnCellInfo *info = list->data;
3591 if (info->pack == GTK_PACK_START)
3595 /* hmm, else the *last* GTK_PACK_END cell */
3596 list = g_list_last (tree_column->cell_list);
3598 for ( ; list; list = list->prev)
3600 PsppSheetViewColumnCellInfo *info = list->data;
3601 if (info->pack == GTK_PACK_END)
3609 pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
3611 GList *list = tree_column->cell_list;
3613 /* *first* GTK_PACK_END cell we find */
3614 for ( ; list ; list = list->next)
3616 PsppSheetViewColumnCellInfo *info = list->data;
3617 if (info->pack == GTK_PACK_END)
3621 /* hmm, else the last GTK_PACK_START cell */
3622 list = g_list_last (tree_column->cell_list);
3624 for ( ; list; list = list->prev)
3626 PsppSheetViewColumnCellInfo *info = list->data;
3627 if (info->pack == GTK_PACK_START)
3635 pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
3639 PsppSheetViewColumnCellInfo *info = current->data;
3641 if (info->pack == GTK_PACK_START)
3643 for (list = current->next; list; list = list->next)
3645 PsppSheetViewColumnCellInfo *inf = list->data;
3646 if (inf->pack == GTK_PACK_START)
3650 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
3651 list = g_list_last (tree_column->cell_list);
3652 for (; list; list = list->prev)
3654 PsppSheetViewColumnCellInfo *inf = list->data;
3655 if (inf->pack == GTK_PACK_END)
3660 for (list = current->prev; list; list = list->prev)
3662 PsppSheetViewColumnCellInfo *inf = list->data;
3663 if (inf->pack == GTK_PACK_END)
3671 pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
3675 PsppSheetViewColumnCellInfo *info = current->data;
3677 if (info->pack == GTK_PACK_END)
3679 for (list = current->next; list; list = list->next)
3681 PsppSheetViewColumnCellInfo *inf = list->data;
3682 if (inf->pack == GTK_PACK_END)
3686 /* out of GTK_PACK_END, get last GTK_PACK_START one */
3687 list = g_list_last (tree_column->cell_list);
3688 for ( ; list; list = list->prev)
3690 PsppSheetViewColumnCellInfo *inf = list->data;
3691 if (inf->pack == GTK_PACK_START)
3696 for (list = current->prev; list; list = list->prev)
3698 PsppSheetViewColumnCellInfo *inf = list->data;
3699 if (inf->pack == GTK_PACK_START)
3707 _pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
3715 count = _pspp_sheet_view_column_count_special_cells (tree_column);
3716 rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
3718 /* if we are the current focus column and have multiple editable cells,
3719 * try to select the next one, else move the focus to the next column
3721 if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
3726 GList *list = tree_column->cell_list;
3727 PsppSheetViewColumnCellInfo *info = NULL;
3729 /* find current focussed cell */
3730 for ( ; list; list = list->next)
3733 if (info->has_focus)
3737 /* not a focussed cell in the focus column? */
3738 if (!list || !info || !info->has_focus)
3743 prev = pspp_sheet_view_column_cell_next (tree_column, list);
3744 next = pspp_sheet_view_column_cell_prev (tree_column, list);
3748 next = pspp_sheet_view_column_cell_next (tree_column, list);
3749 prev = pspp_sheet_view_column_cell_prev (tree_column, list);
3752 info->has_focus = FALSE;
3753 if (direction > 0 && next)
3756 info->has_focus = TRUE;
3759 else if (direction > 0 && !next && !right)
3761 /* keep focus on last cell */
3763 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3765 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3767 info->has_focus = TRUE;
3770 else if (direction < 0 && prev)
3773 info->has_focus = TRUE;
3776 else if (direction < 0 && !prev && !left)
3778 /* keep focus on first cell */
3780 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3782 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3784 info->has_focus = TRUE;
3791 /* we get focus, if we have multiple editable cells, give the correct one
3796 GList *list = tree_column->cell_list;
3798 /* clear focus first */
3799 for ( ; list ; list = list->next)
3801 PsppSheetViewColumnCellInfo *info = list->data;
3802 if (info->has_focus)
3803 info->has_focus = FALSE;
3810 list = pspp_sheet_view_column_cell_last (tree_column);
3811 else if (direction < 0)
3812 list = pspp_sheet_view_column_cell_first (tree_column);
3817 list = pspp_sheet_view_column_cell_first (tree_column);
3818 else if (direction < 0)
3819 list = pspp_sheet_view_column_cell_last (tree_column);
3823 ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
3830 _pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
3832 const GdkRectangle *background_area,
3833 const GdkRectangle *cell_area,
3834 const GdkRectangle *expose_area,
3837 gint focus_line_width;
3838 GtkStateType cell_state;
3840 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3841 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3842 "focus-line-width", &focus_line_width, NULL);
3843 if (tree_column->editable_widget)
3845 /* This function is only called on the editable row when editing.
3848 gtk_paint_focus (tree_column->tree_view->style,
3850 gtk_widget_get_state (tree_column->tree_view),
3852 tree_column->tree_view,
3854 cell_area->x - focus_line_width,
3855 cell_area->y - focus_line_width,
3856 cell_area->width + 2 * focus_line_width,
3857 cell_area->height + 2 * focus_line_width);
3862 GdkRectangle focus_rectangle;
3863 pspp_sheet_view_column_cell_process_action (tree_column,
3873 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3874 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3875 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3876 gtk_paint_focus (tree_column->tree_view->style,
3880 tree_column->tree_view,
3884 focus_rectangle.width,
3885 focus_rectangle.height);
3890 * pspp_sheet_view_column_cell_is_visible:
3891 * @tree_column: A #PsppSheetViewColumn
3893 * Returns %TRUE if any of the cells packed into the @tree_column are visible.
3894 * For this to be meaningful, you must first initialize the cells with
3895 * pspp_sheet_view_column_cell_set_cell_data()
3897 * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
3900 pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
3904 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3906 for (list = tree_column->cell_list; list; list = list->next)
3908 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3910 if (info->cell->visible)
3918 * pspp_sheet_view_column_focus_cell:
3919 * @tree_column: A #PsppSheetViewColumn
3920 * @cell: A #GtkCellRenderer
3922 * Sets the current keyboard focus to be at @cell, if the column contains
3923 * 2 or more editable and activatable cells.
3928 pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
3929 GtkCellRenderer *cell)
3932 gboolean found_cell = FALSE;
3934 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3935 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3937 if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
3940 for (list = tree_column->cell_list; list; list = list->next)
3942 PsppSheetViewColumnCellInfo *info = list->data;
3944 if (info->cell == cell)
3946 info->has_focus = TRUE;
3954 for (list = tree_column->cell_list; list; list = list->next)
3956 PsppSheetViewColumnCellInfo *info = list->data;
3958 if (info->cell != cell)
3959 info->has_focus = FALSE;
3962 /* FIXME: redraw? */
3967 _pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
3971 for (list = tree_column->cell_list; list; list = list->next)
3973 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3975 info->requested_width = 0;
3977 tree_column->dirty = TRUE;
3978 tree_column->requested_width = -1;
3979 tree_column->width = 0;
3981 if (tree_column->tree_view &&
3982 gtk_widget_get_realized (tree_column->tree_view))
3984 _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
3985 gtk_widget_queue_resize (tree_column->tree_view);
3990 _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
3991 GtkCellEditable *cell_editable)
3993 g_return_if_fail (tree_column->editable_widget == NULL);
3995 tree_column->editable_widget = cell_editable;
3999 _pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
4003 g_return_if_fail (tree_column->editable_widget != NULL);
4005 tree_column->editable_widget = NULL;
4006 for (list = tree_column->cell_list; list; list = list->next)
4007 ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
4011 _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
4012 GtkCellRenderer *cell,
4017 PsppSheetViewColumnCellInfo *info;
4023 list = pspp_sheet_view_column_cell_first (column);
4027 info = (PsppSheetViewColumnCellInfo *)list->data;
4029 list = pspp_sheet_view_column_cell_next (column, list);
4031 if (info->cell == cell)
4034 if (info->cell->visible)
4035 l += info->real_width + column->spacing;
4040 info = (PsppSheetViewColumnCellInfo *)list->data;
4042 list = pspp_sheet_view_column_cell_next (column, list);
4044 if (info->cell->visible)
4045 r += info->real_width + column->spacing;
4048 rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
4050 *left = rtl ? r : l;
4053 *right = rtl ? l : r;
4057 * pspp_sheet_view_column_cell_get_position:
4058 * @tree_column: a #PsppSheetViewColumn
4059 * @cell_renderer: a #GtkCellRenderer
4060 * @start_pos: return location for the horizontal position of @cell within
4061 * @tree_column, may be %NULL
4062 * @width: return location for the width of @cell, may be %NULL
4064 * Obtains the horizontal position and size of a cell in a column. If the
4065 * cell is not found in the column, @start_pos and @width are not changed and
4066 * %FALSE is returned.
4068 * Return value: %TRUE if @cell belongs to @tree_column.
4071 pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
4072 GtkCellRenderer *cell_renderer,
4078 gboolean found_cell = FALSE;
4079 PsppSheetViewColumnCellInfo *cellinfo = NULL;
4081 list = pspp_sheet_view_column_cell_first (tree_column);
4082 for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
4084 cellinfo = list->data;
4085 if (cellinfo->cell == cell_renderer)
4091 if (cellinfo->cell->visible)
4092 current_x += cellinfo->real_width;
4098 *start_pos = current_x;
4100 *width = cellinfo->real_width;
4107 * pspp_sheet_view_column_queue_resize:
4108 * @tree_column: A #PsppSheetViewColumn
4110 * Flags the column, and the cell renderers added to this column, to have
4111 * their sizes renegotiated.
4116 pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
4118 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
4120 if (tree_column->tree_view)
4121 _pspp_sheet_view_column_cell_set_dirty (tree_column);
4125 * pspp_sheet_view_column_get_tree_view:
4126 * @tree_column: A #PsppSheetViewColumn
4128 * Returns the #PsppSheetView wherein @tree_column has been inserted. If
4129 * @column is currently not inserted in any tree view, %NULL is
4132 * Return value: The tree view wherein @column has been inserted if any,
4138 pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
4140 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
4142 return tree_column->tree_view;
4146 GtkCellLayout *cell_layout;
4147 GtkCellRenderer *renderer;
4149 } AttributesSubParserData;
4152 attributes_start_element (GMarkupParseContext *context,
4153 const gchar *element_name,
4154 const gchar **names,
4155 const gchar **values,
4159 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4162 if (strcmp (element_name, "attribute") == 0)
4164 for (i = 0; names[i]; i++)
4165 if (strcmp (names[i], "name") == 0)
4166 parser_data->attr_name = g_strdup (values[i]);
4168 else if (strcmp (element_name, "attributes") == 0)
4171 g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
4175 attributes_text_element (GMarkupParseContext *context,
4181 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4186 if (!parser_data->attr_name)
4190 string = g_strndup (text, text_len);
4191 l = strtol (string, &endptr, 0);
4192 if (errno || endptr == string)
4196 GTK_BUILDER_ERROR_INVALID_VALUE,
4197 "Could not parse integer `%s'",
4204 gtk_cell_layout_add_attribute (parser_data->cell_layout,
4205 parser_data->renderer,
4206 parser_data->attr_name, l);
4207 g_free (parser_data->attr_name);
4208 parser_data->attr_name = NULL;
4211 static const GMarkupParser attributes_parser =
4213 attributes_start_element,
4215 attributes_text_element,
4219 _gtk_cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
4220 GtkBuilder *builder,
4222 const gchar *tagname,
4223 GMarkupParser *parser,
4226 AttributesSubParserData *parser_data;
4231 if (strcmp (tagname, "attributes") == 0)
4233 parser_data = g_slice_new0 (AttributesSubParserData);
4234 parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
4235 parser_data->renderer = GTK_CELL_RENDERER (child);
4236 parser_data->attr_name = NULL;
4238 *parser = attributes_parser;
4239 *data = parser_data;
4247 _gtk_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
4248 GtkBuilder *builder,
4250 const gchar *tagname,
4253 AttributesSubParserData *parser_data;
4255 parser_data = (AttributesSubParserData*)data;
4256 g_assert (!parser_data->attr_name);
4257 g_slice_free (AttributesSubParserData, parser_data);
4261 _gtk_cell_layout_buildable_add_child (GtkBuildable *buildable,
4262 GtkBuilder *builder,
4266 GtkCellLayoutIface *iface;
4268 g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
4269 g_return_if_fail (GTK_IS_CELL_RENDERER (child));
4271 iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
4272 g_return_if_fail (iface->pack_start != NULL);
4273 iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);
4277 pspp_sheet_view_column_size_request (PsppSheetViewColumn *tree_column,
4278 GtkRequisition *request)
4280 GtkWidget *base = GTK_WIDGET (tree_column->tree_view);
4281 GtkRequisition label_req;
4282 GtkRequisition align_req;
4283 GtkRequisition arrow_req;
4284 GtkRequisition hbox_req;
4285 GtkStyle **button_style;
4287 if (tree_column->button)
4289 gtk_widget_size_request (tree_column->button, request);
4293 facade_label_get_size_request (0, 0, base, tree_column->title, &label_req);
4294 facade_alignment_get_size_request (0, 0, 0, 0, 0, &label_req, &align_req);
4295 facade_arrow_get_size_request (0, 0, &arrow_req);
4297 facade_hbox_get_base_size_request (0, 2, 2, &hbox_req);
4298 facade_hbox_add_child_size_request (0, &arrow_req, 0, &hbox_req);
4299 facade_hbox_add_child_size_request (0, &align_req, 0, &hbox_req);
4301 button_style = &PSPP_SHEET_VIEW (tree_column->tree_view)->priv->button_style;
4302 if (*button_style == NULL)
4304 *button_style = facade_get_style (base, GTK_TYPE_BUTTON, 0);
4305 g_object_ref (*button_style);
4307 facade_button_get_size_request (0, base, *button_style, &hbox_req, request);
4311 pspp_sheet_view_column_size_allocate (PsppSheetViewColumn *tree_column,
4312 GtkAllocation *allocation)
4314 tree_column->allocation = *allocation;
4315 if (tree_column->button)
4316 gtk_widget_size_allocate (tree_column->button, allocation);
4320 pspp_sheet_view_column_can_focus (PsppSheetViewColumn *tree_column)
4322 return tree_column->reorderable || tree_column->clickable;
4326 pspp_sheet_view_column_set_need_button (PsppSheetViewColumn *tree_column,
4327 gboolean need_button)
4329 if (tree_column->need_button != need_button)
4331 tree_column->need_button = need_button;
4332 pspp_sheet_view_column_update_button (tree_column);
4333 _pspp_sheet_view_column_realize_button (tree_column);