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
88 typedef struct _PsppSheetViewColumnCellInfo PsppSheetViewColumnCellInfo;
89 struct _PsppSheetViewColumnCellInfo
91 GtkCellRenderer *cell;
93 PsppSheetCellDataFunc func;
95 GDestroyNotify destroy;
101 guint in_editing_mode : 1;
105 static void pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface);
107 /* GObject methods */
108 static void pspp_sheet_view_column_set_property (GObject *object,
112 static void pspp_sheet_view_column_get_property (GObject *object,
116 static void pspp_sheet_view_column_finalize (GObject *object);
118 /* GtkCellLayout implementation */
119 static void pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
120 GtkCellRenderer *cell,
122 static void pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
123 GtkCellRenderer *cell,
125 static void pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout);
126 static void pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
127 GtkCellRenderer *cell,
128 const gchar *attribute,
130 static void pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
131 GtkCellRenderer *cell,
132 GtkCellLayoutDataFunc func,
134 GDestroyNotify destroy);
135 static void pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
136 GtkCellRenderer *cell);
137 static void pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
138 GtkCellRenderer *cell,
140 static GList *pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
142 /* Button handling code */
143 static void pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column);
144 void pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
146 /* Button signal handlers */
147 static gint pspp_sheet_view_column_button_event (GtkWidget *widget,
150 static void pspp_sheet_view_column_button_clicked (GtkWidget *widget,
152 static void pspp_sheet_view_column_button_popup_menu (GtkWidget *widget,
154 static gboolean pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
155 gboolean group_cycling,
157 static gboolean on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *);
158 static gboolean on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *,
161 /* Property handlers */
162 static void pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
163 PsppSheetViewColumn *tree_column);
165 /* Internal functions */
166 static void pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
168 static void pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column);
169 static void pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
170 GtkCellRenderer *cell_renderer,
172 static PsppSheetViewColumnCellInfo *pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
173 GtkCellRenderer *cell_renderer);
175 /* cell list manipulation */
176 static GList *pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column);
177 static GList *pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column);
178 static GList *pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
180 static GList *pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
182 static void pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
183 PsppSheetViewColumnCellInfo *info);
184 /* GtkBuildable implementation */
185 static void pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface);
187 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
189 G_DEFINE_TYPE_WITH_CODE (PsppSheetViewColumn, pspp_sheet_view_column, GTK_TYPE_OBJECT,
190 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
191 pspp_sheet_view_column_cell_layout_init)
192 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
193 pspp_sheet_view_column_buildable_init))
197 pspp_sheet_view_column_class_init (PsppSheetViewColumnClass *class)
199 GObjectClass *object_class;
201 object_class = (GObjectClass*) class;
203 class->clicked = on_pspp_sheet_view_column_button_clicked;
204 class->button_press_event = on_pspp_sheet_view_column_button_press_event;
206 object_class->finalize = pspp_sheet_view_column_finalize;
207 object_class->set_property = pspp_sheet_view_column_set_property;
208 object_class->get_property = pspp_sheet_view_column_get_property;
210 tree_column_signals[CLICKED] =
211 g_signal_new ("clicked",
212 G_OBJECT_CLASS_TYPE (object_class),
214 G_STRUCT_OFFSET (PsppSheetViewColumnClass, clicked),
215 g_signal_accumulator_true_handled, NULL,
216 psppire_marshal_BOOLEAN__VOID,
219 tree_column_signals[POPUP_MENU] =
220 g_signal_new ("popup-menu",
221 G_OBJECT_CLASS_TYPE (object_class),
225 g_cclosure_marshal_VOID__VOID,
228 tree_column_signals[QUERY_TOOLTIP] =
229 g_signal_new ("query-tooltip",
230 G_OBJECT_CLASS_TYPE (object_class),
233 g_signal_accumulator_true_handled, NULL,
234 psppire_marshal_BOOLEAN__OBJECT,
238 tree_column_signals[BUTTON_PRESS_EVENT] =
239 g_signal_new ("button-press-event",
240 G_OBJECT_CLASS_TYPE (object_class),
241 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
242 G_STRUCT_OFFSET (PsppSheetViewColumnClass, button_press_event),
243 g_signal_accumulator_true_handled, NULL,
244 psppire_marshal_BOOLEAN__BOXED,
246 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
248 g_object_class_install_property (object_class,
250 g_param_spec_boolean ("visible",
252 P_("Whether to display the column"),
254 GTK_PARAM_READWRITE));
256 g_object_class_install_property (object_class,
258 g_param_spec_boolean ("resizable",
260 P_("Column is user-resizable"),
262 GTK_PARAM_READWRITE));
264 g_object_class_install_property (object_class,
266 g_param_spec_int ("width",
268 P_("Current width of the column"),
272 GTK_PARAM_READABLE));
273 g_object_class_install_property (object_class,
275 g_param_spec_int ("spacing",
277 P_("Space which is inserted between cells"),
281 GTK_PARAM_READWRITE));
283 g_object_class_install_property (object_class,
285 g_param_spec_int ("fixed-width",
287 P_("Current fixed width of the column"),
291 GTK_PARAM_READWRITE));
293 g_object_class_install_property (object_class,
295 g_param_spec_int ("min-width",
297 P_("Minimum allowed width of the column"),
301 GTK_PARAM_READWRITE));
303 g_object_class_install_property (object_class,
305 g_param_spec_int ("max-width",
307 P_("Maximum allowed width of the column"),
311 GTK_PARAM_READWRITE));
313 g_object_class_install_property (object_class,
315 g_param_spec_string ("title",
317 P_("Title to appear in column header"),
319 GTK_PARAM_READWRITE));
321 g_object_class_install_property (object_class,
323 g_param_spec_boolean ("expand",
325 P_("Column gets share of extra width allocated to the widget"),
327 GTK_PARAM_READWRITE));
329 g_object_class_install_property (object_class,
331 g_param_spec_boolean ("clickable",
333 P_("Whether the header can be clicked"),
335 GTK_PARAM_READWRITE));
338 g_object_class_install_property (object_class,
340 g_param_spec_object ("widget",
342 P_("Widget to put in column header button instead of column title"),
344 GTK_PARAM_READWRITE));
346 g_object_class_install_property (object_class,
348 g_param_spec_float ("alignment",
350 P_("X Alignment of the column header text or widget"),
354 GTK_PARAM_READWRITE));
356 g_object_class_install_property (object_class,
358 g_param_spec_boolean ("reorderable",
360 P_("Whether the column can be reordered around the headers"),
362 GTK_PARAM_READWRITE));
364 g_object_class_install_property (object_class,
366 g_param_spec_boolean ("sort-indicator",
367 P_("Sort indicator"),
368 P_("Whether to show a sort indicator"),
370 GTK_PARAM_READWRITE));
372 g_object_class_install_property (object_class,
374 g_param_spec_enum ("sort-order",
376 P_("Sort direction the sort indicator should indicate"),
379 GTK_PARAM_READWRITE));
382 * PsppSheetViewColumn:sort-column-id:
384 * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
385 * clickable. Set to %-1 to make the column unsortable.
389 g_object_class_install_property (object_class,
391 g_param_spec_int ("sort-column-id",
392 P_("Sort column ID"),
393 P_("Logical sort column ID this column sorts on when selected for sorting"),
397 GTK_PARAM_READWRITE));
399 g_object_class_install_property (object_class,
401 g_param_spec_boolean ("quick-edit",
403 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."),
405 GTK_PARAM_READWRITE));
407 g_object_class_install_property (object_class,
409 g_param_spec_boolean ("selected",
411 P_("If true, this column is selected as part of a rectangular selection."),
413 GTK_PARAM_READWRITE));
415 g_object_class_install_property (object_class,
417 g_param_spec_boolean ("selectable",
419 P_("If true, this column may be selected as part of a rectangular selection."),
421 GTK_PARAM_READWRITE));
423 g_object_class_install_property (object_class,
425 g_param_spec_boolean ("row-head",
427 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)."),
429 GTK_PARAM_READWRITE));
431 g_object_class_install_property (object_class,
433 g_param_spec_boolean ("tabbable",
435 P_("If true, Tab and Shift+Tab visit this column. If false, Tab and Shift+Tab skip this column."),
437 GTK_PARAM_READWRITE));
441 pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface)
443 iface->add_child = _gtk_cell_layout_buildable_add_child;
444 iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
445 iface->custom_tag_end = _gtk_cell_layout_buildable_custom_tag_end;
449 pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface)
451 iface->pack_start = pspp_sheet_view_column_cell_layout_pack_start;
452 iface->pack_end = pspp_sheet_view_column_cell_layout_pack_end;
453 iface->clear = pspp_sheet_view_column_cell_layout_clear;
454 iface->add_attribute = pspp_sheet_view_column_cell_layout_add_attribute;
455 iface->set_cell_data_func = pspp_sheet_view_column_cell_layout_set_cell_data_func;
456 iface->clear_attributes = pspp_sheet_view_column_cell_layout_clear_attributes;
457 iface->reorder = pspp_sheet_view_column_cell_layout_reorder;
458 iface->get_cells = pspp_sheet_view_column_cell_layout_get_cells;
462 pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column)
464 tree_column->button = NULL;
465 tree_column->xalign = 0.0;
466 tree_column->width = 0;
467 tree_column->spacing = 0;
468 tree_column->requested_width = -1;
469 tree_column->min_width = -1;
470 tree_column->max_width = -1;
471 tree_column->resized_width = 0;
472 tree_column->visible = TRUE;
473 tree_column->resizable = FALSE;
474 tree_column->expand = FALSE;
475 tree_column->clickable = FALSE;
476 tree_column->dirty = TRUE;
477 tree_column->selected = FALSE;
478 tree_column->selectable = TRUE;
479 tree_column->row_head = FALSE;
480 tree_column->tabbable = TRUE;
481 tree_column->sort_order = GTK_SORT_ASCENDING;
482 tree_column->show_sort_indicator = FALSE;
483 tree_column->property_changed_signal = 0;
484 tree_column->sort_clicked_signal = 0;
485 tree_column->sort_column_changed_signal = 0;
486 tree_column->sort_column_id = -1;
487 tree_column->reorderable = FALSE;
488 tree_column->maybe_reordered = FALSE;
489 tree_column->fixed_width = 1;
490 tree_column->use_resized_width = FALSE;
491 tree_column->title = g_strdup ("");
492 tree_column->quick_edit = TRUE;
493 tree_column->need_button = FALSE;
497 pspp_sheet_view_column_finalize (GObject *object)
499 PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
502 for (list = tree_column->cell_list; list; list = list->next)
504 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
508 GDestroyNotify d = info->destroy;
510 info->destroy = NULL;
513 pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
514 g_object_unref (info->cell);
518 g_free (tree_column->title);
519 g_list_free (tree_column->cell_list);
521 if (tree_column->child)
522 g_object_unref (tree_column->child);
524 G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
528 pspp_sheet_view_column_set_property (GObject *object,
533 PsppSheetViewColumn *tree_column;
535 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
540 pspp_sheet_view_column_set_visible (tree_column,
541 g_value_get_boolean (value));
545 pspp_sheet_view_column_set_resizable (tree_column,
546 g_value_get_boolean (value));
549 case PROP_FIXED_WIDTH:
550 pspp_sheet_view_column_set_fixed_width (tree_column,
551 g_value_get_int (value));
555 pspp_sheet_view_column_set_min_width (tree_column,
556 g_value_get_int (value));
560 pspp_sheet_view_column_set_max_width (tree_column,
561 g_value_get_int (value));
565 pspp_sheet_view_column_set_spacing (tree_column,
566 g_value_get_int (value));
570 pspp_sheet_view_column_set_title (tree_column,
571 g_value_get_string (value));
575 pspp_sheet_view_column_set_expand (tree_column,
576 g_value_get_boolean (value));
580 pspp_sheet_view_column_set_clickable (tree_column,
581 g_value_get_boolean (value));
585 pspp_sheet_view_column_set_widget (tree_column,
586 (GtkWidget*) g_value_get_object (value));
590 pspp_sheet_view_column_set_alignment (tree_column,
591 g_value_get_float (value));
594 case PROP_REORDERABLE:
595 pspp_sheet_view_column_set_reorderable (tree_column,
596 g_value_get_boolean (value));
599 case PROP_SORT_INDICATOR:
600 pspp_sheet_view_column_set_sort_indicator (tree_column,
601 g_value_get_boolean (value));
604 case PROP_SORT_ORDER:
605 pspp_sheet_view_column_set_sort_order (tree_column,
606 g_value_get_enum (value));
609 case PROP_SORT_COLUMN_ID:
610 pspp_sheet_view_column_set_sort_column_id (tree_column,
611 g_value_get_int (value));
614 case PROP_QUICK_EDIT:
615 pspp_sheet_view_column_set_quick_edit (tree_column,
616 g_value_get_boolean (value));
620 pspp_sheet_view_column_set_selected (tree_column,
621 g_value_get_boolean (value));
624 case PROP_SELECTABLE:
625 pspp_sheet_view_column_set_selectable (tree_column,
626 g_value_get_boolean (value));
630 pspp_sheet_view_column_set_row_head (tree_column,
631 g_value_get_boolean (value));
635 pspp_sheet_view_column_set_tabbable (tree_column,
636 g_value_get_boolean (value));
640 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
646 pspp_sheet_view_column_get_property (GObject *object,
651 PsppSheetViewColumn *tree_column;
653 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
658 g_value_set_boolean (value,
659 pspp_sheet_view_column_get_visible (tree_column));
663 g_value_set_boolean (value,
664 pspp_sheet_view_column_get_resizable (tree_column));
668 g_value_set_int (value,
669 pspp_sheet_view_column_get_width (tree_column));
673 g_value_set_int (value,
674 pspp_sheet_view_column_get_spacing (tree_column));
677 case PROP_FIXED_WIDTH:
678 g_value_set_int (value,
679 pspp_sheet_view_column_get_fixed_width (tree_column));
683 g_value_set_int (value,
684 pspp_sheet_view_column_get_min_width (tree_column));
688 g_value_set_int (value,
689 pspp_sheet_view_column_get_max_width (tree_column));
693 g_value_set_string (value,
694 pspp_sheet_view_column_get_title (tree_column));
698 g_value_set_boolean (value,
699 pspp_sheet_view_column_get_expand (tree_column));
703 g_value_set_boolean (value,
704 pspp_sheet_view_column_get_clickable (tree_column));
708 g_value_set_object (value,
709 (GObject*) pspp_sheet_view_column_get_widget (tree_column));
713 g_value_set_float (value,
714 pspp_sheet_view_column_get_alignment (tree_column));
717 case PROP_REORDERABLE:
718 g_value_set_boolean (value,
719 pspp_sheet_view_column_get_reorderable (tree_column));
722 case PROP_SORT_INDICATOR:
723 g_value_set_boolean (value,
724 pspp_sheet_view_column_get_sort_indicator (tree_column));
727 case PROP_SORT_ORDER:
728 g_value_set_enum (value,
729 pspp_sheet_view_column_get_sort_order (tree_column));
732 case PROP_SORT_COLUMN_ID:
733 g_value_set_int (value,
734 pspp_sheet_view_column_get_sort_column_id (tree_column));
737 case PROP_QUICK_EDIT:
738 g_value_set_boolean (value,
739 pspp_sheet_view_column_get_quick_edit (tree_column));
743 g_value_set_boolean (value,
744 pspp_sheet_view_column_get_selected (tree_column));
747 case PROP_SELECTABLE:
748 g_value_set_boolean (value,
749 pspp_sheet_view_column_get_selectable (tree_column));
753 g_value_set_boolean (value,
754 pspp_sheet_view_column_get_row_head (tree_column));
758 g_value_set_boolean (value,
759 pspp_sheet_view_column_get_tabbable (tree_column));
763 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
768 /* Implementation of GtkCellLayout interface
772 pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
773 GtkCellRenderer *cell,
776 PsppSheetViewColumn *column;
777 PsppSheetViewColumnCellInfo *cell_info;
779 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
780 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
781 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
783 g_object_ref_sink (cell);
785 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
786 cell_info->cell = cell;
787 cell_info->expand = expand ? TRUE : FALSE;
788 cell_info->pack = GTK_PACK_START;
789 cell_info->has_focus = 0;
790 cell_info->attributes = NULL;
792 column->cell_list = g_list_append (column->cell_list, cell_info);
796 pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
797 GtkCellRenderer *cell,
800 PsppSheetViewColumn *column;
801 PsppSheetViewColumnCellInfo *cell_info;
803 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
804 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
805 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
807 g_object_ref_sink (cell);
809 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
810 cell_info->cell = cell;
811 cell_info->expand = expand ? TRUE : FALSE;
812 cell_info->pack = GTK_PACK_END;
813 cell_info->has_focus = 0;
814 cell_info->attributes = NULL;
816 column->cell_list = g_list_append (column->cell_list, cell_info);
820 pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
822 PsppSheetViewColumn *column;
824 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
825 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
827 while (column->cell_list)
829 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
831 pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
832 g_object_unref (info->cell);
834 column->cell_list = g_list_delete_link (column->cell_list,
840 pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
841 GtkCellRenderer *cell,
842 const gchar *attribute,
845 PsppSheetViewColumn *tree_column;
846 PsppSheetViewColumnCellInfo *info;
848 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
849 tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
851 info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
852 g_return_if_fail (info != NULL);
854 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
855 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
857 if (tree_column->tree_view)
858 _pspp_sheet_view_column_cell_set_dirty (tree_column);
862 pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
863 GtkCellRenderer *cell,
864 GtkCellLayoutDataFunc func,
866 GDestroyNotify destroy)
868 PsppSheetViewColumn *column;
869 PsppSheetViewColumnCellInfo *info;
871 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
872 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
874 info = pspp_sheet_view_column_get_cell_info (column, cell);
875 g_return_if_fail (info != NULL);
879 GDestroyNotify d = info->destroy;
881 info->destroy = NULL;
885 info->func = (PsppSheetCellDataFunc)func;
886 info->func_data = func_data;
887 info->destroy = destroy;
889 if (column->tree_view)
890 _pspp_sheet_view_column_cell_set_dirty (column);
894 pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
895 GtkCellRenderer *cell_renderer)
897 PsppSheetViewColumn *column;
898 PsppSheetViewColumnCellInfo *info;
900 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
901 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
903 info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
905 pspp_sheet_view_column_clear_attributes_by_info (column, info);
909 pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
910 GtkCellRenderer *cell,
914 PsppSheetViewColumn *column;
915 PsppSheetViewColumnCellInfo *info;
917 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
918 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
920 info = pspp_sheet_view_column_get_cell_info (column, cell);
922 g_return_if_fail (info != NULL);
923 g_return_if_fail (position >= 0);
925 link = g_list_find (column->cell_list, info);
927 g_return_if_fail (link != NULL);
929 column->cell_list = g_list_delete_link (column->cell_list, link);
930 column->cell_list = g_list_insert (column->cell_list, info, position);
932 if (column->tree_view)
933 gtk_widget_queue_draw (column->tree_view);
937 pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
938 PsppSheetViewColumnCellInfo *info)
942 list = info->attributes;
944 while (list && list->next)
947 list = list->next->next;
949 g_slist_free (info->attributes);
950 info->attributes = NULL;
952 if (tree_column->tree_view)
953 _pspp_sheet_view_column_cell_set_dirty (tree_column);
957 on_query_tooltip (GtkWidget *widget,
960 gboolean keyboard_mode,
964 PsppSheetViewColumn *tree_column = user_data;
967 g_signal_emit (tree_column, tree_column_signals[QUERY_TOOLTIP], 0,
973 on_button_pressed (GtkWidget *widget, GdkEventButton *event,
976 PsppSheetViewColumn *tree_column = user_data;
979 /* XXX See "Implement GtkWidget::popup_menu" in GTK+ reference manual. */
980 g_signal_emit (tree_column, tree_column_signals[BUTTON_PRESS_EVENT],
988 /* Button handling code
991 pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
993 PsppSheetView *tree_view;
997 tree_view = (PsppSheetView *) tree_column->tree_view;
999 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1000 g_return_if_fail (tree_column->button == NULL);
1002 gtk_widget_push_composite_child ();
1003 tree_column->button = gtk_button_new ();
1004 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
1005 gtk_widget_pop_composite_child ();
1007 /* make sure we own a reference to it as well. */
1008 if (tree_view->priv->header_window)
1009 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
1010 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
1012 g_signal_connect (tree_column->button, "event",
1013 G_CALLBACK (pspp_sheet_view_column_button_event),
1015 g_signal_connect (tree_column->button, "clicked",
1016 G_CALLBACK (pspp_sheet_view_column_button_clicked),
1018 g_signal_connect (tree_column->button, "popup-menu",
1019 G_CALLBACK (pspp_sheet_view_column_button_popup_menu),
1021 g_signal_connect (tree_column->button, "button-press-event",
1022 G_CALLBACK (on_button_pressed), tree_column);
1024 g_signal_connect (tree_column->button, "query-tooltip",
1025 G_CALLBACK (on_query_tooltip), tree_column);
1026 g_object_set (tree_column->button, "has-tooltip", TRUE, NULL);
1028 tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
1030 hbox = gtk_hbox_new (FALSE, 2);
1031 tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
1033 if (tree_column->child)
1034 child = tree_column->child;
1037 child = gtk_label_new (tree_column->title);
1038 gtk_widget_show (child);
1041 g_signal_connect (child, "mnemonic-activate",
1042 G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
1045 if (tree_column->xalign <= 0.5)
1046 gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
1048 gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
1050 gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
1052 gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
1053 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
1055 gtk_widget_show (hbox);
1056 gtk_widget_show (tree_column->alignment);
1057 pspp_sheet_view_column_update_button (tree_column);
1061 pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
1063 gint sort_column_id = -1;
1065 GtkWidget *alignment;
1067 GtkWidget *current_child;
1068 GtkArrowType arrow_type = GTK_ARROW_NONE;
1069 GtkTreeModel *model;
1072 if (tree_column->tree_view)
1073 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1077 /* Create a button if necessary */
1078 if (tree_column->need_button &&
1079 tree_column->visible &&
1080 tree_column->button == NULL &&
1081 tree_column->tree_view &&
1082 gtk_widget_get_realized (tree_column->tree_view))
1083 pspp_sheet_view_column_create_button (tree_column);
1085 if (! tree_column->button)
1088 hbox = gtk_bin_get_child (GTK_BIN (tree_column->button));
1089 alignment = tree_column->alignment;
1090 arrow = tree_column->arrow;
1091 current_child = gtk_bin_get_child (GTK_BIN (alignment));
1093 /* Set up the actual button */
1094 gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
1097 if (tree_column->child)
1099 if (current_child != tree_column->child)
1101 gtk_container_remove (GTK_CONTAINER (alignment),
1103 gtk_container_add (GTK_CONTAINER (alignment),
1104 tree_column->child);
1109 if (current_child == NULL)
1111 current_child = gtk_label_new (NULL);
1112 gtk_widget_show (current_child);
1113 gtk_container_add (GTK_CONTAINER (alignment),
1117 g_return_if_fail (GTK_IS_LABEL (current_child));
1119 if (tree_column->title)
1120 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1121 tree_column->title);
1123 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1127 if (GTK_IS_TREE_SORTABLE (model))
1128 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1132 if (tree_column->show_sort_indicator)
1134 gboolean alternative;
1136 g_object_get (gtk_widget_get_settings (tree_column->tree_view),
1137 "gtk-alternative-sort-arrows", &alternative,
1140 switch (tree_column->sort_order)
1142 case GTK_SORT_ASCENDING:
1143 arrow_type = alternative ? GTK_ARROW_UP : GTK_ARROW_DOWN;
1146 case GTK_SORT_DESCENDING:
1147 arrow_type = alternative ? GTK_ARROW_DOWN : GTK_ARROW_UP;
1151 g_warning (G_STRLOC": bad sort order");
1156 gtk_arrow_set (GTK_ARROW (arrow),
1160 /* Put arrow on the right if the text is left-or-center justified, and on the
1161 * left otherwise; do this by packing boxes, so flipping text direction will
1164 g_object_ref (arrow);
1165 gtk_container_remove (GTK_CONTAINER (hbox), arrow);
1167 if (tree_column->xalign <= 0.5)
1169 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1173 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1174 /* move it to the front */
1175 gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
1177 g_object_unref (arrow);
1179 if (tree_column->show_sort_indicator
1180 || (GTK_IS_TREE_SORTABLE (model) && tree_column->sort_column_id >= 0))
1181 gtk_widget_show (arrow);
1183 gtk_widget_hide (arrow);
1185 /* It's always safe to hide the button. It isn't always safe to show it, as
1186 * if you show it before it's realized, it'll get the wrong window. */
1187 if (tree_column->button &&
1188 tree_column->tree_view != NULL &&
1189 gtk_widget_get_realized (tree_column->tree_view))
1191 if (tree_column->visible)
1193 gtk_widget_show_now (tree_column->button);
1194 if (tree_column->window)
1196 if (tree_column->resizable)
1198 gdk_window_show (tree_column->window);
1199 gdk_window_raise (tree_column->window);
1203 gdk_window_hide (tree_column->window);
1209 gtk_widget_hide (tree_column->button);
1210 if (tree_column->window)
1211 gdk_window_hide (tree_column->window);
1215 can_focus = pspp_sheet_view_column_can_focus (tree_column);
1216 gtk_widget_set_can_focus (tree_column->button, can_focus);
1217 if (!can_focus && gtk_widget_has_focus (tree_column->button))
1219 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
1220 if (gtk_widget_is_toplevel (toplevel))
1222 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
1226 /* Queue a resize on the assumption that we always want to catch all changes
1227 * and columns don't change all that often.
1229 if (gtk_widget_get_realized (tree_column->tree_view))
1230 gtk_widget_queue_resize (tree_column->tree_view);
1234 /* Button signal handlers
1238 pspp_sheet_view_column_button_event (GtkWidget *widget,
1242 PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
1244 g_return_val_if_fail (event != NULL, FALSE);
1246 if (event->type == GDK_BUTTON_PRESS &&
1247 column->reorderable &&
1248 ((GdkEventButton *)event)->button == 1)
1250 column->maybe_reordered = TRUE;
1251 gdk_window_get_pointer (GTK_BUTTON (widget)->event_window,
1255 gtk_widget_grab_focus (widget);
1258 if (event->type == GDK_BUTTON_RELEASE ||
1259 event->type == GDK_LEAVE_NOTIFY)
1260 column->maybe_reordered = FALSE;
1262 if (event->type == GDK_MOTION_NOTIFY &&
1263 column->maybe_reordered &&
1264 (gtk_drag_check_threshold (widget,
1267 (gint) ((GdkEventMotion *)event)->x,
1268 (gint) ((GdkEventMotion *)event)->y)))
1270 column->maybe_reordered = FALSE;
1271 _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
1274 if (column->clickable == FALSE)
1276 switch (event->type)
1278 case GDK_MOTION_NOTIFY:
1279 case GDK_BUTTON_RELEASE:
1280 case GDK_ENTER_NOTIFY:
1281 case GDK_LEAVE_NOTIFY:
1291 all_rows_selected (PsppSheetView *sheet_view)
1293 PsppSheetSelection *selection = sheet_view->priv->selection;
1294 gint n_rows, n_selected_rows;
1296 n_rows = sheet_view->priv->row_count;
1297 n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
1299 return n_rows > 0 && n_selected_rows >= n_rows;
1303 on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *column,
1304 GdkEventButton *event)
1306 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (column->tree_view);
1307 PsppSheetSelection *selection;
1308 GSignalInvocationHint *hint;
1311 /* We only want to run first, not last, but combining that with return type
1312 `gboolean' makes GObject warn, so just ignore the run_last call. */
1313 hint = g_signal_get_invocation_hint (column);
1314 g_return_val_if_fail (hint != NULL, FALSE);
1315 if (hint->run_type != G_SIGNAL_RUN_FIRST)
1318 g_return_val_if_fail (sheet_view != NULL, FALSE);
1320 selection = sheet_view->priv->selection;
1321 g_return_val_if_fail (selection != NULL, FALSE);
1323 if (pspp_sheet_selection_get_mode (selection) != PSPP_SHEET_SELECTION_RECTANGLE)
1326 modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
1327 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
1329 if (pspp_sheet_selection_count_selected_columns (selection) <= 1
1330 || !all_rows_selected (sheet_view))
1332 pspp_sheet_selection_select_all (selection);
1333 pspp_sheet_selection_unselect_all_columns (selection);
1334 pspp_sheet_selection_select_column (selection, column);
1335 sheet_view->priv->anchor_column = column;
1339 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1340 && modifiers == GDK_CONTROL_MASK)
1342 gboolean is_selected;
1344 if (!all_rows_selected (sheet_view))
1346 pspp_sheet_selection_select_all (selection);
1347 pspp_sheet_selection_unselect_all_columns (selection);
1349 sheet_view->priv->anchor_column = column;
1351 is_selected = pspp_sheet_view_column_get_selected (column);
1352 pspp_sheet_view_column_set_selected (column, !is_selected);
1356 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1357 && modifiers == GDK_SHIFT_MASK)
1359 if (!all_rows_selected (sheet_view))
1361 pspp_sheet_selection_select_all (selection);
1362 pspp_sheet_selection_unselect_all_columns (selection);
1363 sheet_view->priv->anchor_column = column;
1365 else if (sheet_view->priv->anchor_column == NULL)
1366 sheet_view->priv->anchor_column = column;
1368 pspp_sheet_selection_unselect_all_columns (selection);
1369 pspp_sheet_selection_select_column_range (selection,
1370 sheet_view->priv->anchor_column,
1379 on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *column)
1381 PsppSheetSelection *selection;
1382 PsppSheetView *sheet_view;
1384 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (column));
1385 selection = pspp_sheet_view_get_selection (sheet_view);
1386 if (pspp_sheet_selection_get_mode (selection) == PSPP_SHEET_SELECTION_RECTANGLE)
1388 pspp_sheet_selection_select_all (selection);
1389 if (pspp_sheet_view_column_get_row_head (column))
1390 pspp_sheet_selection_select_all_columns (selection);
1393 pspp_sheet_selection_unselect_all_columns (selection);
1394 pspp_sheet_selection_select_column (selection, column);
1396 sheet_view->priv->anchor_column = column;
1403 pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
1405 PsppSheetViewColumn *column = data;
1408 g_signal_emit (column, tree_column_signals[CLICKED], 0, &handled);
1412 pspp_sheet_view_column_button_popup_menu (GtkWidget *widget, gpointer data)
1414 g_signal_emit_by_name (data, "popup-menu");
1418 pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
1419 gboolean group_cycling,
1422 PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
1424 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
1426 PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
1427 if (column->clickable)
1428 gtk_button_clicked (GTK_BUTTON (column->button));
1429 else if (gtk_widget_get_can_focus (column->button))
1430 gtk_widget_grab_focus (column->button);
1432 gtk_widget_grab_focus (column->tree_view);
1438 pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
1439 PsppSheetViewColumn *column)
1441 gint sort_column_id;
1444 if (gtk_tree_sortable_get_sort_column_id (sortable,
1448 if (sort_column_id == column->sort_column_id)
1450 pspp_sheet_view_column_set_sort_indicator (column, TRUE);
1451 pspp_sheet_view_column_set_sort_order (column, order);
1455 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1460 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1465 pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
1468 gint sort_column_id;
1470 gboolean has_sort_column;
1471 gboolean has_default_sort_func;
1473 g_return_if_fail (tree_column->tree_view != NULL);
1476 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1479 has_default_sort_func =
1480 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
1482 if (has_sort_column &&
1483 sort_column_id == tree_column->sort_column_id)
1485 if (order == GTK_SORT_ASCENDING)
1486 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1487 tree_column->sort_column_id,
1488 GTK_SORT_DESCENDING);
1489 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
1490 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1491 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1492 GTK_SORT_ASCENDING);
1494 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1495 tree_column->sort_column_id,
1496 GTK_SORT_ASCENDING);
1500 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1501 tree_column->sort_column_id,
1502 GTK_SORT_ASCENDING);
1508 pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
1510 GtkTreeModel *model;
1512 if (tree_column->tree_view == NULL)
1515 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1520 if (GTK_IS_TREE_SORTABLE (model) &&
1521 tree_column->sort_column_id != -1)
1523 gint real_sort_column_id;
1524 GtkSortType real_order;
1526 if (tree_column->sort_column_changed_signal == 0)
1527 tree_column->sort_column_changed_signal =
1528 g_signal_connect (model, "sort-column-changed",
1529 G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
1532 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1533 &real_sort_column_id,
1535 (real_sort_column_id == tree_column->sort_column_id))
1537 pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
1538 pspp_sheet_view_column_set_sort_order (tree_column, real_order);
1542 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
1548 /* Exported Private Functions.
1549 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1553 _pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
1555 GtkAllocation allocation;
1556 PsppSheetView *tree_view;
1558 guint attributes_mask;
1561 tree_view = (PsppSheetView *)column->tree_view;
1562 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
1564 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1565 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
1566 g_return_if_fail (tree_view->priv->header_window != NULL);
1567 if (!column->need_button || !column->button)
1570 g_return_if_fail (column->button != NULL);
1572 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
1574 if (column->visible)
1575 gtk_widget_show (column->button);
1577 attr.window_type = GDK_WINDOW_CHILD;
1578 attr.wclass = GDK_INPUT_ONLY;
1579 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1580 attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1581 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
1582 (GDK_BUTTON_PRESS_MASK |
1583 GDK_BUTTON_RELEASE_MASK |
1584 GDK_POINTER_MOTION_MASK |
1585 GDK_POINTER_MOTION_HINT_MASK |
1586 GDK_KEY_PRESS_MASK);
1587 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
1588 attr.cursor = gdk_cursor_new_for_display (gdk_window_get_display (tree_view->priv->header_window),
1589 GDK_SB_H_DOUBLE_ARROW);
1591 attr.width = TREE_VIEW_DRAG_WIDTH;
1592 attr.height = tree_view->priv->header_height;
1593 gtk_widget_get_allocation (column->button, &allocation);
1594 attr.x = (allocation.x + (rtl ? 0 : allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
1595 column->window = gdk_window_new (tree_view->priv->header_window,
1596 &attr, attributes_mask);
1597 gdk_window_set_user_data (column->window, tree_view);
1599 pspp_sheet_view_column_update_button (column);
1601 gdk_cursor_unref (attr.cursor);
1605 _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
1607 g_return_if_fail (column != NULL);
1608 if (column->window != NULL)
1610 gdk_window_set_user_data (column->window, NULL);
1611 gdk_window_destroy (column->window);
1612 column->window = NULL;
1617 _pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
1618 GtkTreeModel *old_model)
1620 if (column->sort_column_changed_signal)
1622 g_signal_handler_disconnect (old_model,
1623 column->sort_column_changed_signal);
1624 column->sort_column_changed_signal = 0;
1626 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1630 _pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
1631 PsppSheetView *tree_view)
1633 g_assert (column->tree_view == NULL);
1635 column->tree_view = GTK_WIDGET (tree_view);
1636 if (column->need_button)
1637 pspp_sheet_view_column_create_button (column);
1639 column->property_changed_signal =
1640 g_signal_connect_swapped (tree_view,
1642 G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
1645 pspp_sheet_view_column_setup_sort_column_id_callback (column);
1649 _pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
1651 if (column->tree_view && column->button)
1653 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1655 if (column->property_changed_signal)
1657 g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
1658 column->property_changed_signal = 0;
1661 if (column->sort_column_changed_signal)
1663 g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
1664 column->sort_column_changed_signal);
1665 column->sort_column_changed_signal = 0;
1668 column->tree_view = NULL;
1669 column->button = NULL;
1673 _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
1677 for (list = column->cell_list; list; list = list->next)
1678 if (((PsppSheetViewColumnCellInfo *)list->data)->cell->mode ==
1679 GTK_CELL_RENDERER_MODE_EDITABLE)
1685 /* gets cell being edited */
1687 _pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
1691 for (list = column->cell_list; list; list = list->next)
1692 if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
1693 return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
1699 _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
1704 for (list = column->cell_list; list; list = list->next)
1706 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1708 if ((cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1709 cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
1710 gtk_cell_renderer_get_visible (cellinfo->cell))
1718 _pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
1724 list = pspp_sheet_view_column_cell_first (column);
1725 for (; list; list = pspp_sheet_view_column_cell_next (column, list))
1727 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1728 if (current_x <= x && x <= current_x + cellinfo->real_width)
1729 return cellinfo->cell;
1730 current_x += cellinfo->real_width;
1736 /* Public Functions */
1740 * pspp_sheet_view_column_new:
1742 * Creates a new #PsppSheetViewColumn.
1744 * Return value: A newly created #PsppSheetViewColumn.
1746 PsppSheetViewColumn *
1747 pspp_sheet_view_column_new (void)
1749 PsppSheetViewColumn *tree_column;
1751 tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
1757 * pspp_sheet_view_column_new_with_attributes:
1758 * @title: The title to set the header to.
1759 * @cell: The #GtkCellRenderer.
1760 * @Varargs: A %NULL-terminated list of attributes.
1762 * Creates a new #PsppSheetViewColumn with a number of default values. This is
1763 * equivalent to calling pspp_sheet_view_column_set_title(),
1764 * pspp_sheet_view_column_pack_start(), and
1765 * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
1767 * Here's a simple example:
1769 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1772 * PsppSheetViewColumn *column;
1773 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
1775 * column = pspp_sheet_view_column_new_with_attributes ("Title",
1777 * "text", TEXT_COLUMN,
1778 * "foreground", COLOR_COLUMN,
1783 * Return value: A newly created #PsppSheetViewColumn.
1785 PsppSheetViewColumn *
1786 pspp_sheet_view_column_new_with_attributes (const gchar *title,
1787 GtkCellRenderer *cell,
1790 PsppSheetViewColumn *retval;
1793 retval = pspp_sheet_view_column_new ();
1795 pspp_sheet_view_column_set_title (retval, title);
1796 pspp_sheet_view_column_pack_start (retval, cell, TRUE);
1798 va_start (args, cell);
1799 pspp_sheet_view_column_set_attributesv (retval, cell, args);
1805 static PsppSheetViewColumnCellInfo *
1806 pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
1807 GtkCellRenderer *cell_renderer)
1810 for (list = tree_column->cell_list; list; list = list->next)
1811 if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
1812 return (PsppSheetViewColumnCellInfo *) list->data;
1818 * pspp_sheet_view_column_pack_start:
1819 * @tree_column: A #PsppSheetViewColumn.
1820 * @cell: The #GtkCellRenderer.
1821 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1823 * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
1824 * the @cell is allocated no more space than it needs. Any unused space is divided
1825 * evenly between cells for which @expand is %TRUE.
1828 pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
1829 GtkCellRenderer *cell,
1832 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
1836 * pspp_sheet_view_column_pack_end:
1837 * @tree_column: A #PsppSheetViewColumn.
1838 * @cell: The #GtkCellRenderer.
1839 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1841 * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
1842 * is allocated no more space than it needs. Any unused space is divided
1843 * evenly between cells for which @expand is %TRUE.
1846 pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
1847 GtkCellRenderer *cell,
1850 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
1854 * pspp_sheet_view_column_clear:
1855 * @tree_column: A #PsppSheetViewColumn
1857 * Unsets all the mappings on all renderers on the @tree_column.
1860 pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
1862 gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
1866 pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
1868 PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
1869 GList *retval = NULL, *list;
1871 g_return_val_if_fail (tree_column != NULL, NULL);
1873 for (list = tree_column->cell_list; list; list = list->next)
1875 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
1877 retval = g_list_append (retval, info->cell);
1884 * pspp_sheet_view_column_get_cell_renderers:
1885 * @tree_column: A #PsppSheetViewColumn
1887 * Returns a newly-allocated #GList of all the cell renderers in the column,
1888 * in no particular order. The list must be freed with g_list_free().
1890 * Return value: A list of #GtkCellRenderers
1892 * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
1895 pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
1897 return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
1901 * pspp_sheet_view_column_add_attribute:
1902 * @tree_column: A #PsppSheetViewColumn.
1903 * @cell_renderer: the #GtkCellRenderer to set attributes on
1904 * @attribute: An attribute on the renderer
1905 * @column: The column position on the model to get the attribute from.
1907 * Adds an attribute mapping to the list in @tree_column. The @column is the
1908 * column of the model to get a value from, and the @attribute is the
1909 * parameter on @cell_renderer to be set from the value. So for example
1910 * if column 2 of the model contains strings, you could have the
1911 * "text" attribute of a #GtkCellRendererText get its values from
1915 pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
1916 GtkCellRenderer *cell_renderer,
1917 const gchar *attribute,
1920 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
1921 cell_renderer, attribute, column);
1925 pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
1926 GtkCellRenderer *cell_renderer,
1932 attribute = va_arg (args, gchar *);
1934 pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
1936 while (attribute != NULL)
1938 column = va_arg (args, gint);
1939 pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1940 attribute = va_arg (args, gchar *);
1945 * pspp_sheet_view_column_set_attributes:
1946 * @tree_column: A #PsppSheetViewColumn.
1947 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1948 * @Varargs: A %NULL-terminated list of attributes.
1950 * Sets the attributes in the list as the attributes of @tree_column.
1951 * The attributes should be in attribute/column order, as in
1952 * pspp_sheet_view_column_add_attribute(). All existing attributes
1953 * are removed, and replaced with the new attributes.
1956 pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
1957 GtkCellRenderer *cell_renderer,
1962 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1963 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1964 g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
1966 va_start (args, cell_renderer);
1967 pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
1973 * pspp_sheet_view_column_set_cell_data_func:
1974 * @tree_column: A #PsppSheetViewColumn
1975 * @cell_renderer: A #GtkCellRenderer
1976 * @func: The #PsppSheetViewColumnFunc to use.
1977 * @func_data: The user data for @func.
1978 * @destroy: The destroy notification for @func_data
1980 * Sets the #PsppSheetViewColumnFunc to use for the column. This
1981 * function is used instead of the standard attributes mapping for
1982 * setting the column value, and should set the value of @tree_column's
1983 * cell renderer as appropriate. @func may be %NULL to remove an
1987 pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
1988 GtkCellRenderer *cell_renderer,
1989 PsppSheetCellDataFunc func,
1991 GDestroyNotify destroy)
1993 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
1995 (GtkCellLayoutDataFunc)func,
1996 func_data, destroy);
2001 * pspp_sheet_view_column_clear_attributes:
2002 * @tree_column: a #PsppSheetViewColumn
2003 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
2005 * Clears all existing attributes previously set with
2006 * pspp_sheet_view_column_set_attributes().
2009 pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
2010 GtkCellRenderer *cell_renderer)
2012 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
2017 * pspp_sheet_view_column_set_spacing:
2018 * @tree_column: A #PsppSheetViewColumn.
2019 * @spacing: distance between cell renderers in pixels.
2021 * Sets the spacing field of @tree_column, which is the number of pixels to
2022 * place between cell renderers packed into it.
2025 pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
2028 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2029 g_return_if_fail (spacing >= 0);
2031 if (tree_column->spacing == spacing)
2034 tree_column->spacing = spacing;
2035 if (tree_column->tree_view)
2036 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2040 * pspp_sheet_view_column_get_spacing:
2041 * @tree_column: A #PsppSheetViewColumn.
2043 * Returns the spacing of @tree_column.
2045 * Return value: the spacing of @tree_column.
2048 pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
2050 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2052 return tree_column->spacing;
2055 /* Options for manipulating the columns */
2058 * pspp_sheet_view_column_set_visible:
2059 * @tree_column: A #PsppSheetViewColumn.
2060 * @visible: %TRUE if the @tree_column is visible.
2062 * Sets the visibility of @tree_column.
2065 pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
2068 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2070 visible = !! visible;
2072 if (tree_column->visible == visible)
2075 tree_column->visible = visible;
2077 if (tree_column->visible)
2078 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2080 pspp_sheet_view_column_update_button (tree_column);
2081 g_object_notify (G_OBJECT (tree_column), "visible");
2085 * pspp_sheet_view_column_get_visible:
2086 * @tree_column: A #PsppSheetViewColumn.
2088 * Returns %TRUE if @tree_column is visible.
2090 * Return value: whether the column is visible or not. If it is visible, then
2091 * the tree will show the column.
2094 pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
2096 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2098 return tree_column->visible;
2102 * pspp_sheet_view_column_set_resizable:
2103 * @tree_column: A #PsppSheetViewColumn
2104 * @resizable: %TRUE, if the column can be resized
2106 * If @resizable is %TRUE, then the user can explicitly resize the column by
2107 * grabbing the outer edge of the column button.
2110 pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
2113 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2115 resizable = !! resizable;
2117 if (tree_column->resizable == resizable)
2120 tree_column->resizable = resizable;
2122 pspp_sheet_view_column_update_button (tree_column);
2124 g_object_notify (G_OBJECT (tree_column), "resizable");
2128 * pspp_sheet_view_column_get_resizable:
2129 * @tree_column: A #PsppSheetViewColumn
2131 * Returns %TRUE if the @tree_column can be resized by the end user.
2133 * Return value: %TRUE, if the @tree_column can be resized.
2136 pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
2138 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2140 return tree_column->resizable;
2145 * pspp_sheet_view_column_get_width:
2146 * @tree_column: A #PsppSheetViewColumn.
2148 * Returns the current size of @tree_column in pixels.
2150 * Return value: The current width of @tree_column.
2153 pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
2155 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2157 return tree_column->width;
2161 * pspp_sheet_view_column_set_fixed_width:
2162 * @tree_column: A #PsppSheetViewColumn.
2163 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
2165 * Sets the size of the column in pixels. The size of the column is clamped to
2166 * the min/max width for the column. Please note that the min/max width of the
2167 * column doesn't actually affect the "fixed_width" property of the widget, just
2168 * the actual size when displayed.
2171 pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
2174 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2175 g_return_if_fail (fixed_width > 0);
2177 tree_column->fixed_width = fixed_width;
2178 tree_column->use_resized_width = FALSE;
2180 if (tree_column->tree_view &&
2181 gtk_widget_get_realized (tree_column->tree_view))
2183 gtk_widget_queue_resize (tree_column->tree_view);
2186 g_object_notify (G_OBJECT (tree_column), "fixed-width");
2190 * pspp_sheet_view_column_get_fixed_width:
2191 * @tree_column: a #PsppSheetViewColumn
2193 * Gets the fixed width of the column. This value is only meaning may not be
2194 * the actual width of the column on the screen, just what is requested.
2196 * Return value: the fixed width of the column
2199 pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
2201 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2203 return tree_column->fixed_width;
2207 * pspp_sheet_view_column_set_min_width:
2208 * @tree_column: A #PsppSheetViewColumn.
2209 * @min_width: The minimum width of the column in pixels, or -1.
2211 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
2212 * minimum width is unset.
2215 pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
2218 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2219 g_return_if_fail (min_width >= -1);
2221 if (min_width == tree_column->min_width)
2224 if (tree_column->visible &&
2225 tree_column->tree_view != NULL &&
2226 gtk_widget_get_realized (tree_column->tree_view))
2228 if (min_width > tree_column->width)
2229 gtk_widget_queue_resize (tree_column->tree_view);
2232 tree_column->min_width = min_width;
2233 g_object_freeze_notify (G_OBJECT (tree_column));
2234 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
2236 tree_column->max_width = min_width;
2237 g_object_notify (G_OBJECT (tree_column), "max-width");
2239 g_object_notify (G_OBJECT (tree_column), "min-width");
2240 g_object_thaw_notify (G_OBJECT (tree_column));
2244 * pspp_sheet_view_column_get_min_width:
2245 * @tree_column: A #PsppSheetViewColumn.
2247 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
2250 * Return value: The minimum width of the @tree_column.
2253 pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
2255 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2257 return tree_column->min_width;
2261 * pspp_sheet_view_column_set_max_width:
2262 * @tree_column: A #PsppSheetViewColumn.
2263 * @max_width: The maximum width of the column in pixels, or -1.
2265 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
2266 * maximum width is unset. Note, the column can actually be wider than max
2267 * width if it's the last column in a view. In this case, the column expands to
2268 * fill any extra space.
2271 pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
2274 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2275 g_return_if_fail (max_width >= -1);
2277 if (max_width == tree_column->max_width)
2280 if (tree_column->visible &&
2281 tree_column->tree_view != NULL &&
2282 gtk_widget_get_realized (tree_column->tree_view))
2284 if (max_width != -1 && max_width < tree_column->width)
2285 gtk_widget_queue_resize (tree_column->tree_view);
2288 tree_column->max_width = max_width;
2289 g_object_freeze_notify (G_OBJECT (tree_column));
2290 if (max_width != -1 && max_width < tree_column->min_width)
2292 tree_column->min_width = max_width;
2293 g_object_notify (G_OBJECT (tree_column), "min-width");
2295 g_object_notify (G_OBJECT (tree_column), "max-width");
2296 g_object_thaw_notify (G_OBJECT (tree_column));
2300 * pspp_sheet_view_column_get_max_width:
2301 * @tree_column: A #PsppSheetViewColumn.
2303 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
2306 * Return value: The maximum width of the @tree_column.
2309 pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
2311 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2313 return tree_column->max_width;
2317 * pspp_sheet_view_column_clicked:
2318 * @tree_column: a #PsppSheetViewColumn
2320 * Emits the "clicked" signal on the column. This function will only work if
2321 * @tree_column is clickable.
2324 pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
2326 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2328 if (tree_column->visible &&
2329 tree_column->button &&
2330 tree_column->clickable)
2331 gtk_button_clicked (GTK_BUTTON (tree_column->button));
2335 * pspp_sheet_view_column_set_title:
2336 * @tree_column: A #PsppSheetViewColumn.
2337 * @title: The title of the @tree_column.
2339 * Sets the title of the @tree_column. If a custom widget has been set, then
2340 * this value is ignored.
2343 pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
2348 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2350 new_title = g_strdup (title);
2351 g_free (tree_column->title);
2352 tree_column->title = new_title;
2354 pspp_sheet_view_column_update_button (tree_column);
2355 g_object_notify (G_OBJECT (tree_column), "title");
2359 * pspp_sheet_view_column_get_title:
2360 * @tree_column: A #PsppSheetViewColumn.
2362 * Returns the title of the widget.
2364 * Return value: the title of the column. This string should not be
2365 * modified or freed.
2368 pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
2370 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2372 return tree_column->title;
2376 * pspp_sheet_view_column_set_expand:
2377 * @tree_column: A #PsppSheetViewColumn
2378 * @expand: %TRUE if the column should take available extra space, %FALSE if not
2380 * Sets the column to take available extra space. This space is shared equally
2381 * amongst all columns that have the expand set to %TRUE. If no column has this
2382 * option set, then the last column gets all extra space. By default, every
2383 * column is created with this %FALSE.
2388 pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
2391 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2394 if (tree_column->expand == expand)
2396 tree_column->expand = expand;
2398 if (tree_column->visible &&
2399 tree_column->tree_view != NULL &&
2400 gtk_widget_get_realized (tree_column->tree_view))
2402 /* We want to continue using the original width of the
2403 * column that includes additional space added by the user
2404 * resizing the columns and possibly extra (expanded) space, which
2405 * are not included in the resized width.
2407 tree_column->use_resized_width = FALSE;
2409 gtk_widget_queue_resize (tree_column->tree_view);
2412 g_object_notify (G_OBJECT (tree_column), "expand");
2416 * pspp_sheet_view_column_get_expand:
2417 * @tree_column: a #PsppSheetViewColumn
2419 * Return %TRUE if the column expands to take any available space.
2421 * Return value: %TRUE, if the column expands
2426 pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
2428 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2430 return tree_column->expand;
2434 * pspp_sheet_view_column_set_clickable:
2435 * @tree_column: A #PsppSheetViewColumn.
2436 * @clickable: %TRUE if the header is active.
2438 * Sets the header to be active if @active is %TRUE. When the header is active,
2439 * then it can take keyboard focus, and can be clicked.
2442 pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
2445 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2447 clickable = !! clickable;
2448 if (tree_column->clickable == clickable)
2451 tree_column->clickable = clickable;
2452 pspp_sheet_view_column_update_button (tree_column);
2453 g_object_notify (G_OBJECT (tree_column), "clickable");
2457 * pspp_sheet_view_column_get_clickable:
2458 * @tree_column: a #PsppSheetViewColumn
2460 * Returns %TRUE if the user can click on the header for the column.
2462 * Return value: %TRUE if user can click the column header.
2465 pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
2467 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2469 return tree_column->clickable;
2473 * pspp_sheet_view_column_set_widget:
2474 * @tree_column: A #PsppSheetViewColumn.
2475 * @widget: (allow-none): A child #GtkWidget, or %NULL.
2477 * Sets the widget in the header to be @widget. If widget is %NULL, then the
2478 * header button is set with a #GtkLabel set to the title of @tree_column.
2481 pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
2484 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2485 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
2488 g_object_ref_sink (widget);
2490 if (tree_column->child)
2491 g_object_unref (tree_column->child);
2493 tree_column->child = widget;
2494 pspp_sheet_view_column_update_button (tree_column);
2495 g_object_notify (G_OBJECT (tree_column), "widget");
2499 * pspp_sheet_view_column_get_widget:
2500 * @tree_column: A #PsppSheetViewColumn.
2502 * Returns the #GtkWidget in the button on the column header. If a custom
2503 * widget has not been set then %NULL is returned.
2505 * Return value: The #GtkWidget in the column header, or %NULL
2508 pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
2510 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2512 return tree_column->child;
2516 * pspp_sheet_view_column_set_alignment:
2517 * @tree_column: A #PsppSheetViewColumn.
2518 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2520 * Sets the alignment of the title or custom widget inside the column header.
2521 * The alignment determines its location inside the button -- 0.0 for left, 0.5
2522 * for center, 1.0 for right.
2525 pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
2528 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2530 xalign = CLAMP (xalign, 0.0, 1.0);
2532 if (tree_column->xalign == xalign)
2535 tree_column->xalign = xalign;
2536 pspp_sheet_view_column_update_button (tree_column);
2537 g_object_notify (G_OBJECT (tree_column), "alignment");
2541 * pspp_sheet_view_column_get_alignment:
2542 * @tree_column: A #PsppSheetViewColumn.
2544 * Returns the current x alignment of @tree_column. This value can range
2545 * between 0.0 and 1.0.
2547 * Return value: The current alignent of @tree_column.
2550 pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
2552 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0.5);
2554 return tree_column->xalign;
2558 * pspp_sheet_view_column_set_reorderable:
2559 * @tree_column: A #PsppSheetViewColumn
2560 * @reorderable: %TRUE, if the column can be reordered.
2562 * If @reorderable is %TRUE, then the column can be reordered by the end user
2563 * dragging the header.
2566 pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
2567 gboolean reorderable)
2569 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2572 pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
2574 reorderable = !!reorderable;
2575 if (tree_column->reorderable == reorderable)
2578 tree_column->reorderable = reorderable;
2579 pspp_sheet_view_column_update_button (tree_column);
2580 g_object_notify (G_OBJECT (tree_column), "reorderable");
2584 * pspp_sheet_view_column_get_reorderable:
2585 * @tree_column: A #PsppSheetViewColumn
2587 * Returns %TRUE if the @tree_column can be reordered by the user.
2589 * Return value: %TRUE if the @tree_column can be reordered by the user.
2592 pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
2594 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2596 return tree_column->reorderable;
2600 * pspp_sheet_view_column_set_quick_edit:
2601 * @tree_column: A #PsppSheetViewColumn
2602 * @quick_edit: If true, editing starts upon the first click in the column. If
2603 * false, the first click selects the column and a second click is needed to
2604 * begin editing. This has no effect on cells that are not editable.
2607 pspp_sheet_view_column_set_quick_edit (PsppSheetViewColumn *tree_column,
2608 gboolean quick_edit)
2610 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2612 quick_edit = !!quick_edit;
2613 if (tree_column->quick_edit != quick_edit)
2615 tree_column->quick_edit = quick_edit;
2616 g_object_notify (G_OBJECT (tree_column), "quick-edit");
2621 * pspp_sheet_view_column_get_quick_edit:
2622 * @tree_column: A #PsppSheetViewColumn
2624 * Returns %TRUE if editing starts upon the first click in the column. Returns
2625 * %FALSE, the first click selects the column and a second click is needed to
2626 * begin editing. This is not meaningful for cells that are not editable.
2628 * Return value: %TRUE if editing starts upon the first click.
2631 pspp_sheet_view_column_get_quick_edit (PsppSheetViewColumn *tree_column)
2633 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2635 return tree_column->quick_edit;
2640 * pspp_sheet_view_column_set_selected:
2641 * @tree_column: A #PsppSheetViewColumn
2642 * @selected: If true, the column is selected as part of a rectangular
2646 pspp_sheet_view_column_set_selected (PsppSheetViewColumn *tree_column,
2649 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2651 selected = !!selected;
2652 if (tree_column->selected != selected)
2654 PsppSheetSelection *selection;
2655 PsppSheetView *sheet_view;
2657 if (tree_column->tree_view != NULL)
2658 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2659 tree_column->selected = selected;
2660 g_object_notify (G_OBJECT (tree_column), "selected");
2662 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
2664 selection = pspp_sheet_view_get_selection (sheet_view);
2665 _pspp_sheet_selection_emit_changed (selection);
2670 * pspp_sheet_view_column_get_selected:
2671 * @tree_column: A #PsppSheetViewColumn
2673 * Returns %TRUE if the column is selected as part of a rectangular
2676 * Return value: %TRUE if the column is selected as part of a rectangular
2680 pspp_sheet_view_column_get_selected (PsppSheetViewColumn *tree_column)
2682 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2684 return tree_column->selected;
2688 * pspp_sheet_view_column_set_selectable:
2689 * @tree_column: A #PsppSheetViewColumn
2690 * @selectable: If true, the column may be selected as part of a rectangular
2694 pspp_sheet_view_column_set_selectable (PsppSheetViewColumn *tree_column,
2695 gboolean selectable)
2697 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2699 selectable = !!selectable;
2700 if (tree_column->selectable != selectable)
2702 if (tree_column->tree_view != NULL)
2703 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2704 tree_column->selectable = selectable;
2705 g_object_notify (G_OBJECT (tree_column), "selectable");
2710 * pspp_sheet_view_column_get_selectable:
2711 * @tree_column: A #PsppSheetViewColumn
2713 * Returns %TRUE if the column may be selected as part of a rectangular
2716 * Return value: %TRUE if the column may be selected as part of a rectangular
2720 pspp_sheet_view_column_get_selectable (PsppSheetViewColumn *tree_column)
2722 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2724 return tree_column->selectable;
2729 * pspp_sheet_view_column_set_row_head:
2730 * @tree_column: A #PsppSheetViewColumn
2731 * @row_head: If true, the column is a "row head", analogous to a column head.
2732 * See the description of the row-head property for more information.
2735 pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column,
2738 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2740 row_head = !!row_head;
2741 if (tree_column->row_head != row_head)
2743 tree_column->row_head = row_head;
2744 g_object_notify (G_OBJECT (tree_column), "row_head");
2749 * pspp_sheet_view_column_get_row_head:
2750 * @tree_column: A #PsppSheetViewColumn
2752 * Returns %TRUE if the column is a row head.
2754 * Return value: %TRUE if the column is a row head.
2757 pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column)
2759 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2761 return tree_column->row_head;
2766 * pspp_sheet_view_column_set_tabbable:
2767 * @tree_column: A #PsppSheetViewColumn
2768 * @tabbable: If true, the column is "tabbable", meaning that Tab and Shift+Tab
2769 * in the sheet visit this column. If false, Tab and Shift+Tab skip this
2773 pspp_sheet_view_column_set_tabbable (PsppSheetViewColumn *tree_column,
2776 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2778 tabbable = !!tabbable;
2779 if (tree_column->tabbable != tabbable)
2781 tree_column->tabbable = tabbable;
2782 g_object_notify (G_OBJECT (tree_column), "tabbable");
2787 * pspp_sheet_view_column_get_tabbable:
2788 * @tree_column: A #PsppSheetViewColumn
2790 * Returns %TRUE if the column is tabbable.
2792 * Return value: %TRUE if the column is tabbable.
2795 pspp_sheet_view_column_get_tabbable (PsppSheetViewColumn *tree_column)
2797 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2799 return tree_column->tabbable;
2804 * pspp_sheet_view_column_set_sort_column_id:
2805 * @tree_column: a #PsppSheetViewColumn
2806 * @sort_column_id: The @sort_column_id of the model to sort on.
2808 * Sets the logical @sort_column_id that this column sorts on when this column
2809 * is selected for sorting. Doing so makes the column header clickable.
2812 pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
2813 gint sort_column_id)
2815 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2816 g_return_if_fail (sort_column_id >= -1);
2818 if (tree_column->sort_column_id == sort_column_id)
2821 tree_column->sort_column_id = sort_column_id;
2823 /* Handle unsetting the id */
2824 if (sort_column_id == -1)
2826 GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
2828 if (tree_column->sort_clicked_signal)
2830 g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
2831 tree_column->sort_clicked_signal = 0;
2834 if (tree_column->sort_column_changed_signal)
2836 g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
2837 tree_column->sort_column_changed_signal = 0;
2840 pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2841 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
2842 pspp_sheet_view_column_set_clickable (tree_column, FALSE);
2843 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2847 pspp_sheet_view_column_set_clickable (tree_column, TRUE);
2849 if (! tree_column->sort_clicked_signal)
2850 tree_column->sort_clicked_signal = g_signal_connect (tree_column,
2852 G_CALLBACK (pspp_sheet_view_column_sort),
2855 pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
2856 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2860 * pspp_sheet_view_column_get_sort_column_id:
2861 * @tree_column: a #PsppSheetViewColumn
2863 * Gets the logical @sort_column_id that the model sorts on when this
2864 * column is selected for sorting.
2865 * See pspp_sheet_view_column_set_sort_column_id().
2867 * Return value: the current @sort_column_id for this column, or -1 if
2868 * this column can't be used for sorting.
2871 pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
2873 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2875 return tree_column->sort_column_id;
2879 * pspp_sheet_view_column_set_sort_indicator:
2880 * @tree_column: a #PsppSheetViewColumn
2881 * @setting: %TRUE to display an indicator that the column is sorted
2883 * Call this function with a @setting of %TRUE to display an arrow in
2884 * the header button indicating the column is sorted. Call
2885 * pspp_sheet_view_column_set_sort_order() to change the direction of
2890 pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
2893 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2895 setting = setting != FALSE;
2897 if (setting == tree_column->show_sort_indicator)
2900 tree_column->show_sort_indicator = setting;
2901 pspp_sheet_view_column_update_button (tree_column);
2902 g_object_notify (G_OBJECT (tree_column), "sort-indicator");
2906 * pspp_sheet_view_column_get_sort_indicator:
2907 * @tree_column: a #PsppSheetViewColumn
2909 * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
2911 * Return value: whether the sort indicator arrow is displayed
2914 pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column)
2916 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2918 return tree_column->show_sort_indicator;
2922 * pspp_sheet_view_column_set_sort_order:
2923 * @tree_column: a #PsppSheetViewColumn
2924 * @order: sort order that the sort indicator should indicate
2926 * Changes the appearance of the sort indicator.
2928 * This <emphasis>does not</emphasis> actually sort the model. Use
2929 * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
2930 * support. This function is primarily for custom sorting behavior, and should
2931 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2932 * that. For custom models, the mechanism will vary.
2934 * The sort indicator changes direction to indicate normal sort or reverse sort.
2935 * Note that you must have the sort indicator enabled to see anything when
2936 * calling this function; see pspp_sheet_view_column_set_sort_indicator().
2939 pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
2942 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2944 if (order == tree_column->sort_order)
2947 tree_column->sort_order = order;
2948 pspp_sheet_view_column_update_button (tree_column);
2949 g_object_notify (G_OBJECT (tree_column), "sort-order");
2953 * pspp_sheet_view_column_get_sort_order:
2954 * @tree_column: a #PsppSheetViewColumn
2956 * Gets the value set by pspp_sheet_view_column_set_sort_order().
2958 * Return value: the sort order the sort indicator is indicating
2961 pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column)
2963 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2965 return tree_column->sort_order;
2969 * pspp_sheet_view_column_cell_set_cell_data:
2970 * @tree_column: A #PsppSheetViewColumn.
2971 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2972 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2974 * Sets the cell renderer based on the @tree_model and @iter. That is, for
2975 * every attribute mapping in @tree_column, it will get a value from the set
2976 * column on the @iter, and use that value to set the attribute on the cell
2977 * renderer. This is used primarily by the #PsppSheetView.
2980 pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
2981 GtkTreeModel *tree_model,
2985 GValue value = { 0, };
2988 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2990 if (tree_model == NULL)
2993 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2995 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
2996 GObject *cell = (GObject *) info->cell;
2998 list = info->attributes;
3000 g_object_freeze_notify (cell);
3002 while (list && list->next)
3004 gtk_tree_model_get_value (tree_model, iter,
3005 GPOINTER_TO_INT (list->next->data),
3007 g_object_set_property (cell, (gchar *) list->data, &value);
3008 g_value_unset (&value);
3009 list = list->next->next;
3013 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
3014 g_object_thaw_notify (G_OBJECT (info->cell));
3020 * pspp_sheet_view_column_cell_get_size:
3021 * @tree_column: A #PsppSheetViewColumn.
3022 * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
3023 * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
3024 * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
3025 * @width: (allow-none): location to return width needed to render a cell, or %NULL
3026 * @height: (allow-none): location to return height needed to render a cell, or %NULL
3028 * Obtains the width and height needed to render the column. This is used
3029 * primarily by the #PsppSheetView.
3032 pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
3033 const GdkRectangle *cell_area,
3040 gboolean first_cell = TRUE;
3041 gint focus_line_width;
3043 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3050 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
3052 for (list = tree_column->cell_list; list; list = list->next)
3054 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3056 gint new_height = 0;
3058 g_object_get (info->cell, "visible", &visible, NULL);
3060 if (visible == FALSE)
3063 if (first_cell == FALSE && width)
3064 *width += tree_column->spacing;
3066 gtk_cell_renderer_get_size (info->cell,
3067 tree_column->tree_view,
3075 * height = MAX (*height, new_height + focus_line_width * 2);
3076 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
3078 * width += info->requested_width;
3083 /* rendering, event handling and rendering focus are somewhat complicated, and
3084 * quite a bit of code. Rather than duplicate them, we put them together to
3085 * keep the code in one place.
3087 * To better understand what's going on, check out
3088 * docs/tree-column-sizing.png
3097 pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn *tree_column,
3099 const GdkRectangle *background_area,
3100 const GdkRectangle *cell_area,
3103 const GdkRectangle *expose_area, /* RENDER */
3104 GdkRectangle *focus_rectangle, /* FOCUS */
3105 GtkCellEditable **editable_widget, /* EVENT */
3106 GdkEvent *event, /* EVENT */
3107 gchar *path_string) /* EVENT */
3110 GdkRectangle real_cell_area;
3111 GdkRectangle real_background_area;
3112 GdkRectangle real_expose_area = *cell_area;
3114 gint expand_cell_count = 0;
3115 gint full_requested_width = 0;
3117 gint min_x, min_y, max_x, max_y;
3118 gint focus_line_width;
3120 gint horizontal_separator;
3121 gboolean cursor_row = FALSE;
3122 gboolean first_cell = TRUE;
3124 /* If we have rtl text, we need to transform our areas */
3125 GdkRectangle rtl_cell_area;
3126 GdkRectangle rtl_background_area;
3133 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
3134 special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
3136 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
3138 PsppSheetViewColumnCellInfo *info = NULL;
3139 gboolean found_has_focus = FALSE;
3141 /* one should have focus */
3142 for (list = tree_column->cell_list; list; list = list->next)
3145 if (info && info->has_focus)
3147 found_has_focus = TRUE;
3152 if (!found_has_focus)
3154 /* give the first one focus */
3155 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3156 info->has_focus = TRUE;
3160 cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
3162 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3163 "focus-line-width", &focus_line_width,
3164 "horizontal-separator", &horizontal_separator,
3167 real_cell_area = *cell_area;
3168 real_background_area = *background_area;
3171 real_cell_area.x += focus_line_width;
3172 real_cell_area.y += focus_line_width;
3173 real_cell_area.height -= 2 * focus_line_width;
3176 depth = real_background_area.width - real_cell_area.width;
3178 depth = real_cell_area.x - real_background_area.x;
3180 /* Find out how much extra space we have to allocate */
3181 for (list = tree_column->cell_list; list; list = list->next)
3183 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
3185 if (! gtk_cell_renderer_get_visible (info->cell))
3188 if (info->expand == TRUE)
3189 expand_cell_count ++;
3190 full_requested_width += info->requested_width;
3193 full_requested_width += tree_column->spacing;
3198 extra_space = cell_area->width - full_requested_width;
3199 if (extra_space < 0)
3201 else if (extra_space > 0 && expand_cell_count > 0)
3202 extra_space /= expand_cell_count;
3204 /* iterate list for GTK_PACK_START cells */
3205 for (list = tree_column->cell_list; list; list = list->next)
3207 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3209 if (info->pack == GTK_PACK_END)
3212 if (! gtk_cell_renderer_get_visible (info->cell))
3215 if ((info->has_focus || special_cells == 1) && cursor_row)
3216 flags |= GTK_CELL_RENDERER_FOCUSED;
3218 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3220 info->real_width = info->requested_width + (info->expand?extra_space:0);
3222 /* We constrain ourselves to only the width available */
3223 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3225 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3228 if (real_cell_area.x > cell_area->x + cell_area->width)
3231 real_cell_area.width = info->real_width;
3232 real_cell_area.width -= 2 * focus_line_width;
3236 real_background_area.width = info->real_width + depth;
3240 /* fill the rest of background for the last cell */
3241 real_background_area.width = background_area->x + background_area->width - real_background_area.x;
3244 rtl_cell_area = real_cell_area;
3245 rtl_background_area = real_background_area;
3249 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3250 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3254 if (action == CELL_ACTION_RENDER)
3256 gtk_cell_renderer_render (info->cell,
3258 tree_column->tree_view,
3259 &rtl_background_area,
3265 else if (action == CELL_ACTION_FOCUS)
3267 gint x_offset, y_offset, width, height;
3269 gtk_cell_renderer_get_size (info->cell,
3270 tree_column->tree_view,
3272 &x_offset, &y_offset,
3275 if (special_cells > 1)
3277 if (info->has_focus)
3279 min_x = rtl_cell_area.x + x_offset;
3280 max_x = min_x + width;
3281 min_y = rtl_cell_area.y + y_offset;
3282 max_y = min_y + height;
3287 if (min_x > (rtl_cell_area.x + x_offset))
3288 min_x = rtl_cell_area.x + x_offset;
3289 if (max_x < rtl_cell_area.x + x_offset + width)
3290 max_x = rtl_cell_area.x + x_offset + width;
3291 if (min_y > (rtl_cell_area.y + y_offset))
3292 min_y = rtl_cell_area.y + y_offset;
3293 if (max_y < rtl_cell_area.y + y_offset + height)
3294 max_y = rtl_cell_area.y + y_offset + height;
3298 else if (action == CELL_ACTION_EVENT)
3300 gboolean try_event = FALSE;
3304 if (special_cells == 1)
3306 /* only 1 activatable cell -> whole column can activate */
3307 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3308 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3311 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3312 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3313 /* only activate cell if the user clicked on an individual
3318 else if (special_cells > 1 && info->has_focus)
3320 else if (special_cells == 1)
3325 gboolean visible, mode;
3327 g_object_get (info->cell,
3328 "visible", &visible,
3331 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3333 if (gtk_cell_renderer_activate (info->cell,
3335 tree_column->tree_view,
3337 &rtl_background_area,
3341 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3345 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3348 gtk_cell_renderer_start_editing (info->cell,
3350 tree_column->tree_view,
3352 &rtl_background_area,
3356 if (*editable_widget != NULL)
3358 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3359 info->in_editing_mode = TRUE;
3360 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3362 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3370 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3372 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3373 real_background_area.x += real_background_area.width + tree_column->spacing;
3375 /* Only needed for first cell */
3379 /* iterate list for PACK_END cells */
3380 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
3382 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3384 if (info->pack == GTK_PACK_START)
3387 if (! gtk_cell_renderer_get_visible (info->cell))
3390 if ((info->has_focus || special_cells == 1) && cursor_row)
3391 flags |= GTK_CELL_RENDERER_FOCUSED;
3393 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3395 info->real_width = info->requested_width + (info->expand?extra_space:0);
3397 /* We constrain ourselves to only the width available */
3398 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3400 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3403 if (real_cell_area.x > cell_area->x + cell_area->width)
3406 real_cell_area.width = info->real_width;
3407 real_cell_area.width -= 2 * focus_line_width;
3408 real_background_area.width = info->real_width + depth;
3410 rtl_cell_area = real_cell_area;
3411 rtl_background_area = real_background_area;
3414 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3415 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3419 if (action == CELL_ACTION_RENDER)
3421 gtk_cell_renderer_render (info->cell,
3423 tree_column->tree_view,
3424 &rtl_background_area,
3430 else if (action == CELL_ACTION_FOCUS)
3432 gint x_offset, y_offset, width, height;
3434 gtk_cell_renderer_get_size (info->cell,
3435 tree_column->tree_view,
3437 &x_offset, &y_offset,
3440 if (special_cells > 1)
3442 if (info->has_focus)
3444 min_x = rtl_cell_area.x + x_offset;
3445 max_x = min_x + width;
3446 min_y = rtl_cell_area.y + y_offset;
3447 max_y = min_y + height;
3452 if (min_x > (rtl_cell_area.x + x_offset))
3453 min_x = rtl_cell_area.x + x_offset;
3454 if (max_x < rtl_cell_area.x + x_offset + width)
3455 max_x = rtl_cell_area.x + x_offset + width;
3456 if (min_y > (rtl_cell_area.y + y_offset))
3457 min_y = rtl_cell_area.y + y_offset;
3458 if (max_y < rtl_cell_area.y + y_offset + height)
3459 max_y = rtl_cell_area.y + y_offset + height;
3463 else if (action == CELL_ACTION_EVENT)
3465 gboolean try_event = FALSE;
3469 if (special_cells == 1)
3471 /* only 1 activatable cell -> whole column can activate */
3472 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3473 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3476 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3477 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3478 /* only activate cell if the user clicked on an individual
3483 else if (special_cells > 1 && info->has_focus)
3485 else if (special_cells == 1)
3490 gboolean visible, mode;
3492 g_object_get (info->cell,
3493 "visible", &visible,
3496 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3498 if (gtk_cell_renderer_activate (info->cell,
3500 tree_column->tree_view,
3502 &rtl_background_area,
3506 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3510 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3513 gtk_cell_renderer_start_editing (info->cell,
3515 tree_column->tree_view,
3517 &rtl_background_area,
3521 if (*editable_widget != NULL)
3523 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3524 info->in_editing_mode = TRUE;
3525 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3527 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3534 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3536 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3537 real_background_area.x += (real_background_area.width + tree_column->spacing);
3539 /* Only needed for first cell */
3543 /* fill focus_rectangle when required */
3544 if (action == CELL_ACTION_FOCUS)
3546 if (min_x >= max_x || min_y >= max_y)
3548 *focus_rectangle = *cell_area;
3549 /* don't change the focus_rectangle, just draw it nicely inside
3554 focus_rectangle->x = min_x - focus_line_width;
3555 focus_rectangle->y = min_y - focus_line_width;
3556 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
3557 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
3565 * pspp_sheet_view_column_cell_render:
3566 * @tree_column: A #PsppSheetViewColumn.
3567 * @window: a #GdkDrawable to draw to
3568 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
3569 * @cell_area: area normally rendered by a cell renderer
3570 * @expose_area: area that actually needs updating
3571 * @flags: flags that affect rendering
3573 * Renders the cell contained by #tree_column. This is used primarily by the
3577 _pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
3579 const GdkRectangle *background_area,
3580 const GdkRectangle *cell_area,
3581 const GdkRectangle *expose_area,
3584 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3585 g_return_if_fail (background_area != NULL);
3586 g_return_if_fail (cell_area != NULL);
3587 g_return_if_fail (expose_area != NULL);
3589 pspp_sheet_view_column_cell_process_action (tree_column,
3596 NULL, NULL, NULL, NULL);
3600 _pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
3601 GtkCellEditable **editable_widget,
3604 const GdkRectangle *background_area,
3605 const GdkRectangle *cell_area,
3608 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3610 return pspp_sheet_view_column_cell_process_action (tree_column,
3623 _pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
3624 const GdkRectangle *background_area,
3625 const GdkRectangle *cell_area,
3626 GdkRectangle *focus_area)
3628 pspp_sheet_view_column_cell_process_action (tree_column,
3640 /* cell list manipulation */
3642 pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
3644 GList *list = tree_column->cell_list;
3646 /* first GTK_PACK_START cell we find */
3647 for ( ; list; list = list->next)
3649 PsppSheetViewColumnCellInfo *info = list->data;
3650 if (info->pack == GTK_PACK_START)
3654 /* hmm, else the *last* GTK_PACK_END cell */
3655 list = g_list_last (tree_column->cell_list);
3657 for ( ; list; list = list->prev)
3659 PsppSheetViewColumnCellInfo *info = list->data;
3660 if (info->pack == GTK_PACK_END)
3668 pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
3670 GList *list = tree_column->cell_list;
3672 /* *first* GTK_PACK_END cell we find */
3673 for ( ; list ; list = list->next)
3675 PsppSheetViewColumnCellInfo *info = list->data;
3676 if (info->pack == GTK_PACK_END)
3680 /* hmm, else the last GTK_PACK_START cell */
3681 list = g_list_last (tree_column->cell_list);
3683 for ( ; list; list = list->prev)
3685 PsppSheetViewColumnCellInfo *info = list->data;
3686 if (info->pack == GTK_PACK_START)
3694 pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
3698 PsppSheetViewColumnCellInfo *info = current->data;
3700 if (info->pack == GTK_PACK_START)
3702 for (list = current->next; list; list = list->next)
3704 PsppSheetViewColumnCellInfo *inf = list->data;
3705 if (inf->pack == GTK_PACK_START)
3709 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
3710 list = g_list_last (tree_column->cell_list);
3711 for (; list; list = list->prev)
3713 PsppSheetViewColumnCellInfo *inf = list->data;
3714 if (inf->pack == GTK_PACK_END)
3719 for (list = current->prev; list; list = list->prev)
3721 PsppSheetViewColumnCellInfo *inf = list->data;
3722 if (inf->pack == GTK_PACK_END)
3730 pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
3734 PsppSheetViewColumnCellInfo *info = current->data;
3736 if (info->pack == GTK_PACK_END)
3738 for (list = current->next; list; list = list->next)
3740 PsppSheetViewColumnCellInfo *inf = list->data;
3741 if (inf->pack == GTK_PACK_END)
3745 /* out of GTK_PACK_END, get last GTK_PACK_START one */
3746 list = g_list_last (tree_column->cell_list);
3747 for ( ; list; list = list->prev)
3749 PsppSheetViewColumnCellInfo *inf = list->data;
3750 if (inf->pack == GTK_PACK_START)
3755 for (list = current->prev; list; list = list->prev)
3757 PsppSheetViewColumnCellInfo *inf = list->data;
3758 if (inf->pack == GTK_PACK_START)
3766 _pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
3774 count = _pspp_sheet_view_column_count_special_cells (tree_column);
3775 rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
3777 /* if we are the current focus column and have multiple editable cells,
3778 * try to select the next one, else move the focus to the next column
3780 if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
3785 GList *list = tree_column->cell_list;
3786 PsppSheetViewColumnCellInfo *info = NULL;
3788 /* find current focussed cell */
3789 for ( ; list; list = list->next)
3792 if (info->has_focus)
3796 /* not a focussed cell in the focus column? */
3797 if (!list || !info || !info->has_focus)
3802 prev = pspp_sheet_view_column_cell_next (tree_column, list);
3803 next = pspp_sheet_view_column_cell_prev (tree_column, list);
3807 next = pspp_sheet_view_column_cell_next (tree_column, list);
3808 prev = pspp_sheet_view_column_cell_prev (tree_column, list);
3811 info->has_focus = FALSE;
3812 if (direction > 0 && next)
3815 info->has_focus = TRUE;
3818 else if (direction > 0 && !next && !right)
3820 /* keep focus on last cell */
3822 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3824 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3826 info->has_focus = TRUE;
3829 else if (direction < 0 && prev)
3832 info->has_focus = TRUE;
3835 else if (direction < 0 && !prev && !left)
3837 /* keep focus on first cell */
3839 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3841 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3843 info->has_focus = TRUE;
3850 /* we get focus, if we have multiple editable cells, give the correct one
3855 GList *list = tree_column->cell_list;
3857 /* clear focus first */
3858 for ( ; list ; list = list->next)
3860 PsppSheetViewColumnCellInfo *info = list->data;
3861 if (info->has_focus)
3862 info->has_focus = FALSE;
3869 list = pspp_sheet_view_column_cell_last (tree_column);
3870 else if (direction < 0)
3871 list = pspp_sheet_view_column_cell_first (tree_column);
3876 list = pspp_sheet_view_column_cell_first (tree_column);
3877 else if (direction < 0)
3878 list = pspp_sheet_view_column_cell_last (tree_column);
3882 ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
3889 _pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
3891 const GdkRectangle *background_area,
3892 const GdkRectangle *cell_area,
3893 const GdkRectangle *expose_area,
3896 gint focus_line_width;
3897 GtkStateType cell_state;
3899 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3900 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3901 "focus-line-width", &focus_line_width, NULL);
3902 if (tree_column->editable_widget)
3904 /* This function is only called on the editable row when editing.
3907 gtk_paint_focus (tree_column->tree_view->style,
3909 gtk_widget_get_state (tree_column->tree_view),
3911 tree_column->tree_view,
3913 cell_area->x - focus_line_width,
3914 cell_area->y - focus_line_width,
3915 cell_area->width + 2 * focus_line_width,
3916 cell_area->height + 2 * focus_line_width);
3921 GdkRectangle focus_rectangle;
3922 pspp_sheet_view_column_cell_process_action (tree_column,
3932 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3933 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3934 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3935 gtk_paint_focus (gtk_widget_get_style (GTK_WIDGET (tree_column->tree_view)),
3939 tree_column->tree_view,
3943 focus_rectangle.width,
3944 focus_rectangle.height);
3949 * pspp_sheet_view_column_cell_is_visible:
3950 * @tree_column: A #PsppSheetViewColumn
3952 * Returns %TRUE if any of the cells packed into the @tree_column are visible.
3953 * For this to be meaningful, you must first initialize the cells with
3954 * pspp_sheet_view_column_cell_set_cell_data()
3956 * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
3959 pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
3963 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3965 for (list = tree_column->cell_list; list; list = list->next)
3967 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3969 if (gtk_cell_renderer_get_visible (info->cell))
3977 * pspp_sheet_view_column_focus_cell:
3978 * @tree_column: A #PsppSheetViewColumn
3979 * @cell: A #GtkCellRenderer
3981 * Sets the current keyboard focus to be at @cell, if the column contains
3982 * 2 or more editable and activatable cells.
3987 pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
3988 GtkCellRenderer *cell)
3991 gboolean found_cell = FALSE;
3993 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3994 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3996 if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
3999 for (list = tree_column->cell_list; list; list = list->next)
4001 PsppSheetViewColumnCellInfo *info = list->data;
4003 if (info->cell == cell)
4005 info->has_focus = TRUE;
4013 for (list = tree_column->cell_list; list; list = list->next)
4015 PsppSheetViewColumnCellInfo *info = list->data;
4017 if (info->cell != cell)
4018 info->has_focus = FALSE;
4021 /* FIXME: redraw? */
4026 _pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
4030 for (list = tree_column->cell_list; list; list = list->next)
4032 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
4034 info->requested_width = 0;
4036 tree_column->dirty = TRUE;
4037 tree_column->requested_width = -1;
4038 tree_column->width = 0;
4040 if (tree_column->tree_view &&
4041 gtk_widget_get_realized (tree_column->tree_view))
4043 _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
4044 gtk_widget_queue_resize (tree_column->tree_view);
4049 _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
4050 GtkCellEditable *cell_editable)
4052 g_return_if_fail (tree_column->editable_widget == NULL);
4054 tree_column->editable_widget = cell_editable;
4058 _pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
4062 g_return_if_fail (tree_column->editable_widget != NULL);
4064 tree_column->editable_widget = NULL;
4065 for (list = tree_column->cell_list; list; list = list->next)
4066 ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
4070 _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
4071 GtkCellRenderer *cell,
4076 PsppSheetViewColumnCellInfo *info;
4082 list = pspp_sheet_view_column_cell_first (column);
4086 info = (PsppSheetViewColumnCellInfo *)list->data;
4088 list = pspp_sheet_view_column_cell_next (column, list);
4090 if (info->cell == cell)
4093 if (gtk_cell_renderer_get_visible (info->cell))
4094 l += info->real_width + column->spacing;
4099 info = (PsppSheetViewColumnCellInfo *)list->data;
4101 list = pspp_sheet_view_column_cell_next (column, list);
4103 if (gtk_cell_renderer_get_visible (info->cell))
4104 r += info->real_width + column->spacing;
4107 rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
4109 *left = rtl ? r : l;
4112 *right = rtl ? l : r;
4116 * pspp_sheet_view_column_cell_get_position:
4117 * @tree_column: a #PsppSheetViewColumn
4118 * @cell_renderer: a #GtkCellRenderer
4119 * @start_pos: return location for the horizontal position of @cell within
4120 * @tree_column, may be %NULL
4121 * @width: return location for the width of @cell, may be %NULL
4123 * Obtains the horizontal position and size of a cell in a column. If the
4124 * cell is not found in the column, @start_pos and @width are not changed and
4125 * %FALSE is returned.
4127 * Return value: %TRUE if @cell belongs to @tree_column.
4130 pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
4131 GtkCellRenderer *cell_renderer,
4137 gboolean found_cell = FALSE;
4138 PsppSheetViewColumnCellInfo *cellinfo = NULL;
4140 list = pspp_sheet_view_column_cell_first (tree_column);
4141 for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
4143 cellinfo = list->data;
4144 if (cellinfo->cell == cell_renderer)
4150 if (gtk_cell_renderer_get_visible (cellinfo->cell))
4151 current_x += cellinfo->real_width;
4157 *start_pos = current_x;
4159 *width = cellinfo->real_width;
4166 * pspp_sheet_view_column_queue_resize:
4167 * @tree_column: A #PsppSheetViewColumn
4169 * Flags the column, and the cell renderers added to this column, to have
4170 * their sizes renegotiated.
4175 pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
4177 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
4179 if (tree_column->tree_view)
4180 _pspp_sheet_view_column_cell_set_dirty (tree_column);
4184 * pspp_sheet_view_column_get_tree_view:
4185 * @tree_column: A #PsppSheetViewColumn
4187 * Returns the #PsppSheetView wherein @tree_column has been inserted. If
4188 * @column is currently not inserted in any tree view, %NULL is
4191 * Return value: The tree view wherein @column has been inserted if any,
4197 pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
4199 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
4201 return tree_column->tree_view;
4205 GtkCellLayout *cell_layout;
4206 GtkCellRenderer *renderer;
4208 } AttributesSubParserData;
4211 attributes_start_element (GMarkupParseContext *context,
4212 const gchar *element_name,
4213 const gchar **names,
4214 const gchar **values,
4218 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4221 if (strcmp (element_name, "attribute") == 0)
4223 for (i = 0; names[i]; i++)
4224 if (strcmp (names[i], "name") == 0)
4225 parser_data->attr_name = g_strdup (values[i]);
4227 else if (strcmp (element_name, "attributes") == 0)
4230 g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
4234 attributes_text_element (GMarkupParseContext *context,
4240 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4245 if (!parser_data->attr_name)
4249 string = g_strndup (text, text_len);
4250 l = strtol (string, &endptr, 0);
4251 if (errno || endptr == string)
4255 GTK_BUILDER_ERROR_INVALID_VALUE,
4256 "Could not parse integer `%s'",
4263 gtk_cell_layout_add_attribute (parser_data->cell_layout,
4264 parser_data->renderer,
4265 parser_data->attr_name, l);
4266 g_free (parser_data->attr_name);
4267 parser_data->attr_name = NULL;
4270 static const GMarkupParser attributes_parser =
4272 attributes_start_element,
4274 attributes_text_element,
4278 _gtk_cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
4279 GtkBuilder *builder,
4281 const gchar *tagname,
4282 GMarkupParser *parser,
4285 AttributesSubParserData *parser_data;
4290 if (strcmp (tagname, "attributes") == 0)
4292 parser_data = g_slice_new0 (AttributesSubParserData);
4293 parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
4294 parser_data->renderer = GTK_CELL_RENDERER (child);
4295 parser_data->attr_name = NULL;
4297 *parser = attributes_parser;
4298 *data = parser_data;
4306 _gtk_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
4307 GtkBuilder *builder,
4309 const gchar *tagname,
4312 AttributesSubParserData *parser_data;
4314 parser_data = (AttributesSubParserData*)data;
4315 g_assert (!parser_data->attr_name);
4316 g_slice_free (AttributesSubParserData, parser_data);
4320 _gtk_cell_layout_buildable_add_child (GtkBuildable *buildable,
4321 GtkBuilder *builder,
4325 GtkCellLayoutIface *iface;
4327 g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
4328 g_return_if_fail (GTK_IS_CELL_RENDERER (child));
4330 iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
4331 g_return_if_fail (iface->pack_start != NULL);
4332 iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);
4336 pspp_sheet_view_column_size_request (PsppSheetViewColumn *tree_column,
4337 GtkRequisition *request)
4339 GtkWidget *base = GTK_WIDGET (tree_column->tree_view);
4340 GtkRequisition label_req;
4341 GtkRequisition align_req;
4342 GtkRequisition arrow_req;
4343 GtkRequisition hbox_req;
4344 GtkStyle **button_style;
4346 if (tree_column->button)
4348 gtk_widget_size_request (tree_column->button, request);
4352 facade_label_get_size_request (0, 0, base, tree_column->title, &label_req);
4353 facade_alignment_get_size_request (0, 0, 0, 0, 0, &label_req, &align_req);
4354 facade_arrow_get_size_request (0, 0, &arrow_req);
4356 facade_hbox_get_base_size_request (0, 2, 2, &hbox_req);
4357 facade_hbox_add_child_size_request (0, &arrow_req, 0, &hbox_req);
4358 facade_hbox_add_child_size_request (0, &align_req, 0, &hbox_req);
4360 button_style = &PSPP_SHEET_VIEW (tree_column->tree_view)->priv->button_style;
4361 if (*button_style == NULL)
4363 *button_style = facade_get_style (base, GTK_TYPE_BUTTON, 0);
4364 g_object_ref (*button_style);
4366 facade_button_get_size_request (0, base, *button_style, &hbox_req, request);
4370 pspp_sheet_view_column_size_allocate (PsppSheetViewColumn *tree_column,
4371 GtkAllocation *allocation)
4373 tree_column->allocation = *allocation;
4374 if (tree_column->button)
4375 gtk_widget_size_allocate (tree_column->button, allocation);
4379 pspp_sheet_view_column_can_focus (PsppSheetViewColumn *tree_column)
4381 return tree_column->reorderable || tree_column->clickable;
4385 pspp_sheet_view_column_set_need_button (PsppSheetViewColumn *tree_column,
4386 gboolean need_button)
4388 if (tree_column->need_button != need_button)
4390 tree_column->need_button = need_button;
4391 pspp_sheet_view_column_update_button (tree_column);
4392 _pspp_sheet_view_column_realize_button (tree_column);