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"
48 #define P_(STRING) STRING
49 #define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
50 #define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
86 typedef struct _PsppSheetViewColumnCellInfo PsppSheetViewColumnCellInfo;
87 struct _PsppSheetViewColumnCellInfo
89 GtkCellRenderer *cell;
91 PsppSheetCellDataFunc func;
93 GDestroyNotify destroy;
99 guint in_editing_mode : 1;
103 static void pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface);
105 /* GObject methods */
106 static void pspp_sheet_view_column_set_property (GObject *object,
110 static void pspp_sheet_view_column_get_property (GObject *object,
114 static void pspp_sheet_view_column_finalize (GObject *object);
116 /* GtkCellLayout implementation */
117 static void pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
118 GtkCellRenderer *cell,
120 static void pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
121 GtkCellRenderer *cell,
123 static void pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout);
124 static void pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
125 GtkCellRenderer *cell,
126 const gchar *attribute,
128 static void pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
129 GtkCellRenderer *cell,
130 GtkCellLayoutDataFunc func,
132 GDestroyNotify destroy);
133 static void pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
134 GtkCellRenderer *cell);
135 static void pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
136 GtkCellRenderer *cell,
138 static GList *pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
140 /* Button handling code */
141 static void pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column);
142 static void pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
144 /* Button signal handlers */
145 static gint pspp_sheet_view_column_button_event (GtkWidget *widget,
148 static void pspp_sheet_view_column_button_clicked (GtkWidget *widget,
150 static void pspp_sheet_view_column_button_popup_menu (GtkWidget *widget,
152 static gboolean pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
153 gboolean group_cycling,
155 static gboolean on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *);
156 static gboolean on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *,
159 /* Property handlers */
160 static void pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
161 PsppSheetViewColumn *tree_column);
163 /* Internal functions */
164 static void pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
166 static void pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column);
167 static void pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
168 GtkCellRenderer *cell_renderer,
170 static PsppSheetViewColumnCellInfo *pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
171 GtkCellRenderer *cell_renderer);
173 /* cell list manipulation */
174 static GList *pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column);
175 static GList *pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column);
176 static GList *pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
178 static GList *pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
180 static void pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
181 PsppSheetViewColumnCellInfo *info);
182 /* GtkBuildable implementation */
183 static void pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface);
185 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
187 G_DEFINE_TYPE_WITH_CODE (PsppSheetViewColumn, pspp_sheet_view_column, GTK_TYPE_OBJECT,
188 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
189 pspp_sheet_view_column_cell_layout_init)
190 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
191 pspp_sheet_view_column_buildable_init))
195 pspp_sheet_view_column_class_init (PsppSheetViewColumnClass *class)
197 GObjectClass *object_class;
199 object_class = (GObjectClass*) class;
201 class->clicked = on_pspp_sheet_view_column_button_clicked;
202 class->button_press_event = on_pspp_sheet_view_column_button_press_event;
204 object_class->finalize = pspp_sheet_view_column_finalize;
205 object_class->set_property = pspp_sheet_view_column_set_property;
206 object_class->get_property = pspp_sheet_view_column_get_property;
208 tree_column_signals[CLICKED] =
209 g_signal_new ("clicked",
210 G_OBJECT_CLASS_TYPE (object_class),
212 G_STRUCT_OFFSET (PsppSheetViewColumnClass, clicked),
213 g_signal_accumulator_true_handled, NULL,
214 psppire_marshal_BOOLEAN__VOID,
217 tree_column_signals[POPUP_MENU] =
218 g_signal_new ("popup-menu",
219 G_OBJECT_CLASS_TYPE (object_class),
223 g_cclosure_marshal_VOID__VOID,
226 tree_column_signals[QUERY_TOOLTIP] =
227 g_signal_new ("query-tooltip",
228 G_OBJECT_CLASS_TYPE (object_class),
231 g_signal_accumulator_true_handled, NULL,
232 psppire_marshal_BOOLEAN__OBJECT,
236 tree_column_signals[BUTTON_PRESS_EVENT] =
237 g_signal_new ("button-press-event",
238 G_OBJECT_CLASS_TYPE (object_class),
239 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
240 G_STRUCT_OFFSET (PsppSheetViewColumnClass, button_press_event),
241 g_signal_accumulator_true_handled, NULL,
242 psppire_marshal_BOOLEAN__BOXED,
244 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
246 g_object_class_install_property (object_class,
248 g_param_spec_boolean ("visible",
250 P_("Whether to display the column"),
252 GTK_PARAM_READWRITE));
254 g_object_class_install_property (object_class,
256 g_param_spec_boolean ("resizable",
258 P_("Column is user-resizable"),
260 GTK_PARAM_READWRITE));
262 g_object_class_install_property (object_class,
264 g_param_spec_int ("width",
266 P_("Current width of the column"),
270 GTK_PARAM_READABLE));
271 g_object_class_install_property (object_class,
273 g_param_spec_int ("spacing",
275 P_("Space which is inserted between cells"),
279 GTK_PARAM_READWRITE));
281 g_object_class_install_property (object_class,
283 g_param_spec_int ("fixed-width",
285 P_("Current fixed width of the column"),
289 GTK_PARAM_READWRITE));
291 g_object_class_install_property (object_class,
293 g_param_spec_int ("min-width",
295 P_("Minimum allowed width of the column"),
299 GTK_PARAM_READWRITE));
301 g_object_class_install_property (object_class,
303 g_param_spec_int ("max-width",
305 P_("Maximum allowed width of the column"),
309 GTK_PARAM_READWRITE));
311 g_object_class_install_property (object_class,
313 g_param_spec_string ("title",
315 P_("Title to appear in column header"),
317 GTK_PARAM_READWRITE));
319 g_object_class_install_property (object_class,
321 g_param_spec_boolean ("expand",
323 P_("Column gets share of extra width allocated to the widget"),
325 GTK_PARAM_READWRITE));
327 g_object_class_install_property (object_class,
329 g_param_spec_boolean ("clickable",
331 P_("Whether the header can be clicked"),
333 GTK_PARAM_READWRITE));
336 g_object_class_install_property (object_class,
338 g_param_spec_object ("widget",
340 P_("Widget to put in column header button instead of column title"),
342 GTK_PARAM_READWRITE));
344 g_object_class_install_property (object_class,
346 g_param_spec_float ("alignment",
348 P_("X Alignment of the column header text or widget"),
352 GTK_PARAM_READWRITE));
354 g_object_class_install_property (object_class,
356 g_param_spec_boolean ("reorderable",
358 P_("Whether the column can be reordered around the headers"),
360 GTK_PARAM_READWRITE));
362 g_object_class_install_property (object_class,
364 g_param_spec_boolean ("sort-indicator",
365 P_("Sort indicator"),
366 P_("Whether to show a sort indicator"),
368 GTK_PARAM_READWRITE));
370 g_object_class_install_property (object_class,
372 g_param_spec_enum ("sort-order",
374 P_("Sort direction the sort indicator should indicate"),
377 GTK_PARAM_READWRITE));
380 * PsppSheetViewColumn:sort-column-id:
382 * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
383 * clickable. Set to %-1 to make the column unsortable.
387 g_object_class_install_property (object_class,
389 g_param_spec_int ("sort-column-id",
390 P_("Sort column ID"),
391 P_("Logical sort column ID this column sorts on when selected for sorting"),
395 GTK_PARAM_READWRITE));
397 g_object_class_install_property (object_class,
399 g_param_spec_boolean ("quick-edit",
401 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."),
403 GTK_PARAM_READWRITE));
405 g_object_class_install_property (object_class,
407 g_param_spec_boolean ("selected",
409 P_("If true, this column is selected as part of a rectangular selection."),
411 GTK_PARAM_READWRITE));
413 g_object_class_install_property (object_class,
415 g_param_spec_boolean ("selectable",
417 P_("If true, this column may be selected as part of a rectangular selection."),
419 GTK_PARAM_READWRITE));
421 g_object_class_install_property (object_class,
423 g_param_spec_boolean ("row-head",
425 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)."),
427 GTK_PARAM_READWRITE));
431 pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface)
433 iface->add_child = _gtk_cell_layout_buildable_add_child;
434 iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
435 iface->custom_tag_end = _gtk_cell_layout_buildable_custom_tag_end;
439 pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface)
441 iface->pack_start = pspp_sheet_view_column_cell_layout_pack_start;
442 iface->pack_end = pspp_sheet_view_column_cell_layout_pack_end;
443 iface->clear = pspp_sheet_view_column_cell_layout_clear;
444 iface->add_attribute = pspp_sheet_view_column_cell_layout_add_attribute;
445 iface->set_cell_data_func = pspp_sheet_view_column_cell_layout_set_cell_data_func;
446 iface->clear_attributes = pspp_sheet_view_column_cell_layout_clear_attributes;
447 iface->reorder = pspp_sheet_view_column_cell_layout_reorder;
448 iface->get_cells = pspp_sheet_view_column_cell_layout_get_cells;
452 pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column)
454 tree_column->button = NULL;
455 tree_column->xalign = 0.0;
456 tree_column->width = 0;
457 tree_column->spacing = 0;
458 tree_column->requested_width = -1;
459 tree_column->min_width = -1;
460 tree_column->max_width = -1;
461 tree_column->resized_width = 0;
462 tree_column->visible = TRUE;
463 tree_column->resizable = FALSE;
464 tree_column->expand = FALSE;
465 tree_column->clickable = FALSE;
466 tree_column->dirty = TRUE;
467 tree_column->selected = FALSE;
468 tree_column->selectable = TRUE;
469 tree_column->row_head = FALSE;
470 tree_column->sort_order = GTK_SORT_ASCENDING;
471 tree_column->show_sort_indicator = FALSE;
472 tree_column->property_changed_signal = 0;
473 tree_column->sort_clicked_signal = 0;
474 tree_column->sort_column_changed_signal = 0;
475 tree_column->sort_column_id = -1;
476 tree_column->reorderable = FALSE;
477 tree_column->maybe_reordered = FALSE;
478 tree_column->fixed_width = 1;
479 tree_column->use_resized_width = FALSE;
480 tree_column->title = g_strdup ("");
481 tree_column->quick_edit = TRUE;
485 pspp_sheet_view_column_finalize (GObject *object)
487 PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
490 for (list = tree_column->cell_list; list; list = list->next)
492 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
496 GDestroyNotify d = info->destroy;
498 info->destroy = NULL;
501 pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
502 g_object_unref (info->cell);
506 g_free (tree_column->title);
507 g_list_free (tree_column->cell_list);
509 if (tree_column->child)
510 g_object_unref (tree_column->child);
512 G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
516 pspp_sheet_view_column_set_property (GObject *object,
521 PsppSheetViewColumn *tree_column;
523 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
528 pspp_sheet_view_column_set_visible (tree_column,
529 g_value_get_boolean (value));
533 pspp_sheet_view_column_set_resizable (tree_column,
534 g_value_get_boolean (value));
537 case PROP_FIXED_WIDTH:
538 pspp_sheet_view_column_set_fixed_width (tree_column,
539 g_value_get_int (value));
543 pspp_sheet_view_column_set_min_width (tree_column,
544 g_value_get_int (value));
548 pspp_sheet_view_column_set_max_width (tree_column,
549 g_value_get_int (value));
553 pspp_sheet_view_column_set_spacing (tree_column,
554 g_value_get_int (value));
558 pspp_sheet_view_column_set_title (tree_column,
559 g_value_get_string (value));
563 pspp_sheet_view_column_set_expand (tree_column,
564 g_value_get_boolean (value));
568 pspp_sheet_view_column_set_clickable (tree_column,
569 g_value_get_boolean (value));
573 pspp_sheet_view_column_set_widget (tree_column,
574 (GtkWidget*) g_value_get_object (value));
578 pspp_sheet_view_column_set_alignment (tree_column,
579 g_value_get_float (value));
582 case PROP_REORDERABLE:
583 pspp_sheet_view_column_set_reorderable (tree_column,
584 g_value_get_boolean (value));
587 case PROP_SORT_INDICATOR:
588 pspp_sheet_view_column_set_sort_indicator (tree_column,
589 g_value_get_boolean (value));
592 case PROP_SORT_ORDER:
593 pspp_sheet_view_column_set_sort_order (tree_column,
594 g_value_get_enum (value));
597 case PROP_SORT_COLUMN_ID:
598 pspp_sheet_view_column_set_sort_column_id (tree_column,
599 g_value_get_int (value));
602 case PROP_QUICK_EDIT:
603 pspp_sheet_view_column_set_quick_edit (tree_column,
604 g_value_get_boolean (value));
608 pspp_sheet_view_column_set_selected (tree_column,
609 g_value_get_boolean (value));
612 case PROP_SELECTABLE:
613 pspp_sheet_view_column_set_selectable (tree_column,
614 g_value_get_boolean (value));
618 pspp_sheet_view_column_set_row_head (tree_column,
619 g_value_get_boolean (value));
623 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
629 pspp_sheet_view_column_get_property (GObject *object,
634 PsppSheetViewColumn *tree_column;
636 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
641 g_value_set_boolean (value,
642 pspp_sheet_view_column_get_visible (tree_column));
646 g_value_set_boolean (value,
647 pspp_sheet_view_column_get_resizable (tree_column));
651 g_value_set_int (value,
652 pspp_sheet_view_column_get_width (tree_column));
656 g_value_set_int (value,
657 pspp_sheet_view_column_get_spacing (tree_column));
660 case PROP_FIXED_WIDTH:
661 g_value_set_int (value,
662 pspp_sheet_view_column_get_fixed_width (tree_column));
666 g_value_set_int (value,
667 pspp_sheet_view_column_get_min_width (tree_column));
671 g_value_set_int (value,
672 pspp_sheet_view_column_get_max_width (tree_column));
676 g_value_set_string (value,
677 pspp_sheet_view_column_get_title (tree_column));
681 g_value_set_boolean (value,
682 pspp_sheet_view_column_get_expand (tree_column));
686 g_value_set_boolean (value,
687 pspp_sheet_view_column_get_clickable (tree_column));
691 g_value_set_object (value,
692 (GObject*) pspp_sheet_view_column_get_widget (tree_column));
696 g_value_set_float (value,
697 pspp_sheet_view_column_get_alignment (tree_column));
700 case PROP_REORDERABLE:
701 g_value_set_boolean (value,
702 pspp_sheet_view_column_get_reorderable (tree_column));
705 case PROP_SORT_INDICATOR:
706 g_value_set_boolean (value,
707 pspp_sheet_view_column_get_sort_indicator (tree_column));
710 case PROP_SORT_ORDER:
711 g_value_set_enum (value,
712 pspp_sheet_view_column_get_sort_order (tree_column));
715 case PROP_SORT_COLUMN_ID:
716 g_value_set_int (value,
717 pspp_sheet_view_column_get_sort_column_id (tree_column));
720 case PROP_QUICK_EDIT:
721 g_value_set_boolean (value,
722 pspp_sheet_view_column_get_quick_edit (tree_column));
726 g_value_set_boolean (value,
727 pspp_sheet_view_column_get_selected (tree_column));
730 case PROP_SELECTABLE:
731 g_value_set_boolean (value,
732 pspp_sheet_view_column_get_selectable (tree_column));
736 g_value_set_boolean (value,
737 pspp_sheet_view_column_get_row_head (tree_column));
741 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
746 /* Implementation of GtkCellLayout interface
750 pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
751 GtkCellRenderer *cell,
754 PsppSheetViewColumn *column;
755 PsppSheetViewColumnCellInfo *cell_info;
757 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
758 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
759 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
761 g_object_ref_sink (cell);
763 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
764 cell_info->cell = cell;
765 cell_info->expand = expand ? TRUE : FALSE;
766 cell_info->pack = GTK_PACK_START;
767 cell_info->has_focus = 0;
768 cell_info->attributes = NULL;
770 column->cell_list = g_list_append (column->cell_list, cell_info);
774 pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
775 GtkCellRenderer *cell,
778 PsppSheetViewColumn *column;
779 PsppSheetViewColumnCellInfo *cell_info;
781 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
782 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
783 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
785 g_object_ref_sink (cell);
787 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
788 cell_info->cell = cell;
789 cell_info->expand = expand ? TRUE : FALSE;
790 cell_info->pack = GTK_PACK_END;
791 cell_info->has_focus = 0;
792 cell_info->attributes = NULL;
794 column->cell_list = g_list_append (column->cell_list, cell_info);
798 pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
800 PsppSheetViewColumn *column;
802 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
803 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
805 while (column->cell_list)
807 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
809 pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
810 g_object_unref (info->cell);
812 column->cell_list = g_list_delete_link (column->cell_list,
818 pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
819 GtkCellRenderer *cell,
820 const gchar *attribute,
823 PsppSheetViewColumn *tree_column;
824 PsppSheetViewColumnCellInfo *info;
826 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
827 tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
829 info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
830 g_return_if_fail (info != NULL);
832 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
833 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
835 if (tree_column->tree_view)
836 _pspp_sheet_view_column_cell_set_dirty (tree_column);
840 pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
841 GtkCellRenderer *cell,
842 GtkCellLayoutDataFunc func,
844 GDestroyNotify destroy)
846 PsppSheetViewColumn *column;
847 PsppSheetViewColumnCellInfo *info;
849 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
850 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
852 info = pspp_sheet_view_column_get_cell_info (column, cell);
853 g_return_if_fail (info != NULL);
857 GDestroyNotify d = info->destroy;
859 info->destroy = NULL;
863 info->func = (PsppSheetCellDataFunc)func;
864 info->func_data = func_data;
865 info->destroy = destroy;
867 if (column->tree_view)
868 _pspp_sheet_view_column_cell_set_dirty (column);
872 pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
873 GtkCellRenderer *cell_renderer)
875 PsppSheetViewColumn *column;
876 PsppSheetViewColumnCellInfo *info;
878 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
879 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
881 info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
883 pspp_sheet_view_column_clear_attributes_by_info (column, info);
887 pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
888 GtkCellRenderer *cell,
892 PsppSheetViewColumn *column;
893 PsppSheetViewColumnCellInfo *info;
895 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
896 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
898 info = pspp_sheet_view_column_get_cell_info (column, cell);
900 g_return_if_fail (info != NULL);
901 g_return_if_fail (position >= 0);
903 link = g_list_find (column->cell_list, info);
905 g_return_if_fail (link != NULL);
907 column->cell_list = g_list_delete_link (column->cell_list, link);
908 column->cell_list = g_list_insert (column->cell_list, info, position);
910 if (column->tree_view)
911 gtk_widget_queue_draw (column->tree_view);
915 pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
916 PsppSheetViewColumnCellInfo *info)
920 list = info->attributes;
922 while (list && list->next)
925 list = list->next->next;
927 g_slist_free (info->attributes);
928 info->attributes = NULL;
930 if (tree_column->tree_view)
931 _pspp_sheet_view_column_cell_set_dirty (tree_column);
935 on_query_tooltip (GtkWidget *widget,
938 gboolean keyboard_mode,
942 PsppSheetViewColumn *tree_column = user_data;
945 g_signal_emit (tree_column, tree_column_signals[QUERY_TOOLTIP], 0,
951 on_button_pressed (GtkWidget *widget, GdkEventButton *event,
954 PsppSheetViewColumn *tree_column = user_data;
957 /* XXX See "Implement GtkWidget::popup_menu" in GTK+ reference manual. */
958 g_signal_emit (tree_column, tree_column_signals[BUTTON_PRESS_EVENT],
966 /* Button handling code
969 pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
971 PsppSheetView *tree_view;
975 tree_view = (PsppSheetView *) tree_column->tree_view;
977 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
978 g_return_if_fail (tree_column->button == NULL);
980 gtk_widget_push_composite_child ();
981 tree_column->button = gtk_button_new ();
982 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
983 gtk_widget_pop_composite_child ();
985 /* make sure we own a reference to it as well. */
986 if (tree_view->priv->header_window)
987 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
988 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
990 g_signal_connect (tree_column->button, "event",
991 G_CALLBACK (pspp_sheet_view_column_button_event),
993 g_signal_connect (tree_column->button, "clicked",
994 G_CALLBACK (pspp_sheet_view_column_button_clicked),
996 g_signal_connect (tree_column->button, "popup-menu",
997 G_CALLBACK (pspp_sheet_view_column_button_popup_menu),
999 g_signal_connect (tree_column->button, "button-press-event",
1000 G_CALLBACK (on_button_pressed), tree_column);
1002 g_signal_connect (tree_column->button, "query-tooltip",
1003 G_CALLBACK (on_query_tooltip), tree_column);
1004 g_object_set (tree_column->button, "has-tooltip", TRUE, NULL);
1006 tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
1008 hbox = gtk_hbox_new (FALSE, 2);
1009 tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
1011 if (tree_column->child)
1012 child = tree_column->child;
1015 child = gtk_label_new (tree_column->title);
1016 gtk_widget_show (child);
1019 g_signal_connect (child, "mnemonic-activate",
1020 G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
1023 if (tree_column->xalign <= 0.5)
1024 gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
1026 gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
1028 gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
1030 gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
1031 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
1033 gtk_widget_show (hbox);
1034 gtk_widget_show (tree_column->alignment);
1035 pspp_sheet_view_column_update_button (tree_column);
1039 pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
1041 gint sort_column_id = -1;
1043 GtkWidget *alignment;
1045 GtkWidget *current_child;
1046 GtkArrowType arrow_type = GTK_ARROW_NONE;
1047 GtkTreeModel *model;
1049 if (tree_column->tree_view)
1050 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1054 /* Create a button if necessary */
1055 if (tree_column->visible &&
1056 tree_column->button == NULL &&
1057 tree_column->tree_view &&
1058 gtk_widget_get_realized (tree_column->tree_view))
1059 pspp_sheet_view_column_create_button (tree_column);
1061 if (! tree_column->button)
1064 hbox = GTK_BIN (tree_column->button)->child;
1065 alignment = tree_column->alignment;
1066 arrow = tree_column->arrow;
1067 current_child = GTK_BIN (alignment)->child;
1069 /* Set up the actual button */
1070 gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
1073 if (tree_column->child)
1075 if (current_child != tree_column->child)
1077 gtk_container_remove (GTK_CONTAINER (alignment),
1079 gtk_container_add (GTK_CONTAINER (alignment),
1080 tree_column->child);
1085 if (current_child == NULL)
1087 current_child = gtk_label_new (NULL);
1088 gtk_widget_show (current_child);
1089 gtk_container_add (GTK_CONTAINER (alignment),
1093 g_return_if_fail (GTK_IS_LABEL (current_child));
1095 if (tree_column->title)
1096 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1097 tree_column->title);
1099 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1103 if (GTK_IS_TREE_SORTABLE (model))
1104 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1108 if (tree_column->show_sort_indicator)
1110 gboolean alternative;
1112 g_object_get (gtk_widget_get_settings (tree_column->tree_view),
1113 "gtk-alternative-sort-arrows", &alternative,
1116 switch (tree_column->sort_order)
1118 case GTK_SORT_ASCENDING:
1119 arrow_type = alternative ? GTK_ARROW_UP : GTK_ARROW_DOWN;
1122 case GTK_SORT_DESCENDING:
1123 arrow_type = alternative ? GTK_ARROW_DOWN : GTK_ARROW_UP;
1127 g_warning (G_STRLOC": bad sort order");
1132 gtk_arrow_set (GTK_ARROW (arrow),
1136 /* Put arrow on the right if the text is left-or-center justified, and on the
1137 * left otherwise; do this by packing boxes, so flipping text direction will
1140 g_object_ref (arrow);
1141 gtk_container_remove (GTK_CONTAINER (hbox), arrow);
1143 if (tree_column->xalign <= 0.5)
1145 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1149 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1150 /* move it to the front */
1151 gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
1153 g_object_unref (arrow);
1155 if (tree_column->show_sort_indicator
1156 || (GTK_IS_TREE_SORTABLE (model) && tree_column->sort_column_id >= 0))
1157 gtk_widget_show (arrow);
1159 gtk_widget_hide (arrow);
1161 /* It's always safe to hide the button. It isn't always safe to show it, as
1162 * if you show it before it's realized, it'll get the wrong window. */
1163 if (tree_column->button &&
1164 tree_column->tree_view != NULL &&
1165 gtk_widget_get_realized (tree_column->tree_view))
1167 if (tree_column->visible)
1169 gtk_widget_show_now (tree_column->button);
1170 if (tree_column->window)
1172 if (tree_column->resizable)
1174 gdk_window_show (tree_column->window);
1175 gdk_window_raise (tree_column->window);
1179 gdk_window_hide (tree_column->window);
1185 gtk_widget_hide (tree_column->button);
1186 if (tree_column->window)
1187 gdk_window_hide (tree_column->window);
1191 if (tree_column->reorderable || tree_column->clickable)
1193 gtk_widget_set_can_focus (tree_column->button, TRUE);
1197 gtk_widget_set_can_focus (tree_column->button, FALSE);
1198 if (gtk_widget_has_focus (tree_column->button))
1200 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
1201 if (gtk_widget_is_toplevel (toplevel))
1203 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
1207 /* Queue a resize on the assumption that we always want to catch all changes
1208 * and columns don't change all that often.
1210 if (gtk_widget_get_realized (tree_column->tree_view))
1211 gtk_widget_queue_resize (tree_column->tree_view);
1215 /* Button signal handlers
1219 pspp_sheet_view_column_button_event (GtkWidget *widget,
1223 PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
1225 g_return_val_if_fail (event != NULL, FALSE);
1227 if (event->type == GDK_BUTTON_PRESS &&
1228 column->reorderable &&
1229 ((GdkEventButton *)event)->button == 1)
1231 column->maybe_reordered = TRUE;
1232 gdk_window_get_pointer (GTK_BUTTON (widget)->event_window,
1236 gtk_widget_grab_focus (widget);
1239 if (event->type == GDK_BUTTON_RELEASE ||
1240 event->type == GDK_LEAVE_NOTIFY)
1241 column->maybe_reordered = FALSE;
1243 if (event->type == GDK_MOTION_NOTIFY &&
1244 column->maybe_reordered &&
1245 (gtk_drag_check_threshold (widget,
1248 (gint) ((GdkEventMotion *)event)->x,
1249 (gint) ((GdkEventMotion *)event)->y)))
1251 column->maybe_reordered = FALSE;
1252 _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
1255 if (column->clickable == FALSE)
1257 switch (event->type)
1259 case GDK_MOTION_NOTIFY:
1260 case GDK_BUTTON_RELEASE:
1261 case GDK_ENTER_NOTIFY:
1262 case GDK_LEAVE_NOTIFY:
1272 all_rows_selected (PsppSheetView *sheet_view)
1274 PsppSheetSelection *selection = sheet_view->priv->selection;
1275 gint n_rows, n_selected_rows;
1277 n_rows = sheet_view->priv->row_count;
1278 n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
1280 return n_rows > 0 && n_selected_rows >= n_rows;
1284 on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *column,
1285 GdkEventButton *event)
1287 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (column->tree_view);
1288 PsppSheetSelection *selection;
1289 GSignalInvocationHint *hint;
1292 /* We only want to run first, not last, but combining that with return type
1293 `gboolean' makes GObject warn, so just ignore the run_last call. */
1294 hint = g_signal_get_invocation_hint (column);
1295 g_return_val_if_fail (hint != NULL, FALSE);
1296 if (hint->run_type != G_SIGNAL_RUN_FIRST)
1299 g_return_val_if_fail (sheet_view != NULL, FALSE);
1301 selection = sheet_view->priv->selection;
1302 g_return_val_if_fail (selection != NULL, FALSE);
1304 if (pspp_sheet_selection_get_mode (selection) != PSPP_SHEET_SELECTION_RECTANGLE)
1307 modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
1308 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
1310 if (pspp_sheet_selection_count_selected_columns (selection) <= 1
1311 || !all_rows_selected (sheet_view))
1313 pspp_sheet_selection_select_all (selection);
1314 pspp_sheet_selection_unselect_all_columns (selection);
1315 pspp_sheet_selection_select_column (selection, column);
1316 sheet_view->priv->anchor_column = column;
1320 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1321 && modifiers == GDK_CONTROL_MASK)
1323 gboolean is_selected;
1325 if (!all_rows_selected (sheet_view))
1327 pspp_sheet_selection_select_all (selection);
1328 pspp_sheet_selection_unselect_all_columns (selection);
1330 sheet_view->priv->anchor_column = column;
1332 is_selected = pspp_sheet_view_column_get_selected (column);
1333 pspp_sheet_view_column_set_selected (column, !is_selected);
1337 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1338 && modifiers == GDK_SHIFT_MASK)
1340 if (!all_rows_selected (sheet_view))
1342 pspp_sheet_selection_select_all (selection);
1343 pspp_sheet_selection_unselect_all_columns (selection);
1344 sheet_view->priv->anchor_column = column;
1346 else if (sheet_view->priv->anchor_column == NULL)
1347 sheet_view->priv->anchor_column = column;
1349 pspp_sheet_selection_unselect_all_columns (selection);
1350 pspp_sheet_selection_select_column_range (selection,
1351 sheet_view->priv->anchor_column,
1360 on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *column)
1362 PsppSheetSelection *selection;
1363 PsppSheetView *sheet_view;
1365 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (column));
1366 selection = pspp_sheet_view_get_selection (sheet_view);
1367 if (pspp_sheet_selection_get_mode (selection) == PSPP_SHEET_SELECTION_RECTANGLE)
1369 pspp_sheet_selection_select_all (selection);
1370 pspp_sheet_selection_unselect_all_columns (selection);
1371 pspp_sheet_selection_select_column (selection, column);
1372 sheet_view->priv->anchor_column = column;
1379 pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
1381 PsppSheetViewColumn *column = data;
1384 g_signal_emit (column, tree_column_signals[CLICKED], 0, &handled);
1388 pspp_sheet_view_column_button_popup_menu (GtkWidget *widget, gpointer data)
1390 g_signal_emit_by_name (data, "popup-menu");
1394 pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
1395 gboolean group_cycling,
1398 PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
1400 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
1402 PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
1403 if (column->clickable)
1404 gtk_button_clicked (GTK_BUTTON (column->button));
1405 else if (gtk_widget_get_can_focus (column->button))
1406 gtk_widget_grab_focus (column->button);
1408 gtk_widget_grab_focus (column->tree_view);
1414 pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
1415 PsppSheetViewColumn *column)
1417 gint sort_column_id;
1420 if (gtk_tree_sortable_get_sort_column_id (sortable,
1424 if (sort_column_id == column->sort_column_id)
1426 pspp_sheet_view_column_set_sort_indicator (column, TRUE);
1427 pspp_sheet_view_column_set_sort_order (column, order);
1431 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1436 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1441 pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
1444 gint sort_column_id;
1446 gboolean has_sort_column;
1447 gboolean has_default_sort_func;
1449 g_return_if_fail (tree_column->tree_view != NULL);
1452 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1455 has_default_sort_func =
1456 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
1458 if (has_sort_column &&
1459 sort_column_id == tree_column->sort_column_id)
1461 if (order == GTK_SORT_ASCENDING)
1462 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1463 tree_column->sort_column_id,
1464 GTK_SORT_DESCENDING);
1465 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
1466 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1467 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1468 GTK_SORT_ASCENDING);
1470 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1471 tree_column->sort_column_id,
1472 GTK_SORT_ASCENDING);
1476 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1477 tree_column->sort_column_id,
1478 GTK_SORT_ASCENDING);
1484 pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
1486 GtkTreeModel *model;
1488 if (tree_column->tree_view == NULL)
1491 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1496 if (GTK_IS_TREE_SORTABLE (model) &&
1497 tree_column->sort_column_id != -1)
1499 gint real_sort_column_id;
1500 GtkSortType real_order;
1502 if (tree_column->sort_column_changed_signal == 0)
1503 tree_column->sort_column_changed_signal =
1504 g_signal_connect (model, "sort-column-changed",
1505 G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
1508 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1509 &real_sort_column_id,
1511 (real_sort_column_id == tree_column->sort_column_id))
1513 pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
1514 pspp_sheet_view_column_set_sort_order (tree_column, real_order);
1518 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
1524 /* Exported Private Functions.
1525 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1529 _pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
1531 PsppSheetView *tree_view;
1533 guint attributes_mask;
1536 tree_view = (PsppSheetView *)column->tree_view;
1537 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
1539 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1540 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
1541 g_return_if_fail (tree_view->priv->header_window != NULL);
1542 g_return_if_fail (column->button != NULL);
1544 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
1546 if (column->visible)
1547 gtk_widget_show (column->button);
1549 attr.window_type = GDK_WINDOW_CHILD;
1550 attr.wclass = GDK_INPUT_ONLY;
1551 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1552 attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1553 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
1554 (GDK_BUTTON_PRESS_MASK |
1555 GDK_BUTTON_RELEASE_MASK |
1556 GDK_POINTER_MOTION_MASK |
1557 GDK_POINTER_MOTION_HINT_MASK |
1558 GDK_KEY_PRESS_MASK);
1559 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
1560 attr.cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (tree_view->priv->header_window),
1561 GDK_SB_H_DOUBLE_ARROW);
1563 attr.width = TREE_VIEW_DRAG_WIDTH;
1564 attr.height = tree_view->priv->header_height;
1566 attr.x = (column->button->allocation.x + (rtl ? 0 : column->button->allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
1567 column->window = gdk_window_new (tree_view->priv->header_window,
1568 &attr, attributes_mask);
1569 gdk_window_set_user_data (column->window, tree_view);
1571 pspp_sheet_view_column_update_button (column);
1573 gdk_cursor_unref (attr.cursor);
1577 _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
1579 g_return_if_fail (column != NULL);
1580 g_return_if_fail (column->window != NULL);
1582 gdk_window_set_user_data (column->window, NULL);
1583 gdk_window_destroy (column->window);
1584 column->window = NULL;
1588 _pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
1589 GtkTreeModel *old_model)
1591 if (column->sort_column_changed_signal)
1593 g_signal_handler_disconnect (old_model,
1594 column->sort_column_changed_signal);
1595 column->sort_column_changed_signal = 0;
1597 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1601 _pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
1602 PsppSheetView *tree_view)
1604 g_assert (column->tree_view == NULL);
1606 column->tree_view = GTK_WIDGET (tree_view);
1607 pspp_sheet_view_column_create_button (column);
1609 column->property_changed_signal =
1610 g_signal_connect_swapped (tree_view,
1612 G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
1615 pspp_sheet_view_column_setup_sort_column_id_callback (column);
1619 _pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
1621 if (column->tree_view && column->button)
1623 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1625 if (column->property_changed_signal)
1627 g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
1628 column->property_changed_signal = 0;
1631 if (column->sort_column_changed_signal)
1633 g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
1634 column->sort_column_changed_signal);
1635 column->sort_column_changed_signal = 0;
1638 column->tree_view = NULL;
1639 column->button = NULL;
1643 _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
1647 for (list = column->cell_list; list; list = list->next)
1648 if (((PsppSheetViewColumnCellInfo *)list->data)->cell->mode ==
1649 GTK_CELL_RENDERER_MODE_EDITABLE)
1655 /* gets cell being edited */
1657 _pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
1661 for (list = column->cell_list; list; list = list->next)
1662 if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
1663 return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
1669 _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
1674 for (list = column->cell_list; list; list = list->next)
1676 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1678 if ((cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1679 cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
1680 cellinfo->cell->visible)
1688 _pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
1694 list = pspp_sheet_view_column_cell_first (column);
1695 for (; list; list = pspp_sheet_view_column_cell_next (column, list))
1697 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1698 if (current_x <= x && x <= current_x + cellinfo->real_width)
1699 return cellinfo->cell;
1700 current_x += cellinfo->real_width;
1706 /* Public Functions */
1710 * pspp_sheet_view_column_new:
1712 * Creates a new #PsppSheetViewColumn.
1714 * Return value: A newly created #PsppSheetViewColumn.
1716 PsppSheetViewColumn *
1717 pspp_sheet_view_column_new (void)
1719 PsppSheetViewColumn *tree_column;
1721 tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
1727 * pspp_sheet_view_column_new_with_attributes:
1728 * @title: The title to set the header to.
1729 * @cell: The #GtkCellRenderer.
1730 * @Varargs: A %NULL-terminated list of attributes.
1732 * Creates a new #PsppSheetViewColumn with a number of default values. This is
1733 * equivalent to calling pspp_sheet_view_column_set_title(),
1734 * pspp_sheet_view_column_pack_start(), and
1735 * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
1737 * Here's a simple example:
1739 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1742 * PsppSheetViewColumn *column;
1743 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
1745 * column = pspp_sheet_view_column_new_with_attributes ("Title",
1747 * "text", TEXT_COLUMN,
1748 * "foreground", COLOR_COLUMN,
1753 * Return value: A newly created #PsppSheetViewColumn.
1755 PsppSheetViewColumn *
1756 pspp_sheet_view_column_new_with_attributes (const gchar *title,
1757 GtkCellRenderer *cell,
1760 PsppSheetViewColumn *retval;
1763 retval = pspp_sheet_view_column_new ();
1765 pspp_sheet_view_column_set_title (retval, title);
1766 pspp_sheet_view_column_pack_start (retval, cell, TRUE);
1768 va_start (args, cell);
1769 pspp_sheet_view_column_set_attributesv (retval, cell, args);
1775 static PsppSheetViewColumnCellInfo *
1776 pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
1777 GtkCellRenderer *cell_renderer)
1780 for (list = tree_column->cell_list; list; list = list->next)
1781 if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
1782 return (PsppSheetViewColumnCellInfo *) list->data;
1788 * pspp_sheet_view_column_pack_start:
1789 * @tree_column: A #PsppSheetViewColumn.
1790 * @cell: The #GtkCellRenderer.
1791 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1793 * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
1794 * the @cell is allocated no more space than it needs. Any unused space is divided
1795 * evenly between cells for which @expand is %TRUE.
1798 pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
1799 GtkCellRenderer *cell,
1802 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
1806 * pspp_sheet_view_column_pack_end:
1807 * @tree_column: A #PsppSheetViewColumn.
1808 * @cell: The #GtkCellRenderer.
1809 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1811 * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
1812 * is allocated no more space than it needs. Any unused space is divided
1813 * evenly between cells for which @expand is %TRUE.
1816 pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
1817 GtkCellRenderer *cell,
1820 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
1824 * pspp_sheet_view_column_clear:
1825 * @tree_column: A #PsppSheetViewColumn
1827 * Unsets all the mappings on all renderers on the @tree_column.
1830 pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
1832 gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
1836 pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
1838 PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
1839 GList *retval = NULL, *list;
1841 g_return_val_if_fail (tree_column != NULL, NULL);
1843 for (list = tree_column->cell_list; list; list = list->next)
1845 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
1847 retval = g_list_append (retval, info->cell);
1854 * pspp_sheet_view_column_get_cell_renderers:
1855 * @tree_column: A #PsppSheetViewColumn
1857 * Returns a newly-allocated #GList of all the cell renderers in the column,
1858 * in no particular order. The list must be freed with g_list_free().
1860 * Return value: A list of #GtkCellRenderers
1862 * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
1865 pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
1867 return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
1871 * pspp_sheet_view_column_add_attribute:
1872 * @tree_column: A #PsppSheetViewColumn.
1873 * @cell_renderer: the #GtkCellRenderer to set attributes on
1874 * @attribute: An attribute on the renderer
1875 * @column: The column position on the model to get the attribute from.
1877 * Adds an attribute mapping to the list in @tree_column. The @column is the
1878 * column of the model to get a value from, and the @attribute is the
1879 * parameter on @cell_renderer to be set from the value. So for example
1880 * if column 2 of the model contains strings, you could have the
1881 * "text" attribute of a #GtkCellRendererText get its values from
1885 pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
1886 GtkCellRenderer *cell_renderer,
1887 const gchar *attribute,
1890 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
1891 cell_renderer, attribute, column);
1895 pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
1896 GtkCellRenderer *cell_renderer,
1902 attribute = va_arg (args, gchar *);
1904 pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
1906 while (attribute != NULL)
1908 column = va_arg (args, gint);
1909 pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1910 attribute = va_arg (args, gchar *);
1915 * pspp_sheet_view_column_set_attributes:
1916 * @tree_column: A #PsppSheetViewColumn.
1917 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1918 * @Varargs: A %NULL-terminated list of attributes.
1920 * Sets the attributes in the list as the attributes of @tree_column.
1921 * The attributes should be in attribute/column order, as in
1922 * pspp_sheet_view_column_add_attribute(). All existing attributes
1923 * are removed, and replaced with the new attributes.
1926 pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
1927 GtkCellRenderer *cell_renderer,
1932 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1933 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1934 g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
1936 va_start (args, cell_renderer);
1937 pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
1943 * pspp_sheet_view_column_set_cell_data_func:
1944 * @tree_column: A #PsppSheetViewColumn
1945 * @cell_renderer: A #GtkCellRenderer
1946 * @func: The #PsppSheetViewColumnFunc to use.
1947 * @func_data: The user data for @func.
1948 * @destroy: The destroy notification for @func_data
1950 * Sets the #PsppSheetViewColumnFunc to use for the column. This
1951 * function is used instead of the standard attributes mapping for
1952 * setting the column value, and should set the value of @tree_column's
1953 * cell renderer as appropriate. @func may be %NULL to remove an
1957 pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
1958 GtkCellRenderer *cell_renderer,
1959 PsppSheetCellDataFunc func,
1961 GDestroyNotify destroy)
1963 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
1965 (GtkCellLayoutDataFunc)func,
1966 func_data, destroy);
1971 * pspp_sheet_view_column_clear_attributes:
1972 * @tree_column: a #PsppSheetViewColumn
1973 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1975 * Clears all existing attributes previously set with
1976 * pspp_sheet_view_column_set_attributes().
1979 pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
1980 GtkCellRenderer *cell_renderer)
1982 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
1987 * pspp_sheet_view_column_set_spacing:
1988 * @tree_column: A #PsppSheetViewColumn.
1989 * @spacing: distance between cell renderers in pixels.
1991 * Sets the spacing field of @tree_column, which is the number of pixels to
1992 * place between cell renderers packed into it.
1995 pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
1998 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1999 g_return_if_fail (spacing >= 0);
2001 if (tree_column->spacing == spacing)
2004 tree_column->spacing = spacing;
2005 if (tree_column->tree_view)
2006 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2010 * pspp_sheet_view_column_get_spacing:
2011 * @tree_column: A #PsppSheetViewColumn.
2013 * Returns the spacing of @tree_column.
2015 * Return value: the spacing of @tree_column.
2018 pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
2020 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2022 return tree_column->spacing;
2025 /* Options for manipulating the columns */
2028 * pspp_sheet_view_column_set_visible:
2029 * @tree_column: A #PsppSheetViewColumn.
2030 * @visible: %TRUE if the @tree_column is visible.
2032 * Sets the visibility of @tree_column.
2035 pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
2038 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2040 visible = !! visible;
2042 if (tree_column->visible == visible)
2045 tree_column->visible = visible;
2047 if (tree_column->visible)
2048 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2050 pspp_sheet_view_column_update_button (tree_column);
2051 g_object_notify (G_OBJECT (tree_column), "visible");
2055 * pspp_sheet_view_column_get_visible:
2056 * @tree_column: A #PsppSheetViewColumn.
2058 * Returns %TRUE if @tree_column is visible.
2060 * Return value: whether the column is visible or not. If it is visible, then
2061 * the tree will show the column.
2064 pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
2066 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2068 return tree_column->visible;
2072 * pspp_sheet_view_column_set_resizable:
2073 * @tree_column: A #PsppSheetViewColumn
2074 * @resizable: %TRUE, if the column can be resized
2076 * If @resizable is %TRUE, then the user can explicitly resize the column by
2077 * grabbing the outer edge of the column button.
2080 pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
2083 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2085 resizable = !! resizable;
2087 if (tree_column->resizable == resizable)
2090 tree_column->resizable = resizable;
2092 pspp_sheet_view_column_update_button (tree_column);
2094 g_object_notify (G_OBJECT (tree_column), "resizable");
2098 * pspp_sheet_view_column_get_resizable:
2099 * @tree_column: A #PsppSheetViewColumn
2101 * Returns %TRUE if the @tree_column can be resized by the end user.
2103 * Return value: %TRUE, if the @tree_column can be resized.
2106 pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
2108 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2110 return tree_column->resizable;
2115 * pspp_sheet_view_column_get_width:
2116 * @tree_column: A #PsppSheetViewColumn.
2118 * Returns the current size of @tree_column in pixels.
2120 * Return value: The current width of @tree_column.
2123 pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
2125 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2127 return tree_column->width;
2131 * pspp_sheet_view_column_set_fixed_width:
2132 * @tree_column: A #PsppSheetViewColumn.
2133 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
2135 * Sets the size of the column in pixels. The size of the column is clamped to
2136 * the min/max width for the column. Please note that the min/max width of the
2137 * column doesn't actually affect the "fixed_width" property of the widget, just
2138 * the actual size when displayed.
2141 pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
2144 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2145 g_return_if_fail (fixed_width > 0);
2147 tree_column->fixed_width = fixed_width;
2148 tree_column->use_resized_width = FALSE;
2150 if (tree_column->tree_view &&
2151 gtk_widget_get_realized (tree_column->tree_view))
2153 gtk_widget_queue_resize (tree_column->tree_view);
2156 g_object_notify (G_OBJECT (tree_column), "fixed-width");
2160 * pspp_sheet_view_column_get_fixed_width:
2161 * @tree_column: a #PsppSheetViewColumn
2163 * Gets the fixed width of the column. This value is only meaning may not be
2164 * the actual width of the column on the screen, just what is requested.
2166 * Return value: the fixed width of the column
2169 pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
2171 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2173 return tree_column->fixed_width;
2177 * pspp_sheet_view_column_set_min_width:
2178 * @tree_column: A #PsppSheetViewColumn.
2179 * @min_width: The minimum width of the column in pixels, or -1.
2181 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
2182 * minimum width is unset.
2185 pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
2188 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2189 g_return_if_fail (min_width >= -1);
2191 if (min_width == tree_column->min_width)
2194 if (tree_column->visible &&
2195 tree_column->tree_view != NULL &&
2196 gtk_widget_get_realized (tree_column->tree_view))
2198 if (min_width > tree_column->width)
2199 gtk_widget_queue_resize (tree_column->tree_view);
2202 tree_column->min_width = min_width;
2203 g_object_freeze_notify (G_OBJECT (tree_column));
2204 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
2206 tree_column->max_width = min_width;
2207 g_object_notify (G_OBJECT (tree_column), "max-width");
2209 g_object_notify (G_OBJECT (tree_column), "min-width");
2210 g_object_thaw_notify (G_OBJECT (tree_column));
2214 * pspp_sheet_view_column_get_min_width:
2215 * @tree_column: A #PsppSheetViewColumn.
2217 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
2220 * Return value: The minimum width of the @tree_column.
2223 pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
2225 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2227 return tree_column->min_width;
2231 * pspp_sheet_view_column_set_max_width:
2232 * @tree_column: A #PsppSheetViewColumn.
2233 * @max_width: The maximum width of the column in pixels, or -1.
2235 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
2236 * maximum width is unset. Note, the column can actually be wider than max
2237 * width if it's the last column in a view. In this case, the column expands to
2238 * fill any extra space.
2241 pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
2244 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2245 g_return_if_fail (max_width >= -1);
2247 if (max_width == tree_column->max_width)
2250 if (tree_column->visible &&
2251 tree_column->tree_view != NULL &&
2252 gtk_widget_get_realized (tree_column->tree_view))
2254 if (max_width != -1 && max_width < tree_column->width)
2255 gtk_widget_queue_resize (tree_column->tree_view);
2258 tree_column->max_width = max_width;
2259 g_object_freeze_notify (G_OBJECT (tree_column));
2260 if (max_width != -1 && max_width < tree_column->min_width)
2262 tree_column->min_width = max_width;
2263 g_object_notify (G_OBJECT (tree_column), "min-width");
2265 g_object_notify (G_OBJECT (tree_column), "max-width");
2266 g_object_thaw_notify (G_OBJECT (tree_column));
2270 * pspp_sheet_view_column_get_max_width:
2271 * @tree_column: A #PsppSheetViewColumn.
2273 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
2276 * Return value: The maximum width of the @tree_column.
2279 pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
2281 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2283 return tree_column->max_width;
2287 * pspp_sheet_view_column_clicked:
2288 * @tree_column: a #PsppSheetViewColumn
2290 * Emits the "clicked" signal on the column. This function will only work if
2291 * @tree_column is clickable.
2294 pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
2296 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2298 if (tree_column->visible &&
2299 tree_column->button &&
2300 tree_column->clickable)
2301 gtk_button_clicked (GTK_BUTTON (tree_column->button));
2305 * pspp_sheet_view_column_set_title:
2306 * @tree_column: A #PsppSheetViewColumn.
2307 * @title: The title of the @tree_column.
2309 * Sets the title of the @tree_column. If a custom widget has been set, then
2310 * this value is ignored.
2313 pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
2318 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2320 new_title = g_strdup (title);
2321 g_free (tree_column->title);
2322 tree_column->title = new_title;
2324 pspp_sheet_view_column_update_button (tree_column);
2325 g_object_notify (G_OBJECT (tree_column), "title");
2329 * pspp_sheet_view_column_get_title:
2330 * @tree_column: A #PsppSheetViewColumn.
2332 * Returns the title of the widget.
2334 * Return value: the title of the column. This string should not be
2335 * modified or freed.
2337 G_CONST_RETURN gchar *
2338 pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
2340 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2342 return tree_column->title;
2346 * pspp_sheet_view_column_set_expand:
2347 * @tree_column: A #PsppSheetViewColumn
2348 * @expand: %TRUE if the column should take available extra space, %FALSE if not
2350 * Sets the column to take available extra space. This space is shared equally
2351 * amongst all columns that have the expand set to %TRUE. If no column has this
2352 * option set, then the last column gets all extra space. By default, every
2353 * column is created with this %FALSE.
2358 pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
2361 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2363 expand = expand?TRUE:FALSE;
2364 if (tree_column->expand == expand)
2366 tree_column->expand = expand;
2368 if (tree_column->visible &&
2369 tree_column->tree_view != NULL &&
2370 gtk_widget_get_realized (tree_column->tree_view))
2372 /* We want to continue using the original width of the
2373 * column that includes additional space added by the user
2374 * resizing the columns and possibly extra (expanded) space, which
2375 * are not included in the resized width.
2377 tree_column->use_resized_width = FALSE;
2379 gtk_widget_queue_resize (tree_column->tree_view);
2382 g_object_notify (G_OBJECT (tree_column), "expand");
2386 * pspp_sheet_view_column_get_expand:
2387 * @tree_column: a #PsppSheetViewColumn
2389 * Return %TRUE if the column expands to take any available space.
2391 * Return value: %TRUE, if the column expands
2396 pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
2398 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2400 return tree_column->expand;
2404 * pspp_sheet_view_column_set_clickable:
2405 * @tree_column: A #PsppSheetViewColumn.
2406 * @clickable: %TRUE if the header is active.
2408 * Sets the header to be active if @active is %TRUE. When the header is active,
2409 * then it can take keyboard focus, and can be clicked.
2412 pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
2415 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2417 clickable = !! clickable;
2418 if (tree_column->clickable == clickable)
2421 tree_column->clickable = clickable;
2422 pspp_sheet_view_column_update_button (tree_column);
2423 g_object_notify (G_OBJECT (tree_column), "clickable");
2427 * pspp_sheet_view_column_get_clickable:
2428 * @tree_column: a #PsppSheetViewColumn
2430 * Returns %TRUE if the user can click on the header for the column.
2432 * Return value: %TRUE if user can click the column header.
2435 pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
2437 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2439 return tree_column->clickable;
2443 * pspp_sheet_view_column_set_widget:
2444 * @tree_column: A #PsppSheetViewColumn.
2445 * @widget: (allow-none): A child #GtkWidget, or %NULL.
2447 * Sets the widget in the header to be @widget. If widget is %NULL, then the
2448 * header button is set with a #GtkLabel set to the title of @tree_column.
2451 pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
2454 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2455 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
2458 g_object_ref_sink (widget);
2460 if (tree_column->child)
2461 g_object_unref (tree_column->child);
2463 tree_column->child = widget;
2464 pspp_sheet_view_column_update_button (tree_column);
2465 g_object_notify (G_OBJECT (tree_column), "widget");
2469 * pspp_sheet_view_column_get_widget:
2470 * @tree_column: A #PsppSheetViewColumn.
2472 * Returns the #GtkWidget in the button on the column header. If a custom
2473 * widget has not been set then %NULL is returned.
2475 * Return value: The #GtkWidget in the column header, or %NULL
2478 pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
2480 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2482 return tree_column->child;
2486 * pspp_sheet_view_column_set_alignment:
2487 * @tree_column: A #PsppSheetViewColumn.
2488 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2490 * Sets the alignment of the title or custom widget inside the column header.
2491 * The alignment determines its location inside the button -- 0.0 for left, 0.5
2492 * for center, 1.0 for right.
2495 pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
2498 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2500 xalign = CLAMP (xalign, 0.0, 1.0);
2502 if (tree_column->xalign == xalign)
2505 tree_column->xalign = xalign;
2506 pspp_sheet_view_column_update_button (tree_column);
2507 g_object_notify (G_OBJECT (tree_column), "alignment");
2511 * pspp_sheet_view_column_get_alignment:
2512 * @tree_column: A #PsppSheetViewColumn.
2514 * Returns the current x alignment of @tree_column. This value can range
2515 * between 0.0 and 1.0.
2517 * Return value: The current alignent of @tree_column.
2520 pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
2522 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0.5);
2524 return tree_column->xalign;
2528 * pspp_sheet_view_column_set_reorderable:
2529 * @tree_column: A #PsppSheetViewColumn
2530 * @reorderable: %TRUE, if the column can be reordered.
2532 * If @reorderable is %TRUE, then the column can be reordered by the end user
2533 * dragging the header.
2536 pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
2537 gboolean reorderable)
2539 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2542 pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
2544 if (tree_column->reorderable == (reorderable?TRUE:FALSE))
2547 tree_column->reorderable = (reorderable?TRUE:FALSE);
2548 pspp_sheet_view_column_update_button (tree_column);
2549 g_object_notify (G_OBJECT (tree_column), "reorderable");
2553 * pspp_sheet_view_column_get_reorderable:
2554 * @tree_column: A #PsppSheetViewColumn
2556 * Returns %TRUE if the @tree_column can be reordered by the user.
2558 * Return value: %TRUE if the @tree_column can be reordered by the user.
2561 pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
2563 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2565 return tree_column->reorderable;
2569 * pspp_sheet_view_column_set_quick_edit:
2570 * @tree_column: A #PsppSheetViewColumn
2571 * @quick_edit: If true, editing starts upon the first click in the column. If
2572 * false, the first click selects the column and a second click is needed to
2573 * begin editing. This has no effect on cells that are not editable.
2576 pspp_sheet_view_column_set_quick_edit (PsppSheetViewColumn *tree_column,
2577 gboolean quick_edit)
2579 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2581 quick_edit = !!quick_edit;
2582 if (tree_column->quick_edit != quick_edit)
2584 tree_column->quick_edit = (quick_edit?TRUE:FALSE);
2585 g_object_notify (G_OBJECT (tree_column), "quick-edit");
2590 * pspp_sheet_view_column_get_quick_edit:
2591 * @tree_column: A #PsppSheetViewColumn
2593 * Returns %TRUE if editing starts upon the first click in the column. Returns
2594 * %FALSE, the first click selects the column and a second click is needed to
2595 * begin editing. This is not meaningful for cells that are not editable.
2597 * Return value: %TRUE if editing starts upon the first click.
2600 pspp_sheet_view_column_get_quick_edit (PsppSheetViewColumn *tree_column)
2602 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2604 return tree_column->quick_edit;
2609 * pspp_sheet_view_column_set_selected:
2610 * @tree_column: A #PsppSheetViewColumn
2611 * @selected: If true, the column is selected as part of a rectangular
2615 pspp_sheet_view_column_set_selected (PsppSheetViewColumn *tree_column,
2618 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2620 selected = !!selected;
2621 if (tree_column->selected != selected)
2623 PsppSheetSelection *selection;
2624 PsppSheetView *sheet_view;
2626 if (tree_column->tree_view != NULL)
2627 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2628 tree_column->selected = (selected?TRUE:FALSE);
2629 g_object_notify (G_OBJECT (tree_column), "selected");
2631 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
2633 selection = pspp_sheet_view_get_selection (sheet_view);
2634 _pspp_sheet_selection_emit_changed (selection);
2639 * pspp_sheet_view_column_get_selected:
2640 * @tree_column: A #PsppSheetViewColumn
2642 * Returns %TRUE if the column is selected as part of a rectangular
2645 * Return value: %TRUE if the column is selected as part of a rectangular
2649 pspp_sheet_view_column_get_selected (PsppSheetViewColumn *tree_column)
2651 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2653 return tree_column->selected;
2657 * pspp_sheet_view_column_set_selectable:
2658 * @tree_column: A #PsppSheetViewColumn
2659 * @selectable: If true, the column may be selected as part of a rectangular
2663 pspp_sheet_view_column_set_selectable (PsppSheetViewColumn *tree_column,
2664 gboolean selectable)
2666 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2668 selectable = !!selectable;
2669 if (tree_column->selectable != selectable)
2671 if (tree_column->tree_view != NULL)
2672 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2673 tree_column->selectable = (selectable?TRUE:FALSE);
2674 g_object_notify (G_OBJECT (tree_column), "selectable");
2679 * pspp_sheet_view_column_get_selectable:
2680 * @tree_column: A #PsppSheetViewColumn
2682 * Returns %TRUE if the column may be selected as part of a rectangular
2685 * Return value: %TRUE if the column may be selected as part of a rectangular
2689 pspp_sheet_view_column_get_selectable (PsppSheetViewColumn *tree_column)
2691 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2693 return tree_column->selectable;
2698 * pspp_sheet_view_column_set_row_head:
2699 * @tree_column: A #PsppSheetViewColumn
2700 * @row_head: If true, the column is a "row head", analogous to a column head.
2701 * See the description of the row-head property for more information.
2704 pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column,
2707 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2709 row_head = !!row_head;
2710 if (tree_column->row_head != row_head)
2712 tree_column->row_head = (row_head?TRUE:FALSE);
2713 g_object_notify (G_OBJECT (tree_column), "row_head");
2718 * pspp_sheet_view_column_get_row_head:
2719 * @tree_column: A #PsppSheetViewColumn
2721 * Returns %TRUE if the column is a row head.
2723 * Return value: %TRUE if the column is a row head.
2726 pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column)
2728 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2730 return tree_column->row_head;
2735 * pspp_sheet_view_column_set_sort_column_id:
2736 * @tree_column: a #PsppSheetViewColumn
2737 * @sort_column_id: The @sort_column_id of the model to sort on.
2739 * Sets the logical @sort_column_id that this column sorts on when this column
2740 * is selected for sorting. Doing so makes the column header clickable.
2743 pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
2744 gint sort_column_id)
2746 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2747 g_return_if_fail (sort_column_id >= -1);
2749 if (tree_column->sort_column_id == sort_column_id)
2752 tree_column->sort_column_id = sort_column_id;
2754 /* Handle unsetting the id */
2755 if (sort_column_id == -1)
2757 GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
2759 if (tree_column->sort_clicked_signal)
2761 g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
2762 tree_column->sort_clicked_signal = 0;
2765 if (tree_column->sort_column_changed_signal)
2767 g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
2768 tree_column->sort_column_changed_signal = 0;
2771 pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2772 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
2773 pspp_sheet_view_column_set_clickable (tree_column, FALSE);
2774 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2778 pspp_sheet_view_column_set_clickable (tree_column, TRUE);
2780 if (! tree_column->sort_clicked_signal)
2781 tree_column->sort_clicked_signal = g_signal_connect (tree_column,
2783 G_CALLBACK (pspp_sheet_view_column_sort),
2786 pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
2787 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2791 * pspp_sheet_view_column_get_sort_column_id:
2792 * @tree_column: a #PsppSheetViewColumn
2794 * Gets the logical @sort_column_id that the model sorts on when this
2795 * column is selected for sorting.
2796 * See pspp_sheet_view_column_set_sort_column_id().
2798 * Return value: the current @sort_column_id for this column, or -1 if
2799 * this column can't be used for sorting.
2802 pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
2804 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2806 return tree_column->sort_column_id;
2810 * pspp_sheet_view_column_set_sort_indicator:
2811 * @tree_column: a #PsppSheetViewColumn
2812 * @setting: %TRUE to display an indicator that the column is sorted
2814 * Call this function with a @setting of %TRUE to display an arrow in
2815 * the header button indicating the column is sorted. Call
2816 * pspp_sheet_view_column_set_sort_order() to change the direction of
2821 pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
2824 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2826 setting = setting != FALSE;
2828 if (setting == tree_column->show_sort_indicator)
2831 tree_column->show_sort_indicator = setting;
2832 pspp_sheet_view_column_update_button (tree_column);
2833 g_object_notify (G_OBJECT (tree_column), "sort-indicator");
2837 * pspp_sheet_view_column_get_sort_indicator:
2838 * @tree_column: a #PsppSheetViewColumn
2840 * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
2842 * Return value: whether the sort indicator arrow is displayed
2845 pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column)
2847 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2849 return tree_column->show_sort_indicator;
2853 * pspp_sheet_view_column_set_sort_order:
2854 * @tree_column: a #PsppSheetViewColumn
2855 * @order: sort order that the sort indicator should indicate
2857 * Changes the appearance of the sort indicator.
2859 * This <emphasis>does not</emphasis> actually sort the model. Use
2860 * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
2861 * support. This function is primarily for custom sorting behavior, and should
2862 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2863 * that. For custom models, the mechanism will vary.
2865 * The sort indicator changes direction to indicate normal sort or reverse sort.
2866 * Note that you must have the sort indicator enabled to see anything when
2867 * calling this function; see pspp_sheet_view_column_set_sort_indicator().
2870 pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
2873 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2875 if (order == tree_column->sort_order)
2878 tree_column->sort_order = order;
2879 pspp_sheet_view_column_update_button (tree_column);
2880 g_object_notify (G_OBJECT (tree_column), "sort-order");
2884 * pspp_sheet_view_column_get_sort_order:
2885 * @tree_column: a #PsppSheetViewColumn
2887 * Gets the value set by pspp_sheet_view_column_set_sort_order().
2889 * Return value: the sort order the sort indicator is indicating
2892 pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column)
2894 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2896 return tree_column->sort_order;
2900 * pspp_sheet_view_column_cell_set_cell_data:
2901 * @tree_column: A #PsppSheetViewColumn.
2902 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2903 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2905 * Sets the cell renderer based on the @tree_model and @iter. That is, for
2906 * every attribute mapping in @tree_column, it will get a value from the set
2907 * column on the @iter, and use that value to set the attribute on the cell
2908 * renderer. This is used primarily by the #PsppSheetView.
2911 pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
2912 GtkTreeModel *tree_model,
2916 GValue value = { 0, };
2919 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2921 if (tree_model == NULL)
2924 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2926 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
2927 GObject *cell = (GObject *) info->cell;
2929 list = info->attributes;
2931 g_object_freeze_notify (cell);
2933 while (list && list->next)
2935 gtk_tree_model_get_value (tree_model, iter,
2936 GPOINTER_TO_INT (list->next->data),
2938 g_object_set_property (cell, (gchar *) list->data, &value);
2939 g_value_unset (&value);
2940 list = list->next->next;
2944 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2945 g_object_thaw_notify (G_OBJECT (info->cell));
2951 * pspp_sheet_view_column_cell_get_size:
2952 * @tree_column: A #PsppSheetViewColumn.
2953 * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
2954 * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
2955 * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
2956 * @width: (allow-none): location to return width needed to render a cell, or %NULL
2957 * @height: (allow-none): location to return height needed to render a cell, or %NULL
2959 * Obtains the width and height needed to render the column. This is used
2960 * primarily by the #PsppSheetView.
2963 pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
2964 const GdkRectangle *cell_area,
2971 gboolean first_cell = TRUE;
2972 gint focus_line_width;
2974 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2981 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
2983 for (list = tree_column->cell_list; list; list = list->next)
2985 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2987 gint new_height = 0;
2989 g_object_get (info->cell, "visible", &visible, NULL);
2991 if (visible == FALSE)
2994 if (first_cell == FALSE && width)
2995 *width += tree_column->spacing;
2997 gtk_cell_renderer_get_size (info->cell,
2998 tree_column->tree_view,
3006 * height = MAX (*height, new_height + focus_line_width * 2);
3007 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
3009 * width += info->requested_width;
3014 /* rendering, event handling and rendering focus are somewhat complicated, and
3015 * quite a bit of code. Rather than duplicate them, we put them together to
3016 * keep the code in one place.
3018 * To better understand what's going on, check out
3019 * docs/tree-column-sizing.png
3028 pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn *tree_column,
3030 const GdkRectangle *background_area,
3031 const GdkRectangle *cell_area,
3034 const GdkRectangle *expose_area, /* RENDER */
3035 GdkRectangle *focus_rectangle, /* FOCUS */
3036 GtkCellEditable **editable_widget, /* EVENT */
3037 GdkEvent *event, /* EVENT */
3038 gchar *path_string) /* EVENT */
3041 GdkRectangle real_cell_area;
3042 GdkRectangle real_background_area;
3043 GdkRectangle real_expose_area = *cell_area;
3045 gint expand_cell_count = 0;
3046 gint full_requested_width = 0;
3048 gint min_x, min_y, max_x, max_y;
3049 gint focus_line_width;
3051 gint horizontal_separator;
3052 gboolean cursor_row = FALSE;
3053 gboolean first_cell = TRUE;
3055 /* If we have rtl text, we need to transform our areas */
3056 GdkRectangle rtl_cell_area;
3057 GdkRectangle rtl_background_area;
3064 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
3065 special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
3067 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
3069 PsppSheetViewColumnCellInfo *info = NULL;
3070 gboolean found_has_focus = FALSE;
3072 /* one should have focus */
3073 for (list = tree_column->cell_list; list; list = list->next)
3076 if (info && info->has_focus)
3078 found_has_focus = TRUE;
3083 if (!found_has_focus)
3085 /* give the first one focus */
3086 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3087 info->has_focus = TRUE;
3091 cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
3093 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3094 "focus-line-width", &focus_line_width,
3095 "horizontal-separator", &horizontal_separator,
3098 real_cell_area = *cell_area;
3099 real_background_area = *background_area;
3102 real_cell_area.x += focus_line_width;
3103 real_cell_area.y += focus_line_width;
3104 real_cell_area.height -= 2 * focus_line_width;
3107 depth = real_background_area.width - real_cell_area.width;
3109 depth = real_cell_area.x - real_background_area.x;
3111 /* Find out how much extra space we have to allocate */
3112 for (list = tree_column->cell_list; list; list = list->next)
3114 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
3116 if (! info->cell->visible)
3119 if (info->expand == TRUE)
3120 expand_cell_count ++;
3121 full_requested_width += info->requested_width;
3124 full_requested_width += tree_column->spacing;
3129 extra_space = cell_area->width - full_requested_width;
3130 if (extra_space < 0)
3132 else if (extra_space > 0 && expand_cell_count > 0)
3133 extra_space /= expand_cell_count;
3135 /* iterate list for GTK_PACK_START cells */
3136 for (list = tree_column->cell_list; list; list = list->next)
3138 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3140 if (info->pack == GTK_PACK_END)
3143 if (! info->cell->visible)
3146 if ((info->has_focus || special_cells == 1) && cursor_row)
3147 flags |= GTK_CELL_RENDERER_FOCUSED;
3149 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3151 info->real_width = info->requested_width + (info->expand?extra_space:0);
3153 /* We constrain ourselves to only the width available */
3154 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3156 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3159 if (real_cell_area.x > cell_area->x + cell_area->width)
3162 real_cell_area.width = info->real_width;
3163 real_cell_area.width -= 2 * focus_line_width;
3167 real_background_area.width = info->real_width + depth;
3171 /* fill the rest of background for the last cell */
3172 real_background_area.width = background_area->x + background_area->width - real_background_area.x;
3175 rtl_cell_area = real_cell_area;
3176 rtl_background_area = real_background_area;
3180 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3181 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3185 if (action == CELL_ACTION_RENDER)
3187 gtk_cell_renderer_render (info->cell,
3189 tree_column->tree_view,
3190 &rtl_background_area,
3196 else if (action == CELL_ACTION_FOCUS)
3198 gint x_offset, y_offset, width, height;
3200 gtk_cell_renderer_get_size (info->cell,
3201 tree_column->tree_view,
3203 &x_offset, &y_offset,
3206 if (special_cells > 1)
3208 if (info->has_focus)
3210 min_x = rtl_cell_area.x + x_offset;
3211 max_x = min_x + width;
3212 min_y = rtl_cell_area.y + y_offset;
3213 max_y = min_y + height;
3218 if (min_x > (rtl_cell_area.x + x_offset))
3219 min_x = rtl_cell_area.x + x_offset;
3220 if (max_x < rtl_cell_area.x + x_offset + width)
3221 max_x = rtl_cell_area.x + x_offset + width;
3222 if (min_y > (rtl_cell_area.y + y_offset))
3223 min_y = rtl_cell_area.y + y_offset;
3224 if (max_y < rtl_cell_area.y + y_offset + height)
3225 max_y = rtl_cell_area.y + y_offset + height;
3229 else if (action == CELL_ACTION_EVENT)
3231 gboolean try_event = FALSE;
3235 if (special_cells == 1)
3237 /* only 1 activatable cell -> whole column can activate */
3238 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3239 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3242 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3243 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3244 /* only activate cell if the user clicked on an individual
3249 else if (special_cells > 1 && info->has_focus)
3251 else if (special_cells == 1)
3256 gboolean visible, mode;
3258 g_object_get (info->cell,
3259 "visible", &visible,
3262 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3264 if (gtk_cell_renderer_activate (info->cell,
3266 tree_column->tree_view,
3268 &rtl_background_area,
3272 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3276 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3279 gtk_cell_renderer_start_editing (info->cell,
3281 tree_column->tree_view,
3283 &rtl_background_area,
3287 if (*editable_widget != NULL)
3289 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3290 info->in_editing_mode = TRUE;
3291 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3293 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3301 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3303 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3304 real_background_area.x += real_background_area.width + tree_column->spacing;
3306 /* Only needed for first cell */
3310 /* iterate list for PACK_END cells */
3311 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
3313 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3315 if (info->pack == GTK_PACK_START)
3318 if (! info->cell->visible)
3321 if ((info->has_focus || special_cells == 1) && cursor_row)
3322 flags |= GTK_CELL_RENDERER_FOCUSED;
3324 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3326 info->real_width = info->requested_width + (info->expand?extra_space:0);
3328 /* We constrain ourselves to only the width available */
3329 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3331 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3334 if (real_cell_area.x > cell_area->x + cell_area->width)
3337 real_cell_area.width = info->real_width;
3338 real_cell_area.width -= 2 * focus_line_width;
3339 real_background_area.width = info->real_width + depth;
3341 rtl_cell_area = real_cell_area;
3342 rtl_background_area = real_background_area;
3345 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3346 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3350 if (action == CELL_ACTION_RENDER)
3352 gtk_cell_renderer_render (info->cell,
3354 tree_column->tree_view,
3355 &rtl_background_area,
3361 else if (action == CELL_ACTION_FOCUS)
3363 gint x_offset, y_offset, width, height;
3365 gtk_cell_renderer_get_size (info->cell,
3366 tree_column->tree_view,
3368 &x_offset, &y_offset,
3371 if (special_cells > 1)
3373 if (info->has_focus)
3375 min_x = rtl_cell_area.x + x_offset;
3376 max_x = min_x + width;
3377 min_y = rtl_cell_area.y + y_offset;
3378 max_y = min_y + height;
3383 if (min_x > (rtl_cell_area.x + x_offset))
3384 min_x = rtl_cell_area.x + x_offset;
3385 if (max_x < rtl_cell_area.x + x_offset + width)
3386 max_x = rtl_cell_area.x + x_offset + width;
3387 if (min_y > (rtl_cell_area.y + y_offset))
3388 min_y = rtl_cell_area.y + y_offset;
3389 if (max_y < rtl_cell_area.y + y_offset + height)
3390 max_y = rtl_cell_area.y + y_offset + height;
3394 else if (action == CELL_ACTION_EVENT)
3396 gboolean try_event = FALSE;
3400 if (special_cells == 1)
3402 /* only 1 activatable cell -> whole column can activate */
3403 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3404 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3407 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3408 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3409 /* only activate cell if the user clicked on an individual
3414 else if (special_cells > 1 && info->has_focus)
3416 else if (special_cells == 1)
3421 gboolean visible, mode;
3423 g_object_get (info->cell,
3424 "visible", &visible,
3427 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3429 if (gtk_cell_renderer_activate (info->cell,
3431 tree_column->tree_view,
3433 &rtl_background_area,
3437 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3441 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3444 gtk_cell_renderer_start_editing (info->cell,
3446 tree_column->tree_view,
3448 &rtl_background_area,
3452 if (*editable_widget != NULL)
3454 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3455 info->in_editing_mode = TRUE;
3456 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3458 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3465 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3467 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3468 real_background_area.x += (real_background_area.width + tree_column->spacing);
3470 /* Only needed for first cell */
3474 /* fill focus_rectangle when required */
3475 if (action == CELL_ACTION_FOCUS)
3477 if (min_x >= max_x || min_y >= max_y)
3479 *focus_rectangle = *cell_area;
3480 /* don't change the focus_rectangle, just draw it nicely inside
3485 focus_rectangle->x = min_x - focus_line_width;
3486 focus_rectangle->y = min_y - focus_line_width;
3487 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
3488 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
3496 * pspp_sheet_view_column_cell_render:
3497 * @tree_column: A #PsppSheetViewColumn.
3498 * @window: a #GdkDrawable to draw to
3499 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
3500 * @cell_area: area normally rendered by a cell renderer
3501 * @expose_area: area that actually needs updating
3502 * @flags: flags that affect rendering
3504 * Renders the cell contained by #tree_column. This is used primarily by the
3508 _pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
3510 const GdkRectangle *background_area,
3511 const GdkRectangle *cell_area,
3512 const GdkRectangle *expose_area,
3515 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3516 g_return_if_fail (background_area != NULL);
3517 g_return_if_fail (cell_area != NULL);
3518 g_return_if_fail (expose_area != NULL);
3520 pspp_sheet_view_column_cell_process_action (tree_column,
3527 NULL, NULL, NULL, NULL);
3531 _pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
3532 GtkCellEditable **editable_widget,
3535 const GdkRectangle *background_area,
3536 const GdkRectangle *cell_area,
3539 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3541 return pspp_sheet_view_column_cell_process_action (tree_column,
3554 _pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
3555 const GdkRectangle *background_area,
3556 const GdkRectangle *cell_area,
3557 GdkRectangle *focus_area)
3559 pspp_sheet_view_column_cell_process_action (tree_column,
3571 /* cell list manipulation */
3573 pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
3575 GList *list = tree_column->cell_list;
3577 /* first GTK_PACK_START cell we find */
3578 for ( ; list; list = list->next)
3580 PsppSheetViewColumnCellInfo *info = list->data;
3581 if (info->pack == GTK_PACK_START)
3585 /* hmm, else the *last* GTK_PACK_END cell */
3586 list = g_list_last (tree_column->cell_list);
3588 for ( ; list; list = list->prev)
3590 PsppSheetViewColumnCellInfo *info = list->data;
3591 if (info->pack == GTK_PACK_END)
3599 pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
3601 GList *list = tree_column->cell_list;
3603 /* *first* GTK_PACK_END cell we find */
3604 for ( ; list ; list = list->next)
3606 PsppSheetViewColumnCellInfo *info = list->data;
3607 if (info->pack == GTK_PACK_END)
3611 /* hmm, else the last GTK_PACK_START cell */
3612 list = g_list_last (tree_column->cell_list);
3614 for ( ; list; list = list->prev)
3616 PsppSheetViewColumnCellInfo *info = list->data;
3617 if (info->pack == GTK_PACK_START)
3625 pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
3629 PsppSheetViewColumnCellInfo *info = current->data;
3631 if (info->pack == GTK_PACK_START)
3633 for (list = current->next; list; list = list->next)
3635 PsppSheetViewColumnCellInfo *inf = list->data;
3636 if (inf->pack == GTK_PACK_START)
3640 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
3641 list = g_list_last (tree_column->cell_list);
3642 for (; list; list = list->prev)
3644 PsppSheetViewColumnCellInfo *inf = list->data;
3645 if (inf->pack == GTK_PACK_END)
3650 for (list = current->prev; list; list = list->prev)
3652 PsppSheetViewColumnCellInfo *inf = list->data;
3653 if (inf->pack == GTK_PACK_END)
3661 pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
3665 PsppSheetViewColumnCellInfo *info = current->data;
3667 if (info->pack == GTK_PACK_END)
3669 for (list = current->next; list; list = list->next)
3671 PsppSheetViewColumnCellInfo *inf = list->data;
3672 if (inf->pack == GTK_PACK_END)
3676 /* out of GTK_PACK_END, get last GTK_PACK_START one */
3677 list = g_list_last (tree_column->cell_list);
3678 for ( ; list; list = list->prev)
3680 PsppSheetViewColumnCellInfo *inf = list->data;
3681 if (inf->pack == GTK_PACK_START)
3686 for (list = current->prev; list; list = list->prev)
3688 PsppSheetViewColumnCellInfo *inf = list->data;
3689 if (inf->pack == GTK_PACK_START)
3697 _pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
3705 count = _pspp_sheet_view_column_count_special_cells (tree_column);
3706 rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
3708 /* if we are the current focus column and have multiple editable cells,
3709 * try to select the next one, else move the focus to the next column
3711 if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
3716 GList *list = tree_column->cell_list;
3717 PsppSheetViewColumnCellInfo *info = NULL;
3719 /* find current focussed cell */
3720 for ( ; list; list = list->next)
3723 if (info->has_focus)
3727 /* not a focussed cell in the focus column? */
3728 if (!list || !info || !info->has_focus)
3733 prev = pspp_sheet_view_column_cell_next (tree_column, list);
3734 next = pspp_sheet_view_column_cell_prev (tree_column, list);
3738 next = pspp_sheet_view_column_cell_next (tree_column, list);
3739 prev = pspp_sheet_view_column_cell_prev (tree_column, list);
3742 info->has_focus = FALSE;
3743 if (direction > 0 && next)
3746 info->has_focus = TRUE;
3749 else if (direction > 0 && !next && !right)
3751 /* keep focus on last cell */
3753 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3755 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3757 info->has_focus = TRUE;
3760 else if (direction < 0 && prev)
3763 info->has_focus = TRUE;
3766 else if (direction < 0 && !prev && !left)
3768 /* keep focus on first cell */
3770 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3772 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3774 info->has_focus = TRUE;
3781 /* we get focus, if we have multiple editable cells, give the correct one
3786 GList *list = tree_column->cell_list;
3788 /* clear focus first */
3789 for ( ; list ; list = list->next)
3791 PsppSheetViewColumnCellInfo *info = list->data;
3792 if (info->has_focus)
3793 info->has_focus = FALSE;
3800 list = pspp_sheet_view_column_cell_last (tree_column);
3801 else if (direction < 0)
3802 list = pspp_sheet_view_column_cell_first (tree_column);
3807 list = pspp_sheet_view_column_cell_first (tree_column);
3808 else if (direction < 0)
3809 list = pspp_sheet_view_column_cell_last (tree_column);
3813 ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
3820 _pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
3822 const GdkRectangle *background_area,
3823 const GdkRectangle *cell_area,
3824 const GdkRectangle *expose_area,
3827 gint focus_line_width;
3828 GtkStateType cell_state;
3830 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3831 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3832 "focus-line-width", &focus_line_width, NULL);
3833 if (tree_column->editable_widget)
3835 /* This function is only called on the editable row when editing.
3838 gtk_paint_focus (tree_column->tree_view->style,
3840 gtk_widget_get_state (tree_column->tree_view),
3842 tree_column->tree_view,
3844 cell_area->x - focus_line_width,
3845 cell_area->y - focus_line_width,
3846 cell_area->width + 2 * focus_line_width,
3847 cell_area->height + 2 * focus_line_width);
3852 GdkRectangle focus_rectangle;
3853 pspp_sheet_view_column_cell_process_action (tree_column,
3863 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3864 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3865 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3866 gtk_paint_focus (tree_column->tree_view->style,
3870 tree_column->tree_view,
3874 focus_rectangle.width,
3875 focus_rectangle.height);
3880 * pspp_sheet_view_column_cell_is_visible:
3881 * @tree_column: A #PsppSheetViewColumn
3883 * Returns %TRUE if any of the cells packed into the @tree_column are visible.
3884 * For this to be meaningful, you must first initialize the cells with
3885 * pspp_sheet_view_column_cell_set_cell_data()
3887 * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
3890 pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
3894 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3896 for (list = tree_column->cell_list; list; list = list->next)
3898 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3900 if (info->cell->visible)
3908 * pspp_sheet_view_column_focus_cell:
3909 * @tree_column: A #PsppSheetViewColumn
3910 * @cell: A #GtkCellRenderer
3912 * Sets the current keyboard focus to be at @cell, if the column contains
3913 * 2 or more editable and activatable cells.
3918 pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
3919 GtkCellRenderer *cell)
3922 gboolean found_cell = FALSE;
3924 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3925 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3927 if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
3930 for (list = tree_column->cell_list; list; list = list->next)
3932 PsppSheetViewColumnCellInfo *info = list->data;
3934 if (info->cell == cell)
3936 info->has_focus = TRUE;
3944 for (list = tree_column->cell_list; list; list = list->next)
3946 PsppSheetViewColumnCellInfo *info = list->data;
3948 if (info->cell != cell)
3949 info->has_focus = FALSE;
3952 /* FIXME: redraw? */
3957 _pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
3961 for (list = tree_column->cell_list; list; list = list->next)
3963 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3965 info->requested_width = 0;
3967 tree_column->dirty = TRUE;
3968 tree_column->requested_width = -1;
3969 tree_column->width = 0;
3971 if (tree_column->tree_view &&
3972 gtk_widget_get_realized (tree_column->tree_view))
3974 _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
3975 gtk_widget_queue_resize (tree_column->tree_view);
3980 _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
3981 GtkCellEditable *cell_editable)
3983 g_return_if_fail (tree_column->editable_widget == NULL);
3985 tree_column->editable_widget = cell_editable;
3989 _pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
3993 g_return_if_fail (tree_column->editable_widget != NULL);
3995 tree_column->editable_widget = NULL;
3996 for (list = tree_column->cell_list; list; list = list->next)
3997 ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
4001 _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
4002 GtkCellRenderer *cell,
4007 PsppSheetViewColumnCellInfo *info;
4013 list = pspp_sheet_view_column_cell_first (column);
4017 info = (PsppSheetViewColumnCellInfo *)list->data;
4019 list = pspp_sheet_view_column_cell_next (column, list);
4021 if (info->cell == cell)
4024 if (info->cell->visible)
4025 l += info->real_width + column->spacing;
4030 info = (PsppSheetViewColumnCellInfo *)list->data;
4032 list = pspp_sheet_view_column_cell_next (column, list);
4034 if (info->cell->visible)
4035 r += info->real_width + column->spacing;
4038 rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
4040 *left = rtl ? r : l;
4043 *right = rtl ? l : r;
4047 * pspp_sheet_view_column_cell_get_position:
4048 * @tree_column: a #PsppSheetViewColumn
4049 * @cell_renderer: a #GtkCellRenderer
4050 * @start_pos: return location for the horizontal position of @cell within
4051 * @tree_column, may be %NULL
4052 * @width: return location for the width of @cell, may be %NULL
4054 * Obtains the horizontal position and size of a cell in a column. If the
4055 * cell is not found in the column, @start_pos and @width are not changed and
4056 * %FALSE is returned.
4058 * Return value: %TRUE if @cell belongs to @tree_column.
4061 pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
4062 GtkCellRenderer *cell_renderer,
4068 gboolean found_cell = FALSE;
4069 PsppSheetViewColumnCellInfo *cellinfo = NULL;
4071 list = pspp_sheet_view_column_cell_first (tree_column);
4072 for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
4074 cellinfo = list->data;
4075 if (cellinfo->cell == cell_renderer)
4081 if (cellinfo->cell->visible)
4082 current_x += cellinfo->real_width;
4088 *start_pos = current_x;
4090 *width = cellinfo->real_width;
4097 * pspp_sheet_view_column_queue_resize:
4098 * @tree_column: A #PsppSheetViewColumn
4100 * Flags the column, and the cell renderers added to this column, to have
4101 * their sizes renegotiated.
4106 pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
4108 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
4110 if (tree_column->tree_view)
4111 _pspp_sheet_view_column_cell_set_dirty (tree_column);
4115 * pspp_sheet_view_column_get_tree_view:
4116 * @tree_column: A #PsppSheetViewColumn
4118 * Returns the #PsppSheetView wherein @tree_column has been inserted. If
4119 * @column is currently not inserted in any tree view, %NULL is
4122 * Return value: The tree view wherein @column has been inserted if any,
4128 pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
4130 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
4132 return tree_column->tree_view;
4136 GtkCellLayout *cell_layout;
4137 GtkCellRenderer *renderer;
4139 } AttributesSubParserData;
4142 attributes_start_element (GMarkupParseContext *context,
4143 const gchar *element_name,
4144 const gchar **names,
4145 const gchar **values,
4149 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4152 if (strcmp (element_name, "attribute") == 0)
4154 for (i = 0; names[i]; i++)
4155 if (strcmp (names[i], "name") == 0)
4156 parser_data->attr_name = g_strdup (values[i]);
4158 else if (strcmp (element_name, "attributes") == 0)
4161 g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
4165 attributes_text_element (GMarkupParseContext *context,
4171 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4176 if (!parser_data->attr_name)
4180 string = g_strndup (text, text_len);
4181 l = strtol (string, &endptr, 0);
4182 if (errno || endptr == string)
4186 GTK_BUILDER_ERROR_INVALID_VALUE,
4187 "Could not parse integer `%s'",
4194 gtk_cell_layout_add_attribute (parser_data->cell_layout,
4195 parser_data->renderer,
4196 parser_data->attr_name, l);
4197 g_free (parser_data->attr_name);
4198 parser_data->attr_name = NULL;
4201 static const GMarkupParser attributes_parser =
4203 attributes_start_element,
4205 attributes_text_element,
4209 _gtk_cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
4210 GtkBuilder *builder,
4212 const gchar *tagname,
4213 GMarkupParser *parser,
4216 AttributesSubParserData *parser_data;
4221 if (strcmp (tagname, "attributes") == 0)
4223 parser_data = g_slice_new0 (AttributesSubParserData);
4224 parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
4225 parser_data->renderer = GTK_CELL_RENDERER (child);
4226 parser_data->attr_name = NULL;
4228 *parser = attributes_parser;
4229 *data = parser_data;
4237 _gtk_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
4238 GtkBuilder *builder,
4240 const gchar *tagname,
4243 AttributesSubParserData *parser_data;
4245 parser_data = (AttributesSubParserData*)data;
4246 g_assert (!parser_data->attr_name);
4247 g_slice_free (AttributesSubParserData, parser_data);
4251 _gtk_cell_layout_buildable_add_child (GtkBuildable *buildable,
4252 GtkBuilder *builder,
4256 GtkCellLayoutIface *iface;
4258 g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
4259 g_return_if_fail (GTK_IS_CELL_RENDERER (child));
4261 iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
4262 g_return_if_fail (iface->pack_start != NULL);
4263 iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);