1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2011, 2012 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* gtktreeviewcolumn.c
18 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Library General Public
22 * License as published by the Free Software Foundation; either
23 * version 2 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Library General Public License for more details.
30 * You should have received a copy of the GNU Library General Public
31 * License along with this library; if not, write to the
32 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
33 * Boston, MA 02111-1307, USA.
38 #include "ui/gui/pspp-sheet-private.h"
45 #include "ui/gui/psppire-marshal.h"
46 #include "ui/gui/pspp-sheet-selection.h"
47 #include "ui/gui/pspp-widget-facade.h"
49 #define P_(STRING) STRING
50 #define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
51 #define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
88 typedef struct _PsppSheetViewColumnCellInfo PsppSheetViewColumnCellInfo;
89 struct _PsppSheetViewColumnCellInfo
91 GtkCellRenderer *cell;
93 PsppSheetCellDataFunc func;
95 GDestroyNotify destroy;
101 guint in_editing_mode : 1;
105 static void pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface);
107 /* GObject methods */
108 static void pspp_sheet_view_column_set_property (GObject *object,
112 static void pspp_sheet_view_column_get_property (GObject *object,
116 static void pspp_sheet_view_column_finalize (GObject *object);
118 /* GtkCellLayout implementation */
119 static void pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
120 GtkCellRenderer *cell,
122 static void pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
123 GtkCellRenderer *cell,
125 static void pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout);
126 static void pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
127 GtkCellRenderer *cell,
128 const gchar *attribute,
130 static void pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
131 GtkCellRenderer *cell,
132 GtkCellLayoutDataFunc func,
134 GDestroyNotify destroy);
135 static void pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
136 GtkCellRenderer *cell);
137 static void pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
138 GtkCellRenderer *cell,
140 static GList *pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
142 /* Button handling code */
143 static void pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column);
144 void pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
146 /* Button signal handlers */
147 static gint pspp_sheet_view_column_button_event (GtkWidget *widget,
150 static void pspp_sheet_view_column_button_clicked (GtkWidget *widget,
152 static void pspp_sheet_view_column_button_popup_menu (GtkWidget *widget,
154 static gboolean pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
155 gboolean group_cycling,
157 static gboolean on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *);
158 static gboolean on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *,
161 /* Property handlers */
162 static void pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
163 PsppSheetViewColumn *tree_column);
165 /* Internal functions */
166 static void pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
168 static void pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column);
169 static void pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
170 GtkCellRenderer *cell_renderer,
172 static PsppSheetViewColumnCellInfo *pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
173 GtkCellRenderer *cell_renderer);
175 /* cell list manipulation */
176 static GList *pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column);
177 static GList *pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column);
178 static GList *pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
180 static GList *pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
182 static void pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
183 PsppSheetViewColumnCellInfo *info);
184 /* GtkBuildable implementation */
185 static void pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface);
187 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
189 G_DEFINE_TYPE_WITH_CODE (PsppSheetViewColumn, pspp_sheet_view_column, 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->xalign = 0.0;
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;
515 tree_column->need_button = FALSE;
519 pspp_sheet_view_column_finalize (GObject *object)
521 PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
524 for (list = tree_column->cell_list; list; list = list->next)
526 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
530 GDestroyNotify d = info->destroy;
532 info->destroy = NULL;
535 pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
536 g_object_unref (info->cell);
540 g_free (tree_column->title);
541 g_list_free (tree_column->cell_list);
543 if (tree_column->child)
544 g_object_unref (tree_column->child);
546 G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
550 pspp_sheet_view_column_set_property (GObject *object,
555 PsppSheetViewColumn *tree_column;
557 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
562 pspp_sheet_view_column_set_visible (tree_column,
563 g_value_get_boolean (value));
567 pspp_sheet_view_column_set_resizable (tree_column,
568 g_value_get_boolean (value));
571 case PROP_FIXED_WIDTH:
572 pspp_sheet_view_column_set_fixed_width (tree_column,
573 g_value_get_int (value));
577 pspp_sheet_view_column_set_min_width (tree_column,
578 g_value_get_int (value));
582 pspp_sheet_view_column_set_max_width (tree_column,
583 g_value_get_int (value));
587 pspp_sheet_view_column_set_spacing (tree_column,
588 g_value_get_int (value));
592 pspp_sheet_view_column_set_title (tree_column,
593 g_value_get_string (value));
597 pspp_sheet_view_column_set_expand (tree_column,
598 g_value_get_boolean (value));
602 pspp_sheet_view_column_set_clickable (tree_column,
603 g_value_get_boolean (value));
607 pspp_sheet_view_column_set_widget (tree_column,
608 (GtkWidget*) g_value_get_object (value));
612 pspp_sheet_view_column_set_alignment (tree_column,
613 g_value_get_float (value));
616 case PROP_REORDERABLE:
617 pspp_sheet_view_column_set_reorderable (tree_column,
618 g_value_get_boolean (value));
621 case PROP_SORT_INDICATOR:
622 pspp_sheet_view_column_set_sort_indicator (tree_column,
623 g_value_get_boolean (value));
626 case PROP_SORT_ORDER:
627 pspp_sheet_view_column_set_sort_order (tree_column,
628 g_value_get_enum (value));
631 case PROP_SORT_COLUMN_ID:
632 pspp_sheet_view_column_set_sort_column_id (tree_column,
633 g_value_get_int (value));
636 case PROP_QUICK_EDIT:
637 pspp_sheet_view_column_set_quick_edit (tree_column,
638 g_value_get_boolean (value));
642 pspp_sheet_view_column_set_selected (tree_column,
643 g_value_get_boolean (value));
646 case PROP_SELECTABLE:
647 pspp_sheet_view_column_set_selectable (tree_column,
648 g_value_get_boolean (value));
652 pspp_sheet_view_column_set_row_head (tree_column,
653 g_value_get_boolean (value));
657 pspp_sheet_view_column_set_tabbable (tree_column,
658 g_value_get_boolean (value));
662 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
668 pspp_sheet_view_column_get_property (GObject *object,
673 PsppSheetViewColumn *tree_column;
675 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
680 g_value_set_boolean (value,
681 pspp_sheet_view_column_get_visible (tree_column));
685 g_value_set_boolean (value,
686 pspp_sheet_view_column_get_resizable (tree_column));
690 g_value_set_int (value,
691 pspp_sheet_view_column_get_width (tree_column));
695 g_value_set_int (value,
696 pspp_sheet_view_column_get_spacing (tree_column));
699 case PROP_FIXED_WIDTH:
700 g_value_set_int (value,
701 pspp_sheet_view_column_get_fixed_width (tree_column));
705 g_value_set_int (value,
706 pspp_sheet_view_column_get_min_width (tree_column));
710 g_value_set_int (value,
711 pspp_sheet_view_column_get_max_width (tree_column));
715 g_value_set_string (value,
716 pspp_sheet_view_column_get_title (tree_column));
720 g_value_set_boolean (value,
721 pspp_sheet_view_column_get_expand (tree_column));
725 g_value_set_boolean (value,
726 pspp_sheet_view_column_get_clickable (tree_column));
730 g_value_set_object (value,
731 (GObject*) pspp_sheet_view_column_get_widget (tree_column));
735 g_value_set_float (value,
736 pspp_sheet_view_column_get_alignment (tree_column));
739 case PROP_REORDERABLE:
740 g_value_set_boolean (value,
741 pspp_sheet_view_column_get_reorderable (tree_column));
744 case PROP_SORT_INDICATOR:
745 g_value_set_boolean (value,
746 pspp_sheet_view_column_get_sort_indicator (tree_column));
749 case PROP_SORT_ORDER:
750 g_value_set_enum (value,
751 pspp_sheet_view_column_get_sort_order (tree_column));
754 case PROP_SORT_COLUMN_ID:
755 g_value_set_int (value,
756 pspp_sheet_view_column_get_sort_column_id (tree_column));
759 case PROP_QUICK_EDIT:
760 g_value_set_boolean (value,
761 pspp_sheet_view_column_get_quick_edit (tree_column));
765 g_value_set_boolean (value,
766 pspp_sheet_view_column_get_selected (tree_column));
769 case PROP_SELECTABLE:
770 g_value_set_boolean (value,
771 pspp_sheet_view_column_get_selectable (tree_column));
775 g_value_set_boolean (value,
776 pspp_sheet_view_column_get_row_head (tree_column));
780 g_value_set_boolean (value,
781 pspp_sheet_view_column_get_tabbable (tree_column));
785 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
790 /* Implementation of GtkCellLayout interface
794 pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
795 GtkCellRenderer *cell,
798 PsppSheetViewColumn *column;
799 PsppSheetViewColumnCellInfo *cell_info;
801 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
802 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
803 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
805 g_object_ref_sink (cell);
807 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
808 cell_info->cell = cell;
809 cell_info->expand = expand ? TRUE : FALSE;
810 cell_info->pack = GTK_PACK_START;
811 cell_info->has_focus = 0;
812 cell_info->attributes = NULL;
814 column->cell_list = g_list_append (column->cell_list, cell_info);
818 pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
819 GtkCellRenderer *cell,
822 PsppSheetViewColumn *column;
823 PsppSheetViewColumnCellInfo *cell_info;
825 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
826 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
827 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
829 g_object_ref_sink (cell);
831 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
832 cell_info->cell = cell;
833 cell_info->expand = expand ? TRUE : FALSE;
834 cell_info->pack = GTK_PACK_END;
835 cell_info->has_focus = 0;
836 cell_info->attributes = NULL;
838 column->cell_list = g_list_append (column->cell_list, cell_info);
842 pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
844 PsppSheetViewColumn *column;
846 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
847 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
849 while (column->cell_list)
851 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
853 pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
854 g_object_unref (info->cell);
856 column->cell_list = g_list_delete_link (column->cell_list,
862 pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
863 GtkCellRenderer *cell,
864 const gchar *attribute,
867 PsppSheetViewColumn *tree_column;
868 PsppSheetViewColumnCellInfo *info;
870 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
871 tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
873 info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
874 g_return_if_fail (info != NULL);
876 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
877 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
879 if (tree_column->tree_view)
880 _pspp_sheet_view_column_cell_set_dirty (tree_column);
884 pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
885 GtkCellRenderer *cell,
886 GtkCellLayoutDataFunc func,
888 GDestroyNotify destroy)
890 PsppSheetViewColumn *column;
891 PsppSheetViewColumnCellInfo *info;
893 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
894 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
896 info = pspp_sheet_view_column_get_cell_info (column, cell);
897 g_return_if_fail (info != NULL);
901 GDestroyNotify d = info->destroy;
903 info->destroy = NULL;
907 info->func = (PsppSheetCellDataFunc)func;
908 info->func_data = func_data;
909 info->destroy = destroy;
911 if (column->tree_view)
912 _pspp_sheet_view_column_cell_set_dirty (column);
916 pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
917 GtkCellRenderer *cell_renderer)
919 PsppSheetViewColumn *column;
920 PsppSheetViewColumnCellInfo *info;
922 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
923 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
925 info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
927 pspp_sheet_view_column_clear_attributes_by_info (column, info);
931 pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
932 GtkCellRenderer *cell,
936 PsppSheetViewColumn *column;
937 PsppSheetViewColumnCellInfo *info;
939 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
940 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
942 info = pspp_sheet_view_column_get_cell_info (column, cell);
944 g_return_if_fail (info != NULL);
945 g_return_if_fail (position >= 0);
947 link = g_list_find (column->cell_list, info);
949 g_return_if_fail (link != NULL);
951 column->cell_list = g_list_delete_link (column->cell_list, link);
952 column->cell_list = g_list_insert (column->cell_list, info, position);
954 if (column->tree_view)
955 gtk_widget_queue_draw (column->tree_view);
959 pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
960 PsppSheetViewColumnCellInfo *info)
964 list = info->attributes;
966 while (list && list->next)
969 list = list->next->next;
971 g_slist_free (info->attributes);
972 info->attributes = NULL;
974 if (tree_column->tree_view)
975 _pspp_sheet_view_column_cell_set_dirty (tree_column);
979 on_query_tooltip (GtkWidget *widget,
982 gboolean keyboard_mode,
986 PsppSheetViewColumn *tree_column = user_data;
989 g_signal_emit (tree_column, tree_column_signals[QUERY_TOOLTIP], 0,
995 on_button_pressed (GtkWidget *widget, GdkEventButton *event,
998 PsppSheetViewColumn *tree_column = user_data;
1001 /* XXX See "Implement GtkWidget::popup_menu" in GTK+ reference manual. */
1002 g_signal_emit (tree_column, tree_column_signals[BUTTON_PRESS_EVENT],
1003 0, event, &handled);
1010 /* Button handling code
1013 pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
1015 PsppSheetView *tree_view;
1019 tree_view = (PsppSheetView *) tree_column->tree_view;
1021 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1022 g_return_if_fail (tree_column->button == NULL);
1024 gtk_widget_push_composite_child ();
1025 tree_column->button = gtk_button_new ();
1026 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
1027 gtk_widget_pop_composite_child ();
1029 /* make sure we own a reference to it as well. */
1030 if (tree_view->priv->header_window)
1031 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
1032 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
1034 g_signal_connect (tree_column->button, "event",
1035 G_CALLBACK (pspp_sheet_view_column_button_event),
1037 g_signal_connect (tree_column->button, "clicked",
1038 G_CALLBACK (pspp_sheet_view_column_button_clicked),
1040 g_signal_connect (tree_column->button, "popup-menu",
1041 G_CALLBACK (pspp_sheet_view_column_button_popup_menu),
1043 g_signal_connect (tree_column->button, "button-press-event",
1044 G_CALLBACK (on_button_pressed), tree_column);
1046 g_signal_connect (tree_column->button, "query-tooltip",
1047 G_CALLBACK (on_query_tooltip), tree_column);
1048 g_object_set (tree_column->button, "has-tooltip", TRUE, NULL);
1050 tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
1052 hbox = gtk_hbox_new (FALSE, 2);
1053 tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
1055 if (tree_column->child)
1056 child = tree_column->child;
1059 child = gtk_label_new (tree_column->title);
1060 gtk_widget_show (child);
1063 g_signal_connect (child, "mnemonic-activate",
1064 G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
1067 if (tree_column->xalign <= 0.5)
1068 gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
1070 gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
1072 gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
1074 gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
1075 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
1077 gtk_widget_show (hbox);
1078 gtk_widget_show (tree_column->alignment);
1079 pspp_sheet_view_column_update_button (tree_column);
1083 pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
1085 gint sort_column_id = -1;
1087 GtkWidget *alignment;
1089 GtkWidget *current_child;
1090 GtkArrowType arrow_type = GTK_ARROW_NONE;
1091 GtkTreeModel *model;
1094 if (tree_column->tree_view)
1095 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1099 /* Create a button if necessary */
1100 if (tree_column->need_button &&
1101 tree_column->visible &&
1102 tree_column->button == NULL &&
1103 tree_column->tree_view &&
1104 gtk_widget_get_realized (tree_column->tree_view))
1105 pspp_sheet_view_column_create_button (tree_column);
1107 if (! tree_column->button)
1110 hbox = gtk_bin_get_child (GTK_BIN (tree_column->button));
1111 alignment = tree_column->alignment;
1112 arrow = tree_column->arrow;
1113 current_child = gtk_bin_get_child (GTK_BIN (alignment));
1115 /* Set up the actual button */
1116 gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
1119 if (tree_column->child)
1121 if (current_child != tree_column->child)
1123 gtk_container_remove (GTK_CONTAINER (alignment),
1125 gtk_container_add (GTK_CONTAINER (alignment),
1126 tree_column->child);
1131 if (current_child == NULL)
1133 current_child = gtk_label_new (NULL);
1134 gtk_widget_show (current_child);
1135 gtk_container_add (GTK_CONTAINER (alignment),
1139 g_return_if_fail (GTK_IS_LABEL (current_child));
1141 if (tree_column->title)
1142 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1143 tree_column->title);
1145 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1149 if (GTK_IS_TREE_SORTABLE (model))
1150 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1154 if (tree_column->show_sort_indicator)
1156 gboolean alternative;
1158 g_object_get (gtk_widget_get_settings (tree_column->tree_view),
1159 "gtk-alternative-sort-arrows", &alternative,
1162 switch (tree_column->sort_order)
1164 case GTK_SORT_ASCENDING:
1165 arrow_type = alternative ? GTK_ARROW_UP : GTK_ARROW_DOWN;
1168 case GTK_SORT_DESCENDING:
1169 arrow_type = alternative ? GTK_ARROW_DOWN : GTK_ARROW_UP;
1173 g_warning (G_STRLOC": bad sort order");
1178 gtk_arrow_set (GTK_ARROW (arrow),
1182 /* Put arrow on the right if the text is left-or-center justified, and on the
1183 * left otherwise; do this by packing boxes, so flipping text direction will
1186 g_object_ref (arrow);
1187 gtk_container_remove (GTK_CONTAINER (hbox), arrow);
1189 if (tree_column->xalign <= 0.5)
1191 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1195 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1196 /* move it to the front */
1197 gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
1199 g_object_unref (arrow);
1201 if (tree_column->show_sort_indicator
1202 || (GTK_IS_TREE_SORTABLE (model) && tree_column->sort_column_id >= 0))
1203 gtk_widget_show (arrow);
1205 gtk_widget_hide (arrow);
1207 /* It's always safe to hide the button. It isn't always safe to show it, as
1208 * if you show it before it's realized, it'll get the wrong window. */
1209 if (tree_column->button &&
1210 tree_column->tree_view != NULL &&
1211 gtk_widget_get_realized (tree_column->tree_view))
1213 if (tree_column->visible)
1215 gtk_widget_show_now (tree_column->button);
1216 if (tree_column->window)
1218 if (tree_column->resizable)
1220 gdk_window_show (tree_column->window);
1221 gdk_window_raise (tree_column->window);
1225 gdk_window_hide (tree_column->window);
1231 gtk_widget_hide (tree_column->button);
1232 if (tree_column->window)
1233 gdk_window_hide (tree_column->window);
1237 can_focus = pspp_sheet_view_column_can_focus (tree_column);
1238 gtk_widget_set_can_focus (tree_column->button, can_focus);
1239 if (!can_focus && gtk_widget_has_focus (tree_column->button))
1241 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
1242 if (gtk_widget_is_toplevel (toplevel))
1244 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
1248 /* Queue a resize on the assumption that we always want to catch all changes
1249 * and columns don't change all that often.
1251 if (gtk_widget_get_realized (tree_column->tree_view))
1252 gtk_widget_queue_resize (tree_column->tree_view);
1256 /* Button signal handlers
1260 pspp_sheet_view_column_button_event (GtkWidget *widget,
1264 PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
1266 g_return_val_if_fail (event != NULL, FALSE);
1268 if (event->type == GDK_BUTTON_PRESS &&
1269 column->reorderable &&
1270 ((GdkEventButton *)event)->button == 1)
1272 column->maybe_reordered = TRUE;
1273 gdk_window_get_pointer (gtk_button_get_event_window (GTK_BUTTON (widget)),
1277 gtk_widget_grab_focus (widget);
1280 if (event->type == GDK_BUTTON_RELEASE ||
1281 event->type == GDK_LEAVE_NOTIFY)
1282 column->maybe_reordered = FALSE;
1284 if (event->type == GDK_MOTION_NOTIFY &&
1285 column->maybe_reordered &&
1286 (gtk_drag_check_threshold (widget,
1289 (gint) ((GdkEventMotion *)event)->x,
1290 (gint) ((GdkEventMotion *)event)->y)))
1292 column->maybe_reordered = FALSE;
1293 _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
1296 if (column->clickable == FALSE)
1298 switch (event->type)
1300 case GDK_MOTION_NOTIFY:
1301 case GDK_BUTTON_RELEASE:
1302 case GDK_ENTER_NOTIFY:
1303 case GDK_LEAVE_NOTIFY:
1313 all_rows_selected (PsppSheetView *sheet_view)
1315 PsppSheetSelection *selection = sheet_view->priv->selection;
1316 gint n_rows, n_selected_rows;
1318 n_rows = sheet_view->priv->row_count;
1319 n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
1321 return n_rows > 0 && n_selected_rows >= n_rows;
1325 on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *column,
1326 GdkEventButton *event)
1328 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (column->tree_view);
1329 PsppSheetSelection *selection;
1330 GSignalInvocationHint *hint;
1333 /* We only want to run first, not last, but combining that with return type
1334 `gboolean' makes GObject warn, so just ignore the run_last call. */
1335 hint = g_signal_get_invocation_hint (column);
1336 g_return_val_if_fail (hint != NULL, FALSE);
1337 if (hint->run_type != G_SIGNAL_RUN_FIRST)
1340 g_return_val_if_fail (sheet_view != NULL, FALSE);
1342 selection = sheet_view->priv->selection;
1343 g_return_val_if_fail (selection != NULL, FALSE);
1345 if (pspp_sheet_selection_get_mode (selection) != PSPP_SHEET_SELECTION_RECTANGLE)
1348 modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
1349 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
1351 if (pspp_sheet_selection_count_selected_columns (selection) <= 1
1352 || !all_rows_selected (sheet_view))
1354 pspp_sheet_selection_select_all (selection);
1355 pspp_sheet_selection_unselect_all_columns (selection);
1356 pspp_sheet_selection_select_column (selection, column);
1357 sheet_view->priv->anchor_column = column;
1361 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1362 && modifiers == GDK_CONTROL_MASK)
1364 gboolean is_selected;
1366 if (!all_rows_selected (sheet_view))
1368 pspp_sheet_selection_select_all (selection);
1369 pspp_sheet_selection_unselect_all_columns (selection);
1371 sheet_view->priv->anchor_column = column;
1373 is_selected = pspp_sheet_view_column_get_selected (column);
1374 pspp_sheet_view_column_set_selected (column, !is_selected);
1378 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1379 && modifiers == GDK_SHIFT_MASK)
1381 if (!all_rows_selected (sheet_view))
1383 pspp_sheet_selection_select_all (selection);
1384 pspp_sheet_selection_unselect_all_columns (selection);
1385 sheet_view->priv->anchor_column = column;
1387 else if (sheet_view->priv->anchor_column == NULL)
1388 sheet_view->priv->anchor_column = column;
1390 pspp_sheet_selection_unselect_all_columns (selection);
1391 pspp_sheet_selection_select_column_range (selection,
1392 sheet_view->priv->anchor_column,
1401 on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *column)
1403 PsppSheetSelection *selection;
1404 PsppSheetView *sheet_view;
1406 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (column));
1407 selection = pspp_sheet_view_get_selection (sheet_view);
1408 if (pspp_sheet_selection_get_mode (selection) == PSPP_SHEET_SELECTION_RECTANGLE)
1410 pspp_sheet_selection_select_all (selection);
1411 if (pspp_sheet_view_column_get_row_head (column))
1412 pspp_sheet_selection_select_all_columns (selection);
1415 pspp_sheet_selection_unselect_all_columns (selection);
1416 pspp_sheet_selection_select_column (selection, column);
1418 sheet_view->priv->anchor_column = column;
1425 pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
1427 PsppSheetViewColumn *column = data;
1430 g_signal_emit (column, tree_column_signals[CLICKED], 0, &handled);
1434 pspp_sheet_view_column_button_popup_menu (GtkWidget *widget, gpointer data)
1436 g_signal_emit_by_name (data, "popup-menu");
1440 pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
1441 gboolean group_cycling,
1444 PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
1446 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
1448 PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
1449 if (column->clickable)
1450 gtk_button_clicked (GTK_BUTTON (column->button));
1451 else if (gtk_widget_get_can_focus (column->button))
1452 gtk_widget_grab_focus (column->button);
1454 gtk_widget_grab_focus (column->tree_view);
1460 pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
1461 PsppSheetViewColumn *column)
1463 gint sort_column_id;
1466 if (gtk_tree_sortable_get_sort_column_id (sortable,
1470 if (sort_column_id == column->sort_column_id)
1472 pspp_sheet_view_column_set_sort_indicator (column, TRUE);
1473 pspp_sheet_view_column_set_sort_order (column, order);
1477 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1482 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1487 pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
1490 gint sort_column_id;
1492 gboolean has_sort_column;
1493 gboolean has_default_sort_func;
1495 g_return_if_fail (tree_column->tree_view != NULL);
1498 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1501 has_default_sort_func =
1502 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
1504 if (has_sort_column &&
1505 sort_column_id == tree_column->sort_column_id)
1507 if (order == GTK_SORT_ASCENDING)
1508 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1509 tree_column->sort_column_id,
1510 GTK_SORT_DESCENDING);
1511 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
1512 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1513 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1514 GTK_SORT_ASCENDING);
1516 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1517 tree_column->sort_column_id,
1518 GTK_SORT_ASCENDING);
1522 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1523 tree_column->sort_column_id,
1524 GTK_SORT_ASCENDING);
1530 pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
1532 GtkTreeModel *model;
1534 if (tree_column->tree_view == NULL)
1537 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1542 if (GTK_IS_TREE_SORTABLE (model) &&
1543 tree_column->sort_column_id != -1)
1545 gint real_sort_column_id;
1546 GtkSortType real_order;
1548 if (tree_column->sort_column_changed_signal == 0)
1549 tree_column->sort_column_changed_signal =
1550 g_signal_connect (model, "sort-column-changed",
1551 G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
1554 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1555 &real_sort_column_id,
1557 (real_sort_column_id == tree_column->sort_column_id))
1559 pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
1560 pspp_sheet_view_column_set_sort_order (tree_column, real_order);
1564 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
1570 /* Exported Private Functions.
1571 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1575 _pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
1577 GtkAllocation allocation;
1578 PsppSheetView *tree_view;
1580 guint attributes_mask;
1583 tree_view = (PsppSheetView *)column->tree_view;
1584 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
1586 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1587 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
1588 g_return_if_fail (tree_view->priv->header_window != NULL);
1589 if (!column->need_button || !column->button)
1592 g_return_if_fail (column->button != NULL);
1594 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
1596 if (column->visible)
1597 gtk_widget_show (column->button);
1599 attr.window_type = GDK_WINDOW_CHILD;
1600 attr.wclass = GDK_INPUT_ONLY;
1601 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1602 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
1603 (GDK_BUTTON_PRESS_MASK |
1604 GDK_BUTTON_RELEASE_MASK |
1605 GDK_POINTER_MOTION_MASK |
1606 GDK_POINTER_MOTION_HINT_MASK |
1607 GDK_KEY_PRESS_MASK);
1608 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
1609 attr.cursor = gdk_cursor_new_for_display (gdk_window_get_display (tree_view->priv->header_window),
1610 GDK_SB_H_DOUBLE_ARROW);
1612 attr.width = TREE_VIEW_DRAG_WIDTH;
1613 attr.height = tree_view->priv->header_height;
1614 gtk_widget_get_allocation (column->button, &allocation);
1615 attr.x = (allocation.x + (rtl ? 0 : allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
1616 column->window = gdk_window_new (tree_view->priv->header_window,
1617 &attr, attributes_mask);
1618 gdk_window_set_user_data (column->window, tree_view);
1620 pspp_sheet_view_column_update_button (column);
1622 gdk_cursor_unref (attr.cursor);
1626 _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
1628 g_return_if_fail (column != NULL);
1629 if (column->window != NULL)
1631 gdk_window_set_user_data (column->window, NULL);
1632 gdk_window_destroy (column->window);
1633 column->window = NULL;
1638 _pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
1639 GtkTreeModel *old_model)
1641 if (column->sort_column_changed_signal)
1643 g_signal_handler_disconnect (old_model,
1644 column->sort_column_changed_signal);
1645 column->sort_column_changed_signal = 0;
1647 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1651 _pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
1652 PsppSheetView *tree_view)
1654 g_assert (column->tree_view == NULL);
1656 column->tree_view = GTK_WIDGET (tree_view);
1657 if (column->need_button)
1658 pspp_sheet_view_column_create_button (column);
1660 column->property_changed_signal =
1661 g_signal_connect_swapped (tree_view,
1663 G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
1666 pspp_sheet_view_column_setup_sort_column_id_callback (column);
1670 _pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
1672 if (column->tree_view && column->button)
1674 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1676 if (column->property_changed_signal)
1678 g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
1679 column->property_changed_signal = 0;
1682 if (column->sort_column_changed_signal)
1684 g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
1685 column->sort_column_changed_signal);
1686 column->sort_column_changed_signal = 0;
1689 column->tree_view = NULL;
1690 column->button = NULL;
1694 _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
1698 for (list = column->cell_list; list; list = list->next)
1700 GtkCellRendererMode mode;
1701 g_object_get (((PsppSheetViewColumnCellInfo *)list->data)->cell, "mode", &mode, NULL);
1702 if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
1709 /* gets cell being edited */
1711 _pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
1715 for (list = column->cell_list; list; list = list->next)
1716 if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
1717 return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
1723 _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
1728 for (list = column->cell_list; list; list = list->next)
1730 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1732 GtkCellRendererMode mode;
1733 g_object_get (cellinfo->cell, "mode", &mode, NULL);
1735 if ((mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1736 mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
1737 gtk_cell_renderer_get_visible (cellinfo->cell))
1745 _pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
1751 list = pspp_sheet_view_column_cell_first (column);
1752 for (; list; list = pspp_sheet_view_column_cell_next (column, list))
1754 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1755 if (current_x <= x && x <= current_x + cellinfo->real_width)
1756 return cellinfo->cell;
1757 current_x += cellinfo->real_width;
1763 /* Public Functions */
1767 * pspp_sheet_view_column_new:
1769 * Creates a new #PsppSheetViewColumn.
1771 * Return value: A newly created #PsppSheetViewColumn.
1773 PsppSheetViewColumn *
1774 pspp_sheet_view_column_new (void)
1776 PsppSheetViewColumn *tree_column;
1778 tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
1784 * pspp_sheet_view_column_new_with_attributes:
1785 * @title: The title to set the header to.
1786 * @cell: The #GtkCellRenderer.
1787 * @Varargs: A %NULL-terminated list of attributes.
1789 * Creates a new #PsppSheetViewColumn with a number of default values. This is
1790 * equivalent to calling pspp_sheet_view_column_set_title(),
1791 * pspp_sheet_view_column_pack_start(), and
1792 * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
1794 * Here's a simple example:
1796 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1799 * PsppSheetViewColumn *column;
1800 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
1802 * column = pspp_sheet_view_column_new_with_attributes ("Title",
1804 * "text", TEXT_COLUMN,
1805 * "foreground", COLOR_COLUMN,
1810 * Return value: A newly created #PsppSheetViewColumn.
1812 PsppSheetViewColumn *
1813 pspp_sheet_view_column_new_with_attributes (const gchar *title,
1814 GtkCellRenderer *cell,
1817 PsppSheetViewColumn *retval;
1820 retval = pspp_sheet_view_column_new ();
1822 pspp_sheet_view_column_set_title (retval, title);
1823 pspp_sheet_view_column_pack_start (retval, cell, TRUE);
1825 va_start (args, cell);
1826 pspp_sheet_view_column_set_attributesv (retval, cell, args);
1832 static PsppSheetViewColumnCellInfo *
1833 pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
1834 GtkCellRenderer *cell_renderer)
1837 for (list = tree_column->cell_list; list; list = list->next)
1838 if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
1839 return (PsppSheetViewColumnCellInfo *) list->data;
1845 * pspp_sheet_view_column_pack_start:
1846 * @tree_column: A #PsppSheetViewColumn.
1847 * @cell: The #GtkCellRenderer.
1848 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1850 * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
1851 * the @cell is allocated no more space than it needs. Any unused space is divided
1852 * evenly between cells for which @expand is %TRUE.
1855 pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
1856 GtkCellRenderer *cell,
1859 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
1863 * pspp_sheet_view_column_pack_end:
1864 * @tree_column: A #PsppSheetViewColumn.
1865 * @cell: The #GtkCellRenderer.
1866 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1868 * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
1869 * is allocated no more space than it needs. Any unused space is divided
1870 * evenly between cells for which @expand is %TRUE.
1873 pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
1874 GtkCellRenderer *cell,
1877 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
1881 * pspp_sheet_view_column_clear:
1882 * @tree_column: A #PsppSheetViewColumn
1884 * Unsets all the mappings on all renderers on the @tree_column.
1887 pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
1889 gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
1893 pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
1895 PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
1896 GList *retval = NULL, *list;
1898 g_return_val_if_fail (tree_column != NULL, NULL);
1900 for (list = tree_column->cell_list; list; list = list->next)
1902 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
1904 retval = g_list_append (retval, info->cell);
1911 * pspp_sheet_view_column_get_cell_renderers:
1912 * @tree_column: A #PsppSheetViewColumn
1914 * Returns a newly-allocated #GList of all the cell renderers in the column,
1915 * in no particular order. The list must be freed with g_list_free().
1917 * Return value: A list of #GtkCellRenderers
1919 * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
1922 pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
1924 return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
1928 * pspp_sheet_view_column_add_attribute:
1929 * @tree_column: A #PsppSheetViewColumn.
1930 * @cell_renderer: the #GtkCellRenderer to set attributes on
1931 * @attribute: An attribute on the renderer
1932 * @column: The column position on the model to get the attribute from.
1934 * Adds an attribute mapping to the list in @tree_column. The @column is the
1935 * column of the model to get a value from, and the @attribute is the
1936 * parameter on @cell_renderer to be set from the value. So for example
1937 * if column 2 of the model contains strings, you could have the
1938 * "text" attribute of a #GtkCellRendererText get its values from
1942 pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
1943 GtkCellRenderer *cell_renderer,
1944 const gchar *attribute,
1947 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
1948 cell_renderer, attribute, column);
1952 pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
1953 GtkCellRenderer *cell_renderer,
1959 attribute = va_arg (args, gchar *);
1961 pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
1963 while (attribute != NULL)
1965 column = va_arg (args, gint);
1966 pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1967 attribute = va_arg (args, gchar *);
1972 * pspp_sheet_view_column_set_attributes:
1973 * @tree_column: A #PsppSheetViewColumn.
1974 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1975 * @Varargs: A %NULL-terminated list of attributes.
1977 * Sets the attributes in the list as the attributes of @tree_column.
1978 * The attributes should be in attribute/column order, as in
1979 * pspp_sheet_view_column_add_attribute(). All existing attributes
1980 * are removed, and replaced with the new attributes.
1983 pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
1984 GtkCellRenderer *cell_renderer,
1989 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1990 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1991 g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
1993 va_start (args, cell_renderer);
1994 pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
2000 * pspp_sheet_view_column_set_cell_data_func:
2001 * @tree_column: A #PsppSheetViewColumn
2002 * @cell_renderer: A #GtkCellRenderer
2003 * @func: The #PsppSheetViewColumnFunc to use.
2004 * @func_data: The user data for @func.
2005 * @destroy: The destroy notification for @func_data
2007 * Sets the #PsppSheetViewColumnFunc to use for the column. This
2008 * function is used instead of the standard attributes mapping for
2009 * setting the column value, and should set the value of @tree_column's
2010 * cell renderer as appropriate. @func may be %NULL to remove an
2014 pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
2015 GtkCellRenderer *cell_renderer,
2016 PsppSheetCellDataFunc func,
2018 GDestroyNotify destroy)
2020 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
2022 (GtkCellLayoutDataFunc)func,
2023 func_data, destroy);
2028 * pspp_sheet_view_column_clear_attributes:
2029 * @tree_column: a #PsppSheetViewColumn
2030 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
2032 * Clears all existing attributes previously set with
2033 * pspp_sheet_view_column_set_attributes().
2036 pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
2037 GtkCellRenderer *cell_renderer)
2039 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
2044 * pspp_sheet_view_column_set_spacing:
2045 * @tree_column: A #PsppSheetViewColumn.
2046 * @spacing: distance between cell renderers in pixels.
2048 * Sets the spacing field of @tree_column, which is the number of pixels to
2049 * place between cell renderers packed into it.
2052 pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
2055 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2056 g_return_if_fail (spacing >= 0);
2058 if (tree_column->spacing == spacing)
2061 tree_column->spacing = spacing;
2062 if (tree_column->tree_view)
2063 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2067 * pspp_sheet_view_column_get_spacing:
2068 * @tree_column: A #PsppSheetViewColumn.
2070 * Returns the spacing of @tree_column.
2072 * Return value: the spacing of @tree_column.
2075 pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
2077 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2079 return tree_column->spacing;
2082 /* Options for manipulating the columns */
2085 * pspp_sheet_view_column_set_visible:
2086 * @tree_column: A #PsppSheetViewColumn.
2087 * @visible: %TRUE if the @tree_column is visible.
2089 * Sets the visibility of @tree_column.
2092 pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
2095 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2097 visible = !! visible;
2099 if (tree_column->visible == visible)
2102 tree_column->visible = visible;
2104 if (tree_column->visible)
2105 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2107 pspp_sheet_view_column_update_button (tree_column);
2108 g_object_notify (G_OBJECT (tree_column), "visible");
2112 * pspp_sheet_view_column_get_visible:
2113 * @tree_column: A #PsppSheetViewColumn.
2115 * Returns %TRUE if @tree_column is visible.
2117 * Return value: whether the column is visible or not. If it is visible, then
2118 * the tree will show the column.
2121 pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
2123 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2125 return tree_column->visible;
2129 * pspp_sheet_view_column_set_resizable:
2130 * @tree_column: A #PsppSheetViewColumn
2131 * @resizable: %TRUE, if the column can be resized
2133 * If @resizable is %TRUE, then the user can explicitly resize the column by
2134 * grabbing the outer edge of the column button.
2137 pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
2140 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2142 resizable = !! resizable;
2144 if (tree_column->resizable == resizable)
2147 tree_column->resizable = resizable;
2149 pspp_sheet_view_column_update_button (tree_column);
2151 g_object_notify (G_OBJECT (tree_column), "resizable");
2155 * pspp_sheet_view_column_get_resizable:
2156 * @tree_column: A #PsppSheetViewColumn
2158 * Returns %TRUE if the @tree_column can be resized by the end user.
2160 * Return value: %TRUE, if the @tree_column can be resized.
2163 pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
2165 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2167 return tree_column->resizable;
2172 * pspp_sheet_view_column_get_width:
2173 * @tree_column: A #PsppSheetViewColumn.
2175 * Returns the current size of @tree_column in pixels.
2177 * Return value: The current width of @tree_column.
2180 pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
2182 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2184 return tree_column->width;
2188 * pspp_sheet_view_column_set_fixed_width:
2189 * @tree_column: A #PsppSheetViewColumn.
2190 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
2192 * Sets the size of the column in pixels. The size of the column is clamped to
2193 * the min/max width for the column. Please note that the min/max width of the
2194 * column doesn't actually affect the "fixed_width" property of the widget, just
2195 * the actual size when displayed.
2198 pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
2201 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2202 g_return_if_fail (fixed_width > 0);
2204 tree_column->fixed_width = fixed_width;
2205 tree_column->use_resized_width = FALSE;
2207 if (tree_column->tree_view &&
2208 gtk_widget_get_realized (tree_column->tree_view))
2210 gtk_widget_queue_resize (tree_column->tree_view);
2213 g_object_notify (G_OBJECT (tree_column), "fixed-width");
2217 * pspp_sheet_view_column_get_fixed_width:
2218 * @tree_column: a #PsppSheetViewColumn
2220 * Gets the fixed width of the column. This value is only meaning may not be
2221 * the actual width of the column on the screen, just what is requested.
2223 * Return value: the fixed width of the column
2226 pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
2228 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2230 return tree_column->fixed_width;
2234 * pspp_sheet_view_column_set_min_width:
2235 * @tree_column: A #PsppSheetViewColumn.
2236 * @min_width: The minimum width of the column in pixels, or -1.
2238 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
2239 * minimum width is unset.
2242 pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
2245 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2246 g_return_if_fail (min_width >= -1);
2248 if (min_width == tree_column->min_width)
2251 if (tree_column->visible &&
2252 tree_column->tree_view != NULL &&
2253 gtk_widget_get_realized (tree_column->tree_view))
2255 if (min_width > tree_column->width)
2256 gtk_widget_queue_resize (tree_column->tree_view);
2259 tree_column->min_width = min_width;
2260 g_object_freeze_notify (G_OBJECT (tree_column));
2261 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
2263 tree_column->max_width = min_width;
2264 g_object_notify (G_OBJECT (tree_column), "max-width");
2266 g_object_notify (G_OBJECT (tree_column), "min-width");
2267 g_object_thaw_notify (G_OBJECT (tree_column));
2271 * pspp_sheet_view_column_get_min_width:
2272 * @tree_column: A #PsppSheetViewColumn.
2274 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
2277 * Return value: The minimum width of the @tree_column.
2280 pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
2282 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2284 return tree_column->min_width;
2288 * pspp_sheet_view_column_set_max_width:
2289 * @tree_column: A #PsppSheetViewColumn.
2290 * @max_width: The maximum width of the column in pixels, or -1.
2292 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
2293 * maximum width is unset. Note, the column can actually be wider than max
2294 * width if it's the last column in a view. In this case, the column expands to
2295 * fill any extra space.
2298 pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
2301 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2302 g_return_if_fail (max_width >= -1);
2304 if (max_width == tree_column->max_width)
2307 if (tree_column->visible &&
2308 tree_column->tree_view != NULL &&
2309 gtk_widget_get_realized (tree_column->tree_view))
2311 if (max_width != -1 && max_width < tree_column->width)
2312 gtk_widget_queue_resize (tree_column->tree_view);
2315 tree_column->max_width = max_width;
2316 g_object_freeze_notify (G_OBJECT (tree_column));
2317 if (max_width != -1 && max_width < tree_column->min_width)
2319 tree_column->min_width = max_width;
2320 g_object_notify (G_OBJECT (tree_column), "min-width");
2322 g_object_notify (G_OBJECT (tree_column), "max-width");
2323 g_object_thaw_notify (G_OBJECT (tree_column));
2327 * pspp_sheet_view_column_get_max_width:
2328 * @tree_column: A #PsppSheetViewColumn.
2330 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
2333 * Return value: The maximum width of the @tree_column.
2336 pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
2338 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2340 return tree_column->max_width;
2344 * pspp_sheet_view_column_clicked:
2345 * @tree_column: a #PsppSheetViewColumn
2347 * Emits the "clicked" signal on the column. This function will only work if
2348 * @tree_column is clickable.
2351 pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
2353 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2355 if (tree_column->visible &&
2356 tree_column->button &&
2357 tree_column->clickable)
2358 gtk_button_clicked (GTK_BUTTON (tree_column->button));
2362 * pspp_sheet_view_column_set_title:
2363 * @tree_column: A #PsppSheetViewColumn.
2364 * @title: The title of the @tree_column.
2366 * Sets the title of the @tree_column. If a custom widget has been set, then
2367 * this value is ignored.
2370 pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
2375 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2377 new_title = g_strdup (title);
2378 g_free (tree_column->title);
2379 tree_column->title = new_title;
2381 pspp_sheet_view_column_update_button (tree_column);
2382 g_object_notify (G_OBJECT (tree_column), "title");
2386 * pspp_sheet_view_column_get_title:
2387 * @tree_column: A #PsppSheetViewColumn.
2389 * Returns the title of the widget.
2391 * Return value: the title of the column. This string should not be
2392 * modified or freed.
2395 pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
2397 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2399 return tree_column->title;
2403 * pspp_sheet_view_column_set_expand:
2404 * @tree_column: A #PsppSheetViewColumn
2405 * @expand: %TRUE if the column should take available extra space, %FALSE if not
2407 * Sets the column to take available extra space. This space is shared equally
2408 * amongst all columns that have the expand set to %TRUE. If no column has this
2409 * option set, then the last column gets all extra space. By default, every
2410 * column is created with this %FALSE.
2415 pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
2418 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2421 if (tree_column->expand == expand)
2423 tree_column->expand = expand;
2425 if (tree_column->visible &&
2426 tree_column->tree_view != NULL &&
2427 gtk_widget_get_realized (tree_column->tree_view))
2429 /* We want to continue using the original width of the
2430 * column that includes additional space added by the user
2431 * resizing the columns and possibly extra (expanded) space, which
2432 * are not included in the resized width.
2434 tree_column->use_resized_width = FALSE;
2436 gtk_widget_queue_resize (tree_column->tree_view);
2439 g_object_notify (G_OBJECT (tree_column), "expand");
2443 * pspp_sheet_view_column_get_expand:
2444 * @tree_column: a #PsppSheetViewColumn
2446 * Return %TRUE if the column expands to take any available space.
2448 * Return value: %TRUE, if the column expands
2453 pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
2455 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2457 return tree_column->expand;
2461 * pspp_sheet_view_column_set_clickable:
2462 * @tree_column: A #PsppSheetViewColumn.
2463 * @clickable: %TRUE if the header is active.
2465 * Sets the header to be active if @active is %TRUE. When the header is active,
2466 * then it can take keyboard focus, and can be clicked.
2469 pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
2472 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2474 clickable = !! clickable;
2475 if (tree_column->clickable == clickable)
2478 tree_column->clickable = clickable;
2479 pspp_sheet_view_column_update_button (tree_column);
2480 g_object_notify (G_OBJECT (tree_column), "clickable");
2484 * pspp_sheet_view_column_get_clickable:
2485 * @tree_column: a #PsppSheetViewColumn
2487 * Returns %TRUE if the user can click on the header for the column.
2489 * Return value: %TRUE if user can click the column header.
2492 pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
2494 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2496 return tree_column->clickable;
2500 * pspp_sheet_view_column_set_widget:
2501 * @tree_column: A #PsppSheetViewColumn.
2502 * @widget: (allow-none): A child #GtkWidget, or %NULL.
2504 * Sets the widget in the header to be @widget. If widget is %NULL, then the
2505 * header button is set with a #GtkLabel set to the title of @tree_column.
2508 pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
2511 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2512 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
2515 g_object_ref_sink (widget);
2517 if (tree_column->child)
2518 g_object_unref (tree_column->child);
2520 tree_column->child = widget;
2521 pspp_sheet_view_column_update_button (tree_column);
2522 g_object_notify (G_OBJECT (tree_column), "widget");
2526 * pspp_sheet_view_column_get_widget:
2527 * @tree_column: A #PsppSheetViewColumn.
2529 * Returns the #GtkWidget in the button on the column header. If a custom
2530 * widget has not been set then %NULL is returned.
2532 * Return value: The #GtkWidget in the column header, or %NULL
2535 pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
2537 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2539 return tree_column->child;
2543 * pspp_sheet_view_column_set_alignment:
2544 * @tree_column: A #PsppSheetViewColumn.
2545 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2547 * Sets the alignment of the title or custom widget inside the column header.
2548 * The alignment determines its location inside the button -- 0.0 for left, 0.5
2549 * for center, 1.0 for right.
2552 pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
2555 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2557 xalign = CLAMP (xalign, 0.0, 1.0);
2559 if (tree_column->xalign == xalign)
2562 tree_column->xalign = xalign;
2563 pspp_sheet_view_column_update_button (tree_column);
2564 g_object_notify (G_OBJECT (tree_column), "alignment");
2568 * pspp_sheet_view_column_get_alignment:
2569 * @tree_column: A #PsppSheetViewColumn.
2571 * Returns the current x alignment of @tree_column. This value can range
2572 * between 0.0 and 1.0.
2574 * Return value: The current alignent of @tree_column.
2577 pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
2579 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0.5);
2581 return tree_column->xalign;
2585 * pspp_sheet_view_column_set_reorderable:
2586 * @tree_column: A #PsppSheetViewColumn
2587 * @reorderable: %TRUE, if the column can be reordered.
2589 * If @reorderable is %TRUE, then the column can be reordered by the end user
2590 * dragging the header.
2593 pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
2594 gboolean reorderable)
2596 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2599 pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
2601 reorderable = !!reorderable;
2602 if (tree_column->reorderable == reorderable)
2605 tree_column->reorderable = reorderable;
2606 pspp_sheet_view_column_update_button (tree_column);
2607 g_object_notify (G_OBJECT (tree_column), "reorderable");
2611 * pspp_sheet_view_column_get_reorderable:
2612 * @tree_column: A #PsppSheetViewColumn
2614 * Returns %TRUE if the @tree_column can be reordered by the user.
2616 * Return value: %TRUE if the @tree_column can be reordered by the user.
2619 pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
2621 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2623 return tree_column->reorderable;
2627 * pspp_sheet_view_column_set_quick_edit:
2628 * @tree_column: A #PsppSheetViewColumn
2629 * @quick_edit: If true, editing starts upon the first click in the column. If
2630 * false, the first click selects the column and a second click is needed to
2631 * begin editing. This has no effect on cells that are not editable.
2634 pspp_sheet_view_column_set_quick_edit (PsppSheetViewColumn *tree_column,
2635 gboolean quick_edit)
2637 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2639 quick_edit = !!quick_edit;
2640 if (tree_column->quick_edit != quick_edit)
2642 tree_column->quick_edit = quick_edit;
2643 g_object_notify (G_OBJECT (tree_column), "quick-edit");
2648 * pspp_sheet_view_column_get_quick_edit:
2649 * @tree_column: A #PsppSheetViewColumn
2651 * Returns %TRUE if editing starts upon the first click in the column. Returns
2652 * %FALSE, the first click selects the column and a second click is needed to
2653 * begin editing. This is not meaningful for cells that are not editable.
2655 * Return value: %TRUE if editing starts upon the first click.
2658 pspp_sheet_view_column_get_quick_edit (PsppSheetViewColumn *tree_column)
2660 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2662 return tree_column->quick_edit;
2667 * pspp_sheet_view_column_set_selected:
2668 * @tree_column: A #PsppSheetViewColumn
2669 * @selected: If true, the column is selected as part of a rectangular
2673 pspp_sheet_view_column_set_selected (PsppSheetViewColumn *tree_column,
2676 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2678 selected = !!selected;
2679 if (tree_column->selected != selected)
2681 PsppSheetSelection *selection;
2682 PsppSheetView *sheet_view;
2684 if (tree_column->tree_view != NULL)
2685 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2686 tree_column->selected = selected;
2687 g_object_notify (G_OBJECT (tree_column), "selected");
2689 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
2691 selection = pspp_sheet_view_get_selection (sheet_view);
2692 _pspp_sheet_selection_emit_changed (selection);
2697 * pspp_sheet_view_column_get_selected:
2698 * @tree_column: A #PsppSheetViewColumn
2700 * Returns %TRUE if the column is selected as part of a rectangular
2703 * Return value: %TRUE if the column is selected as part of a rectangular
2707 pspp_sheet_view_column_get_selected (PsppSheetViewColumn *tree_column)
2709 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2711 return tree_column->selected;
2715 * pspp_sheet_view_column_set_selectable:
2716 * @tree_column: A #PsppSheetViewColumn
2717 * @selectable: If true, the column may be selected as part of a rectangular
2721 pspp_sheet_view_column_set_selectable (PsppSheetViewColumn *tree_column,
2722 gboolean selectable)
2724 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2726 selectable = !!selectable;
2727 if (tree_column->selectable != selectable)
2729 if (tree_column->tree_view != NULL)
2730 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2731 tree_column->selectable = selectable;
2732 g_object_notify (G_OBJECT (tree_column), "selectable");
2737 * pspp_sheet_view_column_get_selectable:
2738 * @tree_column: A #PsppSheetViewColumn
2740 * Returns %TRUE if the column may be selected as part of a rectangular
2743 * Return value: %TRUE if the column may be selected as part of a rectangular
2747 pspp_sheet_view_column_get_selectable (PsppSheetViewColumn *tree_column)
2749 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2751 return tree_column->selectable;
2756 * pspp_sheet_view_column_set_row_head:
2757 * @tree_column: A #PsppSheetViewColumn
2758 * @row_head: If true, the column is a "row head", analogous to a column head.
2759 * See the description of the row-head property for more information.
2762 pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column,
2765 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2767 row_head = !!row_head;
2768 if (tree_column->row_head != row_head)
2770 tree_column->row_head = row_head;
2771 g_object_notify (G_OBJECT (tree_column), "row_head");
2776 * pspp_sheet_view_column_get_row_head:
2777 * @tree_column: A #PsppSheetViewColumn
2779 * Returns %TRUE if the column is a row head.
2781 * Return value: %TRUE if the column is a row head.
2784 pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column)
2786 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2788 return tree_column->row_head;
2793 * pspp_sheet_view_column_set_tabbable:
2794 * @tree_column: A #PsppSheetViewColumn
2795 * @tabbable: If true, the column is "tabbable", meaning that Tab and Shift+Tab
2796 * in the sheet visit this column. If false, Tab and Shift+Tab skip this
2800 pspp_sheet_view_column_set_tabbable (PsppSheetViewColumn *tree_column,
2803 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2805 tabbable = !!tabbable;
2806 if (tree_column->tabbable != tabbable)
2808 tree_column->tabbable = tabbable;
2809 g_object_notify (G_OBJECT (tree_column), "tabbable");
2814 * pspp_sheet_view_column_get_tabbable:
2815 * @tree_column: A #PsppSheetViewColumn
2817 * Returns %TRUE if the column is tabbable.
2819 * Return value: %TRUE if the column is tabbable.
2822 pspp_sheet_view_column_get_tabbable (PsppSheetViewColumn *tree_column)
2824 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2826 return tree_column->tabbable;
2831 * pspp_sheet_view_column_set_sort_column_id:
2832 * @tree_column: a #PsppSheetViewColumn
2833 * @sort_column_id: The @sort_column_id of the model to sort on.
2835 * Sets the logical @sort_column_id that this column sorts on when this column
2836 * is selected for sorting. Doing so makes the column header clickable.
2839 pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
2840 gint sort_column_id)
2842 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2843 g_return_if_fail (sort_column_id >= -1);
2845 if (tree_column->sort_column_id == sort_column_id)
2848 tree_column->sort_column_id = sort_column_id;
2850 /* Handle unsetting the id */
2851 if (sort_column_id == -1)
2853 GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
2855 if (tree_column->sort_clicked_signal)
2857 g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
2858 tree_column->sort_clicked_signal = 0;
2861 if (tree_column->sort_column_changed_signal)
2863 g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
2864 tree_column->sort_column_changed_signal = 0;
2867 pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2868 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
2869 pspp_sheet_view_column_set_clickable (tree_column, FALSE);
2870 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2874 pspp_sheet_view_column_set_clickable (tree_column, TRUE);
2876 if (! tree_column->sort_clicked_signal)
2877 tree_column->sort_clicked_signal = g_signal_connect (tree_column,
2879 G_CALLBACK (pspp_sheet_view_column_sort),
2882 pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
2883 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2887 * pspp_sheet_view_column_get_sort_column_id:
2888 * @tree_column: a #PsppSheetViewColumn
2890 * Gets the logical @sort_column_id that the model sorts on when this
2891 * column is selected for sorting.
2892 * See pspp_sheet_view_column_set_sort_column_id().
2894 * Return value: the current @sort_column_id for this column, or -1 if
2895 * this column can't be used for sorting.
2898 pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
2900 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2902 return tree_column->sort_column_id;
2906 * pspp_sheet_view_column_set_sort_indicator:
2907 * @tree_column: a #PsppSheetViewColumn
2908 * @setting: %TRUE to display an indicator that the column is sorted
2910 * Call this function with a @setting of %TRUE to display an arrow in
2911 * the header button indicating the column is sorted. Call
2912 * pspp_sheet_view_column_set_sort_order() to change the direction of
2917 pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
2920 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2922 setting = setting != FALSE;
2924 if (setting == tree_column->show_sort_indicator)
2927 tree_column->show_sort_indicator = setting;
2928 pspp_sheet_view_column_update_button (tree_column);
2929 g_object_notify (G_OBJECT (tree_column), "sort-indicator");
2933 * pspp_sheet_view_column_get_sort_indicator:
2934 * @tree_column: a #PsppSheetViewColumn
2936 * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
2938 * Return value: whether the sort indicator arrow is displayed
2941 pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column)
2943 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2945 return tree_column->show_sort_indicator;
2949 * pspp_sheet_view_column_set_sort_order:
2950 * @tree_column: a #PsppSheetViewColumn
2951 * @order: sort order that the sort indicator should indicate
2953 * Changes the appearance of the sort indicator.
2955 * This <emphasis>does not</emphasis> actually sort the model. Use
2956 * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
2957 * support. This function is primarily for custom sorting behavior, and should
2958 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2959 * that. For custom models, the mechanism will vary.
2961 * The sort indicator changes direction to indicate normal sort or reverse sort.
2962 * Note that you must have the sort indicator enabled to see anything when
2963 * calling this function; see pspp_sheet_view_column_set_sort_indicator().
2966 pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
2969 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2971 if (order == tree_column->sort_order)
2974 tree_column->sort_order = order;
2975 pspp_sheet_view_column_update_button (tree_column);
2976 g_object_notify (G_OBJECT (tree_column), "sort-order");
2980 * pspp_sheet_view_column_get_sort_order:
2981 * @tree_column: a #PsppSheetViewColumn
2983 * Gets the value set by pspp_sheet_view_column_set_sort_order().
2985 * Return value: the sort order the sort indicator is indicating
2988 pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column)
2990 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2992 return tree_column->sort_order;
2996 * pspp_sheet_view_column_cell_set_cell_data:
2997 * @tree_column: A #PsppSheetViewColumn.
2998 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2999 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
3001 * Sets the cell renderer based on the @tree_model and @iter. That is, for
3002 * every attribute mapping in @tree_column, it will get a value from the set
3003 * column on the @iter, and use that value to set the attribute on the cell
3004 * renderer. This is used primarily by the #PsppSheetView.
3007 pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
3008 GtkTreeModel *tree_model,
3012 GValue value = { 0, };
3015 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3017 if (tree_model == NULL)
3020 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
3022 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
3023 GObject *cell = (GObject *) info->cell;
3025 list = info->attributes;
3027 g_object_freeze_notify (cell);
3029 while (list && list->next)
3031 gtk_tree_model_get_value (tree_model, iter,
3032 GPOINTER_TO_INT (list->next->data),
3034 g_object_set_property (cell, (gchar *) list->data, &value);
3035 g_value_unset (&value);
3036 list = list->next->next;
3040 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
3041 g_object_thaw_notify (G_OBJECT (info->cell));
3047 * pspp_sheet_view_column_cell_get_size:
3048 * @tree_column: A #PsppSheetViewColumn.
3049 * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
3050 * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
3051 * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
3052 * @width: (allow-none): location to return width needed to render a cell, or %NULL
3053 * @height: (allow-none): location to return height needed to render a cell, or %NULL
3055 * Obtains the width and height needed to render the column. This is used
3056 * primarily by the #PsppSheetView.
3059 pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
3060 const GdkRectangle *cell_area,
3067 gboolean first_cell = TRUE;
3068 gint focus_line_width;
3070 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3077 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
3079 for (list = tree_column->cell_list; list; list = list->next)
3081 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3083 gint new_height = 0;
3085 g_object_get (info->cell, "visible", &visible, NULL);
3087 if (visible == FALSE)
3090 if (first_cell == FALSE && width)
3091 *width += tree_column->spacing;
3093 gtk_cell_renderer_get_size (info->cell,
3094 tree_column->tree_view,
3102 * height = MAX (*height, new_height + focus_line_width * 2);
3103 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
3105 * width += info->requested_width;
3110 /* rendering, event handling and rendering focus are somewhat complicated, and
3111 * quite a bit of code. Rather than duplicate them, we put them together to
3112 * keep the code in one place.
3114 * To better understand what's going on, check out
3115 * docs/tree-column-sizing.png
3124 pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn *tree_column,
3126 const GdkRectangle *background_area,
3127 const GdkRectangle *cell_area,
3130 const GdkRectangle *expose_area, /* RENDER */
3131 GdkRectangle *focus_rectangle, /* FOCUS */
3132 GtkCellEditable **editable_widget, /* EVENT */
3133 GdkEvent *event, /* EVENT */
3134 gchar *path_string) /* EVENT */
3137 GdkRectangle real_cell_area;
3138 GdkRectangle real_background_area;
3139 GdkRectangle real_expose_area = *cell_area;
3141 gint expand_cell_count = 0;
3142 gint full_requested_width = 0;
3144 gint min_x, min_y, max_x, max_y;
3145 gint focus_line_width;
3147 gint horizontal_separator;
3148 gboolean cursor_row = FALSE;
3149 gboolean first_cell = TRUE;
3151 /* If we have rtl text, we need to transform our areas */
3152 GdkRectangle rtl_cell_area;
3153 GdkRectangle rtl_background_area;
3160 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
3161 special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
3163 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
3165 PsppSheetViewColumnCellInfo *info = NULL;
3166 gboolean found_has_focus = FALSE;
3168 /* one should have focus */
3169 for (list = tree_column->cell_list; list; list = list->next)
3172 if (info && info->has_focus)
3174 found_has_focus = TRUE;
3179 if (!found_has_focus)
3181 /* give the first one focus */
3182 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3183 info->has_focus = TRUE;
3187 cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
3189 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3190 "focus-line-width", &focus_line_width,
3191 "horizontal-separator", &horizontal_separator,
3194 real_cell_area = *cell_area;
3195 real_background_area = *background_area;
3198 real_cell_area.x += focus_line_width;
3199 real_cell_area.y += focus_line_width;
3200 real_cell_area.height -= 2 * focus_line_width;
3203 depth = real_background_area.width - real_cell_area.width;
3205 depth = real_cell_area.x - real_background_area.x;
3207 /* Find out how much extra space we have to allocate */
3208 for (list = tree_column->cell_list; list; list = list->next)
3210 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
3212 if (! gtk_cell_renderer_get_visible (info->cell))
3215 if (info->expand == TRUE)
3216 expand_cell_count ++;
3217 full_requested_width += info->requested_width;
3220 full_requested_width += tree_column->spacing;
3225 extra_space = cell_area->width - full_requested_width;
3226 if (extra_space < 0)
3228 else if (extra_space > 0 && expand_cell_count > 0)
3229 extra_space /= expand_cell_count;
3231 /* iterate list for GTK_PACK_START cells */
3232 for (list = tree_column->cell_list; list; list = list->next)
3234 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3236 if (info->pack == GTK_PACK_END)
3239 if (! gtk_cell_renderer_get_visible (info->cell))
3242 if ((info->has_focus || special_cells == 1) && cursor_row)
3243 flags |= GTK_CELL_RENDERER_FOCUSED;
3245 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3247 info->real_width = info->requested_width + (info->expand?extra_space:0);
3249 /* We constrain ourselves to only the width available */
3250 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3252 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3255 if (real_cell_area.x > cell_area->x + cell_area->width)
3258 real_cell_area.width = info->real_width;
3259 real_cell_area.width -= 2 * focus_line_width;
3263 real_background_area.width = info->real_width + depth;
3267 /* fill the rest of background for the last cell */
3268 real_background_area.width = background_area->x + background_area->width - real_background_area.x;
3271 rtl_cell_area = real_cell_area;
3272 rtl_background_area = real_background_area;
3276 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3277 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3281 if (action == CELL_ACTION_RENDER)
3283 gtk_cell_renderer_render (info->cell,
3285 tree_column->tree_view,
3286 &rtl_background_area,
3292 else if (action == CELL_ACTION_FOCUS)
3294 gint x_offset, y_offset, width, height;
3296 gtk_cell_renderer_get_size (info->cell,
3297 tree_column->tree_view,
3299 &x_offset, &y_offset,
3302 if (special_cells > 1)
3304 if (info->has_focus)
3306 min_x = rtl_cell_area.x + x_offset;
3307 max_x = min_x + width;
3308 min_y = rtl_cell_area.y + y_offset;
3309 max_y = min_y + height;
3314 if (min_x > (rtl_cell_area.x + x_offset))
3315 min_x = rtl_cell_area.x + x_offset;
3316 if (max_x < rtl_cell_area.x + x_offset + width)
3317 max_x = rtl_cell_area.x + x_offset + width;
3318 if (min_y > (rtl_cell_area.y + y_offset))
3319 min_y = rtl_cell_area.y + y_offset;
3320 if (max_y < rtl_cell_area.y + y_offset + height)
3321 max_y = rtl_cell_area.y + y_offset + height;
3325 else if (action == CELL_ACTION_EVENT)
3327 gboolean try_event = FALSE;
3331 if (special_cells == 1)
3333 /* only 1 activatable cell -> whole column can activate */
3334 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3335 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3338 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3339 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3340 /* only activate cell if the user clicked on an individual
3345 else if (special_cells > 1 && info->has_focus)
3347 else if (special_cells == 1)
3352 gboolean visible, mode;
3354 g_object_get (info->cell,
3355 "visible", &visible,
3358 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3360 if (gtk_cell_renderer_activate (info->cell,
3362 tree_column->tree_view,
3364 &rtl_background_area,
3368 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3372 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3375 gtk_cell_renderer_start_editing (info->cell,
3377 tree_column->tree_view,
3379 &rtl_background_area,
3383 if (*editable_widget != NULL)
3385 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3386 info->in_editing_mode = TRUE;
3387 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3389 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3397 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3399 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3400 real_background_area.x += real_background_area.width + tree_column->spacing;
3402 /* Only needed for first cell */
3406 /* iterate list for PACK_END cells */
3407 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
3409 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3411 if (info->pack == GTK_PACK_START)
3414 if (! gtk_cell_renderer_get_visible (info->cell))
3417 if ((info->has_focus || special_cells == 1) && cursor_row)
3418 flags |= GTK_CELL_RENDERER_FOCUSED;
3420 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3422 info->real_width = info->requested_width + (info->expand?extra_space:0);
3424 /* We constrain ourselves to only the width available */
3425 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3427 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3430 if (real_cell_area.x > cell_area->x + cell_area->width)
3433 real_cell_area.width = info->real_width;
3434 real_cell_area.width -= 2 * focus_line_width;
3435 real_background_area.width = info->real_width + depth;
3437 rtl_cell_area = real_cell_area;
3438 rtl_background_area = real_background_area;
3441 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3442 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3446 if (action == CELL_ACTION_RENDER)
3448 gtk_cell_renderer_render (info->cell,
3450 tree_column->tree_view,
3451 &rtl_background_area,
3457 else if (action == CELL_ACTION_FOCUS)
3459 gint x_offset, y_offset, width, height;
3461 gtk_cell_renderer_get_size (info->cell,
3462 tree_column->tree_view,
3464 &x_offset, &y_offset,
3467 if (special_cells > 1)
3469 if (info->has_focus)
3471 min_x = rtl_cell_area.x + x_offset;
3472 max_x = min_x + width;
3473 min_y = rtl_cell_area.y + y_offset;
3474 max_y = min_y + height;
3479 if (min_x > (rtl_cell_area.x + x_offset))
3480 min_x = rtl_cell_area.x + x_offset;
3481 if (max_x < rtl_cell_area.x + x_offset + width)
3482 max_x = rtl_cell_area.x + x_offset + width;
3483 if (min_y > (rtl_cell_area.y + y_offset))
3484 min_y = rtl_cell_area.y + y_offset;
3485 if (max_y < rtl_cell_area.y + y_offset + height)
3486 max_y = rtl_cell_area.y + y_offset + height;
3490 else if (action == CELL_ACTION_EVENT)
3492 gboolean try_event = FALSE;
3496 if (special_cells == 1)
3498 /* only 1 activatable cell -> whole column can activate */
3499 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3500 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3503 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3504 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3505 /* only activate cell if the user clicked on an individual
3510 else if (special_cells > 1 && info->has_focus)
3512 else if (special_cells == 1)
3517 gboolean visible, mode;
3519 g_object_get (info->cell,
3520 "visible", &visible,
3523 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3525 if (gtk_cell_renderer_activate (info->cell,
3527 tree_column->tree_view,
3529 &rtl_background_area,
3533 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3537 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3540 gtk_cell_renderer_start_editing (info->cell,
3542 tree_column->tree_view,
3544 &rtl_background_area,
3548 if (*editable_widget != NULL)
3550 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3551 info->in_editing_mode = TRUE;
3552 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3554 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3561 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3563 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3564 real_background_area.x += (real_background_area.width + tree_column->spacing);
3566 /* Only needed for first cell */
3570 /* fill focus_rectangle when required */
3571 if (action == CELL_ACTION_FOCUS)
3573 if (min_x >= max_x || min_y >= max_y)
3575 *focus_rectangle = *cell_area;
3576 /* don't change the focus_rectangle, just draw it nicely inside
3581 focus_rectangle->x = min_x - focus_line_width;
3582 focus_rectangle->y = min_y - focus_line_width;
3583 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
3584 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
3592 * pspp_sheet_view_column_cell_render:
3593 * @tree_column: A #PsppSheetViewColumn.
3594 * @window: a #GdkDrawable to draw to
3595 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
3596 * @cell_area: area normally rendered by a cell renderer
3597 * @expose_area: area that actually needs updating
3598 * @flags: flags that affect rendering
3600 * Renders the cell contained by #tree_column. This is used primarily by the
3604 _pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
3606 const GdkRectangle *background_area,
3607 const GdkRectangle *cell_area,
3608 const GdkRectangle *expose_area,
3611 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3612 g_return_if_fail (background_area != NULL);
3613 g_return_if_fail (cell_area != NULL);
3614 g_return_if_fail (expose_area != NULL);
3616 pspp_sheet_view_column_cell_process_action (tree_column,
3623 NULL, NULL, NULL, NULL);
3627 _pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
3628 GtkCellEditable **editable_widget,
3631 const GdkRectangle *background_area,
3632 const GdkRectangle *cell_area,
3635 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3637 return pspp_sheet_view_column_cell_process_action (tree_column,
3650 _pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
3651 const GdkRectangle *background_area,
3652 const GdkRectangle *cell_area,
3653 GdkRectangle *focus_area)
3655 pspp_sheet_view_column_cell_process_action (tree_column,
3667 /* cell list manipulation */
3669 pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
3671 GList *list = tree_column->cell_list;
3673 /* first GTK_PACK_START cell we find */
3674 for ( ; list; list = list->next)
3676 PsppSheetViewColumnCellInfo *info = list->data;
3677 if (info->pack == GTK_PACK_START)
3681 /* hmm, else the *last* GTK_PACK_END cell */
3682 list = g_list_last (tree_column->cell_list);
3684 for ( ; list; list = list->prev)
3686 PsppSheetViewColumnCellInfo *info = list->data;
3687 if (info->pack == GTK_PACK_END)
3695 pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
3697 GList *list = tree_column->cell_list;
3699 /* *first* GTK_PACK_END cell we find */
3700 for ( ; list ; list = list->next)
3702 PsppSheetViewColumnCellInfo *info = list->data;
3703 if (info->pack == GTK_PACK_END)
3707 /* hmm, else the last GTK_PACK_START cell */
3708 list = g_list_last (tree_column->cell_list);
3710 for ( ; list; list = list->prev)
3712 PsppSheetViewColumnCellInfo *info = list->data;
3713 if (info->pack == GTK_PACK_START)
3721 pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
3725 PsppSheetViewColumnCellInfo *info = current->data;
3727 if (info->pack == GTK_PACK_START)
3729 for (list = current->next; list; list = list->next)
3731 PsppSheetViewColumnCellInfo *inf = list->data;
3732 if (inf->pack == GTK_PACK_START)
3736 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
3737 list = g_list_last (tree_column->cell_list);
3738 for (; list; list = list->prev)
3740 PsppSheetViewColumnCellInfo *inf = list->data;
3741 if (inf->pack == GTK_PACK_END)
3746 for (list = current->prev; list; list = list->prev)
3748 PsppSheetViewColumnCellInfo *inf = list->data;
3749 if (inf->pack == GTK_PACK_END)
3757 pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
3761 PsppSheetViewColumnCellInfo *info = current->data;
3763 if (info->pack == GTK_PACK_END)
3765 for (list = current->next; list; list = list->next)
3767 PsppSheetViewColumnCellInfo *inf = list->data;
3768 if (inf->pack == GTK_PACK_END)
3772 /* out of GTK_PACK_END, get last GTK_PACK_START one */
3773 list = g_list_last (tree_column->cell_list);
3774 for ( ; list; list = list->prev)
3776 PsppSheetViewColumnCellInfo *inf = list->data;
3777 if (inf->pack == GTK_PACK_START)
3782 for (list = current->prev; list; list = list->prev)
3784 PsppSheetViewColumnCellInfo *inf = list->data;
3785 if (inf->pack == GTK_PACK_START)
3793 _pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
3801 count = _pspp_sheet_view_column_count_special_cells (tree_column);
3802 rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
3804 /* if we are the current focus column and have multiple editable cells,
3805 * try to select the next one, else move the focus to the next column
3807 if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
3812 GList *list = tree_column->cell_list;
3813 PsppSheetViewColumnCellInfo *info = NULL;
3815 /* find current focussed cell */
3816 for ( ; list; list = list->next)
3819 if (info->has_focus)
3823 /* not a focussed cell in the focus column? */
3824 if (!list || !info || !info->has_focus)
3829 prev = pspp_sheet_view_column_cell_next (tree_column, list);
3830 next = pspp_sheet_view_column_cell_prev (tree_column, list);
3834 next = pspp_sheet_view_column_cell_next (tree_column, list);
3835 prev = pspp_sheet_view_column_cell_prev (tree_column, list);
3838 info->has_focus = FALSE;
3839 if (direction > 0 && next)
3842 info->has_focus = TRUE;
3845 else if (direction > 0 && !next && !right)
3847 /* keep focus on last cell */
3849 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3851 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3853 info->has_focus = TRUE;
3856 else if (direction < 0 && prev)
3859 info->has_focus = TRUE;
3862 else if (direction < 0 && !prev && !left)
3864 /* keep focus on first cell */
3866 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3868 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3870 info->has_focus = TRUE;
3877 /* we get focus, if we have multiple editable cells, give the correct one
3882 GList *list = tree_column->cell_list;
3884 /* clear focus first */
3885 for ( ; list ; list = list->next)
3887 PsppSheetViewColumnCellInfo *info = list->data;
3888 if (info->has_focus)
3889 info->has_focus = FALSE;
3896 list = pspp_sheet_view_column_cell_last (tree_column);
3897 else if (direction < 0)
3898 list = pspp_sheet_view_column_cell_first (tree_column);
3903 list = pspp_sheet_view_column_cell_first (tree_column);
3904 else if (direction < 0)
3905 list = pspp_sheet_view_column_cell_last (tree_column);
3909 ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
3916 _pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
3918 const GdkRectangle *background_area,
3919 const GdkRectangle *cell_area,
3920 const GdkRectangle *expose_area,
3923 gint focus_line_width;
3924 GtkStateType cell_state;
3926 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3927 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3928 "focus-line-width", &focus_line_width, NULL);
3929 if (tree_column->editable_widget)
3931 /* This function is only called on the editable row when editing.
3934 gtk_paint_focus (tree_column->tree_view->style,
3936 gtk_widget_get_state (tree_column->tree_view),
3938 tree_column->tree_view,
3940 cell_area->x - focus_line_width,
3941 cell_area->y - focus_line_width,
3942 cell_area->width + 2 * focus_line_width,
3943 cell_area->height + 2 * focus_line_width);
3948 GdkRectangle focus_rectangle;
3949 pspp_sheet_view_column_cell_process_action (tree_column,
3959 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3960 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3961 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3962 gtk_paint_focus (gtk_widget_get_style (GTK_WIDGET (tree_column->tree_view)),
3966 tree_column->tree_view,
3970 focus_rectangle.width,
3971 focus_rectangle.height);
3976 * pspp_sheet_view_column_cell_is_visible:
3977 * @tree_column: A #PsppSheetViewColumn
3979 * Returns %TRUE if any of the cells packed into the @tree_column are visible.
3980 * For this to be meaningful, you must first initialize the cells with
3981 * pspp_sheet_view_column_cell_set_cell_data()
3983 * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
3986 pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
3990 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3992 for (list = tree_column->cell_list; list; list = list->next)
3994 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3996 if (gtk_cell_renderer_get_visible (info->cell))
4004 * pspp_sheet_view_column_focus_cell:
4005 * @tree_column: A #PsppSheetViewColumn
4006 * @cell: A #GtkCellRenderer
4008 * Sets the current keyboard focus to be at @cell, if the column contains
4009 * 2 or more editable and activatable cells.
4014 pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
4015 GtkCellRenderer *cell)
4018 gboolean found_cell = FALSE;
4020 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
4021 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
4023 if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
4026 for (list = tree_column->cell_list; list; list = list->next)
4028 PsppSheetViewColumnCellInfo *info = list->data;
4030 if (info->cell == cell)
4032 info->has_focus = TRUE;
4040 for (list = tree_column->cell_list; list; list = list->next)
4042 PsppSheetViewColumnCellInfo *info = list->data;
4044 if (info->cell != cell)
4045 info->has_focus = FALSE;
4048 /* FIXME: redraw? */
4053 _pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
4057 for (list = tree_column->cell_list; list; list = list->next)
4059 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
4061 info->requested_width = 0;
4063 tree_column->dirty = TRUE;
4064 tree_column->requested_width = -1;
4065 tree_column->width = 0;
4067 if (tree_column->tree_view &&
4068 gtk_widget_get_realized (tree_column->tree_view))
4070 _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
4071 gtk_widget_queue_resize (tree_column->tree_view);
4076 _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
4077 GtkCellEditable *cell_editable)
4079 g_return_if_fail (tree_column->editable_widget == NULL);
4081 tree_column->editable_widget = cell_editable;
4085 _pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
4089 g_return_if_fail (tree_column->editable_widget != NULL);
4091 tree_column->editable_widget = NULL;
4092 for (list = tree_column->cell_list; list; list = list->next)
4093 ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
4097 _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
4098 GtkCellRenderer *cell,
4103 PsppSheetViewColumnCellInfo *info;
4109 list = pspp_sheet_view_column_cell_first (column);
4113 info = (PsppSheetViewColumnCellInfo *)list->data;
4115 list = pspp_sheet_view_column_cell_next (column, list);
4117 if (info->cell == cell)
4120 if (gtk_cell_renderer_get_visible (info->cell))
4121 l += info->real_width + column->spacing;
4126 info = (PsppSheetViewColumnCellInfo *)list->data;
4128 list = pspp_sheet_view_column_cell_next (column, list);
4130 if (gtk_cell_renderer_get_visible (info->cell))
4131 r += info->real_width + column->spacing;
4134 rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
4136 *left = rtl ? r : l;
4139 *right = rtl ? l : r;
4143 * pspp_sheet_view_column_cell_get_position:
4144 * @tree_column: a #PsppSheetViewColumn
4145 * @cell_renderer: a #GtkCellRenderer
4146 * @start_pos: return location for the horizontal position of @cell within
4147 * @tree_column, may be %NULL
4148 * @width: return location for the width of @cell, may be %NULL
4150 * Obtains the horizontal position and size of a cell in a column. If the
4151 * cell is not found in the column, @start_pos and @width are not changed and
4152 * %FALSE is returned.
4154 * Return value: %TRUE if @cell belongs to @tree_column.
4157 pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
4158 GtkCellRenderer *cell_renderer,
4164 gboolean found_cell = FALSE;
4165 PsppSheetViewColumnCellInfo *cellinfo = NULL;
4167 list = pspp_sheet_view_column_cell_first (tree_column);
4168 for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
4170 cellinfo = list->data;
4171 if (cellinfo->cell == cell_renderer)
4177 if (gtk_cell_renderer_get_visible (cellinfo->cell))
4178 current_x += cellinfo->real_width;
4184 *start_pos = current_x;
4186 *width = cellinfo->real_width;
4193 * pspp_sheet_view_column_queue_resize:
4194 * @tree_column: A #PsppSheetViewColumn
4196 * Flags the column, and the cell renderers added to this column, to have
4197 * their sizes renegotiated.
4202 pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
4204 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
4206 if (tree_column->tree_view)
4207 _pspp_sheet_view_column_cell_set_dirty (tree_column);
4211 * pspp_sheet_view_column_get_tree_view:
4212 * @tree_column: A #PsppSheetViewColumn
4214 * Returns the #PsppSheetView wherein @tree_column has been inserted. If
4215 * @column is currently not inserted in any tree view, %NULL is
4218 * Return value: The tree view wherein @column has been inserted if any,
4224 pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
4226 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
4228 return tree_column->tree_view;
4232 GtkCellLayout *cell_layout;
4233 GtkCellRenderer *renderer;
4235 } AttributesSubParserData;
4238 attributes_start_element (GMarkupParseContext *context,
4239 const gchar *element_name,
4240 const gchar **names,
4241 const gchar **values,
4245 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4248 if (strcmp (element_name, "attribute") == 0)
4250 for (i = 0; names[i]; i++)
4251 if (strcmp (names[i], "name") == 0)
4252 parser_data->attr_name = g_strdup (values[i]);
4254 else if (strcmp (element_name, "attributes") == 0)
4257 g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
4261 attributes_text_element (GMarkupParseContext *context,
4267 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4272 if (!parser_data->attr_name)
4276 string = g_strndup (text, text_len);
4277 l = strtol (string, &endptr, 0);
4278 if (errno || endptr == string)
4282 GTK_BUILDER_ERROR_INVALID_VALUE,
4283 "Could not parse integer `%s'",
4290 gtk_cell_layout_add_attribute (parser_data->cell_layout,
4291 parser_data->renderer,
4292 parser_data->attr_name, l);
4293 g_free (parser_data->attr_name);
4294 parser_data->attr_name = NULL;
4297 static const GMarkupParser attributes_parser =
4299 attributes_start_element,
4301 attributes_text_element,
4305 _cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
4306 GtkBuilder *builder,
4308 const gchar *tagname,
4309 GMarkupParser *parser,
4312 AttributesSubParserData *parser_data;
4317 if (strcmp (tagname, "attributes") == 0)
4319 parser_data = g_slice_new0 (AttributesSubParserData);
4320 parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
4321 parser_data->renderer = GTK_CELL_RENDERER (child);
4322 parser_data->attr_name = NULL;
4324 *parser = attributes_parser;
4325 *data = parser_data;
4333 _cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
4334 GtkBuilder *builder,
4336 const gchar *tagname,
4339 AttributesSubParserData *parser_data;
4341 parser_data = (AttributesSubParserData*)data;
4342 g_assert (!parser_data->attr_name);
4343 g_slice_free (AttributesSubParserData, parser_data);
4347 _cell_layout_buildable_add_child (GtkBuildable *buildable,
4348 GtkBuilder *builder,
4352 GtkCellLayoutIface *iface;
4354 g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
4355 g_return_if_fail (GTK_IS_CELL_RENDERER (child));
4357 iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
4358 g_return_if_fail (iface->pack_start != NULL);
4359 iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);
4363 pspp_sheet_view_column_size_request (PsppSheetViewColumn *tree_column,
4364 GtkRequisition *request)
4366 GtkWidget *base = GTK_WIDGET (tree_column->tree_view);
4367 GtkRequisition label_req;
4368 GtkRequisition align_req;
4369 GtkRequisition arrow_req;
4370 GtkRequisition hbox_req;
4371 GtkStyle **button_style;
4373 if (tree_column->button)
4375 gtk_widget_size_request (tree_column->button, request);
4379 facade_label_get_size_request (0, 0, base, tree_column->title, &label_req);
4380 facade_alignment_get_size_request (0, 0, 0, 0, 0, &label_req, &align_req);
4381 facade_arrow_get_size_request (0, 0, &arrow_req);
4383 facade_hbox_get_base_size_request (0, 2, 2, &hbox_req);
4384 facade_hbox_add_child_size_request (0, &arrow_req, 0, &hbox_req);
4385 facade_hbox_add_child_size_request (0, &align_req, 0, &hbox_req);
4387 button_style = &PSPP_SHEET_VIEW (tree_column->tree_view)->priv->button_style;
4388 if (*button_style == NULL)
4390 *button_style = facade_get_style (base, GTK_TYPE_BUTTON, 0);
4391 g_object_ref (*button_style);
4393 facade_button_get_size_request (0, base, *button_style, &hbox_req, request);
4397 pspp_sheet_view_column_size_allocate (PsppSheetViewColumn *tree_column,
4398 GtkAllocation *allocation)
4400 tree_column->allocation = *allocation;
4401 if (tree_column->button)
4402 gtk_widget_size_allocate (tree_column->button, allocation);
4406 pspp_sheet_view_column_can_focus (PsppSheetViewColumn *tree_column)
4408 return tree_column->reorderable || tree_column->clickable;
4412 pspp_sheet_view_column_set_need_button (PsppSheetViewColumn *tree_column,
4413 gboolean need_button)
4415 if (tree_column->need_button != need_button)
4417 tree_column->need_button = need_button;
4418 pspp_sheet_view_column_update_button (tree_column);
4419 _pspp_sheet_view_column_realize_button (tree_column);