1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2011, 2012, 2015 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* gtktreeviewcolumn.c
18 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Library General Public
22 * License as published by the Free Software Foundation; either
23 * version 2 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Library General Public License for more details.
30 * You should have received a copy of the GNU Library General Public
31 * License along with this library; if not, write to the
32 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
33 * Boston, MA 02111-1307, USA.
38 #include "ui/gui/pspp-sheet-private.h"
45 #include "ui/gui/psppire-marshal.h"
46 #include "ui/gui/pspp-sheet-selection.h"
47 #include "ui/gui/pspp-widget-facade.h"
49 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
51 #define P_(STRING) STRING
52 #define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
53 #define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
90 typedef struct _PsppSheetViewColumnCellInfo PsppSheetViewColumnCellInfo;
91 struct _PsppSheetViewColumnCellInfo
93 GtkCellRenderer *cell;
95 PsppSheetCellDataFunc func;
97 GDestroyNotify destroy;
103 guint in_editing_mode : 1;
107 static void pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface);
109 /* GObject methods */
110 static void pspp_sheet_view_column_set_property (GObject *object,
114 static void pspp_sheet_view_column_get_property (GObject *object,
118 static void pspp_sheet_view_column_finalize (GObject *object);
120 /* GtkCellLayout implementation */
121 static void pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
122 GtkCellRenderer *cell,
124 static void pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
125 GtkCellRenderer *cell,
127 static void pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout);
128 static void pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
129 GtkCellRenderer *cell,
130 const gchar *attribute,
132 static void pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
133 GtkCellRenderer *cell,
134 GtkCellLayoutDataFunc func,
136 GDestroyNotify destroy);
137 static void pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
138 GtkCellRenderer *cell);
139 static void pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
140 GtkCellRenderer *cell,
142 static GList *pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
144 /* Button handling code */
145 static void pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column);
146 void pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
148 /* Button signal handlers */
149 static gint pspp_sheet_view_column_button_event (GtkWidget *widget,
150 GdkEventButton *event,
152 static void pspp_sheet_view_column_button_clicked (GtkWidget *widget,
154 static void pspp_sheet_view_column_button_popup_menu (GtkWidget *widget,
156 static gboolean pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
157 gboolean group_cycling,
159 static gboolean on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *);
160 static gboolean on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *,
163 /* Property handlers */
164 static void pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
165 PsppSheetViewColumn *tree_column);
167 /* Internal functions */
168 static void pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
170 static void pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column);
171 static void pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
172 GtkCellRenderer *cell_renderer,
174 static PsppSheetViewColumnCellInfo *pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
175 GtkCellRenderer *cell_renderer);
177 /* cell list manipulation */
178 static GList *pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column);
179 static GList *pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column);
180 static GList *pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
182 static GList *pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
184 static void pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
185 PsppSheetViewColumnCellInfo *info);
186 /* GtkBuildable implementation */
187 static void pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface);
189 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
191 G_DEFINE_TYPE_WITH_CODE (PsppSheetViewColumn, pspp_sheet_view_column, G_TYPE_OBJECT,
192 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
193 pspp_sheet_view_column_cell_layout_init)
194 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
195 pspp_sheet_view_column_buildable_init))
199 pspp_sheet_view_column_class_init (PsppSheetViewColumnClass *class)
201 GObjectClass *object_class;
203 object_class = (GObjectClass*) class;
205 class->clicked = on_pspp_sheet_view_column_button_clicked;
206 class->button_press_event = on_pspp_sheet_view_column_button_press_event;
208 object_class->finalize = pspp_sheet_view_column_finalize;
209 object_class->set_property = pspp_sheet_view_column_set_property;
210 object_class->get_property = pspp_sheet_view_column_get_property;
212 tree_column_signals[CLICKED] =
213 g_signal_new ("clicked",
214 G_OBJECT_CLASS_TYPE (object_class),
216 G_STRUCT_OFFSET (PsppSheetViewColumnClass, clicked),
217 g_signal_accumulator_true_handled, NULL,
218 psppire_marshal_BOOLEAN__VOID,
221 tree_column_signals[POPUP_MENU] =
222 g_signal_new ("popup-menu",
223 G_OBJECT_CLASS_TYPE (object_class),
227 g_cclosure_marshal_VOID__VOID,
230 tree_column_signals[QUERY_TOOLTIP] =
231 g_signal_new ("query-tooltip",
232 G_OBJECT_CLASS_TYPE (object_class),
235 g_signal_accumulator_true_handled, NULL,
236 psppire_marshal_BOOLEAN__OBJECT,
240 tree_column_signals[BUTTON_PRESS_EVENT] =
241 g_signal_new ("button-press-event",
242 G_OBJECT_CLASS_TYPE (object_class),
243 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
244 G_STRUCT_OFFSET (PsppSheetViewColumnClass, button_press_event),
245 g_signal_accumulator_true_handled, NULL,
246 psppire_marshal_BOOLEAN__BOXED,
248 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
250 g_object_class_install_property (object_class,
252 g_param_spec_boolean ("visible",
254 P_("Whether to display the column"),
256 GTK_PARAM_READWRITE));
258 g_object_class_install_property (object_class,
260 g_param_spec_boolean ("resizable",
262 P_("Column is user-resizable"),
264 GTK_PARAM_READWRITE));
266 g_object_class_install_property (object_class,
268 g_param_spec_int ("width",
270 P_("Current width of the column"),
274 GTK_PARAM_READABLE));
275 g_object_class_install_property (object_class,
277 g_param_spec_int ("spacing",
279 P_("Space which is inserted between cells"),
283 GTK_PARAM_READWRITE));
285 g_object_class_install_property (object_class,
287 g_param_spec_int ("fixed-width",
289 P_("Current fixed width of the column"),
293 GTK_PARAM_READWRITE));
295 g_object_class_install_property (object_class,
297 g_param_spec_int ("min-width",
299 P_("Minimum allowed width of the column"),
303 GTK_PARAM_READWRITE));
305 g_object_class_install_property (object_class,
307 g_param_spec_int ("max-width",
309 P_("Maximum allowed width of the column"),
313 GTK_PARAM_READWRITE));
315 g_object_class_install_property (object_class,
317 g_param_spec_string ("title",
319 P_("Title to appear in column header"),
321 GTK_PARAM_READWRITE));
323 g_object_class_install_property (object_class,
325 g_param_spec_boolean ("expand",
327 P_("Column gets share of extra width allocated to the widget"),
329 GTK_PARAM_READWRITE));
331 g_object_class_install_property (object_class,
333 g_param_spec_boolean ("clickable",
335 P_("Whether the header can be clicked"),
337 GTK_PARAM_READWRITE));
340 g_object_class_install_property (object_class,
342 g_param_spec_object ("widget",
344 P_("Widget to put in column header button instead of column title"),
346 GTK_PARAM_READWRITE));
348 g_object_class_install_property (object_class,
350 g_param_spec_float ("alignment",
352 P_("X Alignment of the column header text or widget"),
356 GTK_PARAM_READWRITE));
358 g_object_class_install_property (object_class,
360 g_param_spec_boolean ("reorderable",
362 P_("Whether the column can be reordered around the headers"),
364 GTK_PARAM_READWRITE));
366 g_object_class_install_property (object_class,
368 g_param_spec_boolean ("sort-indicator",
369 P_("Sort indicator"),
370 P_("Whether to show a sort indicator"),
372 GTK_PARAM_READWRITE));
374 g_object_class_install_property (object_class,
376 g_param_spec_enum ("sort-order",
378 P_("Sort direction the sort indicator should indicate"),
381 GTK_PARAM_READWRITE));
384 * PsppSheetViewColumn:sort-column-id:
386 * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
387 * clickable. Set to %-1 to make the column unsortable.
391 g_object_class_install_property (object_class,
393 g_param_spec_int ("sort-column-id",
394 P_("Sort column ID"),
395 P_("Logical sort column ID this column sorts on when selected for sorting"),
399 GTK_PARAM_READWRITE));
401 g_object_class_install_property (object_class,
403 g_param_spec_boolean ("quick-edit",
405 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."),
407 GTK_PARAM_READWRITE));
409 g_object_class_install_property (object_class,
411 g_param_spec_boolean ("selected",
413 P_("If true, this column is selected as part of a rectangular selection."),
415 GTK_PARAM_READWRITE));
417 g_object_class_install_property (object_class,
419 g_param_spec_boolean ("selectable",
421 P_("If true, this column may be selected as part of a rectangular selection."),
423 GTK_PARAM_READWRITE));
425 g_object_class_install_property (object_class,
427 g_param_spec_boolean ("row-head",
429 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)."),
431 GTK_PARAM_READWRITE));
433 g_object_class_install_property (object_class,
435 g_param_spec_boolean ("tabbable",
437 P_("If true, Tab and Shift+Tab visit this column. If false, Tab and Shift+Tab skip this column."),
439 GTK_PARAM_READWRITE));
443 static void _cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
446 const gchar *tagname,
450 static void _cell_layout_buildable_add_child (GtkBuildable *buildable,
456 static gboolean _cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
459 const gchar *tagname,
460 GMarkupParser *parser,
465 pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface)
467 iface->add_child = _cell_layout_buildable_add_child;
468 iface->custom_tag_start = _cell_layout_buildable_custom_tag_start;
469 iface->custom_tag_end = _cell_layout_buildable_custom_tag_end;
473 pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface)
475 iface->pack_start = pspp_sheet_view_column_cell_layout_pack_start;
476 iface->pack_end = pspp_sheet_view_column_cell_layout_pack_end;
477 iface->clear = pspp_sheet_view_column_cell_layout_clear;
478 iface->add_attribute = pspp_sheet_view_column_cell_layout_add_attribute;
479 iface->set_cell_data_func = pspp_sheet_view_column_cell_layout_set_cell_data_func;
480 iface->clear_attributes = pspp_sheet_view_column_cell_layout_clear_attributes;
481 iface->reorder = pspp_sheet_view_column_cell_layout_reorder;
482 iface->get_cells = pspp_sheet_view_column_cell_layout_get_cells;
486 pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column)
488 tree_column->button = NULL;
489 tree_column->halign = GTK_ALIGN_START;
490 tree_column->width = 0;
491 tree_column->spacing = 0;
492 tree_column->requested_width = -1;
493 tree_column->min_width = -1;
494 tree_column->max_width = -1;
495 tree_column->resized_width = 0;
496 tree_column->visible = TRUE;
497 tree_column->resizable = FALSE;
498 tree_column->expand = FALSE;
499 tree_column->clickable = FALSE;
500 tree_column->dirty = TRUE;
501 tree_column->selected = FALSE;
502 tree_column->selectable = TRUE;
503 tree_column->row_head = FALSE;
504 tree_column->tabbable = TRUE;
505 tree_column->sort_order = GTK_SORT_ASCENDING;
506 tree_column->show_sort_indicator = FALSE;
507 tree_column->property_changed_signal = 0;
508 tree_column->sort_clicked_signal = 0;
509 tree_column->sort_column_changed_signal = 0;
510 tree_column->sort_column_id = -1;
511 tree_column->reorderable = FALSE;
512 tree_column->maybe_reordered = FALSE;
513 tree_column->fixed_width = 1;
514 tree_column->use_resized_width = FALSE;
515 tree_column->title = g_strdup ("");
516 tree_column->quick_edit = TRUE;
520 pspp_sheet_view_column_finalize (GObject *object)
522 PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
525 for (list = tree_column->cell_list; list; list = list->next)
527 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
531 GDestroyNotify d = info->destroy;
533 info->destroy = NULL;
536 pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
537 g_object_unref (info->cell);
541 g_free (tree_column->title);
542 g_list_free (tree_column->cell_list);
544 if (tree_column->child)
545 g_object_unref (tree_column->child);
547 G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
551 pspp_sheet_view_column_set_property (GObject *object,
556 PsppSheetViewColumn *tree_column;
558 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
563 pspp_sheet_view_column_set_visible (tree_column,
564 g_value_get_boolean (value));
568 pspp_sheet_view_column_set_resizable (tree_column,
569 g_value_get_boolean (value));
572 case PROP_FIXED_WIDTH:
573 pspp_sheet_view_column_set_fixed_width (tree_column,
574 g_value_get_int (value));
578 pspp_sheet_view_column_set_min_width (tree_column,
579 g_value_get_int (value));
583 pspp_sheet_view_column_set_max_width (tree_column,
584 g_value_get_int (value));
588 pspp_sheet_view_column_set_spacing (tree_column,
589 g_value_get_int (value));
593 pspp_sheet_view_column_set_title (tree_column,
594 g_value_get_string (value));
598 pspp_sheet_view_column_set_expand (tree_column,
599 g_value_get_boolean (value));
603 pspp_sheet_view_column_set_clickable (tree_column,
604 g_value_get_boolean (value));
608 pspp_sheet_view_column_set_widget (tree_column,
609 (GtkWidget*) g_value_get_object (value));
613 pspp_sheet_view_column_set_alignment (tree_column,
614 g_value_get_float (value));
617 case PROP_REORDERABLE:
618 pspp_sheet_view_column_set_reorderable (tree_column,
619 g_value_get_boolean (value));
622 case PROP_SORT_INDICATOR:
623 pspp_sheet_view_column_set_sort_indicator (tree_column,
624 g_value_get_boolean (value));
627 case PROP_SORT_ORDER:
628 pspp_sheet_view_column_set_sort_order (tree_column,
629 g_value_get_enum (value));
632 case PROP_SORT_COLUMN_ID:
633 pspp_sheet_view_column_set_sort_column_id (tree_column,
634 g_value_get_int (value));
637 case PROP_QUICK_EDIT:
638 pspp_sheet_view_column_set_quick_edit (tree_column,
639 g_value_get_boolean (value));
643 pspp_sheet_view_column_set_selected (tree_column,
644 g_value_get_boolean (value));
647 case PROP_SELECTABLE:
648 pspp_sheet_view_column_set_selectable (tree_column,
649 g_value_get_boolean (value));
653 pspp_sheet_view_column_set_row_head (tree_column,
654 g_value_get_boolean (value));
658 pspp_sheet_view_column_set_tabbable (tree_column,
659 g_value_get_boolean (value));
663 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
669 pspp_sheet_view_column_get_property (GObject *object,
674 PsppSheetViewColumn *tree_column;
676 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
681 g_value_set_boolean (value,
682 pspp_sheet_view_column_get_visible (tree_column));
686 g_value_set_boolean (value,
687 pspp_sheet_view_column_get_resizable (tree_column));
691 g_value_set_int (value,
692 pspp_sheet_view_column_get_width (tree_column));
696 g_value_set_int (value,
697 pspp_sheet_view_column_get_spacing (tree_column));
700 case PROP_FIXED_WIDTH:
701 g_value_set_int (value,
702 pspp_sheet_view_column_get_fixed_width (tree_column));
706 g_value_set_int (value,
707 pspp_sheet_view_column_get_min_width (tree_column));
711 g_value_set_int (value,
712 pspp_sheet_view_column_get_max_width (tree_column));
716 g_value_set_string (value,
717 pspp_sheet_view_column_get_title (tree_column));
721 g_value_set_boolean (value,
722 pspp_sheet_view_column_get_expand (tree_column));
726 g_value_set_boolean (value,
727 pspp_sheet_view_column_get_clickable (tree_column));
731 g_value_set_object (value,
732 (GObject*) pspp_sheet_view_column_get_widget (tree_column));
736 g_value_set_float (value,
737 pspp_sheet_view_column_get_alignment (tree_column));
740 case PROP_REORDERABLE:
741 g_value_set_boolean (value,
742 pspp_sheet_view_column_get_reorderable (tree_column));
745 case PROP_SORT_INDICATOR:
746 g_value_set_boolean (value,
747 pspp_sheet_view_column_get_sort_indicator (tree_column));
750 case PROP_SORT_ORDER:
751 g_value_set_enum (value,
752 pspp_sheet_view_column_get_sort_order (tree_column));
755 case PROP_SORT_COLUMN_ID:
756 g_value_set_int (value,
757 pspp_sheet_view_column_get_sort_column_id (tree_column));
760 case PROP_QUICK_EDIT:
761 g_value_set_boolean (value,
762 pspp_sheet_view_column_get_quick_edit (tree_column));
766 g_value_set_boolean (value,
767 pspp_sheet_view_column_get_selected (tree_column));
770 case PROP_SELECTABLE:
771 g_value_set_boolean (value,
772 pspp_sheet_view_column_get_selectable (tree_column));
776 g_value_set_boolean (value,
777 pspp_sheet_view_column_get_row_head (tree_column));
781 g_value_set_boolean (value,
782 pspp_sheet_view_column_get_tabbable (tree_column));
786 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
791 /* Implementation of GtkCellLayout interface
795 pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
796 GtkCellRenderer *cell,
799 PsppSheetViewColumn *column;
800 PsppSheetViewColumnCellInfo *cell_info;
802 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
803 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
804 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
806 g_object_ref_sink (cell);
808 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
809 cell_info->cell = cell;
810 cell_info->expand = expand ? TRUE : FALSE;
811 cell_info->pack = GTK_PACK_START;
812 cell_info->has_focus = 0;
813 cell_info->attributes = NULL;
815 column->cell_list = g_list_append (column->cell_list, cell_info);
819 pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
820 GtkCellRenderer *cell,
823 PsppSheetViewColumn *column;
824 PsppSheetViewColumnCellInfo *cell_info;
826 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
827 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
828 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
830 g_object_ref_sink (cell);
832 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
833 cell_info->cell = cell;
834 cell_info->expand = expand ? TRUE : FALSE;
835 cell_info->pack = GTK_PACK_END;
836 cell_info->has_focus = 0;
837 cell_info->attributes = NULL;
839 column->cell_list = g_list_append (column->cell_list, cell_info);
843 pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
845 PsppSheetViewColumn *column;
847 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
848 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
850 while (column->cell_list)
852 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
854 pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
855 g_object_unref (info->cell);
857 column->cell_list = g_list_delete_link (column->cell_list,
863 pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
864 GtkCellRenderer *cell,
865 const gchar *attribute,
868 PsppSheetViewColumn *tree_column;
869 PsppSheetViewColumnCellInfo *info;
871 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
872 tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
874 info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
875 g_return_if_fail (info != NULL);
877 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
878 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
880 if (tree_column->tree_view)
881 _pspp_sheet_view_column_cell_set_dirty (tree_column);
885 pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
886 GtkCellRenderer *cell,
887 GtkCellLayoutDataFunc func,
889 GDestroyNotify destroy)
891 PsppSheetViewColumn *column;
892 PsppSheetViewColumnCellInfo *info;
894 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
895 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
897 info = pspp_sheet_view_column_get_cell_info (column, cell);
898 g_return_if_fail (info != NULL);
902 GDestroyNotify d = info->destroy;
904 info->destroy = NULL;
908 info->func = (PsppSheetCellDataFunc)func;
909 info->func_data = func_data;
910 info->destroy = destroy;
912 if (column->tree_view)
913 _pspp_sheet_view_column_cell_set_dirty (column);
917 pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
918 GtkCellRenderer *cell_renderer)
920 PsppSheetViewColumn *column;
921 PsppSheetViewColumnCellInfo *info;
923 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
924 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
926 info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
928 pspp_sheet_view_column_clear_attributes_by_info (column, info);
932 pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
933 GtkCellRenderer *cell,
937 PsppSheetViewColumn *column;
938 PsppSheetViewColumnCellInfo *info;
940 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
941 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
943 info = pspp_sheet_view_column_get_cell_info (column, cell);
945 g_return_if_fail (info != NULL);
946 g_return_if_fail (position >= 0);
948 link = g_list_find (column->cell_list, info);
950 g_return_if_fail (link != NULL);
952 column->cell_list = g_list_delete_link (column->cell_list, link);
953 column->cell_list = g_list_insert (column->cell_list, info, position);
955 if (column->tree_view)
956 gtk_widget_queue_draw (column->tree_view);
960 pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
961 PsppSheetViewColumnCellInfo *info)
965 list = info->attributes;
967 while (list && list->next)
970 list = list->next->next;
972 g_slist_free (info->attributes);
973 info->attributes = NULL;
975 if (tree_column->tree_view)
976 _pspp_sheet_view_column_cell_set_dirty (tree_column);
980 on_query_tooltip (GtkWidget *widget,
983 gboolean keyboard_mode,
987 PsppSheetViewColumn *tree_column = user_data;
990 g_signal_emit (tree_column, tree_column_signals[QUERY_TOOLTIP], 0,
996 on_button_pressed (GtkWidget *widget, GdkEventButton *event,
999 PsppSheetViewColumn *tree_column = user_data;
1002 /* XXX See "Implement GtkWidget::popup_menu" in GTK+ reference manual. */
1003 g_signal_emit (tree_column, tree_column_signals[BUTTON_PRESS_EVENT],
1004 0, event, &handled);
1011 /* Button handling code
1014 pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
1016 PsppSheetView *tree_view;
1020 tree_view = (PsppSheetView *) tree_column->tree_view;
1022 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1023 g_return_if_fail (tree_column->button == NULL);
1025 tree_column->button = gtk_button_new ();
1026 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
1028 /* make sure we own a reference to it as well. */
1029 if (tree_view->priv->header_window)
1030 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
1031 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
1033 g_signal_connect (tree_column->button, "event",
1034 G_CALLBACK (pspp_sheet_view_column_button_event),
1036 g_signal_connect (tree_column->button, "clicked",
1037 G_CALLBACK (pspp_sheet_view_column_button_clicked),
1039 g_signal_connect (tree_column->button, "popup-menu",
1040 G_CALLBACK (pspp_sheet_view_column_button_popup_menu),
1042 g_signal_connect (tree_column->button, "button-press-event",
1043 G_CALLBACK (on_button_pressed), tree_column);
1045 g_signal_connect (tree_column->button, "query-tooltip",
1046 G_CALLBACK (on_query_tooltip), tree_column);
1047 g_object_set (tree_column->button, "has-tooltip", TRUE, NULL);
1049 tree_column->bin = gtk_event_box_new ();
1050 g_object_set (tree_column->bin, "halign", GTK_ALIGN_CENTER, NULL);
1052 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
1054 if (tree_column->child)
1055 child = tree_column->child;
1058 child = gtk_label_new (tree_column->title);
1059 gtk_widget_show (child);
1062 g_signal_connect (child, "mnemonic-activate",
1063 G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
1067 gtk_box_pack_start (GTK_BOX (hbox), tree_column->bin, TRUE, TRUE, 0);
1069 gtk_container_add (GTK_CONTAINER (tree_column->bin), child);
1070 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
1072 gtk_widget_show (hbox);
1073 gtk_widget_show (tree_column->bin);
1074 pspp_sheet_view_column_update_button (tree_column);
1078 pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
1080 gint sort_column_id = -1;
1081 GtkWidget *alignment;
1082 GtkWidget *current_child;
1083 GtkTreeModel *model;
1086 if (tree_column->tree_view)
1087 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1091 /* Create a button if necessary */
1092 if (tree_column->visible &&
1093 tree_column->button == NULL &&
1094 tree_column->tree_view &&
1095 gtk_widget_get_realized (tree_column->tree_view))
1096 pspp_sheet_view_column_create_button (tree_column);
1098 if (! tree_column->button)
1101 alignment = tree_column->bin;
1102 current_child = gtk_bin_get_child (GTK_BIN (alignment));
1104 /* Set up the actual button */
1105 g_object_set (alignment,
1106 "halign", tree_column->halign,
1107 "valign", GTK_ALIGN_CENTER, NULL);
1109 if (tree_column->child)
1111 if (current_child != tree_column->child)
1113 gtk_container_remove (GTK_CONTAINER (alignment),
1115 gtk_container_add (GTK_CONTAINER (alignment),
1116 tree_column->child);
1121 if (current_child == NULL)
1123 current_child = gtk_label_new (NULL);
1124 gtk_widget_show (current_child);
1125 gtk_container_add (GTK_CONTAINER (alignment),
1129 g_return_if_fail (GTK_IS_LABEL (current_child));
1131 if (tree_column->title)
1132 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1133 tree_column->title);
1135 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
1139 if (GTK_IS_TREE_SORTABLE (model))
1140 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1145 /* It's always safe to hide the button. It isn't always safe to show it, as
1146 * if you show it before it's realized, it'll get the wrong window. */
1147 if (tree_column->button &&
1148 tree_column->tree_view != NULL &&
1149 gtk_widget_get_realized (tree_column->tree_view))
1151 if (tree_column->visible)
1153 gtk_widget_show (tree_column->button);
1154 if (tree_column->window)
1156 if (tree_column->resizable)
1158 gdk_window_show (tree_column->window);
1159 gdk_window_raise (tree_column->window);
1163 gdk_window_hide (tree_column->window);
1169 gtk_widget_hide (tree_column->button);
1170 if (tree_column->window)
1171 gdk_window_hide (tree_column->window);
1175 can_focus = pspp_sheet_view_column_can_focus (tree_column);
1176 gtk_widget_set_can_focus (tree_column->button, can_focus);
1177 if (!can_focus && gtk_widget_has_focus (tree_column->button))
1179 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
1180 if (gtk_widget_is_toplevel (toplevel))
1182 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
1186 /* Queue a resize on the assumption that we always want to catch all changes
1187 * and columns don't change all that often.
1189 if (gtk_widget_get_realized (tree_column->tree_view))
1190 gtk_widget_queue_resize (tree_column->tree_view);
1194 /* Button signal handlers
1198 pspp_sheet_view_column_button_event (GtkWidget *widget,
1199 GdkEventButton *event,
1202 PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
1204 g_return_val_if_fail (event != NULL, FALSE);
1206 if (event->type == GDK_BUTTON_PRESS &&
1207 column->reorderable &&
1208 ((GdkEventButton *)event)->button == 1)
1210 column->maybe_reordered = TRUE;
1211 gdk_window_get_device_position (gtk_button_get_event_window (GTK_BUTTON (widget)),
1216 gtk_widget_grab_focus (widget);
1219 if (event->type == GDK_BUTTON_RELEASE ||
1220 event->type == GDK_LEAVE_NOTIFY)
1221 column->maybe_reordered = FALSE;
1223 if (event->type == GDK_MOTION_NOTIFY &&
1224 column->maybe_reordered &&
1225 (gtk_drag_check_threshold (widget,
1228 (gint) ((GdkEventMotion *)event)->x,
1229 (gint) ((GdkEventMotion *)event)->y)))
1231 column->maybe_reordered = FALSE;
1232 _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
1235 if (column->clickable == FALSE)
1237 switch (event->type)
1239 case GDK_MOTION_NOTIFY:
1240 case GDK_BUTTON_RELEASE:
1241 case GDK_ENTER_NOTIFY:
1242 case GDK_LEAVE_NOTIFY:
1252 all_rows_selected (PsppSheetView *sheet_view)
1254 PsppSheetSelection *selection = sheet_view->priv->selection;
1255 gint n_rows, n_selected_rows;
1257 n_rows = sheet_view->priv->row_count;
1258 n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
1260 return n_rows > 0 && n_selected_rows >= n_rows;
1264 on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *column,
1265 GdkEventButton *event)
1267 PsppSheetView *sheet_view = PSPP_SHEET_VIEW (column->tree_view);
1268 PsppSheetSelection *selection;
1269 GSignalInvocationHint *hint;
1272 /* We only want to run first, not last, but combining that with return type
1273 `gboolean' makes GObject warn, so just ignore the run_last call. */
1274 hint = g_signal_get_invocation_hint (column);
1275 g_return_val_if_fail (hint != NULL, FALSE);
1276 if (hint->run_type != G_SIGNAL_RUN_FIRST)
1279 g_return_val_if_fail (sheet_view != NULL, FALSE);
1281 selection = sheet_view->priv->selection;
1282 g_return_val_if_fail (selection != NULL, FALSE);
1284 if (pspp_sheet_selection_get_mode (selection) != PSPP_SHEET_SELECTION_RECTANGLE)
1287 modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
1288 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
1290 if (pspp_sheet_selection_count_selected_columns (selection) <= 1
1291 || !all_rows_selected (sheet_view))
1293 pspp_sheet_selection_select_all (selection);
1294 pspp_sheet_selection_unselect_all_columns (selection);
1295 pspp_sheet_selection_select_column (selection, column);
1296 sheet_view->priv->anchor_column = column;
1300 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1301 && modifiers == GDK_CONTROL_MASK)
1303 gboolean is_selected;
1305 if (!all_rows_selected (sheet_view))
1307 pspp_sheet_selection_select_all (selection);
1308 pspp_sheet_selection_unselect_all_columns (selection);
1310 sheet_view->priv->anchor_column = column;
1312 is_selected = pspp_sheet_view_column_get_selected (column);
1313 pspp_sheet_view_column_set_selected (column, !is_selected);
1317 else if (event->type == GDK_BUTTON_PRESS && event->button == 1
1318 && modifiers == GDK_SHIFT_MASK)
1320 if (!all_rows_selected (sheet_view))
1322 pspp_sheet_selection_select_all (selection);
1323 pspp_sheet_selection_unselect_all_columns (selection);
1324 sheet_view->priv->anchor_column = column;
1326 else if (sheet_view->priv->anchor_column == NULL)
1327 sheet_view->priv->anchor_column = column;
1329 pspp_sheet_selection_unselect_all_columns (selection);
1330 pspp_sheet_selection_select_column_range (selection,
1331 sheet_view->priv->anchor_column,
1340 on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *column)
1342 PsppSheetSelection *selection;
1343 PsppSheetView *sheet_view;
1345 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (column));
1346 selection = pspp_sheet_view_get_selection (sheet_view);
1347 if (pspp_sheet_selection_get_mode (selection) == PSPP_SHEET_SELECTION_RECTANGLE)
1349 pspp_sheet_selection_select_all (selection);
1350 if (pspp_sheet_view_column_get_row_head (column))
1351 pspp_sheet_selection_select_all_columns (selection);
1354 pspp_sheet_selection_unselect_all_columns (selection);
1355 pspp_sheet_selection_select_column (selection, column);
1357 sheet_view->priv->anchor_column = column;
1364 pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
1366 PsppSheetViewColumn *column = data;
1369 g_signal_emit (column, tree_column_signals[CLICKED], 0, &handled);
1373 pspp_sheet_view_column_button_popup_menu (GtkWidget *widget, gpointer data)
1375 g_signal_emit_by_name (data, "popup-menu");
1379 pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
1380 gboolean group_cycling,
1383 PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
1385 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
1387 PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
1388 if (column->clickable)
1389 gtk_button_clicked (GTK_BUTTON (column->button));
1390 else if (gtk_widget_get_can_focus (column->button))
1391 gtk_widget_grab_focus (column->button);
1393 gtk_widget_grab_focus (column->tree_view);
1399 pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
1400 PsppSheetViewColumn *column)
1402 gint sort_column_id;
1405 if (gtk_tree_sortable_get_sort_column_id (sortable,
1409 if (sort_column_id == column->sort_column_id)
1411 pspp_sheet_view_column_set_sort_indicator (column, TRUE);
1412 pspp_sheet_view_column_set_sort_order (column, order);
1416 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1421 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1426 pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
1429 gint sort_column_id;
1431 gboolean has_sort_column;
1432 gboolean has_default_sort_func;
1434 g_return_if_fail (tree_column->tree_view != NULL);
1437 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1440 has_default_sort_func =
1441 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
1443 if (has_sort_column &&
1444 sort_column_id == tree_column->sort_column_id)
1446 if (order == GTK_SORT_ASCENDING)
1447 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1448 tree_column->sort_column_id,
1449 GTK_SORT_DESCENDING);
1450 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
1451 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1452 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1453 GTK_SORT_ASCENDING);
1455 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1456 tree_column->sort_column_id,
1457 GTK_SORT_ASCENDING);
1461 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1462 tree_column->sort_column_id,
1463 GTK_SORT_ASCENDING);
1469 pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
1471 GtkTreeModel *model;
1473 if (tree_column->tree_view == NULL)
1476 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1481 if (GTK_IS_TREE_SORTABLE (model) &&
1482 tree_column->sort_column_id != -1)
1484 gint real_sort_column_id;
1485 GtkSortType real_order;
1487 if (tree_column->sort_column_changed_signal == 0)
1488 tree_column->sort_column_changed_signal =
1489 g_signal_connect (model, "sort-column-changed",
1490 G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
1493 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1494 &real_sort_column_id,
1496 (real_sort_column_id == tree_column->sort_column_id))
1498 pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
1499 pspp_sheet_view_column_set_sort_order (tree_column, real_order);
1503 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
1509 /* Exported Private Functions.
1510 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1514 _pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
1516 GtkAllocation allocation;
1517 PsppSheetView *tree_view;
1519 guint attributes_mask;
1522 tree_view = (PsppSheetView *)column->tree_view;
1523 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
1525 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1526 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
1527 g_return_if_fail (tree_view->priv->header_window != NULL);
1528 if (!column->button)
1531 g_return_if_fail (column->button != NULL);
1533 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
1535 if (column->visible)
1536 gtk_widget_show (column->button);
1538 attr.window_type = GDK_WINDOW_CHILD;
1539 attr.wclass = GDK_INPUT_ONLY;
1540 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1541 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
1542 (GDK_BUTTON_PRESS_MASK |
1543 GDK_BUTTON_RELEASE_MASK |
1544 GDK_POINTER_MOTION_MASK |
1545 GDK_POINTER_MOTION_HINT_MASK |
1546 GDK_KEY_PRESS_MASK);
1547 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
1548 attr.cursor = gdk_cursor_new_for_display (gdk_window_get_display (tree_view->priv->header_window),
1549 GDK_SB_H_DOUBLE_ARROW);
1551 attr.width = TREE_VIEW_DRAG_WIDTH;
1552 attr.height = tree_view->priv->header_height;
1553 gtk_widget_get_allocation (column->button, &allocation);
1554 attr.x = (allocation.x + (rtl ? 0 : allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
1555 column->window = gdk_window_new (tree_view->priv->header_window,
1556 &attr, attributes_mask);
1557 gdk_window_set_user_data (column->window, tree_view);
1559 pspp_sheet_view_column_update_button (column);
1561 g_object_unref (attr.cursor);
1565 _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
1567 g_return_if_fail (column != NULL);
1568 if (column->window != NULL)
1570 gdk_window_set_user_data (column->window, NULL);
1571 gdk_window_destroy (column->window);
1572 column->window = NULL;
1577 _pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
1578 GtkTreeModel *old_model)
1580 if (column->sort_column_changed_signal)
1582 g_signal_handler_disconnect (old_model,
1583 column->sort_column_changed_signal);
1584 column->sort_column_changed_signal = 0;
1586 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1590 _pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
1591 PsppSheetView *tree_view)
1593 g_assert (column->tree_view == NULL);
1595 column->tree_view = GTK_WIDGET (tree_view);
1596 pspp_sheet_view_column_create_button (column);
1598 column->property_changed_signal =
1599 g_signal_connect_swapped (tree_view,
1601 G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
1604 pspp_sheet_view_column_setup_sort_column_id_callback (column);
1608 _pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
1610 if (column->tree_view && column->button)
1612 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1614 if (column->property_changed_signal)
1616 g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
1617 column->property_changed_signal = 0;
1620 if (column->sort_column_changed_signal)
1622 g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
1623 column->sort_column_changed_signal);
1624 column->sort_column_changed_signal = 0;
1627 column->tree_view = NULL;
1628 column->button = NULL;
1632 _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
1636 for (list = column->cell_list; list; list = list->next)
1638 GtkCellRendererMode mode;
1639 g_object_get (((PsppSheetViewColumnCellInfo *)list->data)->cell, "mode", &mode, NULL);
1640 if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
1647 /* gets cell being edited */
1649 _pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
1653 for (list = column->cell_list; list; list = list->next)
1654 if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
1655 return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
1661 _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
1666 for (list = column->cell_list; list; list = list->next)
1668 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1670 GtkCellRendererMode mode;
1671 g_object_get (cellinfo->cell, "mode", &mode, NULL);
1673 if ((mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1674 mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
1675 gtk_cell_renderer_get_visible (cellinfo->cell))
1683 _pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
1689 list = pspp_sheet_view_column_cell_first (column);
1690 for (; list; list = pspp_sheet_view_column_cell_next (column, list))
1692 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1693 if (current_x <= x && x <= current_x + cellinfo->real_width)
1694 return cellinfo->cell;
1695 current_x += cellinfo->real_width;
1701 /* Public Functions */
1705 * pspp_sheet_view_column_new:
1707 * Creates a new #PsppSheetViewColumn.
1709 * Return value: A newly created #PsppSheetViewColumn.
1711 PsppSheetViewColumn *
1712 pspp_sheet_view_column_new (void)
1714 PsppSheetViewColumn *tree_column;
1716 tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
1722 * pspp_sheet_view_column_new_with_attributes:
1723 * @title: The title to set the header to.
1724 * @cell: The #GtkCellRenderer.
1725 * @Varargs: A %NULL-terminated list of attributes.
1727 * Creates a new #PsppSheetViewColumn with a number of default values. This is
1728 * equivalent to calling pspp_sheet_view_column_set_title(),
1729 * pspp_sheet_view_column_pack_start(), and
1730 * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
1732 * Here's a simple example:
1734 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1737 * PsppSheetViewColumn *column;
1738 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
1740 * column = pspp_sheet_view_column_new_with_attributes ("Title",
1742 * "text", TEXT_COLUMN,
1743 * "foreground", COLOR_COLUMN,
1748 * Return value: A newly created #PsppSheetViewColumn.
1750 PsppSheetViewColumn *
1751 pspp_sheet_view_column_new_with_attributes (const gchar *title,
1752 GtkCellRenderer *cell,
1755 PsppSheetViewColumn *retval;
1758 retval = pspp_sheet_view_column_new ();
1760 pspp_sheet_view_column_set_title (retval, title);
1761 pspp_sheet_view_column_pack_start (retval, cell, TRUE);
1763 va_start (args, cell);
1764 pspp_sheet_view_column_set_attributesv (retval, cell, args);
1770 static PsppSheetViewColumnCellInfo *
1771 pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
1772 GtkCellRenderer *cell_renderer)
1775 for (list = tree_column->cell_list; list; list = list->next)
1776 if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
1777 return (PsppSheetViewColumnCellInfo *) list->data;
1783 * pspp_sheet_view_column_pack_start:
1784 * @tree_column: A #PsppSheetViewColumn.
1785 * @cell: The #GtkCellRenderer.
1786 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1788 * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
1789 * the @cell is allocated no more space than it needs. Any unused space is divided
1790 * evenly between cells for which @expand is %TRUE.
1793 pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
1794 GtkCellRenderer *cell,
1797 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
1801 * pspp_sheet_view_column_pack_end:
1802 * @tree_column: A #PsppSheetViewColumn.
1803 * @cell: The #GtkCellRenderer.
1804 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1806 * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
1807 * is allocated no more space than it needs. Any unused space is divided
1808 * evenly between cells for which @expand is %TRUE.
1811 pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
1812 GtkCellRenderer *cell,
1815 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
1819 * pspp_sheet_view_column_clear:
1820 * @tree_column: A #PsppSheetViewColumn
1822 * Unsets all the mappings on all renderers on the @tree_column.
1825 pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
1827 gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
1831 pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
1833 PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
1834 GList *retval = NULL, *list;
1836 g_return_val_if_fail (tree_column != NULL, NULL);
1838 for (list = tree_column->cell_list; list; list = list->next)
1840 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
1842 retval = g_list_append (retval, info->cell);
1849 * pspp_sheet_view_column_get_cell_renderers:
1850 * @tree_column: A #PsppSheetViewColumn
1852 * Returns a newly-allocated #GList of all the cell renderers in the column,
1853 * in no particular order. The list must be freed with g_list_free().
1855 * Return value: A list of #GtkCellRenderers
1857 * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
1860 pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
1862 return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
1866 * pspp_sheet_view_column_add_attribute:
1867 * @tree_column: A #PsppSheetViewColumn.
1868 * @cell_renderer: the #GtkCellRenderer to set attributes on
1869 * @attribute: An attribute on the renderer
1870 * @column: The column position on the model to get the attribute from.
1872 * Adds an attribute mapping to the list in @tree_column. The @column is the
1873 * column of the model to get a value from, and the @attribute is the
1874 * parameter on @cell_renderer to be set from the value. So for example
1875 * if column 2 of the model contains strings, you could have the
1876 * "text" attribute of a #GtkCellRendererText get its values from
1880 pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
1881 GtkCellRenderer *cell_renderer,
1882 const gchar *attribute,
1885 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
1886 cell_renderer, attribute, column);
1890 pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
1891 GtkCellRenderer *cell_renderer,
1897 attribute = va_arg (args, gchar *);
1899 pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
1901 while (attribute != NULL)
1903 column = va_arg (args, gint);
1904 pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1905 attribute = va_arg (args, gchar *);
1910 * pspp_sheet_view_column_set_attributes:
1911 * @tree_column: A #PsppSheetViewColumn.
1912 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1913 * @Varargs: A %NULL-terminated list of attributes.
1915 * Sets the attributes in the list as the attributes of @tree_column.
1916 * The attributes should be in attribute/column order, as in
1917 * pspp_sheet_view_column_add_attribute(). All existing attributes
1918 * are removed, and replaced with the new attributes.
1921 pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
1922 GtkCellRenderer *cell_renderer,
1927 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1928 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1929 g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
1931 va_start (args, cell_renderer);
1932 pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
1938 * pspp_sheet_view_column_set_cell_data_func:
1939 * @tree_column: A #PsppSheetViewColumn
1940 * @cell_renderer: A #GtkCellRenderer
1941 * @func: The #PsppSheetViewColumnFunc to use.
1942 * @func_data: The user data for @func.
1943 * @destroy: The destroy notification for @func_data
1945 * Sets the #PsppSheetViewColumnFunc to use for the column. This
1946 * function is used instead of the standard attributes mapping for
1947 * setting the column value, and should set the value of @tree_column's
1948 * cell renderer as appropriate. @func may be %NULL to remove an
1952 pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
1953 GtkCellRenderer *cell_renderer,
1954 PsppSheetCellDataFunc func,
1956 GDestroyNotify destroy)
1958 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
1960 (GtkCellLayoutDataFunc)func,
1961 func_data, destroy);
1966 * pspp_sheet_view_column_clear_attributes:
1967 * @tree_column: a #PsppSheetViewColumn
1968 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1970 * Clears all existing attributes previously set with
1971 * pspp_sheet_view_column_set_attributes().
1974 pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
1975 GtkCellRenderer *cell_renderer)
1977 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
1982 * pspp_sheet_view_column_set_spacing:
1983 * @tree_column: A #PsppSheetViewColumn.
1984 * @spacing: distance between cell renderers in pixels.
1986 * Sets the spacing field of @tree_column, which is the number of pixels to
1987 * place between cell renderers packed into it.
1990 pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
1993 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1994 g_return_if_fail (spacing >= 0);
1996 if (tree_column->spacing == spacing)
1999 tree_column->spacing = spacing;
2000 if (tree_column->tree_view)
2001 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2005 * pspp_sheet_view_column_get_spacing:
2006 * @tree_column: A #PsppSheetViewColumn.
2008 * Returns the spacing of @tree_column.
2010 * Return value: the spacing of @tree_column.
2013 pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
2015 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2017 return tree_column->spacing;
2020 /* Options for manipulating the columns */
2023 * pspp_sheet_view_column_set_visible:
2024 * @tree_column: A #PsppSheetViewColumn.
2025 * @visible: %TRUE if the @tree_column is visible.
2027 * Sets the visibility of @tree_column.
2030 pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
2033 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2035 visible = !! visible;
2037 if (tree_column->visible == visible)
2040 tree_column->visible = visible;
2042 if (tree_column->visible)
2043 _pspp_sheet_view_column_cell_set_dirty (tree_column);
2045 pspp_sheet_view_column_update_button (tree_column);
2046 g_object_notify (G_OBJECT (tree_column), "visible");
2050 * pspp_sheet_view_column_get_visible:
2051 * @tree_column: A #PsppSheetViewColumn.
2053 * Returns %TRUE if @tree_column is visible.
2055 * Return value: whether the column is visible or not. If it is visible, then
2056 * the tree will show the column.
2059 pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
2061 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2063 return tree_column->visible;
2067 * pspp_sheet_view_column_set_resizable:
2068 * @tree_column: A #PsppSheetViewColumn
2069 * @resizable: %TRUE, if the column can be resized
2071 * If @resizable is %TRUE, then the user can explicitly resize the column by
2072 * grabbing the outer edge of the column button.
2075 pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
2078 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2080 resizable = !! resizable;
2082 if (tree_column->resizable == resizable)
2085 tree_column->resizable = resizable;
2087 pspp_sheet_view_column_update_button (tree_column);
2089 g_object_notify (G_OBJECT (tree_column), "resizable");
2093 * pspp_sheet_view_column_get_resizable:
2094 * @tree_column: A #PsppSheetViewColumn
2096 * Returns %TRUE if the @tree_column can be resized by the end user.
2098 * Return value: %TRUE, if the @tree_column can be resized.
2101 pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
2103 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2105 return tree_column->resizable;
2110 * pspp_sheet_view_column_get_width:
2111 * @tree_column: A #PsppSheetViewColumn.
2113 * Returns the current size of @tree_column in pixels.
2115 * Return value: The current width of @tree_column.
2118 pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
2120 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2122 return tree_column->width;
2126 * pspp_sheet_view_column_set_fixed_width:
2127 * @tree_column: A #PsppSheetViewColumn.
2128 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
2130 * Sets the size of the column in pixels. The size of the column is clamped to
2131 * the min/max width for the column. Please note that the min/max width of the
2132 * column doesn't actually affect the "fixed_width" property of the widget, just
2133 * the actual size when displayed.
2136 pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
2139 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2140 g_return_if_fail (fixed_width > 0);
2142 tree_column->fixed_width = fixed_width;
2143 tree_column->use_resized_width = FALSE;
2145 if (tree_column->tree_view &&
2146 gtk_widget_get_realized (tree_column->tree_view))
2148 gtk_widget_queue_resize (tree_column->tree_view);
2151 g_object_notify (G_OBJECT (tree_column), "fixed-width");
2155 * pspp_sheet_view_column_get_fixed_width:
2156 * @tree_column: a #PsppSheetViewColumn
2158 * Gets the fixed width of the column. This value is only meaning may not be
2159 * the actual width of the column on the screen, just what is requested.
2161 * Return value: the fixed width of the column
2164 pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
2166 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2168 return tree_column->fixed_width;
2172 * pspp_sheet_view_column_set_min_width:
2173 * @tree_column: A #PsppSheetViewColumn.
2174 * @min_width: The minimum width of the column in pixels, or -1.
2176 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
2177 * minimum width is unset.
2180 pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
2183 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2184 g_return_if_fail (min_width >= -1);
2186 if (min_width == tree_column->min_width)
2189 if (tree_column->visible &&
2190 tree_column->tree_view != NULL &&
2191 gtk_widget_get_realized (tree_column->tree_view))
2193 if (min_width > tree_column->width)
2194 gtk_widget_queue_resize (tree_column->tree_view);
2197 tree_column->min_width = min_width;
2198 g_object_freeze_notify (G_OBJECT (tree_column));
2199 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
2201 tree_column->max_width = min_width;
2202 g_object_notify (G_OBJECT (tree_column), "max-width");
2204 g_object_notify (G_OBJECT (tree_column), "min-width");
2205 g_object_thaw_notify (G_OBJECT (tree_column));
2209 * pspp_sheet_view_column_get_min_width:
2210 * @tree_column: A #PsppSheetViewColumn.
2212 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
2215 * Return value: The minimum width of the @tree_column.
2218 pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
2220 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2222 return tree_column->min_width;
2226 * pspp_sheet_view_column_set_max_width:
2227 * @tree_column: A #PsppSheetViewColumn.
2228 * @max_width: The maximum width of the column in pixels, or -1.
2230 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
2231 * maximum width is unset. Note, the column can actually be wider than max
2232 * width if it's the last column in a view. In this case, the column expands to
2233 * fill any extra space.
2236 pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
2239 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2240 g_return_if_fail (max_width >= -1);
2242 if (max_width == tree_column->max_width)
2245 if (tree_column->visible &&
2246 tree_column->tree_view != NULL &&
2247 gtk_widget_get_realized (tree_column->tree_view))
2249 if (max_width != -1 && max_width < tree_column->width)
2250 gtk_widget_queue_resize (tree_column->tree_view);
2253 tree_column->max_width = max_width;
2254 g_object_freeze_notify (G_OBJECT (tree_column));
2255 if (max_width != -1 && max_width < tree_column->min_width)
2257 tree_column->min_width = max_width;
2258 g_object_notify (G_OBJECT (tree_column), "min-width");
2260 g_object_notify (G_OBJECT (tree_column), "max-width");
2261 g_object_thaw_notify (G_OBJECT (tree_column));
2265 * pspp_sheet_view_column_get_max_width:
2266 * @tree_column: A #PsppSheetViewColumn.
2268 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
2271 * Return value: The maximum width of the @tree_column.
2274 pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
2276 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2278 return tree_column->max_width;
2282 * pspp_sheet_view_column_clicked:
2283 * @tree_column: a #PsppSheetViewColumn
2285 * Emits the "clicked" signal on the column. This function will only work if
2286 * @tree_column is clickable.
2289 pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
2291 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2293 if (tree_column->visible &&
2294 tree_column->button &&
2295 tree_column->clickable)
2296 gtk_button_clicked (GTK_BUTTON (tree_column->button));
2300 * pspp_sheet_view_column_set_title:
2301 * @tree_column: A #PsppSheetViewColumn.
2302 * @title: The title of the @tree_column.
2304 * Sets the title of the @tree_column. If a custom widget has been set, then
2305 * this value is ignored.
2308 pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
2313 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2315 new_title = g_strdup (title);
2316 g_free (tree_column->title);
2317 tree_column->title = new_title;
2319 pspp_sheet_view_column_update_button (tree_column);
2320 g_object_notify (G_OBJECT (tree_column), "title");
2324 * pspp_sheet_view_column_get_title:
2325 * @tree_column: A #PsppSheetViewColumn.
2327 * Returns the title of the widget.
2329 * Return value: the title of the column. This string should not be
2330 * modified or freed.
2333 pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
2335 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2337 return tree_column->title;
2341 * pspp_sheet_view_column_set_expand:
2342 * @tree_column: A #PsppSheetViewColumn
2343 * @expand: %TRUE if the column should take available extra space, %FALSE if not
2345 * Sets the column to take available extra space. This space is shared equally
2346 * amongst all columns that have the expand set to %TRUE. If no column has this
2347 * option set, then the last column gets all extra space. By default, every
2348 * column is created with this %FALSE.
2353 pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
2356 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2359 if (tree_column->expand == expand)
2361 tree_column->expand = expand;
2363 if (tree_column->visible &&
2364 tree_column->tree_view != NULL &&
2365 gtk_widget_get_realized (tree_column->tree_view))
2367 /* We want to continue using the original width of the
2368 * column that includes additional space added by the user
2369 * resizing the columns and possibly extra (expanded) space, which
2370 * are not included in the resized width.
2372 tree_column->use_resized_width = FALSE;
2374 gtk_widget_queue_resize (tree_column->tree_view);
2377 g_object_notify (G_OBJECT (tree_column), "expand");
2381 * pspp_sheet_view_column_get_expand:
2382 * @tree_column: a #PsppSheetViewColumn
2384 * Return %TRUE if the column expands to take any available space.
2386 * Return value: %TRUE, if the column expands
2391 pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
2393 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2395 return tree_column->expand;
2399 * pspp_sheet_view_column_set_clickable:
2400 * @tree_column: A #PsppSheetViewColumn.
2401 * @clickable: %TRUE if the header is active.
2403 * Sets the header to be active if @active is %TRUE. When the header is active,
2404 * then it can take keyboard focus, and can be clicked.
2407 pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
2410 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2412 clickable = !! clickable;
2413 if (tree_column->clickable == clickable)
2416 tree_column->clickable = clickable;
2417 pspp_sheet_view_column_update_button (tree_column);
2418 g_object_notify (G_OBJECT (tree_column), "clickable");
2422 * pspp_sheet_view_column_get_clickable:
2423 * @tree_column: a #PsppSheetViewColumn
2425 * Returns %TRUE if the user can click on the header for the column.
2427 * Return value: %TRUE if user can click the column header.
2430 pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
2432 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2434 return tree_column->clickable;
2438 * pspp_sheet_view_column_set_widget:
2439 * @tree_column: A #PsppSheetViewColumn.
2440 * @widget: (allow-none): A child #GtkWidget, or %NULL.
2442 * Sets the widget in the header to be @widget. If widget is %NULL, then the
2443 * header button is set with a #GtkLabel set to the title of @tree_column.
2446 pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
2449 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2450 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
2453 g_object_ref_sink (widget);
2455 if (tree_column->child)
2456 g_object_unref (tree_column->child);
2458 tree_column->child = widget;
2459 pspp_sheet_view_column_update_button (tree_column);
2460 g_object_notify (G_OBJECT (tree_column), "widget");
2464 * pspp_sheet_view_column_get_widget:
2465 * @tree_column: A #PsppSheetViewColumn.
2467 * Returns the #GtkWidget in the button on the column header. If a custom
2468 * widget has not been set then %NULL is returned.
2470 * Return value: The #GtkWidget in the column header, or %NULL
2473 pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
2475 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2477 return tree_column->child;
2481 * pspp_sheet_view_column_set_alignment:
2482 * @tree_column: A #PsppSheetViewColumn.
2483 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2485 * Sets the alignment of the title or custom widget inside the column header.
2486 * The alignment determines its location inside the button.
2489 pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
2492 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2495 if (tree_column->halign == xalign)
2498 tree_column->halign = xalign;
2499 pspp_sheet_view_column_update_button (tree_column);
2500 g_object_notify (G_OBJECT (tree_column), "alignment");
2504 * pspp_sheet_view_column_get_alignment:
2505 * @tree_column: A #PsppSheetViewColumn.
2507 * Returns the current x alignment of @tree_column.
2509 * Return value: The current alignent of @tree_column.
2512 pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
2514 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), GTK_ALIGN_CENTER);
2516 return tree_column->halign;
2521 * pspp_sheet_view_column_set_reorderable:
2522 * @tree_column: A #PsppSheetViewColumn
2523 * @reorderable: %TRUE, if the column can be reordered.
2525 * If @reorderable is %TRUE, then the column can be reordered by the end user
2526 * dragging the header.
2529 pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
2530 gboolean reorderable)
2532 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2535 pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
2537 reorderable = !!reorderable;
2538 if (tree_column->reorderable == reorderable)
2541 tree_column->reorderable = reorderable;
2542 pspp_sheet_view_column_update_button (tree_column);
2543 g_object_notify (G_OBJECT (tree_column), "reorderable");
2547 * pspp_sheet_view_column_get_reorderable:
2548 * @tree_column: A #PsppSheetViewColumn
2550 * Returns %TRUE if the @tree_column can be reordered by the user.
2552 * Return value: %TRUE if the @tree_column can be reordered by the user.
2555 pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
2557 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2559 return tree_column->reorderable;
2563 * pspp_sheet_view_column_set_quick_edit:
2564 * @tree_column: A #PsppSheetViewColumn
2565 * @quick_edit: If true, editing starts upon the first click in the column. If
2566 * false, the first click selects the column and a second click is needed to
2567 * begin editing. This has no effect on cells that are not editable.
2570 pspp_sheet_view_column_set_quick_edit (PsppSheetViewColumn *tree_column,
2571 gboolean quick_edit)
2573 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2575 quick_edit = !!quick_edit;
2576 if (tree_column->quick_edit != quick_edit)
2578 tree_column->quick_edit = quick_edit;
2579 g_object_notify (G_OBJECT (tree_column), "quick-edit");
2584 * pspp_sheet_view_column_get_quick_edit:
2585 * @tree_column: A #PsppSheetViewColumn
2587 * Returns %TRUE if editing starts upon the first click in the column. Returns
2588 * %FALSE, the first click selects the column and a second click is needed to
2589 * begin editing. This is not meaningful for cells that are not editable.
2591 * Return value: %TRUE if editing starts upon the first click.
2594 pspp_sheet_view_column_get_quick_edit (PsppSheetViewColumn *tree_column)
2596 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2598 return tree_column->quick_edit;
2603 * pspp_sheet_view_column_set_selected:
2604 * @tree_column: A #PsppSheetViewColumn
2605 * @selected: If true, the column is selected as part of a rectangular
2609 pspp_sheet_view_column_set_selected (PsppSheetViewColumn *tree_column,
2612 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2614 selected = !!selected;
2615 if (tree_column->selected != selected)
2617 PsppSheetSelection *selection;
2618 PsppSheetView *sheet_view;
2620 if (tree_column->tree_view != NULL)
2621 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2622 tree_column->selected = selected;
2623 g_object_notify (G_OBJECT (tree_column), "selected");
2625 sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
2627 selection = pspp_sheet_view_get_selection (sheet_view);
2628 _pspp_sheet_selection_emit_changed (selection);
2633 * pspp_sheet_view_column_get_selected:
2634 * @tree_column: A #PsppSheetViewColumn
2636 * Returns %TRUE if the column is selected as part of a rectangular
2639 * Return value: %TRUE if the column is selected as part of a rectangular
2643 pspp_sheet_view_column_get_selected (PsppSheetViewColumn *tree_column)
2645 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2647 return tree_column->selected;
2651 * pspp_sheet_view_column_set_selectable:
2652 * @tree_column: A #PsppSheetViewColumn
2653 * @selectable: If true, the column may be selected as part of a rectangular
2657 pspp_sheet_view_column_set_selectable (PsppSheetViewColumn *tree_column,
2658 gboolean selectable)
2660 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2662 selectable = !!selectable;
2663 if (tree_column->selectable != selectable)
2665 if (tree_column->tree_view != NULL)
2666 gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
2667 tree_column->selectable = selectable;
2668 g_object_notify (G_OBJECT (tree_column), "selectable");
2673 * pspp_sheet_view_column_get_selectable:
2674 * @tree_column: A #PsppSheetViewColumn
2676 * Returns %TRUE if the column may be selected as part of a rectangular
2679 * Return value: %TRUE if the column may be selected as part of a rectangular
2683 pspp_sheet_view_column_get_selectable (PsppSheetViewColumn *tree_column)
2685 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2687 return tree_column->selectable;
2692 * pspp_sheet_view_column_set_row_head:
2693 * @tree_column: A #PsppSheetViewColumn
2694 * @row_head: If true, the column is a "row head", analogous to a column head.
2695 * See the description of the row-head property for more information.
2698 pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column,
2701 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2703 row_head = !!row_head;
2704 if (tree_column->row_head != row_head)
2706 tree_column->row_head = row_head;
2707 g_object_notify (G_OBJECT (tree_column), "row_head");
2712 * pspp_sheet_view_column_get_row_head:
2713 * @tree_column: A #PsppSheetViewColumn
2715 * Returns %TRUE if the column is a row head.
2717 * Return value: %TRUE if the column is a row head.
2720 pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column)
2722 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2724 return tree_column->row_head;
2729 * pspp_sheet_view_column_set_tabbable:
2730 * @tree_column: A #PsppSheetViewColumn
2731 * @tabbable: If true, the column is "tabbable", meaning that Tab and Shift+Tab
2732 * in the sheet visit this column. If false, Tab and Shift+Tab skip this
2736 pspp_sheet_view_column_set_tabbable (PsppSheetViewColumn *tree_column,
2739 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2741 tabbable = !!tabbable;
2742 if (tree_column->tabbable != tabbable)
2744 tree_column->tabbable = tabbable;
2745 g_object_notify (G_OBJECT (tree_column), "tabbable");
2750 * pspp_sheet_view_column_get_tabbable:
2751 * @tree_column: A #PsppSheetViewColumn
2753 * Returns %TRUE if the column is tabbable.
2755 * Return value: %TRUE if the column is tabbable.
2758 pspp_sheet_view_column_get_tabbable (PsppSheetViewColumn *tree_column)
2760 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2762 return tree_column->tabbable;
2767 * pspp_sheet_view_column_set_sort_column_id:
2768 * @tree_column: a #PsppSheetViewColumn
2769 * @sort_column_id: The @sort_column_id of the model to sort on.
2771 * Sets the logical @sort_column_id that this column sorts on when this column
2772 * is selected for sorting. Doing so makes the column header clickable.
2775 pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
2776 gint sort_column_id)
2778 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2779 g_return_if_fail (sort_column_id >= -1);
2781 if (tree_column->sort_column_id == sort_column_id)
2784 tree_column->sort_column_id = sort_column_id;
2786 /* Handle unsetting the id */
2787 if (sort_column_id == -1)
2789 GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
2791 if (tree_column->sort_clicked_signal)
2793 g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
2794 tree_column->sort_clicked_signal = 0;
2797 if (tree_column->sort_column_changed_signal)
2799 g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
2800 tree_column->sort_column_changed_signal = 0;
2803 pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2804 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
2805 pspp_sheet_view_column_set_clickable (tree_column, FALSE);
2806 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2810 pspp_sheet_view_column_set_clickable (tree_column, TRUE);
2812 if (! tree_column->sort_clicked_signal)
2813 tree_column->sort_clicked_signal = g_signal_connect (tree_column,
2815 G_CALLBACK (pspp_sheet_view_column_sort),
2818 pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
2819 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2823 * pspp_sheet_view_column_get_sort_column_id:
2824 * @tree_column: a #PsppSheetViewColumn
2826 * Gets the logical @sort_column_id that the model sorts on when this
2827 * column is selected for sorting.
2828 * See pspp_sheet_view_column_set_sort_column_id().
2830 * Return value: the current @sort_column_id for this column, or -1 if
2831 * this column can't be used for sorting.
2834 pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
2836 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2838 return tree_column->sort_column_id;
2842 * pspp_sheet_view_column_set_sort_indicator:
2843 * @tree_column: a #PsppSheetViewColumn
2844 * @setting: %TRUE to display an indicator that the column is sorted
2846 * Call this function with a @setting of %TRUE to display an arrow in
2847 * the header button indicating the column is sorted. Call
2848 * pspp_sheet_view_column_set_sort_order() to change the direction of
2853 pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
2856 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2858 setting = setting != FALSE;
2860 if (setting == tree_column->show_sort_indicator)
2863 tree_column->show_sort_indicator = setting;
2864 pspp_sheet_view_column_update_button (tree_column);
2865 g_object_notify (G_OBJECT (tree_column), "sort-indicator");
2869 * pspp_sheet_view_column_get_sort_indicator:
2870 * @tree_column: a #PsppSheetViewColumn
2872 * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
2874 * Return value: whether the sort indicator arrow is displayed
2877 pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column)
2879 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2881 return tree_column->show_sort_indicator;
2885 * pspp_sheet_view_column_set_sort_order:
2886 * @tree_column: a #PsppSheetViewColumn
2887 * @order: sort order that the sort indicator should indicate
2889 * Changes the appearance of the sort indicator.
2891 * This <emphasis>does not</emphasis> actually sort the model. Use
2892 * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
2893 * support. This function is primarily for custom sorting behavior, and should
2894 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2895 * that. For custom models, the mechanism will vary.
2897 * The sort indicator changes direction to indicate normal sort or reverse sort.
2898 * Note that you must have the sort indicator enabled to see anything when
2899 * calling this function; see pspp_sheet_view_column_set_sort_indicator().
2902 pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
2905 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2907 if (order == tree_column->sort_order)
2910 tree_column->sort_order = order;
2911 pspp_sheet_view_column_update_button (tree_column);
2912 g_object_notify (G_OBJECT (tree_column), "sort-order");
2916 * pspp_sheet_view_column_get_sort_order:
2917 * @tree_column: a #PsppSheetViewColumn
2919 * Gets the value set by pspp_sheet_view_column_set_sort_order().
2921 * Return value: the sort order the sort indicator is indicating
2924 pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column)
2926 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2928 return tree_column->sort_order;
2932 * pspp_sheet_view_column_cell_set_cell_data:
2933 * @tree_column: A #PsppSheetViewColumn.
2934 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2935 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2937 * Sets the cell renderer based on the @tree_model and @iter. That is, for
2938 * every attribute mapping in @tree_column, it will get a value from the set
2939 * column on the @iter, and use that value to set the attribute on the cell
2940 * renderer. This is used primarily by the #PsppSheetView.
2943 pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
2944 GtkTreeModel *tree_model,
2948 GValue value = { 0, };
2951 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2953 if (tree_model == NULL)
2956 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2958 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
2959 GObject *cell = (GObject *) info->cell;
2961 list = info->attributes;
2963 g_object_freeze_notify (cell);
2965 while (list && list->next)
2967 gtk_tree_model_get_value (tree_model, iter,
2968 GPOINTER_TO_INT (list->next->data),
2970 g_object_set_property (cell, (gchar *) list->data, &value);
2971 g_value_unset (&value);
2972 list = list->next->next;
2976 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2977 g_object_thaw_notify (G_OBJECT (info->cell));
2983 * pspp_sheet_view_column_cell_get_size:
2984 * @tree_column: A #PsppSheetViewColumn.
2985 * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
2986 * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
2987 * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
2988 * @width: (allow-none): location to return width needed to render a cell, or %NULL
2989 * @height: (allow-none): location to return height needed to render a cell, or %NULL
2991 * Obtains the width and height needed to render the column. This is used
2992 * primarily by the #PsppSheetView.
2995 pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
2996 const GdkRectangle *cell_area,
3003 gboolean first_cell = TRUE;
3004 gint focus_line_width;
3006 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3013 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
3015 for (list = tree_column->cell_list; list; list = list->next)
3017 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3019 gint new_height = 0;
3021 g_object_get (info->cell, "visible", &visible, NULL);
3023 if (visible == FALSE)
3026 if (first_cell == FALSE && width)
3027 *width += tree_column->spacing;
3029 gtk_cell_renderer_get_padding (info->cell, x_offset, y_offset);
3030 gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
3033 gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
3038 * height = MAX (*height, new_height + focus_line_width * 2);
3039 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
3041 * width += info->requested_width;
3046 /* rendering, event handling and rendering focus are somewhat complicated, and
3047 * quite a bit of code. Rather than duplicate them, we put them together to
3048 * keep the code in one place.
3050 * To better understand what's going on, check out
3051 * docs/tree-column-sizing.png
3060 pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn *tree_column,
3062 const GdkRectangle *background_area,
3063 const GdkRectangle *cell_area,
3066 GdkRectangle *focus_rectangle, /* FOCUS */
3067 GtkCellEditable **editable_widget, /* EVENT */
3068 GdkEvent *event, /* EVENT */
3069 gchar *path_string) /* EVENT */
3072 GdkRectangle real_cell_area;
3073 GdkRectangle real_background_area;
3075 gint expand_cell_count = 0;
3076 gint full_requested_width = 0;
3078 gint min_x, min_y, max_x, max_y;
3079 gint focus_line_width;
3081 gint horizontal_separator;
3082 gboolean cursor_row = FALSE;
3083 gboolean first_cell = TRUE;
3085 /* If we have rtl text, we need to transform our areas */
3086 GdkRectangle rtl_cell_area;
3087 GdkRectangle rtl_background_area;
3094 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
3095 special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
3097 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
3099 PsppSheetViewColumnCellInfo *info = NULL;
3100 gboolean found_has_focus = FALSE;
3102 /* one should have focus */
3103 for (list = tree_column->cell_list; list; list = list->next)
3106 if (info && info->has_focus)
3108 found_has_focus = TRUE;
3113 if (!found_has_focus)
3115 /* give the first one focus */
3116 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3117 info->has_focus = TRUE;
3121 cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
3123 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3124 "focus-line-width", &focus_line_width,
3125 "horizontal-separator", &horizontal_separator,
3128 real_cell_area = *cell_area;
3129 real_background_area = *background_area;
3132 real_cell_area.x += focus_line_width;
3133 real_cell_area.y += focus_line_width;
3134 real_cell_area.height -= 2 * focus_line_width;
3137 depth = real_background_area.width - real_cell_area.width;
3139 depth = real_cell_area.x - real_background_area.x;
3141 /* Find out how much extra space we have to allocate */
3142 for (list = tree_column->cell_list; list; list = list->next)
3144 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
3146 if (! gtk_cell_renderer_get_visible (info->cell))
3149 if (info->expand == TRUE)
3150 expand_cell_count ++;
3151 full_requested_width += info->requested_width;
3154 full_requested_width += tree_column->spacing;
3159 extra_space = cell_area->width - full_requested_width;
3160 if (extra_space < 0)
3162 else if (extra_space > 0 && expand_cell_count > 0)
3163 extra_space /= expand_cell_count;
3165 /* iterate list for GTK_PACK_START cells */
3166 for (list = tree_column->cell_list; list; list = list->next)
3168 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3170 if (info->pack == GTK_PACK_END)
3173 if (! gtk_cell_renderer_get_visible (info->cell))
3176 if ((info->has_focus || special_cells == 1) && cursor_row)
3177 flags |= GTK_CELL_RENDERER_FOCUSED;
3179 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3181 info->real_width = info->requested_width + (info->expand?extra_space:0);
3183 /* We constrain ourselves to only the width available */
3184 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3186 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3189 if (real_cell_area.x > cell_area->x + cell_area->width)
3192 real_cell_area.width = info->real_width;
3193 real_cell_area.width -= 2 * focus_line_width;
3197 real_background_area.width = info->real_width + depth;
3201 /* fill the rest of background for the last cell */
3202 real_background_area.width = background_area->x + background_area->width - real_background_area.x;
3205 rtl_cell_area = real_cell_area;
3206 rtl_background_area = real_background_area;
3210 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3211 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3215 if (action == CELL_ACTION_RENDER)
3217 gtk_cell_renderer_render (info->cell,
3219 tree_column->tree_view,
3220 &rtl_background_area,
3225 else if (action == CELL_ACTION_FOCUS)
3227 gint x_offset, y_offset, width, height;
3229 gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
3232 gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
3236 gtk_cell_renderer_get_padding (info->cell,
3237 &x_offset, &y_offset);
3239 if (special_cells > 1)
3241 if (info->has_focus)
3243 min_x = rtl_cell_area.x + x_offset;
3244 max_x = min_x + width;
3245 min_y = rtl_cell_area.y + y_offset;
3246 max_y = min_y + height;
3251 if (min_x > (rtl_cell_area.x + x_offset))
3252 min_x = rtl_cell_area.x + x_offset;
3253 if (max_x < rtl_cell_area.x + x_offset + width)
3254 max_x = rtl_cell_area.x + x_offset + width;
3255 if (min_y > (rtl_cell_area.y + y_offset))
3256 min_y = rtl_cell_area.y + y_offset;
3257 if (max_y < rtl_cell_area.y + y_offset + height)
3258 max_y = rtl_cell_area.y + y_offset + height;
3262 else if (action == CELL_ACTION_EVENT)
3264 gboolean try_event = FALSE;
3268 if (special_cells == 1)
3270 /* only 1 activatable cell -> whole column can activate */
3271 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3272 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3275 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3276 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3277 /* only activate cell if the user clicked on an individual
3282 else if (special_cells > 1 && info->has_focus)
3284 else if (special_cells == 1)
3289 gboolean visible, mode;
3291 g_object_get (info->cell,
3292 "visible", &visible,
3295 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3297 if (gtk_cell_renderer_activate (info->cell,
3299 tree_column->tree_view,
3301 &rtl_background_area,
3305 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3309 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3312 gtk_cell_renderer_start_editing (info->cell,
3314 tree_column->tree_view,
3316 &rtl_background_area,
3320 if (*editable_widget != NULL)
3322 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3323 info->in_editing_mode = TRUE;
3324 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3326 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3334 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3336 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3337 real_background_area.x += real_background_area.width + tree_column->spacing;
3339 /* Only needed for first cell */
3343 /* iterate list for PACK_END cells */
3344 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
3346 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3348 if (info->pack == GTK_PACK_START)
3351 if (! gtk_cell_renderer_get_visible (info->cell))
3354 if ((info->has_focus || special_cells == 1) && cursor_row)
3355 flags |= GTK_CELL_RENDERER_FOCUSED;
3357 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3359 info->real_width = info->requested_width + (info->expand?extra_space:0);
3361 /* We constrain ourselves to only the width available */
3362 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
3364 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
3367 if (real_cell_area.x > cell_area->x + cell_area->width)
3370 real_cell_area.width = info->real_width;
3371 real_cell_area.width -= 2 * focus_line_width;
3372 real_background_area.width = info->real_width + depth;
3374 rtl_cell_area = real_cell_area;
3375 rtl_background_area = real_background_area;
3378 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3379 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3383 if (action == CELL_ACTION_RENDER)
3385 gtk_cell_renderer_render (info->cell,
3387 tree_column->tree_view,
3388 &rtl_background_area,
3393 else if (action == CELL_ACTION_FOCUS)
3395 gint x_offset, y_offset, width, height;
3397 gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
3400 gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
3404 gtk_cell_renderer_get_padding (info->cell,
3405 &x_offset, &y_offset);
3407 if (special_cells > 1)
3409 if (info->has_focus)
3411 min_x = rtl_cell_area.x + x_offset;
3412 max_x = min_x + width;
3413 min_y = rtl_cell_area.y + y_offset;
3414 max_y = min_y + height;
3419 if (min_x > (rtl_cell_area.x + x_offset))
3420 min_x = rtl_cell_area.x + x_offset;
3421 if (max_x < rtl_cell_area.x + x_offset + width)
3422 max_x = rtl_cell_area.x + x_offset + width;
3423 if (min_y > (rtl_cell_area.y + y_offset))
3424 min_y = rtl_cell_area.y + y_offset;
3425 if (max_y < rtl_cell_area.y + y_offset + height)
3426 max_y = rtl_cell_area.y + y_offset + height;
3430 else if (action == CELL_ACTION_EVENT)
3432 gboolean try_event = FALSE;
3436 if (special_cells == 1)
3438 /* only 1 activatable cell -> whole column can activate */
3439 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3440 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3443 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3444 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3445 /* only activate cell if the user clicked on an individual
3450 else if (special_cells > 1 && info->has_focus)
3452 else if (special_cells == 1)
3457 gboolean visible, mode;
3459 g_object_get (info->cell,
3460 "visible", &visible,
3463 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3465 if (gtk_cell_renderer_activate (info->cell,
3467 tree_column->tree_view,
3469 &rtl_background_area,
3473 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3477 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3480 gtk_cell_renderer_start_editing (info->cell,
3482 tree_column->tree_view,
3484 &rtl_background_area,
3488 if (*editable_widget != NULL)
3490 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3491 info->in_editing_mode = TRUE;
3492 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3494 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3501 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3503 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3504 real_background_area.x += (real_background_area.width + tree_column->spacing);
3506 /* Only needed for first cell */
3510 /* fill focus_rectangle when required */
3511 if (action == CELL_ACTION_FOCUS)
3513 if (min_x >= max_x || min_y >= max_y)
3515 *focus_rectangle = *cell_area;
3516 /* don't change the focus_rectangle, just draw it nicely inside
3521 focus_rectangle->x = min_x - focus_line_width;
3522 focus_rectangle->y = min_y - focus_line_width;
3523 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
3524 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
3532 * pspp_sheet_view_column_cell_render:
3533 * @tree_column: A #PsppSheetViewColumn.
3534 * @window: a #GdkDrawable to draw to
3535 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
3536 * @cell_area: area normally rendered by a cell renderer
3537 * @flags: flags that affect rendering
3539 * Renders the cell contained by #tree_column. This is used primarily by the
3543 _pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
3545 const GdkRectangle *background_area,
3546 const GdkRectangle *cell_area,
3549 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3550 g_return_if_fail (background_area != NULL);
3551 g_return_if_fail (cell_area != NULL);
3553 pspp_sheet_view_column_cell_process_action (tree_column,
3559 NULL, NULL, NULL, NULL);
3563 _pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
3564 GtkCellEditable **editable_widget,
3567 const GdkRectangle *background_area,
3568 const GdkRectangle *cell_area,
3571 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3573 return pspp_sheet_view_column_cell_process_action (tree_column,
3586 _pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
3587 const GdkRectangle *background_area,
3588 const GdkRectangle *cell_area,
3589 GdkRectangle *focus_area)
3591 pspp_sheet_view_column_cell_process_action (tree_column,
3602 /* cell list manipulation */
3604 pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
3606 GList *list = tree_column->cell_list;
3608 /* first GTK_PACK_START cell we find */
3609 for ( ; list; list = list->next)
3611 PsppSheetViewColumnCellInfo *info = list->data;
3612 if (info->pack == GTK_PACK_START)
3616 /* hmm, else the *last* GTK_PACK_END cell */
3617 list = g_list_last (tree_column->cell_list);
3619 for ( ; list; list = list->prev)
3621 PsppSheetViewColumnCellInfo *info = list->data;
3622 if (info->pack == GTK_PACK_END)
3630 pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
3632 GList *list = tree_column->cell_list;
3634 /* *first* GTK_PACK_END cell we find */
3635 for ( ; list ; list = list->next)
3637 PsppSheetViewColumnCellInfo *info = list->data;
3638 if (info->pack == GTK_PACK_END)
3642 /* hmm, else the last GTK_PACK_START cell */
3643 list = g_list_last (tree_column->cell_list);
3645 for ( ; list; list = list->prev)
3647 PsppSheetViewColumnCellInfo *info = list->data;
3648 if (info->pack == GTK_PACK_START)
3657 pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
3661 PsppSheetViewColumnCellInfo *info = current->data;
3663 if (info->pack == GTK_PACK_START)
3665 for (list = current->next; list; list = list->next)
3667 PsppSheetViewColumnCellInfo *inf = list->data;
3668 if (inf->pack == GTK_PACK_START)
3672 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
3673 list = g_list_last (tree_column->cell_list);
3674 for (; list; list = list->prev)
3676 PsppSheetViewColumnCellInfo *inf = list->data;
3677 if (inf->pack == GTK_PACK_END)
3682 for (list = current->prev; list; list = list->prev)
3684 PsppSheetViewColumnCellInfo *inf = list->data;
3685 if (inf->pack == GTK_PACK_END)
3693 pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
3697 PsppSheetViewColumnCellInfo *info = current->data;
3699 if (info->pack == GTK_PACK_END)
3701 for (list = current->next; list; list = list->next)
3703 PsppSheetViewColumnCellInfo *inf = list->data;
3704 if (inf->pack == GTK_PACK_END)
3708 /* out of GTK_PACK_END, get last GTK_PACK_START one */
3709 list = g_list_last (tree_column->cell_list);
3710 for ( ; list; list = list->prev)
3712 PsppSheetViewColumnCellInfo *inf = list->data;
3713 if (inf->pack == GTK_PACK_START)
3718 for (list = current->prev; list; list = list->prev)
3720 PsppSheetViewColumnCellInfo *inf = list->data;
3721 if (inf->pack == GTK_PACK_START)
3729 _pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
3737 count = _pspp_sheet_view_column_count_special_cells (tree_column);
3738 rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
3740 /* if we are the current focus column and have multiple editable cells,
3741 * try to select the next one, else move the focus to the next column
3743 if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
3748 GList *list = tree_column->cell_list;
3749 PsppSheetViewColumnCellInfo *info = NULL;
3751 /* find current focussed cell */
3752 for ( ; list; list = list->next)
3755 if (info->has_focus)
3759 /* not a focussed cell in the focus column? */
3760 if (!list || !info || !info->has_focus)
3765 prev = pspp_sheet_view_column_cell_next (tree_column, list);
3766 next = pspp_sheet_view_column_cell_prev (tree_column, list);
3770 next = pspp_sheet_view_column_cell_next (tree_column, list);
3771 prev = pspp_sheet_view_column_cell_prev (tree_column, list);
3774 info->has_focus = FALSE;
3775 if (direction > 0 && next)
3778 info->has_focus = TRUE;
3781 else if (direction > 0 && !next && !right)
3783 /* keep focus on last cell */
3785 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3787 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3789 info->has_focus = TRUE;
3792 else if (direction < 0 && prev)
3795 info->has_focus = TRUE;
3798 else if (direction < 0 && !prev && !left)
3800 /* keep focus on first cell */
3802 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3804 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3806 info->has_focus = TRUE;
3813 /* we get focus, if we have multiple editable cells, give the correct one
3818 GList *list = tree_column->cell_list;
3820 /* clear focus first */
3821 for ( ; list ; list = list->next)
3823 PsppSheetViewColumnCellInfo *info = list->data;
3824 if (info->has_focus)
3825 info->has_focus = FALSE;
3832 list = pspp_sheet_view_column_cell_last (tree_column);
3833 else if (direction < 0)
3834 list = pspp_sheet_view_column_cell_first (tree_column);
3839 list = pspp_sheet_view_column_cell_first (tree_column);
3840 else if (direction < 0)
3841 list = pspp_sheet_view_column_cell_last (tree_column);
3845 ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
3852 _pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
3854 const GdkRectangle *background_area,
3855 const GdkRectangle *cell_area,
3858 gint focus_line_width;
3859 GtkStateType cell_state;
3861 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3862 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3863 "focus-line-width", &focus_line_width, NULL);
3864 if (tree_column->editable_widget)
3866 /* This function is only called on the editable row when editing.
3869 gtk_paint_focus (tree_column->tree_view->style,
3871 gtk_widget_get_state (tree_column->tree_view),
3873 tree_column->tree_view,
3875 cell_area->x - focus_line_width,
3876 cell_area->y - focus_line_width,
3877 cell_area->width + 2 * focus_line_width,
3878 cell_area->height + 2 * focus_line_width);
3883 GdkRectangle focus_rectangle;
3884 pspp_sheet_view_column_cell_process_action (tree_column,
3893 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3894 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3895 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3897 gtk_paint_focus (gtk_widget_get_style (GTK_WIDGET (tree_column->tree_view)),
3900 tree_column->tree_view,
3904 focus_rectangle.width,
3905 focus_rectangle.height);
3910 * pspp_sheet_view_column_cell_is_visible:
3911 * @tree_column: A #PsppSheetViewColumn
3913 * Returns %TRUE if any of the cells packed into the @tree_column are visible.
3914 * For this to be meaningful, you must first initialize the cells with
3915 * pspp_sheet_view_column_cell_set_cell_data()
3917 * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
3920 pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
3924 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3926 for (list = tree_column->cell_list; list; list = list->next)
3928 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3930 if (gtk_cell_renderer_get_visible (info->cell))
3938 * pspp_sheet_view_column_focus_cell:
3939 * @tree_column: A #PsppSheetViewColumn
3940 * @cell: A #GtkCellRenderer
3942 * Sets the current keyboard focus to be at @cell, if the column contains
3943 * 2 or more editable and activatable cells.
3948 pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
3949 GtkCellRenderer *cell)
3952 gboolean found_cell = FALSE;
3954 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3955 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3957 if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
3960 for (list = tree_column->cell_list; list; list = list->next)
3962 PsppSheetViewColumnCellInfo *info = list->data;
3964 if (info->cell == cell)
3966 info->has_focus = TRUE;
3974 for (list = tree_column->cell_list; list; list = list->next)
3976 PsppSheetViewColumnCellInfo *info = list->data;
3978 if (info->cell != cell)
3979 info->has_focus = FALSE;
3982 /* FIXME: redraw? */
3987 _pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
3991 for (list = tree_column->cell_list; list; list = list->next)
3993 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3995 info->requested_width = 0;
3997 tree_column->dirty = TRUE;
3998 tree_column->requested_width = -1;
3999 tree_column->width = 0;
4001 if (tree_column->tree_view &&
4002 PSPP_SHEET_VIEW (tree_column->tree_view)->priv->resized &&
4003 gtk_widget_get_realized (tree_column->tree_view))
4005 PSPP_SHEET_VIEW (tree_column->tree_view)->priv->resized = FALSE;
4006 _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
4007 gtk_widget_queue_resize (tree_column->tree_view);
4012 _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
4013 GtkCellEditable *cell_editable)
4015 g_return_if_fail (tree_column->editable_widget == NULL);
4017 tree_column->editable_widget = cell_editable;
4021 _pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
4025 g_return_if_fail (tree_column->editable_widget != NULL);
4027 tree_column->editable_widget = NULL;
4028 for (list = tree_column->cell_list; list; list = list->next)
4029 ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
4033 _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
4034 GtkCellRenderer *cell,
4039 PsppSheetViewColumnCellInfo *info;
4045 list = pspp_sheet_view_column_cell_first (column);
4049 info = (PsppSheetViewColumnCellInfo *)list->data;
4051 list = pspp_sheet_view_column_cell_next (column, list);
4053 if (info->cell == cell)
4056 if (gtk_cell_renderer_get_visible (info->cell))
4057 l += info->real_width + column->spacing;
4062 info = (PsppSheetViewColumnCellInfo *)list->data;
4064 list = pspp_sheet_view_column_cell_next (column, list);
4066 if (gtk_cell_renderer_get_visible (info->cell))
4067 r += info->real_width + column->spacing;
4070 rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
4072 *left = rtl ? r : l;
4075 *right = rtl ? l : r;
4079 * pspp_sheet_view_column_cell_get_position:
4080 * @tree_column: a #PsppSheetViewColumn
4081 * @cell_renderer: a #GtkCellRenderer
4082 * @start_pos: return location for the horizontal position of @cell within
4083 * @tree_column, may be %NULL
4084 * @width: return location for the width of @cell, may be %NULL
4086 * Obtains the horizontal position and size of a cell in a column. If the
4087 * cell is not found in the column, @start_pos and @width are not changed and
4088 * %FALSE is returned.
4090 * Return value: %TRUE if @cell belongs to @tree_column.
4093 pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
4094 GtkCellRenderer *cell_renderer,
4100 gboolean found_cell = FALSE;
4101 PsppSheetViewColumnCellInfo *cellinfo = NULL;
4103 list = pspp_sheet_view_column_cell_first (tree_column);
4104 for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
4106 cellinfo = list->data;
4107 if (cellinfo->cell == cell_renderer)
4113 if (gtk_cell_renderer_get_visible (cellinfo->cell))
4114 current_x += cellinfo->real_width;
4120 *start_pos = current_x;
4122 *width = cellinfo->real_width;
4129 * pspp_sheet_view_column_queue_resize:
4130 * @tree_column: A #PsppSheetViewColumn
4132 * Flags the column, and the cell renderers added to this column, to have
4133 * their sizes renegotiated.
4138 pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
4140 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
4142 if (tree_column->tree_view)
4143 _pspp_sheet_view_column_cell_set_dirty (tree_column);
4147 * pspp_sheet_view_column_get_tree_view:
4148 * @tree_column: A #PsppSheetViewColumn
4150 * Returns the #PsppSheetView wherein @tree_column has been inserted. If
4151 * @column is currently not inserted in any tree view, %NULL is
4154 * Return value: The tree view wherein @column has been inserted if any,
4160 pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
4162 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
4164 return tree_column->tree_view;
4168 GtkCellLayout *cell_layout;
4169 GtkCellRenderer *renderer;
4171 } AttributesSubParserData;
4174 attributes_start_element (GMarkupParseContext *context,
4175 const gchar *element_name,
4176 const gchar **names,
4177 const gchar **values,
4181 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4184 if (strcmp (element_name, "attribute") == 0)
4186 for (i = 0; names[i]; i++)
4187 if (strcmp (names[i], "name") == 0)
4188 parser_data->attr_name = g_strdup (values[i]);
4190 else if (strcmp (element_name, "attributes") == 0)
4193 g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
4197 attributes_text_element (GMarkupParseContext *context,
4203 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
4208 if (!parser_data->attr_name)
4212 string = g_strndup (text, text_len);
4213 l = strtol (string, &endptr, 0);
4214 if (errno || endptr == string)
4218 GTK_BUILDER_ERROR_INVALID_VALUE,
4219 "Could not parse integer `%s'",
4226 gtk_cell_layout_add_attribute (parser_data->cell_layout,
4227 parser_data->renderer,
4228 parser_data->attr_name, l);
4229 g_free (parser_data->attr_name);
4230 parser_data->attr_name = NULL;
4233 static const GMarkupParser attributes_parser =
4235 attributes_start_element,
4237 attributes_text_element,
4241 _cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
4242 GtkBuilder *builder,
4244 const gchar *tagname,
4245 GMarkupParser *parser,
4248 AttributesSubParserData *parser_data;
4253 if (strcmp (tagname, "attributes") == 0)
4255 parser_data = g_slice_new0 (AttributesSubParserData);
4256 parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
4257 parser_data->renderer = GTK_CELL_RENDERER (child);
4258 parser_data->attr_name = NULL;
4260 *parser = attributes_parser;
4261 *data = parser_data;
4269 _cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
4270 GtkBuilder *builder,
4272 const gchar *tagname,
4275 AttributesSubParserData *parser_data;
4277 parser_data = (AttributesSubParserData*)data;
4278 g_assert (!parser_data->attr_name);
4279 g_slice_free (AttributesSubParserData, parser_data);
4283 _cell_layout_buildable_add_child (GtkBuildable *buildable,
4284 GtkBuilder *builder,
4288 GtkCellLayoutIface *iface;
4290 g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
4291 g_return_if_fail (GTK_IS_CELL_RENDERER (child));
4293 iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
4294 g_return_if_fail (iface->pack_start != NULL);
4295 iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);
4299 pspp_sheet_view_column_size_request (PsppSheetViewColumn *tree_column,
4300 GtkRequisition *request)
4302 GtkWidget *base = GTK_WIDGET (tree_column->tree_view);
4303 GtkRequisition label_req;
4304 GtkRequisition align_req;
4305 GtkRequisition arrow_req;
4306 GtkRequisition hbox_req;
4307 GtkStyle **button_style;
4309 if (tree_column->button)
4311 gtk_widget_get_preferred_size (tree_column->button, NULL, request);
4315 facade_label_get_size_request (0, 0, base, tree_column->title, &label_req);
4316 facade_alignment_get_size_request (0, 0, 0, 0, 0, &label_req, &align_req);
4317 facade_arrow_get_size_request (0, 0, &arrow_req);
4319 facade_hbox_get_base_size_request (0, 2, 2, &hbox_req);
4320 facade_hbox_add_child_size_request (0, &arrow_req, 0, &hbox_req);
4321 facade_hbox_add_child_size_request (0, &align_req, 0, &hbox_req);
4323 button_style = &PSPP_SHEET_VIEW (tree_column->tree_view)->priv->button_style;
4324 if (*button_style == NULL)
4326 *button_style = facade_get_style (base, GTK_TYPE_BUTTON, 0);
4327 g_object_ref (*button_style);
4329 facade_button_get_size_request (0, base, *button_style, &hbox_req, request);
4333 pspp_sheet_view_column_size_allocate (PsppSheetViewColumn *tree_column,
4334 GtkAllocation *allocation)
4336 tree_column->allocation = *allocation;
4337 if (tree_column->button)
4338 gtk_widget_size_allocate (tree_column->button, allocation);
4342 pspp_sheet_view_column_can_focus (PsppSheetViewColumn *tree_column)
4344 return tree_column->reorderable || tree_column->clickable;