1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2011, 2012 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* gtktreeviewcolumn.c
18 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Library General Public
22 * License as published by the Free Software Foundation; either
23 * version 2 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Library General Public License for more details.
30 * You should have received a copy of the GNU Library General Public
31 * License along with this library; if not, write to the
32 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
33 * Boston, MA 02111-1307, USA.
38 #include "ui/gui/pspp-sheet-private.h"
45 #include "ui/gui/psppire-marshal.h"
47 #define P_(STRING) STRING
48 #define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
49 #define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
79 typedef struct _PsppSheetViewColumnCellInfo PsppSheetViewColumnCellInfo;
80 struct _PsppSheetViewColumnCellInfo
82 GtkCellRenderer *cell;
84 PsppSheetCellDataFunc func;
86 GDestroyNotify destroy;
92 guint in_editing_mode : 1;
96 static void pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface);
99 static void pspp_sheet_view_column_set_property (GObject *object,
103 static void pspp_sheet_view_column_get_property (GObject *object,
107 static void pspp_sheet_view_column_finalize (GObject *object);
109 /* GtkCellLayout implementation */
110 static void pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
111 GtkCellRenderer *cell,
113 static void pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
114 GtkCellRenderer *cell,
116 static void pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout);
117 static void pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
118 GtkCellRenderer *cell,
119 const gchar *attribute,
121 static void pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
122 GtkCellRenderer *cell,
123 GtkCellLayoutDataFunc func,
125 GDestroyNotify destroy);
126 static void pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
127 GtkCellRenderer *cell);
128 static void pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
129 GtkCellRenderer *cell,
131 static GList *pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
133 /* Button handling code */
134 static void pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column);
135 static void pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
137 /* Button signal handlers */
138 static gint pspp_sheet_view_column_button_event (GtkWidget *widget,
141 static void pspp_sheet_view_column_button_clicked (GtkWidget *widget,
143 static gboolean pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
144 gboolean group_cycling,
147 /* Property handlers */
148 static void pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
149 PsppSheetViewColumn *tree_column);
151 /* Internal functions */
152 static void pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
154 static void pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column);
155 static void pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
156 GtkCellRenderer *cell_renderer,
158 static PsppSheetViewColumnCellInfo *pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
159 GtkCellRenderer *cell_renderer);
161 /* cell list manipulation */
162 static GList *pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column);
163 static GList *pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column);
164 static GList *pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
166 static GList *pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
168 static void pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
169 PsppSheetViewColumnCellInfo *info);
170 /* GtkBuildable implementation */
171 static void pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface);
173 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
175 G_DEFINE_TYPE_WITH_CODE (PsppSheetViewColumn, pspp_sheet_view_column, GTK_TYPE_OBJECT,
176 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
177 pspp_sheet_view_column_cell_layout_init)
178 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
179 pspp_sheet_view_column_buildable_init))
183 pspp_sheet_view_column_class_init (PsppSheetViewColumnClass *class)
185 GObjectClass *object_class;
187 object_class = (GObjectClass*) class;
189 class->clicked = NULL;
191 object_class->finalize = pspp_sheet_view_column_finalize;
192 object_class->set_property = pspp_sheet_view_column_set_property;
193 object_class->get_property = pspp_sheet_view_column_get_property;
195 tree_column_signals[CLICKED] =
196 g_signal_new ("clicked",
197 G_OBJECT_CLASS_TYPE (object_class),
199 G_STRUCT_OFFSET (PsppSheetViewColumnClass, clicked),
201 g_cclosure_marshal_VOID__VOID,
204 tree_column_signals[QUERY_TOOLTIP] =
205 g_signal_new ("query-tooltip",
206 G_OBJECT_CLASS_TYPE (object_class),
209 g_signal_accumulator_true_handled, NULL,
210 psppire_marshal_BOOLEAN__OBJECT,
214 g_object_class_install_property (object_class,
216 g_param_spec_boolean ("visible",
218 P_("Whether to display the column"),
220 GTK_PARAM_READWRITE));
222 g_object_class_install_property (object_class,
224 g_param_spec_boolean ("resizable",
226 P_("Column is user-resizable"),
228 GTK_PARAM_READWRITE));
230 g_object_class_install_property (object_class,
232 g_param_spec_int ("width",
234 P_("Current width of the column"),
238 GTK_PARAM_READABLE));
239 g_object_class_install_property (object_class,
241 g_param_spec_int ("spacing",
243 P_("Space which is inserted between cells"),
247 GTK_PARAM_READWRITE));
249 g_object_class_install_property (object_class,
251 g_param_spec_int ("fixed-width",
253 P_("Current fixed width of the column"),
257 GTK_PARAM_READWRITE));
259 g_object_class_install_property (object_class,
261 g_param_spec_int ("min-width",
263 P_("Minimum allowed width of the column"),
267 GTK_PARAM_READWRITE));
269 g_object_class_install_property (object_class,
271 g_param_spec_int ("max-width",
273 P_("Maximum allowed width of the column"),
277 GTK_PARAM_READWRITE));
279 g_object_class_install_property (object_class,
281 g_param_spec_string ("title",
283 P_("Title to appear in column header"),
285 GTK_PARAM_READWRITE));
287 g_object_class_install_property (object_class,
289 g_param_spec_boolean ("expand",
291 P_("Column gets share of extra width allocated to the widget"),
293 GTK_PARAM_READWRITE));
295 g_object_class_install_property (object_class,
297 g_param_spec_boolean ("clickable",
299 P_("Whether the header can be clicked"),
301 GTK_PARAM_READWRITE));
304 g_object_class_install_property (object_class,
306 g_param_spec_object ("widget",
308 P_("Widget to put in column header button instead of column title"),
310 GTK_PARAM_READWRITE));
312 g_object_class_install_property (object_class,
314 g_param_spec_float ("alignment",
316 P_("X Alignment of the column header text or widget"),
320 GTK_PARAM_READWRITE));
322 g_object_class_install_property (object_class,
324 g_param_spec_boolean ("reorderable",
326 P_("Whether the column can be reordered around the headers"),
328 GTK_PARAM_READWRITE));
330 g_object_class_install_property (object_class,
332 g_param_spec_boolean ("sort-indicator",
333 P_("Sort indicator"),
334 P_("Whether to show a sort indicator"),
336 GTK_PARAM_READWRITE));
338 g_object_class_install_property (object_class,
340 g_param_spec_enum ("sort-order",
342 P_("Sort direction the sort indicator should indicate"),
345 GTK_PARAM_READWRITE));
348 * PsppSheetViewColumn:sort-column-id:
350 * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
351 * clickable. Set to %-1 to make the column unsortable.
355 g_object_class_install_property (object_class,
357 g_param_spec_int ("sort-column-id",
358 P_("Sort column ID"),
359 P_("Logical sort column ID this column sorts on when selected for sorting"),
363 GTK_PARAM_READWRITE));
367 pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface)
369 iface->add_child = _gtk_cell_layout_buildable_add_child;
370 iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
371 iface->custom_tag_end = _gtk_cell_layout_buildable_custom_tag_end;
375 pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface)
377 iface->pack_start = pspp_sheet_view_column_cell_layout_pack_start;
378 iface->pack_end = pspp_sheet_view_column_cell_layout_pack_end;
379 iface->clear = pspp_sheet_view_column_cell_layout_clear;
380 iface->add_attribute = pspp_sheet_view_column_cell_layout_add_attribute;
381 iface->set_cell_data_func = pspp_sheet_view_column_cell_layout_set_cell_data_func;
382 iface->clear_attributes = pspp_sheet_view_column_cell_layout_clear_attributes;
383 iface->reorder = pspp_sheet_view_column_cell_layout_reorder;
384 iface->get_cells = pspp_sheet_view_column_cell_layout_get_cells;
388 pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column)
390 tree_column->button = NULL;
391 tree_column->xalign = 0.0;
392 tree_column->width = 0;
393 tree_column->spacing = 0;
394 tree_column->requested_width = -1;
395 tree_column->min_width = -1;
396 tree_column->max_width = -1;
397 tree_column->resized_width = 0;
398 tree_column->visible = TRUE;
399 tree_column->resizable = FALSE;
400 tree_column->expand = FALSE;
401 tree_column->clickable = FALSE;
402 tree_column->dirty = TRUE;
403 tree_column->sort_order = GTK_SORT_ASCENDING;
404 tree_column->show_sort_indicator = FALSE;
405 tree_column->property_changed_signal = 0;
406 tree_column->sort_clicked_signal = 0;
407 tree_column->sort_column_changed_signal = 0;
408 tree_column->sort_column_id = -1;
409 tree_column->reorderable = FALSE;
410 tree_column->maybe_reordered = FALSE;
411 tree_column->fixed_width = 1;
412 tree_column->use_resized_width = FALSE;
413 tree_column->title = g_strdup ("");
417 pspp_sheet_view_column_finalize (GObject *object)
419 PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
422 for (list = tree_column->cell_list; list; list = list->next)
424 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
428 GDestroyNotify d = info->destroy;
430 info->destroy = NULL;
433 pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
434 g_object_unref (info->cell);
438 g_free (tree_column->title);
439 g_list_free (tree_column->cell_list);
441 if (tree_column->child)
442 g_object_unref (tree_column->child);
444 G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
448 pspp_sheet_view_column_set_property (GObject *object,
453 PsppSheetViewColumn *tree_column;
455 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
460 pspp_sheet_view_column_set_visible (tree_column,
461 g_value_get_boolean (value));
465 pspp_sheet_view_column_set_resizable (tree_column,
466 g_value_get_boolean (value));
469 case PROP_FIXED_WIDTH:
470 pspp_sheet_view_column_set_fixed_width (tree_column,
471 g_value_get_int (value));
475 pspp_sheet_view_column_set_min_width (tree_column,
476 g_value_get_int (value));
480 pspp_sheet_view_column_set_max_width (tree_column,
481 g_value_get_int (value));
485 pspp_sheet_view_column_set_spacing (tree_column,
486 g_value_get_int (value));
490 pspp_sheet_view_column_set_title (tree_column,
491 g_value_get_string (value));
495 pspp_sheet_view_column_set_expand (tree_column,
496 g_value_get_boolean (value));
500 pspp_sheet_view_column_set_clickable (tree_column,
501 g_value_get_boolean (value));
505 pspp_sheet_view_column_set_widget (tree_column,
506 (GtkWidget*) g_value_get_object (value));
510 pspp_sheet_view_column_set_alignment (tree_column,
511 g_value_get_float (value));
514 case PROP_REORDERABLE:
515 pspp_sheet_view_column_set_reorderable (tree_column,
516 g_value_get_boolean (value));
519 case PROP_SORT_INDICATOR:
520 pspp_sheet_view_column_set_sort_indicator (tree_column,
521 g_value_get_boolean (value));
524 case PROP_SORT_ORDER:
525 pspp_sheet_view_column_set_sort_order (tree_column,
526 g_value_get_enum (value));
529 case PROP_SORT_COLUMN_ID:
530 pspp_sheet_view_column_set_sort_column_id (tree_column,
531 g_value_get_int (value));
535 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
541 pspp_sheet_view_column_get_property (GObject *object,
546 PsppSheetViewColumn *tree_column;
548 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
553 g_value_set_boolean (value,
554 pspp_sheet_view_column_get_visible (tree_column));
558 g_value_set_boolean (value,
559 pspp_sheet_view_column_get_resizable (tree_column));
563 g_value_set_int (value,
564 pspp_sheet_view_column_get_width (tree_column));
568 g_value_set_int (value,
569 pspp_sheet_view_column_get_spacing (tree_column));
572 case PROP_FIXED_WIDTH:
573 g_value_set_int (value,
574 pspp_sheet_view_column_get_fixed_width (tree_column));
578 g_value_set_int (value,
579 pspp_sheet_view_column_get_min_width (tree_column));
583 g_value_set_int (value,
584 pspp_sheet_view_column_get_max_width (tree_column));
588 g_value_set_string (value,
589 pspp_sheet_view_column_get_title (tree_column));
593 g_value_set_boolean (value,
594 pspp_sheet_view_column_get_expand (tree_column));
598 g_value_set_boolean (value,
599 pspp_sheet_view_column_get_clickable (tree_column));
603 g_value_set_object (value,
604 (GObject*) pspp_sheet_view_column_get_widget (tree_column));
608 g_value_set_float (value,
609 pspp_sheet_view_column_get_alignment (tree_column));
612 case PROP_REORDERABLE:
613 g_value_set_boolean (value,
614 pspp_sheet_view_column_get_reorderable (tree_column));
617 case PROP_SORT_INDICATOR:
618 g_value_set_boolean (value,
619 pspp_sheet_view_column_get_sort_indicator (tree_column));
622 case PROP_SORT_ORDER:
623 g_value_set_enum (value,
624 pspp_sheet_view_column_get_sort_order (tree_column));
627 case PROP_SORT_COLUMN_ID:
628 g_value_set_int (value,
629 pspp_sheet_view_column_get_sort_column_id (tree_column));
633 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
638 /* Implementation of GtkCellLayout interface
642 pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
643 GtkCellRenderer *cell,
646 PsppSheetViewColumn *column;
647 PsppSheetViewColumnCellInfo *cell_info;
649 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
650 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
651 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
653 g_object_ref_sink (cell);
655 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
656 cell_info->cell = cell;
657 cell_info->expand = expand ? TRUE : FALSE;
658 cell_info->pack = GTK_PACK_START;
659 cell_info->has_focus = 0;
660 cell_info->attributes = NULL;
662 column->cell_list = g_list_append (column->cell_list, cell_info);
666 pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
667 GtkCellRenderer *cell,
670 PsppSheetViewColumn *column;
671 PsppSheetViewColumnCellInfo *cell_info;
673 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
674 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
675 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
677 g_object_ref_sink (cell);
679 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
680 cell_info->cell = cell;
681 cell_info->expand = expand ? TRUE : FALSE;
682 cell_info->pack = GTK_PACK_END;
683 cell_info->has_focus = 0;
684 cell_info->attributes = NULL;
686 column->cell_list = g_list_append (column->cell_list, cell_info);
690 pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
692 PsppSheetViewColumn *column;
694 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
695 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
697 while (column->cell_list)
699 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
701 pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
702 g_object_unref (info->cell);
704 column->cell_list = g_list_delete_link (column->cell_list,
710 pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
711 GtkCellRenderer *cell,
712 const gchar *attribute,
715 PsppSheetViewColumn *tree_column;
716 PsppSheetViewColumnCellInfo *info;
718 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
719 tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
721 info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
722 g_return_if_fail (info != NULL);
724 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
725 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
727 if (tree_column->tree_view)
728 _pspp_sheet_view_column_cell_set_dirty (tree_column);
732 pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
733 GtkCellRenderer *cell,
734 GtkCellLayoutDataFunc func,
736 GDestroyNotify destroy)
738 PsppSheetViewColumn *column;
739 PsppSheetViewColumnCellInfo *info;
741 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
742 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
744 info = pspp_sheet_view_column_get_cell_info (column, cell);
745 g_return_if_fail (info != NULL);
749 GDestroyNotify d = info->destroy;
751 info->destroy = NULL;
755 info->func = (PsppSheetCellDataFunc)func;
756 info->func_data = func_data;
757 info->destroy = destroy;
759 if (column->tree_view)
760 _pspp_sheet_view_column_cell_set_dirty (column);
764 pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
765 GtkCellRenderer *cell_renderer)
767 PsppSheetViewColumn *column;
768 PsppSheetViewColumnCellInfo *info;
770 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
771 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
773 info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
775 pspp_sheet_view_column_clear_attributes_by_info (column, info);
779 pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
780 GtkCellRenderer *cell,
784 PsppSheetViewColumn *column;
785 PsppSheetViewColumnCellInfo *info;
787 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
788 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
790 info = pspp_sheet_view_column_get_cell_info (column, cell);
792 g_return_if_fail (info != NULL);
793 g_return_if_fail (position >= 0);
795 link = g_list_find (column->cell_list, info);
797 g_return_if_fail (link != NULL);
799 column->cell_list = g_list_delete_link (column->cell_list, link);
800 column->cell_list = g_list_insert (column->cell_list, info, position);
802 if (column->tree_view)
803 gtk_widget_queue_draw (column->tree_view);
807 pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
808 PsppSheetViewColumnCellInfo *info)
812 list = info->attributes;
814 while (list && list->next)
817 list = list->next->next;
819 g_slist_free (info->attributes);
820 info->attributes = NULL;
822 if (tree_column->tree_view)
823 _pspp_sheet_view_column_cell_set_dirty (tree_column);
827 on_query_tooltip (GtkWidget *widget,
830 gboolean keyboard_mode,
834 PsppSheetViewColumn *tree_column = user_data;
837 g_signal_emit (tree_column, tree_column_signals[QUERY_TOOLTIP], 0,
845 /* Button handling code
848 pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
850 PsppSheetView *tree_view;
854 tree_view = (PsppSheetView *) tree_column->tree_view;
856 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
857 g_return_if_fail (tree_column->button == NULL);
859 gtk_widget_push_composite_child ();
860 tree_column->button = gtk_button_new ();
861 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
862 gtk_widget_pop_composite_child ();
864 /* make sure we own a reference to it as well. */
865 if (tree_view->priv->header_window)
866 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
867 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
869 g_signal_connect (tree_column->button, "event",
870 G_CALLBACK (pspp_sheet_view_column_button_event),
872 g_signal_connect (tree_column->button, "clicked",
873 G_CALLBACK (pspp_sheet_view_column_button_clicked),
876 g_signal_connect (tree_column->button, "query-tooltip",
877 G_CALLBACK (on_query_tooltip), tree_column);
878 g_object_set (tree_column->button, "has-tooltip", TRUE, NULL);
880 tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
882 hbox = gtk_hbox_new (FALSE, 2);
883 tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
885 if (tree_column->child)
886 child = tree_column->child;
889 child = gtk_label_new (tree_column->title);
890 gtk_widget_show (child);
893 g_signal_connect (child, "mnemonic-activate",
894 G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
897 if (tree_column->xalign <= 0.5)
898 gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
900 gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
902 gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
904 gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
905 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
907 gtk_widget_show (hbox);
908 gtk_widget_show (tree_column->alignment);
909 pspp_sheet_view_column_update_button (tree_column);
913 pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
915 gint sort_column_id = -1;
917 GtkWidget *alignment;
919 GtkWidget *current_child;
920 GtkArrowType arrow_type = GTK_ARROW_NONE;
923 if (tree_column->tree_view)
924 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
928 /* Create a button if necessary */
929 if (tree_column->visible &&
930 tree_column->button == NULL &&
931 tree_column->tree_view &&
932 gtk_widget_get_realized (tree_column->tree_view))
933 pspp_sheet_view_column_create_button (tree_column);
935 if (! tree_column->button)
938 hbox = GTK_BIN (tree_column->button)->child;
939 alignment = tree_column->alignment;
940 arrow = tree_column->arrow;
941 current_child = GTK_BIN (alignment)->child;
943 /* Set up the actual button */
944 gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
947 if (tree_column->child)
949 if (current_child != tree_column->child)
951 gtk_container_remove (GTK_CONTAINER (alignment),
953 gtk_container_add (GTK_CONTAINER (alignment),
959 if (current_child == NULL)
961 current_child = gtk_label_new (NULL);
962 gtk_widget_show (current_child);
963 gtk_container_add (GTK_CONTAINER (alignment),
967 g_return_if_fail (GTK_IS_LABEL (current_child));
969 if (tree_column->title)
970 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
973 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
977 if (GTK_IS_TREE_SORTABLE (model))
978 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
982 if (tree_column->show_sort_indicator)
984 gboolean alternative;
986 g_object_get (gtk_widget_get_settings (tree_column->tree_view),
987 "gtk-alternative-sort-arrows", &alternative,
990 switch (tree_column->sort_order)
992 case GTK_SORT_ASCENDING:
993 arrow_type = alternative ? GTK_ARROW_UP : GTK_ARROW_DOWN;
996 case GTK_SORT_DESCENDING:
997 arrow_type = alternative ? GTK_ARROW_DOWN : GTK_ARROW_UP;
1001 g_warning (G_STRLOC": bad sort order");
1006 gtk_arrow_set (GTK_ARROW (arrow),
1010 /* Put arrow on the right if the text is left-or-center justified, and on the
1011 * left otherwise; do this by packing boxes, so flipping text direction will
1014 g_object_ref (arrow);
1015 gtk_container_remove (GTK_CONTAINER (hbox), arrow);
1017 if (tree_column->xalign <= 0.5)
1019 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1023 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1024 /* move it to the front */
1025 gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
1027 g_object_unref (arrow);
1029 if (tree_column->show_sort_indicator
1030 || (GTK_IS_TREE_SORTABLE (model) && tree_column->sort_column_id >= 0))
1031 gtk_widget_show (arrow);
1033 gtk_widget_hide (arrow);
1035 /* It's always safe to hide the button. It isn't always safe to show it, as
1036 * if you show it before it's realized, it'll get the wrong window. */
1037 if (tree_column->button &&
1038 tree_column->tree_view != NULL &&
1039 gtk_widget_get_realized (tree_column->tree_view))
1041 if (tree_column->visible)
1043 gtk_widget_show_now (tree_column->button);
1044 if (tree_column->window)
1046 if (tree_column->resizable)
1048 gdk_window_show (tree_column->window);
1049 gdk_window_raise (tree_column->window);
1053 gdk_window_hide (tree_column->window);
1059 gtk_widget_hide (tree_column->button);
1060 if (tree_column->window)
1061 gdk_window_hide (tree_column->window);
1065 if (tree_column->reorderable || tree_column->clickable)
1067 gtk_widget_set_can_focus (tree_column->button, TRUE);
1071 gtk_widget_set_can_focus (tree_column->button, FALSE);
1072 if (gtk_widget_has_focus (tree_column->button))
1074 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
1075 if (gtk_widget_is_toplevel (toplevel))
1077 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
1081 /* Queue a resize on the assumption that we always want to catch all changes
1082 * and columns don't change all that often.
1084 if (gtk_widget_get_realized (tree_column->tree_view))
1085 gtk_widget_queue_resize (tree_column->tree_view);
1089 /* Button signal handlers
1093 pspp_sheet_view_column_button_event (GtkWidget *widget,
1097 PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
1099 g_return_val_if_fail (event != NULL, FALSE);
1101 if (event->type == GDK_BUTTON_PRESS &&
1102 column->reorderable &&
1103 ((GdkEventButton *)event)->button == 1)
1105 column->maybe_reordered = TRUE;
1106 gdk_window_get_pointer (GTK_BUTTON (widget)->event_window,
1110 gtk_widget_grab_focus (widget);
1113 if (event->type == GDK_BUTTON_RELEASE ||
1114 event->type == GDK_LEAVE_NOTIFY)
1115 column->maybe_reordered = FALSE;
1117 if (event->type == GDK_MOTION_NOTIFY &&
1118 column->maybe_reordered &&
1119 (gtk_drag_check_threshold (widget,
1122 (gint) ((GdkEventMotion *)event)->x,
1123 (gint) ((GdkEventMotion *)event)->y)))
1125 column->maybe_reordered = FALSE;
1126 _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
1129 if (column->clickable == FALSE)
1131 switch (event->type)
1133 case GDK_BUTTON_PRESS:
1134 case GDK_2BUTTON_PRESS:
1135 case GDK_3BUTTON_PRESS:
1136 case GDK_MOTION_NOTIFY:
1137 case GDK_BUTTON_RELEASE:
1138 case GDK_ENTER_NOTIFY:
1139 case GDK_LEAVE_NOTIFY:
1150 pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
1152 g_signal_emit_by_name (data, "clicked");
1156 pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
1157 gboolean group_cycling,
1160 PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
1162 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
1164 PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
1165 if (column->clickable)
1166 gtk_button_clicked (GTK_BUTTON (column->button));
1167 else if (gtk_widget_get_can_focus (column->button))
1168 gtk_widget_grab_focus (column->button);
1170 gtk_widget_grab_focus (column->tree_view);
1176 pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
1177 PsppSheetViewColumn *column)
1179 gint sort_column_id;
1182 if (gtk_tree_sortable_get_sort_column_id (sortable,
1186 if (sort_column_id == column->sort_column_id)
1188 pspp_sheet_view_column_set_sort_indicator (column, TRUE);
1189 pspp_sheet_view_column_set_sort_order (column, order);
1193 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1198 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1203 pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
1206 gint sort_column_id;
1208 gboolean has_sort_column;
1209 gboolean has_default_sort_func;
1211 g_return_if_fail (tree_column->tree_view != NULL);
1214 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1217 has_default_sort_func =
1218 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
1220 if (has_sort_column &&
1221 sort_column_id == tree_column->sort_column_id)
1223 if (order == GTK_SORT_ASCENDING)
1224 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1225 tree_column->sort_column_id,
1226 GTK_SORT_DESCENDING);
1227 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
1228 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1229 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1230 GTK_SORT_ASCENDING);
1232 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1233 tree_column->sort_column_id,
1234 GTK_SORT_ASCENDING);
1238 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1239 tree_column->sort_column_id,
1240 GTK_SORT_ASCENDING);
1246 pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
1248 GtkTreeModel *model;
1250 if (tree_column->tree_view == NULL)
1253 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1258 if (GTK_IS_TREE_SORTABLE (model) &&
1259 tree_column->sort_column_id != -1)
1261 gint real_sort_column_id;
1262 GtkSortType real_order;
1264 if (tree_column->sort_column_changed_signal == 0)
1265 tree_column->sort_column_changed_signal =
1266 g_signal_connect (model, "sort-column-changed",
1267 G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
1270 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1271 &real_sort_column_id,
1273 (real_sort_column_id == tree_column->sort_column_id))
1275 pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
1276 pspp_sheet_view_column_set_sort_order (tree_column, real_order);
1280 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
1286 /* Exported Private Functions.
1287 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1291 _pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
1293 PsppSheetView *tree_view;
1295 guint attributes_mask;
1298 tree_view = (PsppSheetView *)column->tree_view;
1299 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
1301 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1302 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
1303 g_return_if_fail (tree_view->priv->header_window != NULL);
1304 g_return_if_fail (column->button != NULL);
1306 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
1308 if (column->visible)
1309 gtk_widget_show (column->button);
1311 attr.window_type = GDK_WINDOW_CHILD;
1312 attr.wclass = GDK_INPUT_ONLY;
1313 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1314 attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1315 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
1316 (GDK_BUTTON_PRESS_MASK |
1317 GDK_BUTTON_RELEASE_MASK |
1318 GDK_POINTER_MOTION_MASK |
1319 GDK_POINTER_MOTION_HINT_MASK |
1320 GDK_KEY_PRESS_MASK);
1321 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
1322 attr.cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (tree_view->priv->header_window),
1323 GDK_SB_H_DOUBLE_ARROW);
1325 attr.width = TREE_VIEW_DRAG_WIDTH;
1326 attr.height = tree_view->priv->header_height;
1328 attr.x = (column->button->allocation.x + (rtl ? 0 : column->button->allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
1329 column->window = gdk_window_new (tree_view->priv->header_window,
1330 &attr, attributes_mask);
1331 gdk_window_set_user_data (column->window, tree_view);
1333 pspp_sheet_view_column_update_button (column);
1335 gdk_cursor_unref (attr.cursor);
1339 _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
1341 g_return_if_fail (column != NULL);
1342 g_return_if_fail (column->window != NULL);
1344 gdk_window_set_user_data (column->window, NULL);
1345 gdk_window_destroy (column->window);
1346 column->window = NULL;
1350 _pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
1351 GtkTreeModel *old_model)
1353 if (column->sort_column_changed_signal)
1355 g_signal_handler_disconnect (old_model,
1356 column->sort_column_changed_signal);
1357 column->sort_column_changed_signal = 0;
1359 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1363 _pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
1364 PsppSheetView *tree_view)
1366 g_assert (column->tree_view == NULL);
1368 column->tree_view = GTK_WIDGET (tree_view);
1369 pspp_sheet_view_column_create_button (column);
1371 column->property_changed_signal =
1372 g_signal_connect_swapped (tree_view,
1374 G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
1377 pspp_sheet_view_column_setup_sort_column_id_callback (column);
1381 _pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
1383 if (column->tree_view && column->button)
1385 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1387 if (column->property_changed_signal)
1389 g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
1390 column->property_changed_signal = 0;
1393 if (column->sort_column_changed_signal)
1395 g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
1396 column->sort_column_changed_signal);
1397 column->sort_column_changed_signal = 0;
1400 column->tree_view = NULL;
1401 column->button = NULL;
1405 _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
1409 for (list = column->cell_list; list; list = list->next)
1410 if (((PsppSheetViewColumnCellInfo *)list->data)->cell->mode ==
1411 GTK_CELL_RENDERER_MODE_EDITABLE)
1417 /* gets cell being edited */
1419 _pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
1423 for (list = column->cell_list; list; list = list->next)
1424 if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
1425 return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
1431 _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
1436 for (list = column->cell_list; list; list = list->next)
1438 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1440 if ((cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1441 cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
1442 cellinfo->cell->visible)
1450 _pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
1456 list = pspp_sheet_view_column_cell_first (column);
1457 for (; list; list = pspp_sheet_view_column_cell_next (column, list))
1459 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1460 if (current_x <= x && x <= current_x + cellinfo->real_width)
1461 return cellinfo->cell;
1462 current_x += cellinfo->real_width;
1468 /* Public Functions */
1472 * pspp_sheet_view_column_new:
1474 * Creates a new #PsppSheetViewColumn.
1476 * Return value: A newly created #PsppSheetViewColumn.
1478 PsppSheetViewColumn *
1479 pspp_sheet_view_column_new (void)
1481 PsppSheetViewColumn *tree_column;
1483 tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
1489 * pspp_sheet_view_column_new_with_attributes:
1490 * @title: The title to set the header to.
1491 * @cell: The #GtkCellRenderer.
1492 * @Varargs: A %NULL-terminated list of attributes.
1494 * Creates a new #PsppSheetViewColumn with a number of default values. This is
1495 * equivalent to calling pspp_sheet_view_column_set_title(),
1496 * pspp_sheet_view_column_pack_start(), and
1497 * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
1499 * Here's a simple example:
1501 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1504 * PsppSheetViewColumn *column;
1505 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
1507 * column = pspp_sheet_view_column_new_with_attributes ("Title",
1509 * "text", TEXT_COLUMN,
1510 * "foreground", COLOR_COLUMN,
1515 * Return value: A newly created #PsppSheetViewColumn.
1517 PsppSheetViewColumn *
1518 pspp_sheet_view_column_new_with_attributes (const gchar *title,
1519 GtkCellRenderer *cell,
1522 PsppSheetViewColumn *retval;
1525 retval = pspp_sheet_view_column_new ();
1527 pspp_sheet_view_column_set_title (retval, title);
1528 pspp_sheet_view_column_pack_start (retval, cell, TRUE);
1530 va_start (args, cell);
1531 pspp_sheet_view_column_set_attributesv (retval, cell, args);
1537 static PsppSheetViewColumnCellInfo *
1538 pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
1539 GtkCellRenderer *cell_renderer)
1542 for (list = tree_column->cell_list; list; list = list->next)
1543 if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
1544 return (PsppSheetViewColumnCellInfo *) list->data;
1550 * pspp_sheet_view_column_pack_start:
1551 * @tree_column: A #PsppSheetViewColumn.
1552 * @cell: The #GtkCellRenderer.
1553 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1555 * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
1556 * the @cell is allocated no more space than it needs. Any unused space is divided
1557 * evenly between cells for which @expand is %TRUE.
1560 pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
1561 GtkCellRenderer *cell,
1564 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
1568 * pspp_sheet_view_column_pack_end:
1569 * @tree_column: A #PsppSheetViewColumn.
1570 * @cell: The #GtkCellRenderer.
1571 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1573 * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
1574 * is allocated no more space than it needs. Any unused space is divided
1575 * evenly between cells for which @expand is %TRUE.
1578 pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
1579 GtkCellRenderer *cell,
1582 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
1586 * pspp_sheet_view_column_clear:
1587 * @tree_column: A #PsppSheetViewColumn
1589 * Unsets all the mappings on all renderers on the @tree_column.
1592 pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
1594 gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
1598 pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
1600 PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
1601 GList *retval = NULL, *list;
1603 g_return_val_if_fail (tree_column != NULL, NULL);
1605 for (list = tree_column->cell_list; list; list = list->next)
1607 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
1609 retval = g_list_append (retval, info->cell);
1616 * pspp_sheet_view_column_get_cell_renderers:
1617 * @tree_column: A #PsppSheetViewColumn
1619 * Returns a newly-allocated #GList of all the cell renderers in the column,
1620 * in no particular order. The list must be freed with g_list_free().
1622 * Return value: A list of #GtkCellRenderers
1624 * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
1627 pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
1629 return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
1633 * pspp_sheet_view_column_add_attribute:
1634 * @tree_column: A #PsppSheetViewColumn.
1635 * @cell_renderer: the #GtkCellRenderer to set attributes on
1636 * @attribute: An attribute on the renderer
1637 * @column: The column position on the model to get the attribute from.
1639 * Adds an attribute mapping to the list in @tree_column. The @column is the
1640 * column of the model to get a value from, and the @attribute is the
1641 * parameter on @cell_renderer to be set from the value. So for example
1642 * if column 2 of the model contains strings, you could have the
1643 * "text" attribute of a #GtkCellRendererText get its values from
1647 pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
1648 GtkCellRenderer *cell_renderer,
1649 const gchar *attribute,
1652 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
1653 cell_renderer, attribute, column);
1657 pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
1658 GtkCellRenderer *cell_renderer,
1664 attribute = va_arg (args, gchar *);
1666 pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
1668 while (attribute != NULL)
1670 column = va_arg (args, gint);
1671 pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1672 attribute = va_arg (args, gchar *);
1677 * pspp_sheet_view_column_set_attributes:
1678 * @tree_column: A #PsppSheetViewColumn.
1679 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1680 * @Varargs: A %NULL-terminated list of attributes.
1682 * Sets the attributes in the list as the attributes of @tree_column.
1683 * The attributes should be in attribute/column order, as in
1684 * pspp_sheet_view_column_add_attribute(). All existing attributes
1685 * are removed, and replaced with the new attributes.
1688 pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
1689 GtkCellRenderer *cell_renderer,
1694 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1695 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1696 g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
1698 va_start (args, cell_renderer);
1699 pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
1705 * pspp_sheet_view_column_set_cell_data_func:
1706 * @tree_column: A #PsppSheetViewColumn
1707 * @cell_renderer: A #GtkCellRenderer
1708 * @func: The #PsppSheetViewColumnFunc to use.
1709 * @func_data: The user data for @func.
1710 * @destroy: The destroy notification for @func_data
1712 * Sets the #PsppSheetViewColumnFunc to use for the column. This
1713 * function is used instead of the standard attributes mapping for
1714 * setting the column value, and should set the value of @tree_column's
1715 * cell renderer as appropriate. @func may be %NULL to remove an
1719 pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
1720 GtkCellRenderer *cell_renderer,
1721 PsppSheetCellDataFunc func,
1723 GDestroyNotify destroy)
1725 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
1727 (GtkCellLayoutDataFunc)func,
1728 func_data, destroy);
1733 * pspp_sheet_view_column_clear_attributes:
1734 * @tree_column: a #PsppSheetViewColumn
1735 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1737 * Clears all existing attributes previously set with
1738 * pspp_sheet_view_column_set_attributes().
1741 pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
1742 GtkCellRenderer *cell_renderer)
1744 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
1749 * pspp_sheet_view_column_set_spacing:
1750 * @tree_column: A #PsppSheetViewColumn.
1751 * @spacing: distance between cell renderers in pixels.
1753 * Sets the spacing field of @tree_column, which is the number of pixels to
1754 * place between cell renderers packed into it.
1757 pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
1760 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1761 g_return_if_fail (spacing >= 0);
1763 if (tree_column->spacing == spacing)
1766 tree_column->spacing = spacing;
1767 if (tree_column->tree_view)
1768 _pspp_sheet_view_column_cell_set_dirty (tree_column);
1772 * pspp_sheet_view_column_get_spacing:
1773 * @tree_column: A #PsppSheetViewColumn.
1775 * Returns the spacing of @tree_column.
1777 * Return value: the spacing of @tree_column.
1780 pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
1782 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
1784 return tree_column->spacing;
1787 /* Options for manipulating the columns */
1790 * pspp_sheet_view_column_set_visible:
1791 * @tree_column: A #PsppSheetViewColumn.
1792 * @visible: %TRUE if the @tree_column is visible.
1794 * Sets the visibility of @tree_column.
1797 pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
1800 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1802 visible = !! visible;
1804 if (tree_column->visible == visible)
1807 tree_column->visible = visible;
1809 if (tree_column->visible)
1810 _pspp_sheet_view_column_cell_set_dirty (tree_column);
1812 pspp_sheet_view_column_update_button (tree_column);
1813 g_object_notify (G_OBJECT (tree_column), "visible");
1817 * pspp_sheet_view_column_get_visible:
1818 * @tree_column: A #PsppSheetViewColumn.
1820 * Returns %TRUE if @tree_column is visible.
1822 * Return value: whether the column is visible or not. If it is visible, then
1823 * the tree will show the column.
1826 pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
1828 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
1830 return tree_column->visible;
1834 * pspp_sheet_view_column_set_resizable:
1835 * @tree_column: A #PsppSheetViewColumn
1836 * @resizable: %TRUE, if the column can be resized
1838 * If @resizable is %TRUE, then the user can explicitly resize the column by
1839 * grabbing the outer edge of the column button.
1842 pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
1845 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1847 resizable = !! resizable;
1849 if (tree_column->resizable == resizable)
1852 tree_column->resizable = resizable;
1854 pspp_sheet_view_column_update_button (tree_column);
1856 g_object_notify (G_OBJECT (tree_column), "resizable");
1860 * pspp_sheet_view_column_get_resizable:
1861 * @tree_column: A #PsppSheetViewColumn
1863 * Returns %TRUE if the @tree_column can be resized by the end user.
1865 * Return value: %TRUE, if the @tree_column can be resized.
1868 pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
1870 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
1872 return tree_column->resizable;
1877 * pspp_sheet_view_column_get_width:
1878 * @tree_column: A #PsppSheetViewColumn.
1880 * Returns the current size of @tree_column in pixels.
1882 * Return value: The current width of @tree_column.
1885 pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
1887 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
1889 return tree_column->width;
1893 * pspp_sheet_view_column_set_fixed_width:
1894 * @tree_column: A #PsppSheetViewColumn.
1895 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
1897 * Sets the size of the column in pixels. The size of the column is clamped to
1898 * the min/max width for the column. Please note that the min/max width of the
1899 * column doesn't actually affect the "fixed_width" property of the widget, just
1900 * the actual size when displayed.
1903 pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
1906 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1907 g_return_if_fail (fixed_width > 0);
1909 tree_column->fixed_width = fixed_width;
1910 tree_column->use_resized_width = FALSE;
1912 if (tree_column->tree_view &&
1913 gtk_widget_get_realized (tree_column->tree_view))
1915 gtk_widget_queue_resize (tree_column->tree_view);
1918 g_object_notify (G_OBJECT (tree_column), "fixed-width");
1922 * pspp_sheet_view_column_get_fixed_width:
1923 * @tree_column: a #PsppSheetViewColumn
1925 * Gets the fixed width of the column. This value is only meaning may not be
1926 * the actual width of the column on the screen, just what is requested.
1928 * Return value: the fixed width of the column
1931 pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
1933 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
1935 return tree_column->fixed_width;
1939 * pspp_sheet_view_column_set_min_width:
1940 * @tree_column: A #PsppSheetViewColumn.
1941 * @min_width: The minimum width of the column in pixels, or -1.
1943 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
1944 * minimum width is unset.
1947 pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
1950 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1951 g_return_if_fail (min_width >= -1);
1953 if (min_width == tree_column->min_width)
1956 if (tree_column->visible &&
1957 tree_column->tree_view != NULL &&
1958 gtk_widget_get_realized (tree_column->tree_view))
1960 if (min_width > tree_column->width)
1961 gtk_widget_queue_resize (tree_column->tree_view);
1964 tree_column->min_width = min_width;
1965 g_object_freeze_notify (G_OBJECT (tree_column));
1966 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
1968 tree_column->max_width = min_width;
1969 g_object_notify (G_OBJECT (tree_column), "max-width");
1971 g_object_notify (G_OBJECT (tree_column), "min-width");
1972 g_object_thaw_notify (G_OBJECT (tree_column));
1976 * pspp_sheet_view_column_get_min_width:
1977 * @tree_column: A #PsppSheetViewColumn.
1979 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
1982 * Return value: The minimum width of the @tree_column.
1985 pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
1987 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
1989 return tree_column->min_width;
1993 * pspp_sheet_view_column_set_max_width:
1994 * @tree_column: A #PsppSheetViewColumn.
1995 * @max_width: The maximum width of the column in pixels, or -1.
1997 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
1998 * maximum width is unset. Note, the column can actually be wider than max
1999 * width if it's the last column in a view. In this case, the column expands to
2000 * fill any extra space.
2003 pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
2006 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2007 g_return_if_fail (max_width >= -1);
2009 if (max_width == tree_column->max_width)
2012 if (tree_column->visible &&
2013 tree_column->tree_view != NULL &&
2014 gtk_widget_get_realized (tree_column->tree_view))
2016 if (max_width != -1 && max_width < tree_column->width)
2017 gtk_widget_queue_resize (tree_column->tree_view);
2020 tree_column->max_width = max_width;
2021 g_object_freeze_notify (G_OBJECT (tree_column));
2022 if (max_width != -1 && max_width < tree_column->min_width)
2024 tree_column->min_width = max_width;
2025 g_object_notify (G_OBJECT (tree_column), "min-width");
2027 g_object_notify (G_OBJECT (tree_column), "max-width");
2028 g_object_thaw_notify (G_OBJECT (tree_column));
2032 * pspp_sheet_view_column_get_max_width:
2033 * @tree_column: A #PsppSheetViewColumn.
2035 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
2038 * Return value: The maximum width of the @tree_column.
2041 pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
2043 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2045 return tree_column->max_width;
2049 * pspp_sheet_view_column_clicked:
2050 * @tree_column: a #PsppSheetViewColumn
2052 * Emits the "clicked" signal on the column. This function will only work if
2053 * @tree_column is clickable.
2056 pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
2058 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2060 if (tree_column->visible &&
2061 tree_column->button &&
2062 tree_column->clickable)
2063 gtk_button_clicked (GTK_BUTTON (tree_column->button));
2067 * pspp_sheet_view_column_set_title:
2068 * @tree_column: A #PsppSheetViewColumn.
2069 * @title: The title of the @tree_column.
2071 * Sets the title of the @tree_column. If a custom widget has been set, then
2072 * this value is ignored.
2075 pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
2080 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2082 new_title = g_strdup (title);
2083 g_free (tree_column->title);
2084 tree_column->title = new_title;
2086 pspp_sheet_view_column_update_button (tree_column);
2087 g_object_notify (G_OBJECT (tree_column), "title");
2091 * pspp_sheet_view_column_get_title:
2092 * @tree_column: A #PsppSheetViewColumn.
2094 * Returns the title of the widget.
2096 * Return value: the title of the column. This string should not be
2097 * modified or freed.
2099 G_CONST_RETURN gchar *
2100 pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
2102 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2104 return tree_column->title;
2108 * pspp_sheet_view_column_set_expand:
2109 * @tree_column: A #PsppSheetViewColumn
2110 * @expand: %TRUE if the column should take available extra space, %FALSE if not
2112 * Sets the column to take available extra space. This space is shared equally
2113 * amongst all columns that have the expand set to %TRUE. If no column has this
2114 * option set, then the last column gets all extra space. By default, every
2115 * column is created with this %FALSE.
2120 pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
2123 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2125 expand = expand?TRUE:FALSE;
2126 if (tree_column->expand == expand)
2128 tree_column->expand = expand;
2130 if (tree_column->visible &&
2131 tree_column->tree_view != NULL &&
2132 gtk_widget_get_realized (tree_column->tree_view))
2134 /* We want to continue using the original width of the
2135 * column that includes additional space added by the user
2136 * resizing the columns and possibly extra (expanded) space, which
2137 * are not included in the resized width.
2139 tree_column->use_resized_width = FALSE;
2141 gtk_widget_queue_resize (tree_column->tree_view);
2144 g_object_notify (G_OBJECT (tree_column), "expand");
2148 * pspp_sheet_view_column_get_expand:
2149 * @tree_column: a #PsppSheetViewColumn
2151 * Return %TRUE if the column expands to take any available space.
2153 * Return value: %TRUE, if the column expands
2158 pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
2160 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2162 return tree_column->expand;
2166 * pspp_sheet_view_column_set_clickable:
2167 * @tree_column: A #PsppSheetViewColumn.
2168 * @clickable: %TRUE if the header is active.
2170 * Sets the header to be active if @active is %TRUE. When the header is active,
2171 * then it can take keyboard focus, and can be clicked.
2174 pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
2177 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2179 clickable = !! clickable;
2180 if (tree_column->clickable == clickable)
2183 tree_column->clickable = clickable;
2184 pspp_sheet_view_column_update_button (tree_column);
2185 g_object_notify (G_OBJECT (tree_column), "clickable");
2189 * pspp_sheet_view_column_get_clickable:
2190 * @tree_column: a #PsppSheetViewColumn
2192 * Returns %TRUE if the user can click on the header for the column.
2194 * Return value: %TRUE if user can click the column header.
2197 pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
2199 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2201 return tree_column->clickable;
2205 * pspp_sheet_view_column_set_widget:
2206 * @tree_column: A #PsppSheetViewColumn.
2207 * @widget: (allow-none): A child #GtkWidget, or %NULL.
2209 * Sets the widget in the header to be @widget. If widget is %NULL, then the
2210 * header button is set with a #GtkLabel set to the title of @tree_column.
2213 pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
2216 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2217 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
2220 g_object_ref_sink (widget);
2222 if (tree_column->child)
2223 g_object_unref (tree_column->child);
2225 tree_column->child = widget;
2226 pspp_sheet_view_column_update_button (tree_column);
2227 g_object_notify (G_OBJECT (tree_column), "widget");
2231 * pspp_sheet_view_column_get_widget:
2232 * @tree_column: A #PsppSheetViewColumn.
2234 * Returns the #GtkWidget in the button on the column header. If a custom
2235 * widget has not been set then %NULL is returned.
2237 * Return value: The #GtkWidget in the column header, or %NULL
2240 pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
2242 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2244 return tree_column->child;
2248 * pspp_sheet_view_column_set_alignment:
2249 * @tree_column: A #PsppSheetViewColumn.
2250 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2252 * Sets the alignment of the title or custom widget inside the column header.
2253 * The alignment determines its location inside the button -- 0.0 for left, 0.5
2254 * for center, 1.0 for right.
2257 pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
2260 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2262 xalign = CLAMP (xalign, 0.0, 1.0);
2264 if (tree_column->xalign == xalign)
2267 tree_column->xalign = xalign;
2268 pspp_sheet_view_column_update_button (tree_column);
2269 g_object_notify (G_OBJECT (tree_column), "alignment");
2273 * pspp_sheet_view_column_get_alignment:
2274 * @tree_column: A #PsppSheetViewColumn.
2276 * Returns the current x alignment of @tree_column. This value can range
2277 * between 0.0 and 1.0.
2279 * Return value: The current alignent of @tree_column.
2282 pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
2284 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0.5);
2286 return tree_column->xalign;
2290 * pspp_sheet_view_column_set_reorderable:
2291 * @tree_column: A #PsppSheetViewColumn
2292 * @reorderable: %TRUE, if the column can be reordered.
2294 * If @reorderable is %TRUE, then the column can be reordered by the end user
2295 * dragging the header.
2298 pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
2299 gboolean reorderable)
2301 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2304 pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
2306 if (tree_column->reorderable == (reorderable?TRUE:FALSE))
2309 tree_column->reorderable = (reorderable?TRUE:FALSE);
2310 pspp_sheet_view_column_update_button (tree_column);
2311 g_object_notify (G_OBJECT (tree_column), "reorderable");
2315 * pspp_sheet_view_column_get_reorderable:
2316 * @tree_column: A #PsppSheetViewColumn
2318 * Returns %TRUE if the @tree_column can be reordered by the user.
2320 * Return value: %TRUE if the @tree_column can be reordered by the user.
2323 pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
2325 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2327 return tree_column->reorderable;
2332 * pspp_sheet_view_column_set_sort_column_id:
2333 * @tree_column: a #PsppSheetViewColumn
2334 * @sort_column_id: The @sort_column_id of the model to sort on.
2336 * Sets the logical @sort_column_id that this column sorts on when this column
2337 * is selected for sorting. Doing so makes the column header clickable.
2340 pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
2341 gint sort_column_id)
2343 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2344 g_return_if_fail (sort_column_id >= -1);
2346 if (tree_column->sort_column_id == sort_column_id)
2349 tree_column->sort_column_id = sort_column_id;
2351 /* Handle unsetting the id */
2352 if (sort_column_id == -1)
2354 GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
2356 if (tree_column->sort_clicked_signal)
2358 g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
2359 tree_column->sort_clicked_signal = 0;
2362 if (tree_column->sort_column_changed_signal)
2364 g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
2365 tree_column->sort_column_changed_signal = 0;
2368 pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2369 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
2370 pspp_sheet_view_column_set_clickable (tree_column, FALSE);
2371 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2375 pspp_sheet_view_column_set_clickable (tree_column, TRUE);
2377 if (! tree_column->sort_clicked_signal)
2378 tree_column->sort_clicked_signal = g_signal_connect (tree_column,
2380 G_CALLBACK (pspp_sheet_view_column_sort),
2383 pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
2384 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2388 * pspp_sheet_view_column_get_sort_column_id:
2389 * @tree_column: a #PsppSheetViewColumn
2391 * Gets the logical @sort_column_id that the model sorts on when this
2392 * column is selected for sorting.
2393 * See pspp_sheet_view_column_set_sort_column_id().
2395 * Return value: the current @sort_column_id for this column, or -1 if
2396 * this column can't be used for sorting.
2399 pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
2401 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2403 return tree_column->sort_column_id;
2407 * pspp_sheet_view_column_set_sort_indicator:
2408 * @tree_column: a #PsppSheetViewColumn
2409 * @setting: %TRUE to display an indicator that the column is sorted
2411 * Call this function with a @setting of %TRUE to display an arrow in
2412 * the header button indicating the column is sorted. Call
2413 * pspp_sheet_view_column_set_sort_order() to change the direction of
2418 pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
2421 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2423 setting = setting != FALSE;
2425 if (setting == tree_column->show_sort_indicator)
2428 tree_column->show_sort_indicator = setting;
2429 pspp_sheet_view_column_update_button (tree_column);
2430 g_object_notify (G_OBJECT (tree_column), "sort-indicator");
2434 * pspp_sheet_view_column_get_sort_indicator:
2435 * @tree_column: a #PsppSheetViewColumn
2437 * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
2439 * Return value: whether the sort indicator arrow is displayed
2442 pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column)
2444 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2446 return tree_column->show_sort_indicator;
2450 * pspp_sheet_view_column_set_sort_order:
2451 * @tree_column: a #PsppSheetViewColumn
2452 * @order: sort order that the sort indicator should indicate
2454 * Changes the appearance of the sort indicator.
2456 * This <emphasis>does not</emphasis> actually sort the model. Use
2457 * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
2458 * support. This function is primarily for custom sorting behavior, and should
2459 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2460 * that. For custom models, the mechanism will vary.
2462 * The sort indicator changes direction to indicate normal sort or reverse sort.
2463 * Note that you must have the sort indicator enabled to see anything when
2464 * calling this function; see pspp_sheet_view_column_set_sort_indicator().
2467 pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
2470 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2472 if (order == tree_column->sort_order)
2475 tree_column->sort_order = order;
2476 pspp_sheet_view_column_update_button (tree_column);
2477 g_object_notify (G_OBJECT (tree_column), "sort-order");
2481 * pspp_sheet_view_column_get_sort_order:
2482 * @tree_column: a #PsppSheetViewColumn
2484 * Gets the value set by pspp_sheet_view_column_set_sort_order().
2486 * Return value: the sort order the sort indicator is indicating
2489 pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column)
2491 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2493 return tree_column->sort_order;
2497 * pspp_sheet_view_column_cell_set_cell_data:
2498 * @tree_column: A #PsppSheetViewColumn.
2499 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2500 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2502 * Sets the cell renderer based on the @tree_model and @iter. That is, for
2503 * every attribute mapping in @tree_column, it will get a value from the set
2504 * column on the @iter, and use that value to set the attribute on the cell
2505 * renderer. This is used primarily by the #PsppSheetView.
2508 pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
2509 GtkTreeModel *tree_model,
2513 GValue value = { 0, };
2516 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2518 if (tree_model == NULL)
2521 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2523 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
2524 GObject *cell = (GObject *) info->cell;
2526 list = info->attributes;
2528 g_object_freeze_notify (cell);
2530 while (list && list->next)
2532 gtk_tree_model_get_value (tree_model, iter,
2533 GPOINTER_TO_INT (list->next->data),
2535 g_object_set_property (cell, (gchar *) list->data, &value);
2536 g_value_unset (&value);
2537 list = list->next->next;
2541 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2542 g_object_thaw_notify (G_OBJECT (info->cell));
2548 * pspp_sheet_view_column_cell_get_size:
2549 * @tree_column: A #PsppSheetViewColumn.
2550 * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
2551 * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
2552 * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
2553 * @width: (allow-none): location to return width needed to render a cell, or %NULL
2554 * @height: (allow-none): location to return height needed to render a cell, or %NULL
2556 * Obtains the width and height needed to render the column. This is used
2557 * primarily by the #PsppSheetView.
2560 pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
2561 const GdkRectangle *cell_area,
2568 gboolean first_cell = TRUE;
2569 gint focus_line_width;
2571 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2578 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
2580 for (list = tree_column->cell_list; list; list = list->next)
2582 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2584 gint new_height = 0;
2586 g_object_get (info->cell, "visible", &visible, NULL);
2588 if (visible == FALSE)
2591 if (first_cell == FALSE && width)
2592 *width += tree_column->spacing;
2594 gtk_cell_renderer_get_size (info->cell,
2595 tree_column->tree_view,
2603 * height = MAX (*height, new_height + focus_line_width * 2);
2604 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
2606 * width += info->requested_width;
2611 /* rendering, event handling and rendering focus are somewhat complicated, and
2612 * quite a bit of code. Rather than duplicate them, we put them together to
2613 * keep the code in one place.
2615 * To better understand what's going on, check out
2616 * docs/tree-column-sizing.png
2625 pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn *tree_column,
2627 const GdkRectangle *background_area,
2628 const GdkRectangle *cell_area,
2631 const GdkRectangle *expose_area, /* RENDER */
2632 GdkRectangle *focus_rectangle, /* FOCUS */
2633 GtkCellEditable **editable_widget, /* EVENT */
2634 GdkEvent *event, /* EVENT */
2635 gchar *path_string) /* EVENT */
2638 GdkRectangle real_cell_area;
2639 GdkRectangle real_background_area;
2640 GdkRectangle real_expose_area = *cell_area;
2642 gint expand_cell_count = 0;
2643 gint full_requested_width = 0;
2645 gint min_x, min_y, max_x, max_y;
2646 gint focus_line_width;
2648 gint horizontal_separator;
2649 gboolean cursor_row = FALSE;
2650 gboolean first_cell = TRUE;
2652 /* If we have rtl text, we need to transform our areas */
2653 GdkRectangle rtl_cell_area;
2654 GdkRectangle rtl_background_area;
2661 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
2662 special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
2664 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
2666 PsppSheetViewColumnCellInfo *info = NULL;
2667 gboolean found_has_focus = FALSE;
2669 /* one should have focus */
2670 for (list = tree_column->cell_list; list; list = list->next)
2673 if (info && info->has_focus)
2675 found_has_focus = TRUE;
2680 if (!found_has_focus)
2682 /* give the first one focus */
2683 info = pspp_sheet_view_column_cell_first (tree_column)->data;
2684 info->has_focus = TRUE;
2688 cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
2690 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
2691 "focus-line-width", &focus_line_width,
2692 "horizontal-separator", &horizontal_separator,
2695 real_cell_area = *cell_area;
2696 real_background_area = *background_area;
2699 real_cell_area.x += focus_line_width;
2700 real_cell_area.y += focus_line_width;
2701 real_cell_area.height -= 2 * focus_line_width;
2704 depth = real_background_area.width - real_cell_area.width;
2706 depth = real_cell_area.x - real_background_area.x;
2708 /* Find out how much extra space we have to allocate */
2709 for (list = tree_column->cell_list; list; list = list->next)
2711 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
2713 if (! info->cell->visible)
2716 if (info->expand == TRUE)
2717 expand_cell_count ++;
2718 full_requested_width += info->requested_width;
2721 full_requested_width += tree_column->spacing;
2726 extra_space = cell_area->width - full_requested_width;
2727 if (extra_space < 0)
2729 else if (extra_space > 0 && expand_cell_count > 0)
2730 extra_space /= expand_cell_count;
2732 /* iterate list for GTK_PACK_START cells */
2733 for (list = tree_column->cell_list; list; list = list->next)
2735 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2737 if (info->pack == GTK_PACK_END)
2740 if (! info->cell->visible)
2743 if ((info->has_focus || special_cells == 1) && cursor_row)
2744 flags |= GTK_CELL_RENDERER_FOCUSED;
2746 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2748 info->real_width = info->requested_width + (info->expand?extra_space:0);
2750 /* We constrain ourselves to only the width available */
2751 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
2753 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
2756 if (real_cell_area.x > cell_area->x + cell_area->width)
2759 real_cell_area.width = info->real_width;
2760 real_cell_area.width -= 2 * focus_line_width;
2764 real_background_area.width = info->real_width + depth;
2768 /* fill the rest of background for the last cell */
2769 real_background_area.width = background_area->x + background_area->width - real_background_area.x;
2772 rtl_cell_area = real_cell_area;
2773 rtl_background_area = real_background_area;
2777 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
2778 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
2782 if (action == CELL_ACTION_RENDER)
2784 gtk_cell_renderer_render (info->cell,
2786 tree_column->tree_view,
2787 &rtl_background_area,
2793 else if (action == CELL_ACTION_FOCUS)
2795 gint x_offset, y_offset, width, height;
2797 gtk_cell_renderer_get_size (info->cell,
2798 tree_column->tree_view,
2800 &x_offset, &y_offset,
2803 if (special_cells > 1)
2805 if (info->has_focus)
2807 min_x = rtl_cell_area.x + x_offset;
2808 max_x = min_x + width;
2809 min_y = rtl_cell_area.y + y_offset;
2810 max_y = min_y + height;
2815 if (min_x > (rtl_cell_area.x + x_offset))
2816 min_x = rtl_cell_area.x + x_offset;
2817 if (max_x < rtl_cell_area.x + x_offset + width)
2818 max_x = rtl_cell_area.x + x_offset + width;
2819 if (min_y > (rtl_cell_area.y + y_offset))
2820 min_y = rtl_cell_area.y + y_offset;
2821 if (max_y < rtl_cell_area.y + y_offset + height)
2822 max_y = rtl_cell_area.y + y_offset + height;
2826 else if (action == CELL_ACTION_EVENT)
2828 gboolean try_event = FALSE;
2832 if (special_cells == 1)
2834 /* only 1 activatable cell -> whole column can activate */
2835 if (cell_area->x <= ((GdkEventButton *)event)->x &&
2836 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
2839 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
2840 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
2841 /* only activate cell if the user clicked on an individual
2846 else if (special_cells > 1 && info->has_focus)
2848 else if (special_cells == 1)
2853 gboolean visible, mode;
2855 g_object_get (info->cell,
2856 "visible", &visible,
2859 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2861 if (gtk_cell_renderer_activate (info->cell,
2863 tree_column->tree_view,
2865 &rtl_background_area,
2869 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2873 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2876 gtk_cell_renderer_start_editing (info->cell,
2878 tree_column->tree_view,
2880 &rtl_background_area,
2884 if (*editable_widget != NULL)
2886 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2887 info->in_editing_mode = TRUE;
2888 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
2890 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2898 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2900 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
2901 real_background_area.x += real_background_area.width + tree_column->spacing;
2903 /* Only needed for first cell */
2907 /* iterate list for PACK_END cells */
2908 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
2910 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2912 if (info->pack == GTK_PACK_START)
2915 if (! info->cell->visible)
2918 if ((info->has_focus || special_cells == 1) && cursor_row)
2919 flags |= GTK_CELL_RENDERER_FOCUSED;
2921 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2923 info->real_width = info->requested_width + (info->expand?extra_space:0);
2925 /* We constrain ourselves to only the width available */
2926 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
2928 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
2931 if (real_cell_area.x > cell_area->x + cell_area->width)
2934 real_cell_area.width = info->real_width;
2935 real_cell_area.width -= 2 * focus_line_width;
2936 real_background_area.width = info->real_width + depth;
2938 rtl_cell_area = real_cell_area;
2939 rtl_background_area = real_background_area;
2942 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
2943 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
2947 if (action == CELL_ACTION_RENDER)
2949 gtk_cell_renderer_render (info->cell,
2951 tree_column->tree_view,
2952 &rtl_background_area,
2958 else if (action == CELL_ACTION_FOCUS)
2960 gint x_offset, y_offset, width, height;
2962 gtk_cell_renderer_get_size (info->cell,
2963 tree_column->tree_view,
2965 &x_offset, &y_offset,
2968 if (special_cells > 1)
2970 if (info->has_focus)
2972 min_x = rtl_cell_area.x + x_offset;
2973 max_x = min_x + width;
2974 min_y = rtl_cell_area.y + y_offset;
2975 max_y = min_y + height;
2980 if (min_x > (rtl_cell_area.x + x_offset))
2981 min_x = rtl_cell_area.x + x_offset;
2982 if (max_x < rtl_cell_area.x + x_offset + width)
2983 max_x = rtl_cell_area.x + x_offset + width;
2984 if (min_y > (rtl_cell_area.y + y_offset))
2985 min_y = rtl_cell_area.y + y_offset;
2986 if (max_y < rtl_cell_area.y + y_offset + height)
2987 max_y = rtl_cell_area.y + y_offset + height;
2991 else if (action == CELL_ACTION_EVENT)
2993 gboolean try_event = FALSE;
2997 if (special_cells == 1)
2999 /* only 1 activatable cell -> whole column can activate */
3000 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3001 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3004 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3005 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3006 /* only activate cell if the user clicked on an individual
3011 else if (special_cells > 1 && info->has_focus)
3013 else if (special_cells == 1)
3018 gboolean visible, mode;
3020 g_object_get (info->cell,
3021 "visible", &visible,
3024 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3026 if (gtk_cell_renderer_activate (info->cell,
3028 tree_column->tree_view,
3030 &rtl_background_area,
3034 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3038 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3041 gtk_cell_renderer_start_editing (info->cell,
3043 tree_column->tree_view,
3045 &rtl_background_area,
3049 if (*editable_widget != NULL)
3051 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3052 info->in_editing_mode = TRUE;
3053 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3055 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3062 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3064 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3065 real_background_area.x += (real_background_area.width + tree_column->spacing);
3067 /* Only needed for first cell */
3071 /* fill focus_rectangle when required */
3072 if (action == CELL_ACTION_FOCUS)
3074 if (min_x >= max_x || min_y >= max_y)
3076 *focus_rectangle = *cell_area;
3077 /* don't change the focus_rectangle, just draw it nicely inside
3082 focus_rectangle->x = min_x - focus_line_width;
3083 focus_rectangle->y = min_y - focus_line_width;
3084 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
3085 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
3093 * pspp_sheet_view_column_cell_render:
3094 * @tree_column: A #PsppSheetViewColumn.
3095 * @window: a #GdkDrawable to draw to
3096 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
3097 * @cell_area: area normally rendered by a cell renderer
3098 * @expose_area: area that actually needs updating
3099 * @flags: flags that affect rendering
3101 * Renders the cell contained by #tree_column. This is used primarily by the
3105 _pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
3107 const GdkRectangle *background_area,
3108 const GdkRectangle *cell_area,
3109 const GdkRectangle *expose_area,
3112 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3113 g_return_if_fail (background_area != NULL);
3114 g_return_if_fail (cell_area != NULL);
3115 g_return_if_fail (expose_area != NULL);
3117 pspp_sheet_view_column_cell_process_action (tree_column,
3124 NULL, NULL, NULL, NULL);
3128 _pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
3129 GtkCellEditable **editable_widget,
3132 const GdkRectangle *background_area,
3133 const GdkRectangle *cell_area,
3136 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3138 return pspp_sheet_view_column_cell_process_action (tree_column,
3151 _pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
3152 const GdkRectangle *background_area,
3153 const GdkRectangle *cell_area,
3154 GdkRectangle *focus_area)
3156 pspp_sheet_view_column_cell_process_action (tree_column,
3168 /* cell list manipulation */
3170 pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
3172 GList *list = tree_column->cell_list;
3174 /* first GTK_PACK_START cell we find */
3175 for ( ; list; list = list->next)
3177 PsppSheetViewColumnCellInfo *info = list->data;
3178 if (info->pack == GTK_PACK_START)
3182 /* hmm, else the *last* GTK_PACK_END cell */
3183 list = g_list_last (tree_column->cell_list);
3185 for ( ; list; list = list->prev)
3187 PsppSheetViewColumnCellInfo *info = list->data;
3188 if (info->pack == GTK_PACK_END)
3196 pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
3198 GList *list = tree_column->cell_list;
3200 /* *first* GTK_PACK_END cell we find */
3201 for ( ; list ; list = list->next)
3203 PsppSheetViewColumnCellInfo *info = list->data;
3204 if (info->pack == GTK_PACK_END)
3208 /* hmm, else the last GTK_PACK_START cell */
3209 list = g_list_last (tree_column->cell_list);
3211 for ( ; list; list = list->prev)
3213 PsppSheetViewColumnCellInfo *info = list->data;
3214 if (info->pack == GTK_PACK_START)
3222 pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
3226 PsppSheetViewColumnCellInfo *info = current->data;
3228 if (info->pack == GTK_PACK_START)
3230 for (list = current->next; list; list = list->next)
3232 PsppSheetViewColumnCellInfo *inf = list->data;
3233 if (inf->pack == GTK_PACK_START)
3237 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
3238 list = g_list_last (tree_column->cell_list);
3239 for (; list; list = list->prev)
3241 PsppSheetViewColumnCellInfo *inf = list->data;
3242 if (inf->pack == GTK_PACK_END)
3247 for (list = current->prev; list; list = list->prev)
3249 PsppSheetViewColumnCellInfo *inf = list->data;
3250 if (inf->pack == GTK_PACK_END)
3258 pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
3262 PsppSheetViewColumnCellInfo *info = current->data;
3264 if (info->pack == GTK_PACK_END)
3266 for (list = current->next; list; list = list->next)
3268 PsppSheetViewColumnCellInfo *inf = list->data;
3269 if (inf->pack == GTK_PACK_END)
3273 /* out of GTK_PACK_END, get last GTK_PACK_START one */
3274 list = g_list_last (tree_column->cell_list);
3275 for ( ; list; list = list->prev)
3277 PsppSheetViewColumnCellInfo *inf = list->data;
3278 if (inf->pack == GTK_PACK_START)
3283 for (list = current->prev; list; list = list->prev)
3285 PsppSheetViewColumnCellInfo *inf = list->data;
3286 if (inf->pack == GTK_PACK_START)
3294 _pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
3302 count = _pspp_sheet_view_column_count_special_cells (tree_column);
3303 rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
3305 /* if we are the current focus column and have multiple editable cells,
3306 * try to select the next one, else move the focus to the next column
3308 if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
3313 GList *list = tree_column->cell_list;
3314 PsppSheetViewColumnCellInfo *info = NULL;
3316 /* find current focussed cell */
3317 for ( ; list; list = list->next)
3320 if (info->has_focus)
3324 /* not a focussed cell in the focus column? */
3325 if (!list || !info || !info->has_focus)
3330 prev = pspp_sheet_view_column_cell_next (tree_column, list);
3331 next = pspp_sheet_view_column_cell_prev (tree_column, list);
3335 next = pspp_sheet_view_column_cell_next (tree_column, list);
3336 prev = pspp_sheet_view_column_cell_prev (tree_column, list);
3339 info->has_focus = FALSE;
3340 if (direction > 0 && next)
3343 info->has_focus = TRUE;
3346 else if (direction > 0 && !next && !right)
3348 /* keep focus on last cell */
3350 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3352 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3354 info->has_focus = TRUE;
3357 else if (direction < 0 && prev)
3360 info->has_focus = TRUE;
3363 else if (direction < 0 && !prev && !left)
3365 /* keep focus on first cell */
3367 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3369 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3371 info->has_focus = TRUE;
3378 /* we get focus, if we have multiple editable cells, give the correct one
3383 GList *list = tree_column->cell_list;
3385 /* clear focus first */
3386 for ( ; list ; list = list->next)
3388 PsppSheetViewColumnCellInfo *info = list->data;
3389 if (info->has_focus)
3390 info->has_focus = FALSE;
3397 list = pspp_sheet_view_column_cell_last (tree_column);
3398 else if (direction < 0)
3399 list = pspp_sheet_view_column_cell_first (tree_column);
3404 list = pspp_sheet_view_column_cell_first (tree_column);
3405 else if (direction < 0)
3406 list = pspp_sheet_view_column_cell_last (tree_column);
3410 ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
3417 _pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
3419 const GdkRectangle *background_area,
3420 const GdkRectangle *cell_area,
3421 const GdkRectangle *expose_area,
3424 gint focus_line_width;
3425 GtkStateType cell_state;
3427 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3428 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3429 "focus-line-width", &focus_line_width, NULL);
3430 if (tree_column->editable_widget)
3432 /* This function is only called on the editable row when editing.
3435 gtk_paint_focus (tree_column->tree_view->style,
3437 gtk_widget_get_state (tree_column->tree_view),
3439 tree_column->tree_view,
3441 cell_area->x - focus_line_width,
3442 cell_area->y - focus_line_width,
3443 cell_area->width + 2 * focus_line_width,
3444 cell_area->height + 2 * focus_line_width);
3449 GdkRectangle focus_rectangle;
3450 pspp_sheet_view_column_cell_process_action (tree_column,
3460 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3461 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3462 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3463 gtk_paint_focus (tree_column->tree_view->style,
3467 tree_column->tree_view,
3471 focus_rectangle.width,
3472 focus_rectangle.height);
3477 * pspp_sheet_view_column_cell_is_visible:
3478 * @tree_column: A #PsppSheetViewColumn
3480 * Returns %TRUE if any of the cells packed into the @tree_column are visible.
3481 * For this to be meaningful, you must first initialize the cells with
3482 * pspp_sheet_view_column_cell_set_cell_data()
3484 * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
3487 pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
3491 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3493 for (list = tree_column->cell_list; list; list = list->next)
3495 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3497 if (info->cell->visible)
3505 * pspp_sheet_view_column_focus_cell:
3506 * @tree_column: A #PsppSheetViewColumn
3507 * @cell: A #GtkCellRenderer
3509 * Sets the current keyboard focus to be at @cell, if the column contains
3510 * 2 or more editable and activatable cells.
3515 pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
3516 GtkCellRenderer *cell)
3519 gboolean found_cell = FALSE;
3521 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3522 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3524 if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
3527 for (list = tree_column->cell_list; list; list = list->next)
3529 PsppSheetViewColumnCellInfo *info = list->data;
3531 if (info->cell == cell)
3533 info->has_focus = TRUE;
3541 for (list = tree_column->cell_list; list; list = list->next)
3543 PsppSheetViewColumnCellInfo *info = list->data;
3545 if (info->cell != cell)
3546 info->has_focus = FALSE;
3549 /* FIXME: redraw? */
3554 _pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
3558 for (list = tree_column->cell_list; list; list = list->next)
3560 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3562 info->requested_width = 0;
3564 tree_column->dirty = TRUE;
3565 tree_column->requested_width = -1;
3566 tree_column->width = 0;
3568 if (tree_column->tree_view &&
3569 gtk_widget_get_realized (tree_column->tree_view))
3571 _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
3572 gtk_widget_queue_resize (tree_column->tree_view);
3577 _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
3578 GtkCellEditable *cell_editable)
3580 g_return_if_fail (tree_column->editable_widget == NULL);
3582 tree_column->editable_widget = cell_editable;
3586 _pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
3590 g_return_if_fail (tree_column->editable_widget != NULL);
3592 tree_column->editable_widget = NULL;
3593 for (list = tree_column->cell_list; list; list = list->next)
3594 ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
3598 _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
3599 GtkCellRenderer *cell,
3604 PsppSheetViewColumnCellInfo *info;
3610 list = pspp_sheet_view_column_cell_first (column);
3614 info = (PsppSheetViewColumnCellInfo *)list->data;
3616 list = pspp_sheet_view_column_cell_next (column, list);
3618 if (info->cell == cell)
3621 if (info->cell->visible)
3622 l += info->real_width + column->spacing;
3627 info = (PsppSheetViewColumnCellInfo *)list->data;
3629 list = pspp_sheet_view_column_cell_next (column, list);
3631 if (info->cell->visible)
3632 r += info->real_width + column->spacing;
3635 rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
3637 *left = rtl ? r : l;
3640 *right = rtl ? l : r;
3644 * pspp_sheet_view_column_cell_get_position:
3645 * @tree_column: a #PsppSheetViewColumn
3646 * @cell_renderer: a #GtkCellRenderer
3647 * @start_pos: return location for the horizontal position of @cell within
3648 * @tree_column, may be %NULL
3649 * @width: return location for the width of @cell, may be %NULL
3651 * Obtains the horizontal position and size of a cell in a column. If the
3652 * cell is not found in the column, @start_pos and @width are not changed and
3653 * %FALSE is returned.
3655 * Return value: %TRUE if @cell belongs to @tree_column.
3658 pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
3659 GtkCellRenderer *cell_renderer,
3665 gboolean found_cell = FALSE;
3666 PsppSheetViewColumnCellInfo *cellinfo = NULL;
3668 list = pspp_sheet_view_column_cell_first (tree_column);
3669 for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
3671 cellinfo = list->data;
3672 if (cellinfo->cell == cell_renderer)
3678 if (cellinfo->cell->visible)
3679 current_x += cellinfo->real_width;
3685 *start_pos = current_x;
3687 *width = cellinfo->real_width;
3694 * pspp_sheet_view_column_queue_resize:
3695 * @tree_column: A #PsppSheetViewColumn
3697 * Flags the column, and the cell renderers added to this column, to have
3698 * their sizes renegotiated.
3703 pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
3705 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3707 if (tree_column->tree_view)
3708 _pspp_sheet_view_column_cell_set_dirty (tree_column);
3712 * pspp_sheet_view_column_get_tree_view:
3713 * @tree_column: A #PsppSheetViewColumn
3715 * Returns the #PsppSheetView wherein @tree_column has been inserted. If
3716 * @column is currently not inserted in any tree view, %NULL is
3719 * Return value: The tree view wherein @column has been inserted if any,
3725 pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
3727 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
3729 return tree_column->tree_view;
3733 GtkCellLayout *cell_layout;
3734 GtkCellRenderer *renderer;
3736 } AttributesSubParserData;
3739 attributes_start_element (GMarkupParseContext *context,
3740 const gchar *element_name,
3741 const gchar **names,
3742 const gchar **values,
3746 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
3749 if (strcmp (element_name, "attribute") == 0)
3751 for (i = 0; names[i]; i++)
3752 if (strcmp (names[i], "name") == 0)
3753 parser_data->attr_name = g_strdup (values[i]);
3755 else if (strcmp (element_name, "attributes") == 0)
3758 g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
3762 attributes_text_element (GMarkupParseContext *context,
3768 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
3773 if (!parser_data->attr_name)
3777 string = g_strndup (text, text_len);
3778 l = strtol (string, &endptr, 0);
3779 if (errno || endptr == string)
3783 GTK_BUILDER_ERROR_INVALID_VALUE,
3784 "Could not parse integer `%s'",
3791 gtk_cell_layout_add_attribute (parser_data->cell_layout,
3792 parser_data->renderer,
3793 parser_data->attr_name, l);
3794 g_free (parser_data->attr_name);
3795 parser_data->attr_name = NULL;
3798 static const GMarkupParser attributes_parser =
3800 attributes_start_element,
3802 attributes_text_element,
3806 _gtk_cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
3807 GtkBuilder *builder,
3809 const gchar *tagname,
3810 GMarkupParser *parser,
3813 AttributesSubParserData *parser_data;
3818 if (strcmp (tagname, "attributes") == 0)
3820 parser_data = g_slice_new0 (AttributesSubParserData);
3821 parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
3822 parser_data->renderer = GTK_CELL_RENDERER (child);
3823 parser_data->attr_name = NULL;
3825 *parser = attributes_parser;
3826 *data = parser_data;
3834 _gtk_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
3835 GtkBuilder *builder,
3837 const gchar *tagname,
3840 AttributesSubParserData *parser_data;
3842 parser_data = (AttributesSubParserData*)data;
3843 g_assert (!parser_data->attr_name);
3844 g_slice_free (AttributesSubParserData, parser_data);
3848 _gtk_cell_layout_buildable_add_child (GtkBuildable *buildable,
3849 GtkBuilder *builder,
3853 GtkCellLayoutIface *iface;
3855 g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
3856 g_return_if_fail (GTK_IS_CELL_RENDERER (child));
3858 iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
3859 g_return_if_fail (iface->pack_start != NULL);
3860 iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);