1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2011, 2012, 2015 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,
148 GdkEventButton *event,
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, G_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 static void _cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
444 const gchar *tagname,
448 static void _cell_layout_buildable_add_child (GtkBuildable *buildable,
454 static gboolean _cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
457 const gchar *tagname,
458 GMarkupParser *parser,
463 pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface)
465 iface->add_child = _cell_layout_buildable_add_child;
466 iface->custom_tag_start = _cell_layout_buildable_custom_tag_start;
467 iface->custom_tag_end = _cell_layout_buildable_custom_tag_end;
471 pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface)
473 iface->pack_start = pspp_sheet_view_column_cell_layout_pack_start;
474 iface->pack_end = pspp_sheet_view_column_cell_layout_pack_end;
475 iface->clear = pspp_sheet_view_column_cell_layout_clear;
476 iface->add_attribute = pspp_sheet_view_column_cell_layout_add_attribute;
477 iface->set_cell_data_func = pspp_sheet_view_column_cell_layout_set_cell_data_func;
478 iface->clear_attributes = pspp_sheet_view_column_cell_layout_clear_attributes;
479 iface->reorder = pspp_sheet_view_column_cell_layout_reorder;
480 iface->get_cells = pspp_sheet_view_column_cell_layout_get_cells;
484 pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column)
486 tree_column->button = NULL;
487 tree_column->halign = GTK_ALIGN_START;
488 tree_column->width = 0;
489 tree_column->spacing = 0;
490 tree_column->requested_width = -1;
491 tree_column->min_width = -1;
492 tree_column->max_width = -1;
493 tree_column->resized_width = 0;
494 tree_column->visible = TRUE;
495 tree_column->resizable = FALSE;
496 tree_column->expand = FALSE;
497 tree_column->clickable = FALSE;
498 tree_column->dirty = TRUE;
499 tree_column->selected = FALSE;
500 tree_column->selectable = TRUE;
501 tree_column->row_head = FALSE;
502 tree_column->tabbable = TRUE;
503 tree_column->sort_order = GTK_SORT_ASCENDING;
504 tree_column->show_sort_indicator = FALSE;
505 tree_column->property_changed_signal = 0;
506 tree_column->sort_clicked_signal = 0;
507 tree_column->sort_column_changed_signal = 0;
508 tree_column->sort_column_id = -1;
509 tree_column->reorderable = FALSE;
510 tree_column->maybe_reordered = FALSE;
511 tree_column->fixed_width = 1;
512 tree_column->use_resized_width = FALSE;
513 tree_column->title = g_strdup ("");
514 tree_column->quick_edit = TRUE;
518 pspp_sheet_view_column_finalize (GObject *object)
520 PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
523 for (list = tree_column->cell_list; list; list = list->next)
525 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
529 GDestroyNotify d = info->destroy;
531 info->destroy = NULL;
534 pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
535 g_object_unref (info->cell);
539 g_free (tree_column->title);
540 g_list_free (tree_column->cell_list);
542 if (tree_column->child)
543 g_object_unref (tree_column->child);
545 G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
549 pspp_sheet_view_column_set_property (GObject *object,
554 PsppSheetViewColumn *tree_column;
556 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
561 pspp_sheet_view_column_set_visible (tree_column,
562 g_value_get_boolean (value));
566 pspp_sheet_view_column_set_resizable (tree_column,
567 g_value_get_boolean (value));
570 case PROP_FIXED_WIDTH:
571 pspp_sheet_view_column_set_fixed_width (tree_column,
572 g_value_get_int (value));
576 pspp_sheet_view_column_set_min_width (tree_column,
577 g_value_get_int (value));
581 pspp_sheet_view_column_set_max_width (tree_column,
582 g_value_get_int (value));
586 pspp_sheet_view_column_set_spacing (tree_column,
587 g_value_get_int (value));
591 pspp_sheet_view_column_set_title (tree_column,
592 g_value_get_string (value));
596 pspp_sheet_view_column_set_expand (tree_column,
597 g_value_get_boolean (value));
601 pspp_sheet_view_column_set_clickable (tree_column,
602 g_value_get_boolean (value));
606 pspp_sheet_view_column_set_widget (tree_column,
607 (GtkWidget*) g_value_get_object (value));
611 pspp_sheet_view_column_set_alignment (tree_column,
612 g_value_get_float (value));
615 case PROP_REORDERABLE:
616 pspp_sheet_view_column_set_reorderable (tree_column,
617 g_value_get_boolean (value));
620 case PROP_SORT_INDICATOR:
621 pspp_sheet_view_column_set_sort_indicator (tree_column,
622 g_value_get_boolean (value));
625 case PROP_SORT_ORDER:
626 pspp_sheet_view_column_set_sort_order (tree_column,
627 g_value_get_enum (value));
630 case PROP_SORT_COLUMN_ID:
631 pspp_sheet_view_column_set_sort_column_id (tree_column,
632 g_value_get_int (value));
635 case PROP_QUICK_EDIT:
636 pspp_sheet_view_column_set_quick_edit (tree_column,
637 g_value_get_boolean (value));
641 pspp_sheet_view_column_set_selected (tree_column,
642 g_value_get_boolean (value));
645 case PROP_SELECTABLE:
646 pspp_sheet_view_column_set_selectable (tree_column,
647 g_value_get_boolean (value));
651 pspp_sheet_view_column_set_row_head (tree_column,
652 g_value_get_boolean (value));
656 pspp_sheet_view_column_set_tabbable (tree_column,
657 g_value_get_boolean (value));
661 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
667 pspp_sheet_view_column_get_property (GObject *object,
672 PsppSheetViewColumn *tree_column;
674 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
679 g_value_set_boolean (value,
680 pspp_sheet_view_column_get_visible (tree_column));
684 g_value_set_boolean (value,
685 pspp_sheet_view_column_get_resizable (tree_column));
689 g_value_set_int (value,
690 pspp_sheet_view_column_get_width (tree_column));
694 g_value_set_int (value,
695 pspp_sheet_view_column_get_spacing (tree_column));
698 case PROP_FIXED_WIDTH:
699 g_value_set_int (value,
700 pspp_sheet_view_column_get_fixed_width (tree_column));
704 g_value_set_int (value,
705 pspp_sheet_view_column_get_min_width (tree_column));
709 g_value_set_int (value,
710 pspp_sheet_view_column_get_max_width (tree_column));
714 g_value_set_string (value,
715 pspp_sheet_view_column_get_title (tree_column));
719 g_value_set_boolean (value,
720 pspp_sheet_view_column_get_expand (tree_column));
724 g_value_set_boolean (value,
725 pspp_sheet_view_column_get_clickable (tree_column));
729 g_value_set_object (value,
730 (GObject*) pspp_sheet_view_column_get_widget (tree_column));
734 g_value_set_float (value,
735 pspp_sheet_view_column_get_alignment (tree_column));
738 case PROP_REORDERABLE:
739 g_value_set_boolean (value,
740 pspp_sheet_view_column_get_reorderable (tree_column));
743 case PROP_SORT_INDICATOR:
744 g_value_set_boolean (value,
745 pspp_sheet_view_column_get_sort_indicator (tree_column));
748 case PROP_SORT_ORDER:
749 g_value_set_enum (value,
750 pspp_sheet_view_column_get_sort_order (tree_column));
753 case PROP_SORT_COLUMN_ID:
754 g_value_set_int (value,
755 pspp_sheet_view_column_get_sort_column_id (tree_column));
758 case PROP_QUICK_EDIT:
759 g_value_set_boolean (value,
760 pspp_sheet_view_column_get_quick_edit (tree_column));
764 g_value_set_boolean (value,
765 pspp_sheet_view_column_get_selected (tree_column));
768 case PROP_SELECTABLE:
769 g_value_set_boolean (value,
770 pspp_sheet_view_column_get_selectable (tree_column));
774 g_value_set_boolean (value,
775 pspp_sheet_view_column_get_row_head (tree_column));
779 g_value_set_boolean (value,
780 pspp_sheet_view_column_get_tabbable (tree_column));
784 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
789 /* Implementation of GtkCellLayout interface
793 pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
794 GtkCellRenderer *cell,
797 PsppSheetViewColumn *column;
798 PsppSheetViewColumnCellInfo *cell_info;
800 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
801 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
802 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
804 g_object_ref_sink (cell);
806 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
807 cell_info->cell = cell;
808 cell_info->expand = expand ? TRUE : FALSE;
809 cell_info->pack = GTK_PACK_START;
810 cell_info->has_focus = 0;
811 cell_info->attributes = NULL;
813 column->cell_list = g_list_append (column->cell_list, cell_info);
817 pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
818 GtkCellRenderer *cell,
821 PsppSheetViewColumn *column;
822 PsppSheetViewColumnCellInfo *cell_info;
824 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
825 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
826 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
828 g_object_ref_sink (cell);
830 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
831 cell_info->cell = cell;
832 cell_info->expand = expand ? TRUE : FALSE;
833 cell_info->pack = GTK_PACK_END;
834 cell_info->has_focus = 0;
835 cell_info->attributes = NULL;
837 column->cell_list = g_list_append (column->cell_list, cell_info);
841 pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
843 PsppSheetViewColumn *column;
845 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
846 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
848 while (column->cell_list)
850 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
852 pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
853 g_object_unref (info->cell);
855 column->cell_list = g_list_delete_link (column->cell_list,
861 pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
862 GtkCellRenderer *cell,
863 const gchar *attribute,
866 PsppSheetViewColumn *tree_column;
867 PsppSheetViewColumnCellInfo *info;
869 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
870 tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
872 info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
873 g_return_if_fail (info != NULL);
875 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
876 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
878 if (tree_column->tree_view)
879 _pspp_sheet_view_column_cell_set_dirty (tree_column);
883 pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
884 GtkCellRenderer *cell,
885 GtkCellLayoutDataFunc func,
887 GDestroyNotify destroy)
889 PsppSheetViewColumn *column;
890 PsppSheetViewColumnCellInfo *info;
892 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
893 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
895 info = pspp_sheet_view_column_get_cell_info (column, cell);
896 g_return_if_fail (info != NULL);
900 GDestroyNotify d = info->destroy;
902 info->destroy = NULL;
906 info->func = (PsppSheetCellDataFunc)func;
907 info->func_data = func_data;
908 info->destroy = destroy;
910 if (column->tree_view)
911 _pspp_sheet_view_column_cell_set_dirty (column);
915 pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
916 GtkCellRenderer *cell_renderer)
918 PsppSheetViewColumn *column;
919 PsppSheetViewColumnCellInfo *info;
921 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
922 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
924 info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
926 pspp_sheet_view_column_clear_attributes_by_info (column, info);
930 pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
931 GtkCellRenderer *cell,
935 PsppSheetViewColumn *column;
936 PsppSheetViewColumnCellInfo *info;
938 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
939 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
941 info = pspp_sheet_view_column_get_cell_info (column, cell);
943 g_return_if_fail (info != NULL);
944 g_return_if_fail (position >= 0);
946 link = g_list_find (column->cell_list, info);
948 g_return_if_fail (link != NULL);
950 column->cell_list = g_list_delete_link (column->cell_list, link);
951 column->cell_list = g_list_insert (column->cell_list, info, position);
953 if (column->tree_view)
954 gtk_widget_queue_draw (column->tree_view);
958 pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
959 PsppSheetViewColumnCellInfo *info)
963 list = info->attributes;
965 while (list && list->next)
968 list = list->next->next;
970 g_slist_free (info->attributes);
971 info->attributes = NULL;
973 if (tree_column->tree_view)
974 _pspp_sheet_view_column_cell_set_dirty (tree_column);
978 on_query_tooltip (GtkWidget *widget,
981 gboolean keyboard_mode,
985 PsppSheetViewColumn *tree_column = user_data;
988 g_signal_emit (tree_column, tree_column_signals[QUERY_TOOLTIP], 0,
994 on_button_pressed (GtkWidget *widget, GdkEventButton *event,
997 PsppSheetViewColumn *tree_column = user_data;
1000 /* XXX See "Implement GtkWidget::popup_menu" in GTK+ reference manual. */
1001 g_signal_emit (tree_column, tree_column_signals[BUTTON_PRESS_EVENT],
1002 0, event, &handled);
1009 /* Button handling code
1012 pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
1014 PsppSheetView *tree_view;
1018 tree_view = (PsppSheetView *) tree_column->tree_view;
1020 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1021 g_return_if_fail (tree_column->button == NULL);
1023 tree_column->button = gtk_button_new ();
1024 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
1026 /* make sure we own a reference to it as well. */
1027 if (tree_view->priv->header_window)
1028 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
1029 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
1031 g_signal_connect (tree_column->button, "event",
1032 G_CALLBACK (pspp_sheet_view_column_button_event),
1034 g_signal_connect (tree_column->button, "clicked",
1035 G_CALLBACK (pspp_sheet_view_column_button_clicked),
1037 g_signal_connect (tree_column->button, "popup-menu",
1038 G_CALLBACK (pspp_sheet_view_column_button_popup_menu),
1040 g_signal_connect (tree_column->button, "button-press-event",
1041 G_CALLBACK (on_button_pressed), tree_column);
1043 g_signal_connect (tree_column->button, "query-tooltip",
1044 G_CALLBACK (on_query_tooltip), tree_column);
1045 g_object_set (tree_column->button, "has-tooltip", TRUE, NULL);
1047 tree_column->bin = gtk_event_box_new ();
1048 g_object_set (tree_column->bin, "halign", GTK_ALIGN_CENTER, NULL);
1050 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
1052 if (tree_column->child)
1053 child = tree_column->child;
1056 child = gtk_label_new (tree_column->title);
1057 gtk_widget_show (child);
1060 g_signal_connect (child, "mnemonic-activate",
1061 G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
1065 gtk_box_pack_start (GTK_BOX (hbox), tree_column->bin, TRUE, TRUE, 0);
1067 gtk_container_add (GTK_CONTAINER (tree_column->bin), child);
1068 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
1070 gtk_widget_show (hbox);
1071 gtk_widget_show (tree_column->bin);
1072 pspp_sheet_view_column_update_button (tree_column);
1076 pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
1078 gint sort_column_id = -1;
1079 GtkWidget *alignment;
1080 GtkWidget *current_child;
1081 GtkTreeModel *model;
1084 if (tree_column->tree_view)
1085 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1089 /* Create a button if necessary */
1090 if (tree_column->visible &&
1091 tree_column->button == NULL &&
1092 tree_column->tree_view &&
1093 gtk_widget_get_realized (tree_column->tree_view))
1094 pspp_sheet_view_column_create_button (tree_column);
1096 if (! tree_column->button)
1099 alignment = tree_column->bin;
1100 current_child = gtk_bin_get_child (GTK_BIN (alignment));
1102 /* Set up the actual button */
1103 g_object_set (alignment,
1104 "halign", tree_column->halign,
1105 "valign", GTK_ALIGN_CENTER, NULL);
1107 if (tree_column->child)
1109 if (current_child != tree_column->child)
1111 gtk_container_remove (GTK_CONTAINER (alignment),
1113 gtk_container_add (GTK_CONTAINER (alignment),
1114 tree_column->child);
1119 if (current_child == NULL)
1121 current_child = gtk_label_new (NULL);
1122 gtk_widget_show (current_child);
1123 gtk_container_add (GTK_CONTAINER (alignment),
1127 g_return_if_fail (GTK_IS_LABEL (current_child));
1129 if (tree_column->title)
1130 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1131 tree_column->title);
1133 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1137 if (GTK_IS_TREE_SORTABLE (model))
1138 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1143 /* It's always safe to hide the button. It isn't always safe to show it, as
1144 * if you show it before it's realized, it'll get the wrong window. */
1145 if (tree_column->button &&
1146 tree_column->tree_view != NULL &&
1147 gtk_widget_get_realized (tree_column->tree_view))
1149 if (tree_column->visible)
1151 gtk_widget_show (tree_column->button);
1152 if (tree_column->window)
1154 if (tree_column->resizable)
1156 gdk_window_show (tree_column->window);
1157 gdk_window_raise (tree_column->window);
1161 gdk_window_hide (tree_column->window);
1167 gtk_widget_hide (tree_column->button);
1168 if (tree_column->window)
1169 gdk_window_hide (tree_column->window);
1173 can_focus = pspp_sheet_view_column_can_focus (tree_column);
1174 gtk_widget_set_can_focus (tree_column->button, can_focus);
1175 if (!can_focus && gtk_widget_has_focus (tree_column->button))
1177 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
1178 if (gtk_widget_is_toplevel (toplevel))
1180 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
1184 /* Queue a resize on the assumption that we always want to catch all changes
1185 * and columns don't change all that often.
1187 if (gtk_widget_get_realized (tree_column->tree_view))
1188 gtk_widget_queue_resize (tree_column->tree_view);
1192 /* Button signal handlers
1196 pspp_sheet_view_column_button_event (GtkWidget *widget,
1197 GdkEventButton *event,
1200 PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
1202 g_return_val_if_fail (event != NULL, FALSE);
1204 if (event->type == GDK_BUTTON_PRESS &&
1205 column->reorderable &&
1206 ((GdkEventButton *)event)->button == 1)
1208 column->maybe_reordered = TRUE;
1209 gdk_window_get_device_position (gtk_button_get_event_window (GTK_BUTTON (widget)),
1214 gtk_widget_grab_focus (widget);
1217 if (event->type == GDK_BUTTON_RELEASE ||
1218 event->type == GDK_LEAVE_NOTIFY)
1219 column->maybe_reordered = FALSE;
1221 if (event->type == GDK_MOTION_NOTIFY &&
1222 column->maybe_reordered &&
1223 (gtk_drag_check_threshold (widget,
1226 (gint) ((GdkEventMotion *)event)->x,
1227 (gint) ((GdkEventMotion *)event)->y)))
1229 column->maybe_reordered = FALSE;
1230 _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
1233 if (column->clickable == FALSE)
1235 switch (event->type)
1237 case GDK_MOTION_NOTIFY:
1238 case GDK_BUTTON_RELEASE:
1239 case GDK_ENTER_NOTIFY:
1240 case GDK_LEAVE_NOTIFY:
1250 all_rows_selected (PsppSheetView *sheet_view)
1252 PsppSheetSelection *selection = sheet_view->priv->selection;
1253 gint n_rows, n_selected_rows;
1255 n_rows = sheet_view->priv->row_count;
1256 n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
1258 return n_rows > 0 && n_selected_rows >= n_rows;
1262 on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *column,
1263 GdkEventButton *event)
1265 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (column->tree_view);
1266 PsppSheetSelection *selection;
1267 GSignalInvocationHint *hint;
1270 /* We only want to run first, not last, but combining that with return type
1271 `gboolean' makes GObject warn, so just ignore the run_last call. */
1272 hint = g_signal_get_invocation_hint (column);
1273 g_return_val_if_fail (hint != NULL, FALSE);
1274 if (hint->run_type != G_SIGNAL_RUN_FIRST)
1277 g_return_val_if_fail (sheet_view != NULL, FALSE);
1279 selection = sheet_view->priv->selection;
1280 g_return_val_if_fail (selection != NULL, FALSE);
1282 if (pspp_sheet_selection_get_mode (selection) != PSPP_SHEET_SELECTION_RECTANGLE)
1285 modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
1286 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
1288 if (pspp_sheet_selection_count_selected_columns (selection) <= 1
1289 || !all_rows_selected (sheet_view))
1291 pspp_sheet_selection_select_all (selection);
1292 pspp_sheet_selection_unselect_all_columns (selection);
1293 pspp_sheet_selection_select_column (selection, column);
1294 sheet_view->priv->anchor_column = column;
1298 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1299 && modifiers == GDK_CONTROL_MASK)
1301 gboolean is_selected;
1303 if (!all_rows_selected (sheet_view))
1305 pspp_sheet_selection_select_all (selection);
1306 pspp_sheet_selection_unselect_all_columns (selection);
1308 sheet_view->priv->anchor_column = column;
1310 is_selected = pspp_sheet_view_column_get_selected (column);
1311 pspp_sheet_view_column_set_selected (column, !is_selected);
1315 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1316 && modifiers == GDK_SHIFT_MASK)
1318 if (!all_rows_selected (sheet_view))
1320 pspp_sheet_selection_select_all (selection);
1321 pspp_sheet_selection_unselect_all_columns (selection);
1322 sheet_view->priv->anchor_column = column;
1324 else if (sheet_view->priv->anchor_column == NULL)
1325 sheet_view->priv->anchor_column = column;
1327 pspp_sheet_selection_unselect_all_columns (selection);
1328 pspp_sheet_selection_select_column_range (selection,
1329 sheet_view->priv->anchor_column,
1338 on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *column)
1340 PsppSheetSelection *selection;
1341 PsppSheetView *sheet_view;
1343 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (column));
1344 selection = pspp_sheet_view_get_selection (sheet_view);
1345 if (pspp_sheet_selection_get_mode (selection) == PSPP_SHEET_SELECTION_RECTANGLE)
1347 pspp_sheet_selection_select_all (selection);
1348 if (pspp_sheet_view_column_get_row_head (column))
1349 pspp_sheet_selection_select_all_columns (selection);
1352 pspp_sheet_selection_unselect_all_columns (selection);
1353 pspp_sheet_selection_select_column (selection, column);
1355 sheet_view->priv->anchor_column = column;
1362 pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
1364 PsppSheetViewColumn *column = data;
1367 g_signal_emit (column, tree_column_signals[CLICKED], 0, &handled);
1371 pspp_sheet_view_column_button_popup_menu (GtkWidget *widget, gpointer data)
1373 g_signal_emit_by_name (data, "popup-menu");
1377 pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
1378 gboolean group_cycling,
1381 PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
1383 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
1385 PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
1386 if (column->clickable)
1387 gtk_button_clicked (GTK_BUTTON (column->button));
1388 else if (gtk_widget_get_can_focus (column->button))
1389 gtk_widget_grab_focus (column->button);
1391 gtk_widget_grab_focus (column->tree_view);
1397 pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
1398 PsppSheetViewColumn *column)
1400 gint sort_column_id;
1403 if (gtk_tree_sortable_get_sort_column_id (sortable,
1407 if (sort_column_id == column->sort_column_id)
1409 pspp_sheet_view_column_set_sort_indicator (column, TRUE);
1410 pspp_sheet_view_column_set_sort_order (column, order);
1414 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1419 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1424 pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
1427 gint sort_column_id;
1429 gboolean has_sort_column;
1430 gboolean has_default_sort_func;
1432 g_return_if_fail (tree_column->tree_view != NULL);
1435 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1438 has_default_sort_func =
1439 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
1441 if (has_sort_column &&
1442 sort_column_id == tree_column->sort_column_id)
1444 if (order == GTK_SORT_ASCENDING)
1445 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1446 tree_column->sort_column_id,
1447 GTK_SORT_DESCENDING);
1448 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
1449 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1450 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1451 GTK_SORT_ASCENDING);
1453 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1454 tree_column->sort_column_id,
1455 GTK_SORT_ASCENDING);
1459 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1460 tree_column->sort_column_id,
1461 GTK_SORT_ASCENDING);
1467 pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
1469 GtkTreeModel *model;
1471 if (tree_column->tree_view == NULL)
1474 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1479 if (GTK_IS_TREE_SORTABLE (model) &&
1480 tree_column->sort_column_id != -1)
1482 gint real_sort_column_id;
1483 GtkSortType real_order;
1485 if (tree_column->sort_column_changed_signal == 0)
1486 tree_column->sort_column_changed_signal =
1487 g_signal_connect (model, "sort-column-changed",
1488 G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
1491 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1492 &real_sort_column_id,
1494 (real_sort_column_id == tree_column->sort_column_id))
1496 pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
1497 pspp_sheet_view_column_set_sort_order (tree_column, real_order);
1501 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
1507 /* Exported Private Functions.
1508 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1512 _pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
1514 GtkAllocation allocation;
1515 PsppSheetView *tree_view;
1517 guint attributes_mask;
1520 tree_view = (PsppSheetView *)column->tree_view;
1521 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
1523 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1524 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
1525 g_return_if_fail (tree_view->priv->header_window != NULL);
1526 if (!column->button)
1529 g_return_if_fail (column->button != NULL);
1531 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
1533 if (column->visible)
1534 gtk_widget_show (column->button);
1536 attr.window_type = GDK_WINDOW_CHILD;
1537 attr.wclass = GDK_INPUT_ONLY;
1538 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1539 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
1540 (GDK_BUTTON_PRESS_MASK |
1541 GDK_BUTTON_RELEASE_MASK |
1542 GDK_POINTER_MOTION_MASK |
1543 GDK_POINTER_MOTION_HINT_MASK |
1544 GDK_KEY_PRESS_MASK);
1545 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
1546 attr.cursor = gdk_cursor_new_for_display (gdk_window_get_display (tree_view->priv->header_window),
1547 GDK_SB_H_DOUBLE_ARROW);
1549 attr.width = TREE_VIEW_DRAG_WIDTH;
1550 attr.height = tree_view->priv->header_height;
1551 gtk_widget_get_allocation (column->button, &allocation);
1552 attr.x = (allocation.x + (rtl ? 0 : allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
1553 column->window = gdk_window_new (tree_view->priv->header_window,
1554 &attr, attributes_mask);
1555 gdk_window_set_user_data (column->window, tree_view);
1557 pspp_sheet_view_column_update_button (column);
1559 g_object_unref (attr.cursor);
1563 _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
1565 g_return_if_fail (column != NULL);
1566 if (column->window != NULL)
1568 gdk_window_set_user_data (column->window, NULL);
1569 gdk_window_destroy (column->window);
1570 column->window = NULL;
1575 _pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
1576 GtkTreeModel *old_model)
1578 if (column->sort_column_changed_signal)
1580 g_signal_handler_disconnect (old_model,
1581 column->sort_column_changed_signal);
1582 column->sort_column_changed_signal = 0;
1584 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1588 _pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
1589 PsppSheetView *tree_view)
1591 g_assert (column->tree_view == NULL);
1593 column->tree_view = GTK_WIDGET (tree_view);
1594 pspp_sheet_view_column_create_button (column);
1596 column->property_changed_signal =
1597 g_signal_connect_swapped (tree_view,
1599 G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
1602 pspp_sheet_view_column_setup_sort_column_id_callback (column);
1606 _pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
1608 if (column->tree_view && column->button)
1610 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1612 if (column->property_changed_signal)
1614 g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
1615 column->property_changed_signal = 0;
1618 if (column->sort_column_changed_signal)
1620 g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
1621 column->sort_column_changed_signal);
1622 column->sort_column_changed_signal = 0;
1625 column->tree_view = NULL;
1626 column->button = NULL;
1630 _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
1634 for (list = column->cell_list; list; list = list->next)
1636 GtkCellRendererMode mode;
1637 g_object_get (((PsppSheetViewColumnCellInfo *)list->data)->cell, "mode", &mode, NULL);
1638 if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
1645 /* gets cell being edited */
1647 _pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
1651 for (list = column->cell_list; list; list = list->next)
1652 if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
1653 return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
1659 _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
1664 for (list = column->cell_list; list; list = list->next)
1666 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1668 GtkCellRendererMode mode;
1669 g_object_get (cellinfo->cell, "mode", &mode, NULL);
1671 if ((mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1672 mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
1673 gtk_cell_renderer_get_visible (cellinfo->cell))
1681 _pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
1687 list = pspp_sheet_view_column_cell_first (column);
1688 for (; list; list = pspp_sheet_view_column_cell_next (column, list))
1690 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1691 if (current_x <= x && x <= current_x + cellinfo->real_width)
1692 return cellinfo->cell;
1693 current_x += cellinfo->real_width;
1699 /* Public Functions */
1703 * pspp_sheet_view_column_new:
1705 * Creates a new #PsppSheetViewColumn.
1707 * Return value: A newly created #PsppSheetViewColumn.
1709 PsppSheetViewColumn *
1710 pspp_sheet_view_column_new (void)
1712 PsppSheetViewColumn *tree_column;
1714 tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
1720 * pspp_sheet_view_column_new_with_attributes:
1721 * @title: The title to set the header to.
1722 * @cell: The #GtkCellRenderer.
1723 * @Varargs: A %NULL-terminated list of attributes.
1725 * Creates a new #PsppSheetViewColumn with a number of default values. This is
1726 * equivalent to calling pspp_sheet_view_column_set_title(),
1727 * pspp_sheet_view_column_pack_start(), and
1728 * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
1730 * Here's a simple example:
1732 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1735 * PsppSheetViewColumn *column;
1736 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
1738 * column = pspp_sheet_view_column_new_with_attributes ("Title",
1740 * "text", TEXT_COLUMN,
1741 * "foreground", COLOR_COLUMN,
1746 * Return value: A newly created #PsppSheetViewColumn.
1748 PsppSheetViewColumn *
1749 pspp_sheet_view_column_new_with_attributes (const gchar *title,
1750 GtkCellRenderer *cell,
1753 PsppSheetViewColumn *retval;
1756 retval = pspp_sheet_view_column_new ();
1758 pspp_sheet_view_column_set_title (retval, title);
1759 pspp_sheet_view_column_pack_start (retval, cell, TRUE);
1761 va_start (args, cell);
1762 pspp_sheet_view_column_set_attributesv (retval, cell, args);
1768 static PsppSheetViewColumnCellInfo *
1769 pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
1770 GtkCellRenderer *cell_renderer)
1773 for (list = tree_column->cell_list; list; list = list->next)
1774 if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
1775 return (PsppSheetViewColumnCellInfo *) list->data;
1781 * pspp_sheet_view_column_pack_start:
1782 * @tree_column: A #PsppSheetViewColumn.
1783 * @cell: The #GtkCellRenderer.
1784 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1786 * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
1787 * the @cell is allocated no more space than it needs. Any unused space is divided
1788 * evenly between cells for which @expand is %TRUE.
1791 pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
1792 GtkCellRenderer *cell,
1795 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
1799 * pspp_sheet_view_column_pack_end:
1800 * @tree_column: A #PsppSheetViewColumn.
1801 * @cell: The #GtkCellRenderer.
1802 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1804 * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
1805 * is allocated no more space than it needs. Any unused space is divided
1806 * evenly between cells for which @expand is %TRUE.
1809 pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
1810 GtkCellRenderer *cell,
1813 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
1817 * pspp_sheet_view_column_clear:
1818 * @tree_column: A #PsppSheetViewColumn
1820 * Unsets all the mappings on all renderers on the @tree_column.
1823 pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
1825 gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
1829 pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
1831 PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
1832 GList *retval = NULL, *list;
1834 g_return_val_if_fail (tree_column != NULL, NULL);
1836 for (list = tree_column->cell_list; list; list = list->next)
1838 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
1840 retval = g_list_append (retval, info->cell);
1847 * pspp_sheet_view_column_get_cell_renderers:
1848 * @tree_column: A #PsppSheetViewColumn
1850 * Returns a newly-allocated #GList of all the cell renderers in the column,
1851 * in no particular order. The list must be freed with g_list_free().
1853 * Return value: A list of #GtkCellRenderers
1855 * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
1858 pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
1860 return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
1864 * pspp_sheet_view_column_add_attribute:
1865 * @tree_column: A #PsppSheetViewColumn.
1866 * @cell_renderer: the #GtkCellRenderer to set attributes on
1867 * @attribute: An attribute on the renderer
1868 * @column: The column position on the model to get the attribute from.
1870 * Adds an attribute mapping to the list in @tree_column. The @column is the
1871 * column of the model to get a value from, and the @attribute is the
1872 * parameter on @cell_renderer to be set from the value. So for example
1873 * if column 2 of the model contains strings, you could have the
1874 * "text" attribute of a #GtkCellRendererText get its values from
1878 pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
1879 GtkCellRenderer *cell_renderer,
1880 const gchar *attribute,
1883 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
1884 cell_renderer, attribute, column);
1888 pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
1889 GtkCellRenderer *cell_renderer,
1895 attribute = va_arg (args, gchar *);
1897 pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
1899 while (attribute != NULL)
1901 column = va_arg (args, gint);
1902 pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1903 attribute = va_arg (args, gchar *);
1908 * pspp_sheet_view_column_set_attributes:
1909 * @tree_column: A #PsppSheetViewColumn.
1910 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1911 * @Varargs: A %NULL-terminated list of attributes.
1913 * Sets the attributes in the list as the attributes of @tree_column.
1914 * The attributes should be in attribute/column order, as in
1915 * pspp_sheet_view_column_add_attribute(). All existing attributes
1916 * are removed, and replaced with the new attributes.
1919 pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
1920 GtkCellRenderer *cell_renderer,
1925 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1926 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1927 g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
1929 va_start (args, cell_renderer);
1930 pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
1936 * pspp_sheet_view_column_set_cell_data_func:
1937 * @tree_column: A #PsppSheetViewColumn
1938 * @cell_renderer: A #GtkCellRenderer
1939 * @func: The #PsppSheetViewColumnFunc to use.
1940 * @func_data: The user data for @func.
1941 * @destroy: The destroy notification for @func_data
1943 * Sets the #PsppSheetViewColumnFunc to use for the column. This
1944 * function is used instead of the standard attributes mapping for
1945 * setting the column value, and should set the value of @tree_column's
1946 * cell renderer as appropriate. @func may be %NULL to remove an
1950 pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
1951 GtkCellRenderer *cell_renderer,
1952 PsppSheetCellDataFunc func,
1954 GDestroyNotify destroy)
1956 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
1958 (GtkCellLayoutDataFunc)func,
1959 func_data, destroy);
1964 * pspp_sheet_view_column_clear_attributes:
1965 * @tree_column: a #PsppSheetViewColumn
1966 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1968 * Clears all existing attributes previously set with
1969 * pspp_sheet_view_column_set_attributes().
1972 pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
1973 GtkCellRenderer *cell_renderer)
1975 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
1980 * pspp_sheet_view_column_set_spacing:
1981 * @tree_column: A #PsppSheetViewColumn.
1982 * @spacing: distance between cell renderers in pixels.
1984 * Sets the spacing field of @tree_column, which is the number of pixels to
1985 * place between cell renderers packed into it.
1988 pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
1991 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1992 g_return_if_fail (spacing >= 0);
1994 if (tree_column->spacing == spacing)
1997 tree_column->spacing = spacing;
1998 if (tree_column->tree_view)
1999 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2003 * pspp_sheet_view_column_get_spacing:
2004 * @tree_column: A #PsppSheetViewColumn.
2006 * Returns the spacing of @tree_column.
2008 * Return value: the spacing of @tree_column.
2011 pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
2013 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2015 return tree_column->spacing;
2018 /* Options for manipulating the columns */
2021 * pspp_sheet_view_column_set_visible:
2022 * @tree_column: A #PsppSheetViewColumn.
2023 * @visible: %TRUE if the @tree_column is visible.
2025 * Sets the visibility of @tree_column.
2028 pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
2031 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2033 visible = !! visible;
2035 if (tree_column->visible == visible)
2038 tree_column->visible = visible;
2040 if (tree_column->visible)
2041 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2043 pspp_sheet_view_column_update_button (tree_column);
2044 g_object_notify (G_OBJECT (tree_column), "visible");
2048 * pspp_sheet_view_column_get_visible:
2049 * @tree_column: A #PsppSheetViewColumn.
2051 * Returns %TRUE if @tree_column is visible.
2053 * Return value: whether the column is visible or not. If it is visible, then
2054 * the tree will show the column.
2057 pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
2059 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2061 return tree_column->visible;
2065 * pspp_sheet_view_column_set_resizable:
2066 * @tree_column: A #PsppSheetViewColumn
2067 * @resizable: %TRUE, if the column can be resized
2069 * If @resizable is %TRUE, then the user can explicitly resize the column by
2070 * grabbing the outer edge of the column button.
2073 pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
2076 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2078 resizable = !! resizable;
2080 if (tree_column->resizable == resizable)
2083 tree_column->resizable = resizable;
2085 pspp_sheet_view_column_update_button (tree_column);
2087 g_object_notify (G_OBJECT (tree_column), "resizable");
2091 * pspp_sheet_view_column_get_resizable:
2092 * @tree_column: A #PsppSheetViewColumn
2094 * Returns %TRUE if the @tree_column can be resized by the end user.
2096 * Return value: %TRUE, if the @tree_column can be resized.
2099 pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
2101 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2103 return tree_column->resizable;
2108 * pspp_sheet_view_column_get_width:
2109 * @tree_column: A #PsppSheetViewColumn.
2111 * Returns the current size of @tree_column in pixels.
2113 * Return value: The current width of @tree_column.
2116 pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
2118 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2120 return tree_column->width;
2124 * pspp_sheet_view_column_set_fixed_width:
2125 * @tree_column: A #PsppSheetViewColumn.
2126 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
2128 * Sets the size of the column in pixels. The size of the column is clamped to
2129 * the min/max width for the column. Please note that the min/max width of the
2130 * column doesn't actually affect the "fixed_width" property of the widget, just
2131 * the actual size when displayed.
2134 pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
2137 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2138 g_return_if_fail (fixed_width > 0);
2140 tree_column->fixed_width = fixed_width;
2141 tree_column->use_resized_width = FALSE;
2143 if (tree_column->tree_view &&
2144 gtk_widget_get_realized (tree_column->tree_view))
2146 gtk_widget_queue_resize (tree_column->tree_view);
2149 g_object_notify (G_OBJECT (tree_column), "fixed-width");
2153 * pspp_sheet_view_column_get_fixed_width:
2154 * @tree_column: a #PsppSheetViewColumn
2156 * Gets the fixed width of the column. This value is only meaning may not be
2157 * the actual width of the column on the screen, just what is requested.
2159 * Return value: the fixed width of the column
2162 pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
2164 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2166 return tree_column->fixed_width;
2170 * pspp_sheet_view_column_set_min_width:
2171 * @tree_column: A #PsppSheetViewColumn.
2172 * @min_width: The minimum width of the column in pixels, or -1.
2174 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
2175 * minimum width is unset.
2178 pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
2181 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2182 g_return_if_fail (min_width >= -1);
2184 if (min_width == tree_column->min_width)
2187 if (tree_column->visible &&
2188 tree_column->tree_view != NULL &&
2189 gtk_widget_get_realized (tree_column->tree_view))
2191 if (min_width > tree_column->width)
2192 gtk_widget_queue_resize (tree_column->tree_view);
2195 tree_column->min_width = min_width;
2196 g_object_freeze_notify (G_OBJECT (tree_column));
2197 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
2199 tree_column->max_width = min_width;
2200 g_object_notify (G_OBJECT (tree_column), "max-width");
2202 g_object_notify (G_OBJECT (tree_column), "min-width");
2203 g_object_thaw_notify (G_OBJECT (tree_column));
2207 * pspp_sheet_view_column_get_min_width:
2208 * @tree_column: A #PsppSheetViewColumn.
2210 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
2213 * Return value: The minimum width of the @tree_column.
2216 pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
2218 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2220 return tree_column->min_width;
2224 * pspp_sheet_view_column_set_max_width:
2225 * @tree_column: A #PsppSheetViewColumn.
2226 * @max_width: The maximum width of the column in pixels, or -1.
2228 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
2229 * maximum width is unset. Note, the column can actually be wider than max
2230 * width if it's the last column in a view. In this case, the column expands to
2231 * fill any extra space.
2234 pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
2237 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2238 g_return_if_fail (max_width >= -1);
2240 if (max_width == tree_column->max_width)
2243 if (tree_column->visible &&
2244 tree_column->tree_view != NULL &&
2245 gtk_widget_get_realized (tree_column->tree_view))
2247 if (max_width != -1 && max_width < tree_column->width)
2248 gtk_widget_queue_resize (tree_column->tree_view);
2251 tree_column->max_width = max_width;
2252 g_object_freeze_notify (G_OBJECT (tree_column));
2253 if (max_width != -1 && max_width < tree_column->min_width)
2255 tree_column->min_width = max_width;
2256 g_object_notify (G_OBJECT (tree_column), "min-width");
2258 g_object_notify (G_OBJECT (tree_column), "max-width");
2259 g_object_thaw_notify (G_OBJECT (tree_column));
2263 * pspp_sheet_view_column_get_max_width:
2264 * @tree_column: A #PsppSheetViewColumn.
2266 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
2269 * Return value: The maximum width of the @tree_column.
2272 pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
2274 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2276 return tree_column->max_width;
2280 * pspp_sheet_view_column_clicked:
2281 * @tree_column: a #PsppSheetViewColumn
2283 * Emits the "clicked" signal on the column. This function will only work if
2284 * @tree_column is clickable.
2287 pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
2289 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2291 if (tree_column->visible &&
2292 tree_column->button &&
2293 tree_column->clickable)
2294 gtk_button_clicked (GTK_BUTTON (tree_column->button));
2298 * pspp_sheet_view_column_set_title:
2299 * @tree_column: A #PsppSheetViewColumn.
2300 * @title: The title of the @tree_column.
2302 * Sets the title of the @tree_column. If a custom widget has been set, then
2303 * this value is ignored.
2306 pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
2311 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2313 new_title = g_strdup (title);
2314 g_free (tree_column->title);
2315 tree_column->title = new_title;
2317 pspp_sheet_view_column_update_button (tree_column);
2318 g_object_notify (G_OBJECT (tree_column), "title");
2322 * pspp_sheet_view_column_get_title:
2323 * @tree_column: A #PsppSheetViewColumn.
2325 * Returns the title of the widget.
2327 * Return value: the title of the column. This string should not be
2328 * modified or freed.
2331 pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
2333 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2335 return tree_column->title;
2339 * pspp_sheet_view_column_set_expand:
2340 * @tree_column: A #PsppSheetViewColumn
2341 * @expand: %TRUE if the column should take available extra space, %FALSE if not
2343 * Sets the column to take available extra space. This space is shared equally
2344 * amongst all columns that have the expand set to %TRUE. If no column has this
2345 * option set, then the last column gets all extra space. By default, every
2346 * column is created with this %FALSE.
2351 pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
2354 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2357 if (tree_column->expand == expand)
2359 tree_column->expand = expand;
2361 if (tree_column->visible &&
2362 tree_column->tree_view != NULL &&
2363 gtk_widget_get_realized (tree_column->tree_view))
2365 /* We want to continue using the original width of the
2366 * column that includes additional space added by the user
2367 * resizing the columns and possibly extra (expanded) space, which
2368 * are not included in the resized width.
2370 tree_column->use_resized_width = FALSE;
2372 gtk_widget_queue_resize (tree_column->tree_view);
2375 g_object_notify (G_OBJECT (tree_column), "expand");
2379 * pspp_sheet_view_column_get_expand:
2380 * @tree_column: a #PsppSheetViewColumn
2382 * Return %TRUE if the column expands to take any available space.
2384 * Return value: %TRUE, if the column expands
2389 pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
2391 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2393 return tree_column->expand;
2397 * pspp_sheet_view_column_set_clickable:
2398 * @tree_column: A #PsppSheetViewColumn.
2399 * @clickable: %TRUE if the header is active.
2401 * Sets the header to be active if @active is %TRUE. When the header is active,
2402 * then it can take keyboard focus, and can be clicked.
2405 pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
2408 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2410 clickable = !! clickable;
2411 if (tree_column->clickable == clickable)
2414 tree_column->clickable = clickable;
2415 pspp_sheet_view_column_update_button (tree_column);
2416 g_object_notify (G_OBJECT (tree_column), "clickable");
2420 * pspp_sheet_view_column_get_clickable:
2421 * @tree_column: a #PsppSheetViewColumn
2423 * Returns %TRUE if the user can click on the header for the column.
2425 * Return value: %TRUE if user can click the column header.
2428 pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
2430 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2432 return tree_column->clickable;
2436 * pspp_sheet_view_column_set_widget:
2437 * @tree_column: A #PsppSheetViewColumn.
2438 * @widget: (allow-none): A child #GtkWidget, or %NULL.
2440 * Sets the widget in the header to be @widget. If widget is %NULL, then the
2441 * header button is set with a #GtkLabel set to the title of @tree_column.
2444 pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
2447 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2448 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
2451 g_object_ref_sink (widget);
2453 if (tree_column->child)
2454 g_object_unref (tree_column->child);
2456 tree_column->child = widget;
2457 pspp_sheet_view_column_update_button (tree_column);
2458 g_object_notify (G_OBJECT (tree_column), "widget");
2462 * pspp_sheet_view_column_get_widget:
2463 * @tree_column: A #PsppSheetViewColumn.
2465 * Returns the #GtkWidget in the button on the column header. If a custom
2466 * widget has not been set then %NULL is returned.
2468 * Return value: The #GtkWidget in the column header, or %NULL
2471 pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
2473 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2475 return tree_column->child;
2479 * pspp_sheet_view_column_set_alignment:
2480 * @tree_column: A #PsppSheetViewColumn.
2481 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2483 * Sets the alignment of the title or custom widget inside the column header.
2484 * The alignment determines its location inside the button.
2487 pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
2490 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2493 if (tree_column->halign == xalign)
2496 tree_column->halign = xalign;
2497 pspp_sheet_view_column_update_button (tree_column);
2498 g_object_notify (G_OBJECT (tree_column), "alignment");
2502 * pspp_sheet_view_column_get_alignment:
2503 * @tree_column: A #PsppSheetViewColumn.
2505 * Returns the current x alignment of @tree_column.
2507 * Return value: The current alignent of @tree_column.
2510 pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
2512 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), GTK_ALIGN_CENTER);
2514 return tree_column->halign;
2519 * pspp_sheet_view_column_set_reorderable:
2520 * @tree_column: A #PsppSheetViewColumn
2521 * @reorderable: %TRUE, if the column can be reordered.
2523 * If @reorderable is %TRUE, then the column can be reordered by the end user
2524 * dragging the header.
2527 pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
2528 gboolean reorderable)
2530 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2533 pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
2535 reorderable = !!reorderable;
2536 if (tree_column->reorderable == reorderable)
2539 tree_column->reorderable = reorderable;
2540 pspp_sheet_view_column_update_button (tree_column);
2541 g_object_notify (G_OBJECT (tree_column), "reorderable");
2545 * pspp_sheet_view_column_get_reorderable:
2546 * @tree_column: A #PsppSheetViewColumn
2548 * Returns %TRUE if the @tree_column can be reordered by the user.
2550 * Return value: %TRUE if the @tree_column can be reordered by the user.
2553 pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
2555 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2557 return tree_column->reorderable;
2561 * pspp_sheet_view_column_set_quick_edit:
2562 * @tree_column: A #PsppSheetViewColumn
2563 * @quick_edit: If true, editing starts upon the first click in the column. If
2564 * false, the first click selects the column and a second click is needed to
2565 * begin editing. This has no effect on cells that are not editable.
2568 pspp_sheet_view_column_set_quick_edit (PsppSheetViewColumn *tree_column,
2569 gboolean quick_edit)
2571 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2573 quick_edit = !!quick_edit;
2574 if (tree_column->quick_edit != quick_edit)
2576 tree_column->quick_edit = quick_edit;
2577 g_object_notify (G_OBJECT (tree_column), "quick-edit");
2582 * pspp_sheet_view_column_get_quick_edit:
2583 * @tree_column: A #PsppSheetViewColumn
2585 * Returns %TRUE if editing starts upon the first click in the column. Returns
2586 * %FALSE, the first click selects the column and a second click is needed to
2587 * begin editing. This is not meaningful for cells that are not editable.
2589 * Return value: %TRUE if editing starts upon the first click.
2592 pspp_sheet_view_column_get_quick_edit (PsppSheetViewColumn *tree_column)
2594 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2596 return tree_column->quick_edit;
2601 * pspp_sheet_view_column_set_selected:
2602 * @tree_column: A #PsppSheetViewColumn
2603 * @selected: If true, the column is selected as part of a rectangular
2607 pspp_sheet_view_column_set_selected (PsppSheetViewColumn *tree_column,
2610 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2612 selected = !!selected;
2613 if (tree_column->selected != selected)
2615 PsppSheetSelection *selection;
2616 PsppSheetView *sheet_view;
2618 if (tree_column->tree_view != NULL)
2619 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2620 tree_column->selected = selected;
2621 g_object_notify (G_OBJECT (tree_column), "selected");
2623 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
2625 selection = pspp_sheet_view_get_selection (sheet_view);
2626 _pspp_sheet_selection_emit_changed (selection);
2631 * pspp_sheet_view_column_get_selected:
2632 * @tree_column: A #PsppSheetViewColumn
2634 * Returns %TRUE if the column is selected as part of a rectangular
2637 * Return value: %TRUE if the column is selected as part of a rectangular
2641 pspp_sheet_view_column_get_selected (PsppSheetViewColumn *tree_column)
2643 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2645 return tree_column->selected;
2649 * pspp_sheet_view_column_set_selectable:
2650 * @tree_column: A #PsppSheetViewColumn
2651 * @selectable: If true, the column may be selected as part of a rectangular
2655 pspp_sheet_view_column_set_selectable (PsppSheetViewColumn *tree_column,
2656 gboolean selectable)
2658 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2660 selectable = !!selectable;
2661 if (tree_column->selectable != selectable)
2663 if (tree_column->tree_view != NULL)
2664 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2665 tree_column->selectable = selectable;
2666 g_object_notify (G_OBJECT (tree_column), "selectable");
2671 * pspp_sheet_view_column_get_selectable:
2672 * @tree_column: A #PsppSheetViewColumn
2674 * Returns %TRUE if the column may be selected as part of a rectangular
2677 * Return value: %TRUE if the column may be selected as part of a rectangular
2681 pspp_sheet_view_column_get_selectable (PsppSheetViewColumn *tree_column)
2683 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2685 return tree_column->selectable;
2690 * pspp_sheet_view_column_set_row_head:
2691 * @tree_column: A #PsppSheetViewColumn
2692 * @row_head: If true, the column is a "row head", analogous to a column head.
2693 * See the description of the row-head property for more information.
2696 pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column,
2699 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2701 row_head = !!row_head;
2702 if (tree_column->row_head != row_head)
2704 tree_column->row_head = row_head;
2705 g_object_notify (G_OBJECT (tree_column), "row_head");
2710 * pspp_sheet_view_column_get_row_head:
2711 * @tree_column: A #PsppSheetViewColumn
2713 * Returns %TRUE if the column is a row head.
2715 * Return value: %TRUE if the column is a row head.
2718 pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column)
2720 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2722 return tree_column->row_head;
2727 * pspp_sheet_view_column_set_tabbable:
2728 * @tree_column: A #PsppSheetViewColumn
2729 * @tabbable: If true, the column is "tabbable", meaning that Tab and Shift+Tab
2730 * in the sheet visit this column. If false, Tab and Shift+Tab skip this
2734 pspp_sheet_view_column_set_tabbable (PsppSheetViewColumn *tree_column,
2737 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2739 tabbable = !!tabbable;
2740 if (tree_column->tabbable != tabbable)
2742 tree_column->tabbable = tabbable;
2743 g_object_notify (G_OBJECT (tree_column), "tabbable");
2748 * pspp_sheet_view_column_get_tabbable:
2749 * @tree_column: A #PsppSheetViewColumn
2751 * Returns %TRUE if the column is tabbable.
2753 * Return value: %TRUE if the column is tabbable.
2756 pspp_sheet_view_column_get_tabbable (PsppSheetViewColumn *tree_column)
2758 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2760 return tree_column->tabbable;
2765 * pspp_sheet_view_column_set_sort_column_id:
2766 * @tree_column: a #PsppSheetViewColumn
2767 * @sort_column_id: The @sort_column_id of the model to sort on.
2769 * Sets the logical @sort_column_id that this column sorts on when this column
2770 * is selected for sorting. Doing so makes the column header clickable.
2773 pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
2774 gint sort_column_id)
2776 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2777 g_return_if_fail (sort_column_id >= -1);
2779 if (tree_column->sort_column_id == sort_column_id)
2782 tree_column->sort_column_id = sort_column_id;
2784 /* Handle unsetting the id */
2785 if (sort_column_id == -1)
2787 GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
2789 if (tree_column->sort_clicked_signal)
2791 g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
2792 tree_column->sort_clicked_signal = 0;
2795 if (tree_column->sort_column_changed_signal)
2797 g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
2798 tree_column->sort_column_changed_signal = 0;
2801 pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2802 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
2803 pspp_sheet_view_column_set_clickable (tree_column, FALSE);
2804 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2808 pspp_sheet_view_column_set_clickable (tree_column, TRUE);
2810 if (! tree_column->sort_clicked_signal)
2811 tree_column->sort_clicked_signal = g_signal_connect (tree_column,
2813 G_CALLBACK (pspp_sheet_view_column_sort),
2816 pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
2817 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2821 * pspp_sheet_view_column_get_sort_column_id:
2822 * @tree_column: a #PsppSheetViewColumn
2824 * Gets the logical @sort_column_id that the model sorts on when this
2825 * column is selected for sorting.
2826 * See pspp_sheet_view_column_set_sort_column_id().
2828 * Return value: the current @sort_column_id for this column, or -1 if
2829 * this column can't be used for sorting.
2832 pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
2834 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2836 return tree_column->sort_column_id;
2840 * pspp_sheet_view_column_set_sort_indicator:
2841 * @tree_column: a #PsppSheetViewColumn
2842 * @setting: %TRUE to display an indicator that the column is sorted
2844 * Call this function with a @setting of %TRUE to display an arrow in
2845 * the header button indicating the column is sorted. Call
2846 * pspp_sheet_view_column_set_sort_order() to change the direction of
2851 pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
2854 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2856 setting = setting != FALSE;
2858 if (setting == tree_column->show_sort_indicator)
2861 tree_column->show_sort_indicator = setting;
2862 pspp_sheet_view_column_update_button (tree_column);
2863 g_object_notify (G_OBJECT (tree_column), "sort-indicator");
2867 * pspp_sheet_view_column_get_sort_indicator:
2868 * @tree_column: a #PsppSheetViewColumn
2870 * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
2872 * Return value: whether the sort indicator arrow is displayed
2875 pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column)
2877 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2879 return tree_column->show_sort_indicator;
2883 * pspp_sheet_view_column_set_sort_order:
2884 * @tree_column: a #PsppSheetViewColumn
2885 * @order: sort order that the sort indicator should indicate
2887 * Changes the appearance of the sort indicator.
2889 * This <emphasis>does not</emphasis> actually sort the model. Use
2890 * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
2891 * support. This function is primarily for custom sorting behavior, and should
2892 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2893 * that. For custom models, the mechanism will vary.
2895 * The sort indicator changes direction to indicate normal sort or reverse sort.
2896 * Note that you must have the sort indicator enabled to see anything when
2897 * calling this function; see pspp_sheet_view_column_set_sort_indicator().
2900 pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
2903 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2905 if (order == tree_column->sort_order)
2908 tree_column->sort_order = order;
2909 pspp_sheet_view_column_update_button (tree_column);
2910 g_object_notify (G_OBJECT (tree_column), "sort-order");
2914 * pspp_sheet_view_column_get_sort_order:
2915 * @tree_column: a #PsppSheetViewColumn
2917 * Gets the value set by pspp_sheet_view_column_set_sort_order().
2919 * Return value: the sort order the sort indicator is indicating
2922 pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column)
2924 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2926 return tree_column->sort_order;
2930 * pspp_sheet_view_column_cell_set_cell_data:
2931 * @tree_column: A #PsppSheetViewColumn.
2932 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2933 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2935 * Sets the cell renderer based on the @tree_model and @iter. That is, for
2936 * every attribute mapping in @tree_column, it will get a value from the set
2937 * column on the @iter, and use that value to set the attribute on the cell
2938 * renderer. This is used primarily by the #PsppSheetView.
2941 pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
2942 GtkTreeModel *tree_model,
2946 GValue value = { 0, };
2949 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2951 if (tree_model == NULL)
2954 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2956 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
2957 GObject *cell = (GObject *) info->cell;
2959 list = info->attributes;
2961 g_object_freeze_notify (cell);
2963 while (list && list->next)
2965 gtk_tree_model_get_value (tree_model, iter,
2966 GPOINTER_TO_INT (list->next->data),
2968 g_object_set_property (cell, (gchar *) list->data, &value);
2969 g_value_unset (&value);
2970 list = list->next->next;
2974 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2975 g_object_thaw_notify (G_OBJECT (info->cell));
2981 * pspp_sheet_view_column_cell_get_size:
2982 * @tree_column: A #PsppSheetViewColumn.
2983 * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
2984 * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
2985 * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
2986 * @width: (allow-none): location to return width needed to render a cell, or %NULL
2987 * @height: (allow-none): location to return height needed to render a cell, or %NULL
2989 * Obtains the width and height needed to render the column. This is used
2990 * primarily by the #PsppSheetView.
2993 pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
2994 const GdkRectangle *cell_area,
3001 gboolean first_cell = TRUE;
3002 gint focus_line_width;
3004 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3011 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
3013 for (list = tree_column->cell_list; list; list = list->next)
3015 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3017 gint new_height = 0;
3019 g_object_get (info->cell, "visible", &visible, NULL);
3021 if (visible == FALSE)
3024 if (first_cell == FALSE && width)
3025 *width += tree_column->spacing;
3027 gtk_cell_renderer_get_padding (info->cell, x_offset, y_offset);
3028 gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
3031 gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
3036 * height = MAX (*height, new_height + focus_line_width * 2);
3037 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
3039 * width += info->requested_width;
3044 /* rendering, event handling and rendering focus are somewhat complicated, and
3045 * quite a bit of code. Rather than duplicate them, we put them together to
3046 * keep the code in one place.
3048 * To better understand what's going on, check out
3049 * docs/tree-column-sizing.png
3058 pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn *tree_column,
3060 const GdkRectangle *background_area,
3061 const GdkRectangle *cell_area,
3064 GdkRectangle *focus_rectangle, /* FOCUS */
3065 GtkCellEditable **editable_widget, /* EVENT */
3066 GdkEvent *event, /* EVENT */
3067 gchar *path_string) /* EVENT */
3070 GdkRectangle real_cell_area;
3071 GdkRectangle real_background_area;
3073 gint expand_cell_count = 0;
3074 gint full_requested_width = 0;
3076 gint min_x, min_y, max_x, max_y;
3077 gint focus_line_width;
3079 gint horizontal_separator;
3080 gboolean cursor_row = FALSE;
3081 gboolean first_cell = TRUE;
3083 /* If we have rtl text, we need to transform our areas */
3084 GdkRectangle rtl_cell_area;
3085 GdkRectangle rtl_background_area;
3092 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
3093 special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
3095 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
3097 PsppSheetViewColumnCellInfo *info = NULL;
3098 gboolean found_has_focus = FALSE;
3100 /* one should have focus */
3101 for (list = tree_column->cell_list; list; list = list->next)
3104 if (info && info->has_focus)
3106 found_has_focus = TRUE;
3111 if (!found_has_focus)
3113 /* give the first one focus */
3114 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3115 info->has_focus = TRUE;
3119 cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
3121 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3122 "focus-line-width", &focus_line_width,
3123 "horizontal-separator", &horizontal_separator,
3126 real_cell_area = *cell_area;
3127 real_background_area = *background_area;
3130 real_cell_area.x += focus_line_width;
3131 real_cell_area.y += focus_line_width;
3132 real_cell_area.height -= 2 * focus_line_width;
3135 depth = real_background_area.width - real_cell_area.width;
3137 depth = real_cell_area.x - real_background_area.x;
3139 /* Find out how much extra space we have to allocate */
3140 for (list = tree_column->cell_list; list; list = list->next)
3142 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
3144 if (! gtk_cell_renderer_get_visible (info->cell))
3147 if (info->expand == TRUE)
3148 expand_cell_count ++;
3149 full_requested_width += info->requested_width;
3152 full_requested_width += tree_column->spacing;
3157 extra_space = cell_area->width - full_requested_width;
3158 if (extra_space < 0)
3160 else if (extra_space > 0 && expand_cell_count > 0)
3161 extra_space /= expand_cell_count;
3163 /* iterate list for GTK_PACK_START cells */
3164 for (list = tree_column->cell_list; list; list = list->next)
3166 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3168 if (info->pack == GTK_PACK_END)
3171 if (! gtk_cell_renderer_get_visible (info->cell))
3174 if ((info->has_focus || special_cells == 1) && cursor_row)
3175 flags |= GTK_CELL_RENDERER_FOCUSED;
3177 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3179 info->real_width = info->requested_width + (info->expand?extra_space:0);
3181 /* We constrain ourselves to only the width available */
3182 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3184 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3187 if (real_cell_area.x > cell_area->x + cell_area->width)
3190 real_cell_area.width = info->real_width;
3191 real_cell_area.width -= 2 * focus_line_width;
3195 real_background_area.width = info->real_width + depth;
3199 /* fill the rest of background for the last cell */
3200 real_background_area.width = background_area->x + background_area->width - real_background_area.x;
3203 rtl_cell_area = real_cell_area;
3204 rtl_background_area = real_background_area;
3208 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3209 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3213 if (action == CELL_ACTION_RENDER)
3215 gtk_cell_renderer_render (info->cell,
3217 tree_column->tree_view,
3218 &rtl_background_area,
3223 else if (action == CELL_ACTION_FOCUS)
3225 gint x_offset, y_offset, width, height;
3227 gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
3230 gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
3234 gtk_cell_renderer_get_padding (info->cell,
3235 &x_offset, &y_offset);
3237 if (special_cells > 1)
3239 if (info->has_focus)
3241 min_x = rtl_cell_area.x + x_offset;
3242 max_x = min_x + width;
3243 min_y = rtl_cell_area.y + y_offset;
3244 max_y = min_y + height;
3249 if (min_x > (rtl_cell_area.x + x_offset))
3250 min_x = rtl_cell_area.x + x_offset;
3251 if (max_x < rtl_cell_area.x + x_offset + width)
3252 max_x = rtl_cell_area.x + x_offset + width;
3253 if (min_y > (rtl_cell_area.y + y_offset))
3254 min_y = rtl_cell_area.y + y_offset;
3255 if (max_y < rtl_cell_area.y + y_offset + height)
3256 max_y = rtl_cell_area.y + y_offset + height;
3260 else if (action == CELL_ACTION_EVENT)
3262 gboolean try_event = FALSE;
3266 if (special_cells == 1)
3268 /* only 1 activatable cell -> whole column can activate */
3269 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3270 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3273 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3274 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3275 /* only activate cell if the user clicked on an individual
3280 else if (special_cells > 1 && info->has_focus)
3282 else if (special_cells == 1)
3287 gboolean visible, mode;
3289 g_object_get (info->cell,
3290 "visible", &visible,
3293 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3295 if (gtk_cell_renderer_activate (info->cell,
3297 tree_column->tree_view,
3299 &rtl_background_area,
3303 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3307 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3310 gtk_cell_renderer_start_editing (info->cell,
3312 tree_column->tree_view,
3314 &rtl_background_area,
3318 if (*editable_widget != NULL)
3320 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3321 info->in_editing_mode = TRUE;
3322 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3324 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3332 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3334 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3335 real_background_area.x += real_background_area.width + tree_column->spacing;
3337 /* Only needed for first cell */
3341 /* iterate list for PACK_END cells */
3342 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
3344 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3346 if (info->pack == GTK_PACK_START)
3349 if (! gtk_cell_renderer_get_visible (info->cell))
3352 if ((info->has_focus || special_cells == 1) && cursor_row)
3353 flags |= GTK_CELL_RENDERER_FOCUSED;
3355 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3357 info->real_width = info->requested_width + (info->expand?extra_space:0);
3359 /* We constrain ourselves to only the width available */
3360 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3362 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3365 if (real_cell_area.x > cell_area->x + cell_area->width)
3368 real_cell_area.width = info->real_width;
3369 real_cell_area.width -= 2 * focus_line_width;
3370 real_background_area.width = info->real_width + depth;
3372 rtl_cell_area = real_cell_area;
3373 rtl_background_area = real_background_area;
3376 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3377 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3381 if (action == CELL_ACTION_RENDER)
3383 gtk_cell_renderer_render (info->cell,
3385 tree_column->tree_view,
3386 &rtl_background_area,
3391 else if (action == CELL_ACTION_FOCUS)
3393 gint x_offset, y_offset, width, height;
3395 gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
3398 gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
3402 gtk_cell_renderer_get_padding (info->cell,
3403 &x_offset, &y_offset);
3405 if (special_cells > 1)
3407 if (info->has_focus)
3409 min_x = rtl_cell_area.x + x_offset;
3410 max_x = min_x + width;
3411 min_y = rtl_cell_area.y + y_offset;
3412 max_y = min_y + height;
3417 if (min_x > (rtl_cell_area.x + x_offset))
3418 min_x = rtl_cell_area.x + x_offset;
3419 if (max_x < rtl_cell_area.x + x_offset + width)
3420 max_x = rtl_cell_area.x + x_offset + width;
3421 if (min_y > (rtl_cell_area.y + y_offset))
3422 min_y = rtl_cell_area.y + y_offset;
3423 if (max_y < rtl_cell_area.y + y_offset + height)
3424 max_y = rtl_cell_area.y + y_offset + height;
3428 else if (action == CELL_ACTION_EVENT)
3430 gboolean try_event = FALSE;
3434 if (special_cells == 1)
3436 /* only 1 activatable cell -> whole column can activate */
3437 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3438 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3441 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3442 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3443 /* only activate cell if the user clicked on an individual
3448 else if (special_cells > 1 && info->has_focus)
3450 else if (special_cells == 1)
3455 gboolean visible, mode;
3457 g_object_get (info->cell,
3458 "visible", &visible,
3461 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3463 if (gtk_cell_renderer_activate (info->cell,
3465 tree_column->tree_view,
3467 &rtl_background_area,
3471 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3475 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3478 gtk_cell_renderer_start_editing (info->cell,
3480 tree_column->tree_view,
3482 &rtl_background_area,
3486 if (*editable_widget != NULL)
3488 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3489 info->in_editing_mode = TRUE;
3490 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3492 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3499 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3501 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3502 real_background_area.x += (real_background_area.width + tree_column->spacing);
3504 /* Only needed for first cell */
3508 /* fill focus_rectangle when required */
3509 if (action == CELL_ACTION_FOCUS)
3511 if (min_x >= max_x || min_y >= max_y)
3513 *focus_rectangle = *cell_area;
3514 /* don't change the focus_rectangle, just draw it nicely inside
3519 focus_rectangle->x = min_x - focus_line_width;
3520 focus_rectangle->y = min_y - focus_line_width;
3521 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
3522 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
3530 * pspp_sheet_view_column_cell_render:
3531 * @tree_column: A #PsppSheetViewColumn.
3532 * @window: a #GdkDrawable to draw to
3533 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
3534 * @cell_area: area normally rendered by a cell renderer
3535 * @flags: flags that affect rendering
3537 * Renders the cell contained by #tree_column. This is used primarily by the
3541 _pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
3543 const GdkRectangle *background_area,
3544 const GdkRectangle *cell_area,
3547 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3548 g_return_if_fail (background_area != NULL);
3549 g_return_if_fail (cell_area != NULL);
3551 pspp_sheet_view_column_cell_process_action (tree_column,
3557 NULL, NULL, NULL, NULL);
3561 _pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
3562 GtkCellEditable **editable_widget,
3565 const GdkRectangle *background_area,
3566 const GdkRectangle *cell_area,
3569 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3571 return pspp_sheet_view_column_cell_process_action (tree_column,
3584 _pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
3585 const GdkRectangle *background_area,
3586 const GdkRectangle *cell_area,
3587 GdkRectangle *focus_area)
3589 pspp_sheet_view_column_cell_process_action (tree_column,
3600 /* cell list manipulation */
3602 pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
3604 GList *list = tree_column->cell_list;
3606 /* first GTK_PACK_START cell we find */
3607 for ( ; list; list = list->next)
3609 PsppSheetViewColumnCellInfo *info = list->data;
3610 if (info->pack == GTK_PACK_START)
3614 /* hmm, else the *last* GTK_PACK_END cell */
3615 list = g_list_last (tree_column->cell_list);
3617 for ( ; list; list = list->prev)
3619 PsppSheetViewColumnCellInfo *info = list->data;
3620 if (info->pack == GTK_PACK_END)
3628 pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
3630 GList *list = tree_column->cell_list;
3632 /* *first* GTK_PACK_END cell we find */
3633 for ( ; list ; list = list->next)
3635 PsppSheetViewColumnCellInfo *info = list->data;
3636 if (info->pack == GTK_PACK_END)
3640 /* hmm, else the last GTK_PACK_START cell */
3641 list = g_list_last (tree_column->cell_list);
3643 for ( ; list; list = list->prev)
3645 PsppSheetViewColumnCellInfo *info = list->data;
3646 if (info->pack == GTK_PACK_START)
3655 pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
3659 PsppSheetViewColumnCellInfo *info = current->data;
3661 if (info->pack == GTK_PACK_START)
3663 for (list = current->next; list; list = list->next)
3665 PsppSheetViewColumnCellInfo *inf = list->data;
3666 if (inf->pack == GTK_PACK_START)
3670 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
3671 list = g_list_last (tree_column->cell_list);
3672 for (; list; list = list->prev)
3674 PsppSheetViewColumnCellInfo *inf = list->data;
3675 if (inf->pack == GTK_PACK_END)
3680 for (list = current->prev; list; list = list->prev)
3682 PsppSheetViewColumnCellInfo *inf = list->data;
3683 if (inf->pack == GTK_PACK_END)
3691 pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
3695 PsppSheetViewColumnCellInfo *info = current->data;
3697 if (info->pack == GTK_PACK_END)
3699 for (list = current->next; list; list = list->next)
3701 PsppSheetViewColumnCellInfo *inf = list->data;
3702 if (inf->pack == GTK_PACK_END)
3706 /* out of GTK_PACK_END, get last GTK_PACK_START one */
3707 list = g_list_last (tree_column->cell_list);
3708 for ( ; list; list = list->prev)
3710 PsppSheetViewColumnCellInfo *inf = list->data;
3711 if (inf->pack == GTK_PACK_START)
3716 for (list = current->prev; list; list = list->prev)
3718 PsppSheetViewColumnCellInfo *inf = list->data;
3719 if (inf->pack == GTK_PACK_START)
3727 _pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
3735 count = _pspp_sheet_view_column_count_special_cells (tree_column);
3736 rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
3738 /* if we are the current focus column and have multiple editable cells,
3739 * try to select the next one, else move the focus to the next column
3741 if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
3746 GList *list = tree_column->cell_list;
3747 PsppSheetViewColumnCellInfo *info = NULL;
3749 /* find current focussed cell */
3750 for ( ; list; list = list->next)
3753 if (info->has_focus)
3757 /* not a focussed cell in the focus column? */
3758 if (!list || !info || !info->has_focus)
3763 prev = pspp_sheet_view_column_cell_next (tree_column, list);
3764 next = pspp_sheet_view_column_cell_prev (tree_column, list);
3768 next = pspp_sheet_view_column_cell_next (tree_column, list);
3769 prev = pspp_sheet_view_column_cell_prev (tree_column, list);
3772 info->has_focus = FALSE;
3773 if (direction > 0 && next)
3776 info->has_focus = TRUE;
3779 else if (direction > 0 && !next && !right)
3781 /* keep focus on last cell */
3783 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3785 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3787 info->has_focus = TRUE;
3790 else if (direction < 0 && prev)
3793 info->has_focus = TRUE;
3796 else if (direction < 0 && !prev && !left)
3798 /* keep focus on first cell */
3800 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3802 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3804 info->has_focus = TRUE;
3811 /* we get focus, if we have multiple editable cells, give the correct one
3816 GList *list = tree_column->cell_list;
3818 /* clear focus first */
3819 for ( ; list ; list = list->next)
3821 PsppSheetViewColumnCellInfo *info = list->data;
3822 if (info->has_focus)
3823 info->has_focus = FALSE;
3830 list = pspp_sheet_view_column_cell_last (tree_column);
3831 else if (direction < 0)
3832 list = pspp_sheet_view_column_cell_first (tree_column);
3837 list = pspp_sheet_view_column_cell_first (tree_column);
3838 else if (direction < 0)
3839 list = pspp_sheet_view_column_cell_last (tree_column);
3843 ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
3850 _pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
3852 const GdkRectangle *background_area,
3853 const GdkRectangle *cell_area,
3856 gint focus_line_width;
3857 GtkStateType cell_state;
3859 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3860 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3861 "focus-line-width", &focus_line_width, NULL);
3862 if (tree_column->editable_widget)
3864 /* This function is only called on the editable row when editing.
3867 gtk_paint_focus (tree_column->tree_view->style,
3869 gtk_widget_get_state (tree_column->tree_view),
3871 tree_column->tree_view,
3873 cell_area->x - focus_line_width,
3874 cell_area->y - focus_line_width,
3875 cell_area->width + 2 * focus_line_width,
3876 cell_area->height + 2 * focus_line_width);
3881 GdkRectangle focus_rectangle;
3882 pspp_sheet_view_column_cell_process_action (tree_column,
3891 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3892 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3893 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3895 gtk_paint_focus (gtk_widget_get_style (GTK_WIDGET (tree_column->tree_view)),
3898 tree_column->tree_view,
3902 focus_rectangle.width,
3903 focus_rectangle.height);
3908 * pspp_sheet_view_column_cell_is_visible:
3909 * @tree_column: A #PsppSheetViewColumn
3911 * Returns %TRUE if any of the cells packed into the @tree_column are visible.
3912 * For this to be meaningful, you must first initialize the cells with
3913 * pspp_sheet_view_column_cell_set_cell_data()
3915 * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
3918 pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
3922 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3924 for (list = tree_column->cell_list; list; list = list->next)
3926 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3928 if (gtk_cell_renderer_get_visible (info->cell))
3936 * pspp_sheet_view_column_focus_cell:
3937 * @tree_column: A #PsppSheetViewColumn
3938 * @cell: A #GtkCellRenderer
3940 * Sets the current keyboard focus to be at @cell, if the column contains
3941 * 2 or more editable and activatable cells.
3946 pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
3947 GtkCellRenderer *cell)
3950 gboolean found_cell = FALSE;
3952 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3953 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3955 if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
3958 for (list = tree_column->cell_list; list; list = list->next)
3960 PsppSheetViewColumnCellInfo *info = list->data;
3962 if (info->cell == cell)
3964 info->has_focus = TRUE;
3972 for (list = tree_column->cell_list; list; list = list->next)
3974 PsppSheetViewColumnCellInfo *info = list->data;
3976 if (info->cell != cell)
3977 info->has_focus = FALSE;
3980 /* FIXME: redraw? */
3985 _pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
3989 for (list = tree_column->cell_list; list; list = list->next)
3991 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3993 info->requested_width = 0;
3995 tree_column->dirty = TRUE;
3996 tree_column->requested_width = -1;
3997 tree_column->width = 0;
3999 if (tree_column->tree_view &&
4000 gtk_widget_get_realized (tree_column->tree_view))
4002 _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
4003 gtk_widget_queue_resize (tree_column->tree_view);
4008 _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
4009 GtkCellEditable *cell_editable)
4011 g_return_if_fail (tree_column->editable_widget == NULL);
4013 tree_column->editable_widget = cell_editable;
4017 _pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
4021 g_return_if_fail (tree_column->editable_widget != NULL);
4023 tree_column->editable_widget = NULL;
4024 for (list = tree_column->cell_list; list; list = list->next)
4025 ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
4029 _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
4030 GtkCellRenderer *cell,
4035 PsppSheetViewColumnCellInfo *info;
4041 list = pspp_sheet_view_column_cell_first (column);
4045 info = (PsppSheetViewColumnCellInfo *)list->data;
4047 list = pspp_sheet_view_column_cell_next (column, list);
4049 if (info->cell == cell)
4052 if (gtk_cell_renderer_get_visible (info->cell))
4053 l += info->real_width + column->spacing;
4058 info = (PsppSheetViewColumnCellInfo *)list->data;
4060 list = pspp_sheet_view_column_cell_next (column, list);
4062 if (gtk_cell_renderer_get_visible (info->cell))
4063 r += info->real_width + column->spacing;
4066 rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
4068 *left = rtl ? r : l;
4071 *right = rtl ? l : r;
4075 * pspp_sheet_view_column_cell_get_position:
4076 * @tree_column: a #PsppSheetViewColumn
4077 * @cell_renderer: a #GtkCellRenderer
4078 * @start_pos: return location for the horizontal position of @cell within
4079 * @tree_column, may be %NULL
4080 * @width: return location for the width of @cell, may be %NULL
4082 * Obtains the horizontal position and size of a cell in a column. If the
4083 * cell is not found in the column, @start_pos and @width are not changed and
4084 * %FALSE is returned.
4086 * Return value: %TRUE if @cell belongs to @tree_column.
4089 pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
4090 GtkCellRenderer *cell_renderer,
4096 gboolean found_cell = FALSE;
4097 PsppSheetViewColumnCellInfo *cellinfo = NULL;
4099 list = pspp_sheet_view_column_cell_first (tree_column);
4100 for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
4102 cellinfo = list->data;
4103 if (cellinfo->cell == cell_renderer)
4109 if (gtk_cell_renderer_get_visible (cellinfo->cell))
4110 current_x += cellinfo->real_width;
4116 *start_pos = current_x;
4118 *width = cellinfo->real_width;
4125 * pspp_sheet_view_column_queue_resize:
4126 * @tree_column: A #PsppSheetViewColumn
4128 * Flags the column, and the cell renderers added to this column, to have
4129 * their sizes renegotiated.
4134 pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
4136 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
4138 if (tree_column->tree_view)
4139 _pspp_sheet_view_column_cell_set_dirty (tree_column);
4143 * pspp_sheet_view_column_get_tree_view:
4144 * @tree_column: A #PsppSheetViewColumn
4146 * Returns the #PsppSheetView wherein @tree_column has been inserted. If
4147 * @column is currently not inserted in any tree view, %NULL is
4150 * Return value: The tree view wherein @column has been inserted if any,
4156 pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
4158 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
4160 return tree_column->tree_view;
4164 GtkCellLayout *cell_layout;
4165 GtkCellRenderer *renderer;
4167 } AttributesSubParserData;
4170 attributes_start_element (GMarkupParseContext *context,
4171 const gchar *element_name,
4172 const gchar **names,
4173 const gchar **values,
4177 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4180 if (strcmp (element_name, "attribute") == 0)
4182 for (i = 0; names[i]; i++)
4183 if (strcmp (names[i], "name") == 0)
4184 parser_data->attr_name = g_strdup (values[i]);
4186 else if (strcmp (element_name, "attributes") == 0)
4189 g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
4193 attributes_text_element (GMarkupParseContext *context,
4199 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4204 if (!parser_data->attr_name)
4208 string = g_strndup (text, text_len);
4209 l = strtol (string, &endptr, 0);
4210 if (errno || endptr == string)
4214 GTK_BUILDER_ERROR_INVALID_VALUE,
4215 "Could not parse integer `%s'",
4222 gtk_cell_layout_add_attribute (parser_data->cell_layout,
4223 parser_data->renderer,
4224 parser_data->attr_name, l);
4225 g_free (parser_data->attr_name);
4226 parser_data->attr_name = NULL;
4229 static const GMarkupParser attributes_parser =
4231 attributes_start_element,
4233 attributes_text_element,
4237 _cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
4238 GtkBuilder *builder,
4240 const gchar *tagname,
4241 GMarkupParser *parser,
4244 AttributesSubParserData *parser_data;
4249 if (strcmp (tagname, "attributes") == 0)
4251 parser_data = g_slice_new0 (AttributesSubParserData);
4252 parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
4253 parser_data->renderer = GTK_CELL_RENDERER (child);
4254 parser_data->attr_name = NULL;
4256 *parser = attributes_parser;
4257 *data = parser_data;
4265 _cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
4266 GtkBuilder *builder,
4268 const gchar *tagname,
4271 AttributesSubParserData *parser_data;
4273 parser_data = (AttributesSubParserData*)data;
4274 g_assert (!parser_data->attr_name);
4275 g_slice_free (AttributesSubParserData, parser_data);
4279 _cell_layout_buildable_add_child (GtkBuildable *buildable,
4280 GtkBuilder *builder,
4284 GtkCellLayoutIface *iface;
4286 g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
4287 g_return_if_fail (GTK_IS_CELL_RENDERER (child));
4289 iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
4290 g_return_if_fail (iface->pack_start != NULL);
4291 iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);
4295 pspp_sheet_view_column_size_request (PsppSheetViewColumn *tree_column,
4296 GtkRequisition *request)
4298 GtkWidget *base = GTK_WIDGET (tree_column->tree_view);
4299 GtkRequisition label_req;
4300 GtkRequisition align_req;
4301 GtkRequisition arrow_req;
4302 GtkRequisition hbox_req;
4303 GtkStyle **button_style;
4305 if (tree_column->button)
4307 gtk_widget_get_preferred_size (tree_column->button, NULL, request);
4311 facade_label_get_size_request (0, 0, base, tree_column->title, &label_req);
4312 facade_alignment_get_size_request (0, 0, 0, 0, 0, &label_req, &align_req);
4313 facade_arrow_get_size_request (0, 0, &arrow_req);
4315 facade_hbox_get_base_size_request (0, 2, 2, &hbox_req);
4316 facade_hbox_add_child_size_request (0, &arrow_req, 0, &hbox_req);
4317 facade_hbox_add_child_size_request (0, &align_req, 0, &hbox_req);
4319 button_style = &PSPP_SHEET_VIEW (tree_column->tree_view)->priv->button_style;
4320 if (*button_style == NULL)
4322 *button_style = facade_get_style (base, GTK_TYPE_BUTTON, 0);
4323 g_object_ref (*button_style);
4325 facade_button_get_size_request (0, base, *button_style, &hbox_req, request);
4329 pspp_sheet_view_column_size_allocate (PsppSheetViewColumn *tree_column,
4330 GtkAllocation *allocation)
4332 tree_column->allocation = *allocation;
4333 if (tree_column->button)
4334 gtk_widget_size_allocate (tree_column->button, allocation);
4338 pspp_sheet_view_column_can_focus (PsppSheetViewColumn *tree_column)
4340 return tree_column->reorderable || tree_column->clickable;