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
78 typedef struct _PsppSheetViewColumnCellInfo PsppSheetViewColumnCellInfo;
79 struct _PsppSheetViewColumnCellInfo
81 GtkCellRenderer *cell;
83 PsppSheetCellDataFunc func;
85 GDestroyNotify destroy;
91 guint in_editing_mode : 1;
95 static void pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface);
98 static void pspp_sheet_view_column_set_property (GObject *object,
102 static void pspp_sheet_view_column_get_property (GObject *object,
106 static void pspp_sheet_view_column_finalize (GObject *object);
108 /* GtkCellLayout implementation */
109 static void pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
110 GtkCellRenderer *cell,
112 static void pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
113 GtkCellRenderer *cell,
115 static void pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout);
116 static void pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
117 GtkCellRenderer *cell,
118 const gchar *attribute,
120 static void pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
121 GtkCellRenderer *cell,
122 GtkCellLayoutDataFunc func,
124 GDestroyNotify destroy);
125 static void pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
126 GtkCellRenderer *cell);
127 static void pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
128 GtkCellRenderer *cell,
130 static GList *pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
132 /* Button handling code */
133 static void pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column);
134 static void pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
136 /* Button signal handlers */
137 static gint pspp_sheet_view_column_button_event (GtkWidget *widget,
140 static void pspp_sheet_view_column_button_clicked (GtkWidget *widget,
142 static gboolean pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
143 gboolean group_cycling,
146 /* Property handlers */
147 static void pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
148 PsppSheetViewColumn *tree_column);
150 /* Internal functions */
151 static void pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
153 static void pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column);
154 static void pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
155 GtkCellRenderer *cell_renderer,
157 static PsppSheetViewColumnCellInfo *pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
158 GtkCellRenderer *cell_renderer);
160 /* cell list manipulation */
161 static GList *pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column);
162 static GList *pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column);
163 static GList *pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
165 static GList *pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
167 static void pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
168 PsppSheetViewColumnCellInfo *info);
169 /* GtkBuildable implementation */
170 static void pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface);
172 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
174 G_DEFINE_TYPE_WITH_CODE (PsppSheetViewColumn, pspp_sheet_view_column, GTK_TYPE_OBJECT,
175 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
176 pspp_sheet_view_column_cell_layout_init)
177 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
178 pspp_sheet_view_column_buildable_init))
182 pspp_sheet_view_column_class_init (PsppSheetViewColumnClass *class)
184 GObjectClass *object_class;
186 object_class = (GObjectClass*) class;
188 class->clicked = NULL;
190 object_class->finalize = pspp_sheet_view_column_finalize;
191 object_class->set_property = pspp_sheet_view_column_set_property;
192 object_class->get_property = pspp_sheet_view_column_get_property;
194 tree_column_signals[CLICKED] =
195 g_signal_new ("clicked",
196 G_OBJECT_CLASS_TYPE (object_class),
198 G_STRUCT_OFFSET (PsppSheetViewColumnClass, clicked),
200 g_cclosure_marshal_VOID__VOID,
203 g_object_class_install_property (object_class,
205 g_param_spec_boolean ("visible",
207 P_("Whether to display the column"),
209 GTK_PARAM_READWRITE));
211 g_object_class_install_property (object_class,
213 g_param_spec_boolean ("resizable",
215 P_("Column is user-resizable"),
217 GTK_PARAM_READWRITE));
219 g_object_class_install_property (object_class,
221 g_param_spec_int ("width",
223 P_("Current width of the column"),
227 GTK_PARAM_READABLE));
228 g_object_class_install_property (object_class,
230 g_param_spec_int ("spacing",
232 P_("Space which is inserted between cells"),
236 GTK_PARAM_READWRITE));
238 g_object_class_install_property (object_class,
240 g_param_spec_int ("fixed-width",
242 P_("Current fixed width of the column"),
246 GTK_PARAM_READWRITE));
248 g_object_class_install_property (object_class,
250 g_param_spec_int ("min-width",
252 P_("Minimum allowed width of the column"),
256 GTK_PARAM_READWRITE));
258 g_object_class_install_property (object_class,
260 g_param_spec_int ("max-width",
262 P_("Maximum allowed width of the column"),
266 GTK_PARAM_READWRITE));
268 g_object_class_install_property (object_class,
270 g_param_spec_string ("title",
272 P_("Title to appear in column header"),
274 GTK_PARAM_READWRITE));
276 g_object_class_install_property (object_class,
278 g_param_spec_boolean ("expand",
280 P_("Column gets share of extra width allocated to the widget"),
282 GTK_PARAM_READWRITE));
284 g_object_class_install_property (object_class,
286 g_param_spec_boolean ("clickable",
288 P_("Whether the header can be clicked"),
290 GTK_PARAM_READWRITE));
293 g_object_class_install_property (object_class,
295 g_param_spec_object ("widget",
297 P_("Widget to put in column header button instead of column title"),
299 GTK_PARAM_READWRITE));
301 g_object_class_install_property (object_class,
303 g_param_spec_float ("alignment",
305 P_("X Alignment of the column header text or widget"),
309 GTK_PARAM_READWRITE));
311 g_object_class_install_property (object_class,
313 g_param_spec_boolean ("reorderable",
315 P_("Whether the column can be reordered around the headers"),
317 GTK_PARAM_READWRITE));
319 g_object_class_install_property (object_class,
321 g_param_spec_boolean ("sort-indicator",
322 P_("Sort indicator"),
323 P_("Whether to show a sort indicator"),
325 GTK_PARAM_READWRITE));
327 g_object_class_install_property (object_class,
329 g_param_spec_enum ("sort-order",
331 P_("Sort direction the sort indicator should indicate"),
334 GTK_PARAM_READWRITE));
337 * PsppSheetViewColumn:sort-column-id:
339 * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
340 * clickable. Set to %-1 to make the column unsortable.
344 g_object_class_install_property (object_class,
346 g_param_spec_int ("sort-column-id",
347 P_("Sort column ID"),
348 P_("Logical sort column ID this column sorts on when selected for sorting"),
352 GTK_PARAM_READWRITE));
356 pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface)
358 iface->add_child = _gtk_cell_layout_buildable_add_child;
359 iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
360 iface->custom_tag_end = _gtk_cell_layout_buildable_custom_tag_end;
364 pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface)
366 iface->pack_start = pspp_sheet_view_column_cell_layout_pack_start;
367 iface->pack_end = pspp_sheet_view_column_cell_layout_pack_end;
368 iface->clear = pspp_sheet_view_column_cell_layout_clear;
369 iface->add_attribute = pspp_sheet_view_column_cell_layout_add_attribute;
370 iface->set_cell_data_func = pspp_sheet_view_column_cell_layout_set_cell_data_func;
371 iface->clear_attributes = pspp_sheet_view_column_cell_layout_clear_attributes;
372 iface->reorder = pspp_sheet_view_column_cell_layout_reorder;
373 iface->get_cells = pspp_sheet_view_column_cell_layout_get_cells;
377 pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column)
379 tree_column->button = NULL;
380 tree_column->xalign = 0.0;
381 tree_column->width = 0;
382 tree_column->spacing = 0;
383 tree_column->requested_width = -1;
384 tree_column->min_width = -1;
385 tree_column->max_width = -1;
386 tree_column->resized_width = 0;
387 tree_column->visible = TRUE;
388 tree_column->resizable = FALSE;
389 tree_column->expand = FALSE;
390 tree_column->clickable = FALSE;
391 tree_column->dirty = TRUE;
392 tree_column->sort_order = GTK_SORT_ASCENDING;
393 tree_column->show_sort_indicator = FALSE;
394 tree_column->property_changed_signal = 0;
395 tree_column->sort_clicked_signal = 0;
396 tree_column->sort_column_changed_signal = 0;
397 tree_column->sort_column_id = -1;
398 tree_column->reorderable = FALSE;
399 tree_column->maybe_reordered = FALSE;
400 tree_column->fixed_width = 1;
401 tree_column->use_resized_width = FALSE;
402 tree_column->title = g_strdup ("");
406 pspp_sheet_view_column_finalize (GObject *object)
408 PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
411 for (list = tree_column->cell_list; list; list = list->next)
413 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
417 GDestroyNotify d = info->destroy;
419 info->destroy = NULL;
422 pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
423 g_object_unref (info->cell);
427 g_free (tree_column->title);
428 g_list_free (tree_column->cell_list);
430 if (tree_column->child)
431 g_object_unref (tree_column->child);
433 G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
437 pspp_sheet_view_column_set_property (GObject *object,
442 PsppSheetViewColumn *tree_column;
444 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
449 pspp_sheet_view_column_set_visible (tree_column,
450 g_value_get_boolean (value));
454 pspp_sheet_view_column_set_resizable (tree_column,
455 g_value_get_boolean (value));
458 case PROP_FIXED_WIDTH:
459 pspp_sheet_view_column_set_fixed_width (tree_column,
460 g_value_get_int (value));
464 pspp_sheet_view_column_set_min_width (tree_column,
465 g_value_get_int (value));
469 pspp_sheet_view_column_set_max_width (tree_column,
470 g_value_get_int (value));
474 pspp_sheet_view_column_set_spacing (tree_column,
475 g_value_get_int (value));
479 pspp_sheet_view_column_set_title (tree_column,
480 g_value_get_string (value));
484 pspp_sheet_view_column_set_expand (tree_column,
485 g_value_get_boolean (value));
489 pspp_sheet_view_column_set_clickable (tree_column,
490 g_value_get_boolean (value));
494 pspp_sheet_view_column_set_widget (tree_column,
495 (GtkWidget*) g_value_get_object (value));
499 pspp_sheet_view_column_set_alignment (tree_column,
500 g_value_get_float (value));
503 case PROP_REORDERABLE:
504 pspp_sheet_view_column_set_reorderable (tree_column,
505 g_value_get_boolean (value));
508 case PROP_SORT_INDICATOR:
509 pspp_sheet_view_column_set_sort_indicator (tree_column,
510 g_value_get_boolean (value));
513 case PROP_SORT_ORDER:
514 pspp_sheet_view_column_set_sort_order (tree_column,
515 g_value_get_enum (value));
518 case PROP_SORT_COLUMN_ID:
519 pspp_sheet_view_column_set_sort_column_id (tree_column,
520 g_value_get_int (value));
524 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
530 pspp_sheet_view_column_get_property (GObject *object,
535 PsppSheetViewColumn *tree_column;
537 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
542 g_value_set_boolean (value,
543 pspp_sheet_view_column_get_visible (tree_column));
547 g_value_set_boolean (value,
548 pspp_sheet_view_column_get_resizable (tree_column));
552 g_value_set_int (value,
553 pspp_sheet_view_column_get_width (tree_column));
557 g_value_set_int (value,
558 pspp_sheet_view_column_get_spacing (tree_column));
561 case PROP_FIXED_WIDTH:
562 g_value_set_int (value,
563 pspp_sheet_view_column_get_fixed_width (tree_column));
567 g_value_set_int (value,
568 pspp_sheet_view_column_get_min_width (tree_column));
572 g_value_set_int (value,
573 pspp_sheet_view_column_get_max_width (tree_column));
577 g_value_set_string (value,
578 pspp_sheet_view_column_get_title (tree_column));
582 g_value_set_boolean (value,
583 pspp_sheet_view_column_get_expand (tree_column));
587 g_value_set_boolean (value,
588 pspp_sheet_view_column_get_clickable (tree_column));
592 g_value_set_object (value,
593 (GObject*) pspp_sheet_view_column_get_widget (tree_column));
597 g_value_set_float (value,
598 pspp_sheet_view_column_get_alignment (tree_column));
601 case PROP_REORDERABLE:
602 g_value_set_boolean (value,
603 pspp_sheet_view_column_get_reorderable (tree_column));
606 case PROP_SORT_INDICATOR:
607 g_value_set_boolean (value,
608 pspp_sheet_view_column_get_sort_indicator (tree_column));
611 case PROP_SORT_ORDER:
612 g_value_set_enum (value,
613 pspp_sheet_view_column_get_sort_order (tree_column));
616 case PROP_SORT_COLUMN_ID:
617 g_value_set_int (value,
618 pspp_sheet_view_column_get_sort_column_id (tree_column));
622 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
627 /* Implementation of GtkCellLayout interface
631 pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
632 GtkCellRenderer *cell,
635 PsppSheetViewColumn *column;
636 PsppSheetViewColumnCellInfo *cell_info;
638 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
639 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
640 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
642 g_object_ref_sink (cell);
644 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
645 cell_info->cell = cell;
646 cell_info->expand = expand ? TRUE : FALSE;
647 cell_info->pack = GTK_PACK_START;
648 cell_info->has_focus = 0;
649 cell_info->attributes = NULL;
651 column->cell_list = g_list_append (column->cell_list, cell_info);
655 pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
656 GtkCellRenderer *cell,
659 PsppSheetViewColumn *column;
660 PsppSheetViewColumnCellInfo *cell_info;
662 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
663 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
664 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
666 g_object_ref_sink (cell);
668 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
669 cell_info->cell = cell;
670 cell_info->expand = expand ? TRUE : FALSE;
671 cell_info->pack = GTK_PACK_END;
672 cell_info->has_focus = 0;
673 cell_info->attributes = NULL;
675 column->cell_list = g_list_append (column->cell_list, cell_info);
679 pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
681 PsppSheetViewColumn *column;
683 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
684 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
686 while (column->cell_list)
688 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
690 pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
691 g_object_unref (info->cell);
693 column->cell_list = g_list_delete_link (column->cell_list,
699 pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
700 GtkCellRenderer *cell,
701 const gchar *attribute,
704 PsppSheetViewColumn *tree_column;
705 PsppSheetViewColumnCellInfo *info;
707 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
708 tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
710 info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
711 g_return_if_fail (info != NULL);
713 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
714 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
716 if (tree_column->tree_view)
717 _pspp_sheet_view_column_cell_set_dirty (tree_column);
721 pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
722 GtkCellRenderer *cell,
723 GtkCellLayoutDataFunc func,
725 GDestroyNotify destroy)
727 PsppSheetViewColumn *column;
728 PsppSheetViewColumnCellInfo *info;
730 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
731 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
733 info = pspp_sheet_view_column_get_cell_info (column, cell);
734 g_return_if_fail (info != NULL);
738 GDestroyNotify d = info->destroy;
740 info->destroy = NULL;
744 info->func = (PsppSheetCellDataFunc)func;
745 info->func_data = func_data;
746 info->destroy = destroy;
748 if (column->tree_view)
749 _pspp_sheet_view_column_cell_set_dirty (column);
753 pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
754 GtkCellRenderer *cell_renderer)
756 PsppSheetViewColumn *column;
757 PsppSheetViewColumnCellInfo *info;
759 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
760 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
762 info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
764 pspp_sheet_view_column_clear_attributes_by_info (column, info);
768 pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
769 GtkCellRenderer *cell,
773 PsppSheetViewColumn *column;
774 PsppSheetViewColumnCellInfo *info;
776 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
777 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
779 info = pspp_sheet_view_column_get_cell_info (column, cell);
781 g_return_if_fail (info != NULL);
782 g_return_if_fail (position >= 0);
784 link = g_list_find (column->cell_list, info);
786 g_return_if_fail (link != NULL);
788 column->cell_list = g_list_delete_link (column->cell_list, link);
789 column->cell_list = g_list_insert (column->cell_list, info, position);
791 if (column->tree_view)
792 gtk_widget_queue_draw (column->tree_view);
796 pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
797 PsppSheetViewColumnCellInfo *info)
801 list = info->attributes;
803 while (list && list->next)
806 list = list->next->next;
808 g_slist_free (info->attributes);
809 info->attributes = NULL;
811 if (tree_column->tree_view)
812 _pspp_sheet_view_column_cell_set_dirty (tree_column);
818 /* Button handling code
821 pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
823 PsppSheetView *tree_view;
827 tree_view = (PsppSheetView *) tree_column->tree_view;
829 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
830 g_return_if_fail (tree_column->button == NULL);
832 gtk_widget_push_composite_child ();
833 tree_column->button = gtk_button_new ();
834 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
835 gtk_widget_pop_composite_child ();
837 /* make sure we own a reference to it as well. */
838 if (tree_view->priv->header_window)
839 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
840 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
842 g_signal_connect (tree_column->button, "event",
843 G_CALLBACK (pspp_sheet_view_column_button_event),
845 g_signal_connect (tree_column->button, "clicked",
846 G_CALLBACK (pspp_sheet_view_column_button_clicked),
849 tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
851 hbox = gtk_hbox_new (FALSE, 2);
852 tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
854 if (tree_column->child)
855 child = tree_column->child;
858 child = gtk_label_new (tree_column->title);
859 gtk_widget_show (child);
862 g_signal_connect (child, "mnemonic-activate",
863 G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
866 if (tree_column->xalign <= 0.5)
867 gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
869 gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
871 gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
873 gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
874 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
876 gtk_widget_show (hbox);
877 gtk_widget_show (tree_column->alignment);
878 pspp_sheet_view_column_update_button (tree_column);
882 pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
884 gint sort_column_id = -1;
886 GtkWidget *alignment;
888 GtkWidget *current_child;
889 GtkArrowType arrow_type = GTK_ARROW_NONE;
892 if (tree_column->tree_view)
893 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
897 /* Create a button if necessary */
898 if (tree_column->visible &&
899 tree_column->button == NULL &&
900 tree_column->tree_view &&
901 gtk_widget_get_realized (tree_column->tree_view))
902 pspp_sheet_view_column_create_button (tree_column);
904 if (! tree_column->button)
907 hbox = GTK_BIN (tree_column->button)->child;
908 alignment = tree_column->alignment;
909 arrow = tree_column->arrow;
910 current_child = GTK_BIN (alignment)->child;
912 /* Set up the actual button */
913 gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
916 if (tree_column->child)
918 if (current_child != tree_column->child)
920 gtk_container_remove (GTK_CONTAINER (alignment),
922 gtk_container_add (GTK_CONTAINER (alignment),
928 if (current_child == NULL)
930 current_child = gtk_label_new (NULL);
931 gtk_widget_show (current_child);
932 gtk_container_add (GTK_CONTAINER (alignment),
936 g_return_if_fail (GTK_IS_LABEL (current_child));
938 if (tree_column->title)
939 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
942 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
946 if (GTK_IS_TREE_SORTABLE (model))
947 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
951 if (tree_column->show_sort_indicator)
953 gboolean alternative;
955 g_object_get (gtk_widget_get_settings (tree_column->tree_view),
956 "gtk-alternative-sort-arrows", &alternative,
959 switch (tree_column->sort_order)
961 case GTK_SORT_ASCENDING:
962 arrow_type = alternative ? GTK_ARROW_UP : GTK_ARROW_DOWN;
965 case GTK_SORT_DESCENDING:
966 arrow_type = alternative ? GTK_ARROW_DOWN : GTK_ARROW_UP;
970 g_warning (G_STRLOC": bad sort order");
975 gtk_arrow_set (GTK_ARROW (arrow),
979 /* Put arrow on the right if the text is left-or-center justified, and on the
980 * left otherwise; do this by packing boxes, so flipping text direction will
983 g_object_ref (arrow);
984 gtk_container_remove (GTK_CONTAINER (hbox), arrow);
986 if (tree_column->xalign <= 0.5)
988 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
992 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
993 /* move it to the front */
994 gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
996 g_object_unref (arrow);
998 if (tree_column->show_sort_indicator
999 || (GTK_IS_TREE_SORTABLE (model) && tree_column->sort_column_id >= 0))
1000 gtk_widget_show (arrow);
1002 gtk_widget_hide (arrow);
1004 /* It's always safe to hide the button. It isn't always safe to show it, as
1005 * if you show it before it's realized, it'll get the wrong window. */
1006 if (tree_column->button &&
1007 tree_column->tree_view != NULL &&
1008 gtk_widget_get_realized (tree_column->tree_view))
1010 if (tree_column->visible)
1012 gtk_widget_show_now (tree_column->button);
1013 if (tree_column->window)
1015 if (tree_column->resizable)
1017 gdk_window_show (tree_column->window);
1018 gdk_window_raise (tree_column->window);
1022 gdk_window_hide (tree_column->window);
1028 gtk_widget_hide (tree_column->button);
1029 if (tree_column->window)
1030 gdk_window_hide (tree_column->window);
1034 if (tree_column->reorderable || tree_column->clickable)
1036 gtk_widget_set_can_focus (tree_column->button, TRUE);
1040 gtk_widget_set_can_focus (tree_column->button, FALSE);
1041 if (gtk_widget_has_focus (tree_column->button))
1043 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
1044 if (gtk_widget_is_toplevel (toplevel))
1046 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
1050 /* Queue a resize on the assumption that we always want to catch all changes
1051 * and columns don't change all that often.
1053 if (gtk_widget_get_realized (tree_column->tree_view))
1054 gtk_widget_queue_resize (tree_column->tree_view);
1058 /* Button signal handlers
1062 pspp_sheet_view_column_button_event (GtkWidget *widget,
1066 PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
1068 g_return_val_if_fail (event != NULL, FALSE);
1070 if (event->type == GDK_BUTTON_PRESS &&
1071 column->reorderable &&
1072 ((GdkEventButton *)event)->button == 1)
1074 column->maybe_reordered = TRUE;
1075 gdk_window_get_pointer (GTK_BUTTON (widget)->event_window,
1079 gtk_widget_grab_focus (widget);
1082 if (event->type == GDK_BUTTON_RELEASE ||
1083 event->type == GDK_LEAVE_NOTIFY)
1084 column->maybe_reordered = FALSE;
1086 if (event->type == GDK_MOTION_NOTIFY &&
1087 column->maybe_reordered &&
1088 (gtk_drag_check_threshold (widget,
1091 (gint) ((GdkEventMotion *)event)->x,
1092 (gint) ((GdkEventMotion *)event)->y)))
1094 column->maybe_reordered = FALSE;
1095 _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
1098 if (column->clickable == FALSE)
1100 switch (event->type)
1102 case GDK_BUTTON_PRESS:
1103 case GDK_2BUTTON_PRESS:
1104 case GDK_3BUTTON_PRESS:
1105 case GDK_MOTION_NOTIFY:
1106 case GDK_BUTTON_RELEASE:
1107 case GDK_ENTER_NOTIFY:
1108 case GDK_LEAVE_NOTIFY:
1119 pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
1121 g_signal_emit_by_name (data, "clicked");
1125 pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
1126 gboolean group_cycling,
1129 PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
1131 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
1133 PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
1134 if (column->clickable)
1135 gtk_button_clicked (GTK_BUTTON (column->button));
1136 else if (gtk_widget_get_can_focus (column->button))
1137 gtk_widget_grab_focus (column->button);
1139 gtk_widget_grab_focus (column->tree_view);
1145 pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
1146 PsppSheetViewColumn *column)
1148 gint sort_column_id;
1151 if (gtk_tree_sortable_get_sort_column_id (sortable,
1155 if (sort_column_id == column->sort_column_id)
1157 pspp_sheet_view_column_set_sort_indicator (column, TRUE);
1158 pspp_sheet_view_column_set_sort_order (column, order);
1162 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1167 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1172 pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
1175 gint sort_column_id;
1177 gboolean has_sort_column;
1178 gboolean has_default_sort_func;
1180 g_return_if_fail (tree_column->tree_view != NULL);
1183 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1186 has_default_sort_func =
1187 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
1189 if (has_sort_column &&
1190 sort_column_id == tree_column->sort_column_id)
1192 if (order == GTK_SORT_ASCENDING)
1193 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1194 tree_column->sort_column_id,
1195 GTK_SORT_DESCENDING);
1196 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
1197 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1198 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1199 GTK_SORT_ASCENDING);
1201 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1202 tree_column->sort_column_id,
1203 GTK_SORT_ASCENDING);
1207 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1208 tree_column->sort_column_id,
1209 GTK_SORT_ASCENDING);
1215 pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
1217 GtkTreeModel *model;
1219 if (tree_column->tree_view == NULL)
1222 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1227 if (GTK_IS_TREE_SORTABLE (model) &&
1228 tree_column->sort_column_id != -1)
1230 gint real_sort_column_id;
1231 GtkSortType real_order;
1233 if (tree_column->sort_column_changed_signal == 0)
1234 tree_column->sort_column_changed_signal =
1235 g_signal_connect (model, "sort-column-changed",
1236 G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
1239 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1240 &real_sort_column_id,
1242 (real_sort_column_id == tree_column->sort_column_id))
1244 pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
1245 pspp_sheet_view_column_set_sort_order (tree_column, real_order);
1249 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
1255 /* Exported Private Functions.
1256 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1260 _pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
1262 PsppSheetView *tree_view;
1264 guint attributes_mask;
1267 tree_view = (PsppSheetView *)column->tree_view;
1268 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
1270 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1271 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
1272 g_return_if_fail (tree_view->priv->header_window != NULL);
1273 g_return_if_fail (column->button != NULL);
1275 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
1277 if (column->visible)
1278 gtk_widget_show (column->button);
1280 attr.window_type = GDK_WINDOW_CHILD;
1281 attr.wclass = GDK_INPUT_ONLY;
1282 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1283 attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1284 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
1285 (GDK_BUTTON_PRESS_MASK |
1286 GDK_BUTTON_RELEASE_MASK |
1287 GDK_POINTER_MOTION_MASK |
1288 GDK_POINTER_MOTION_HINT_MASK |
1289 GDK_KEY_PRESS_MASK);
1290 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
1291 attr.cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (tree_view->priv->header_window),
1292 GDK_SB_H_DOUBLE_ARROW);
1294 attr.width = TREE_VIEW_DRAG_WIDTH;
1295 attr.height = tree_view->priv->header_height;
1297 attr.x = (column->button->allocation.x + (rtl ? 0 : column->button->allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
1298 column->window = gdk_window_new (tree_view->priv->header_window,
1299 &attr, attributes_mask);
1300 gdk_window_set_user_data (column->window, tree_view);
1302 pspp_sheet_view_column_update_button (column);
1304 gdk_cursor_unref (attr.cursor);
1308 _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
1310 g_return_if_fail (column != NULL);
1311 g_return_if_fail (column->window != NULL);
1313 gdk_window_set_user_data (column->window, NULL);
1314 gdk_window_destroy (column->window);
1315 column->window = NULL;
1319 _pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
1320 GtkTreeModel *old_model)
1322 if (column->sort_column_changed_signal)
1324 g_signal_handler_disconnect (old_model,
1325 column->sort_column_changed_signal);
1326 column->sort_column_changed_signal = 0;
1328 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1332 _pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
1333 PsppSheetView *tree_view)
1335 g_assert (column->tree_view == NULL);
1337 column->tree_view = GTK_WIDGET (tree_view);
1338 pspp_sheet_view_column_create_button (column);
1340 column->property_changed_signal =
1341 g_signal_connect_swapped (tree_view,
1343 G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
1346 pspp_sheet_view_column_setup_sort_column_id_callback (column);
1350 _pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
1352 if (column->tree_view && column->button)
1354 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1356 if (column->property_changed_signal)
1358 g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
1359 column->property_changed_signal = 0;
1362 if (column->sort_column_changed_signal)
1364 g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
1365 column->sort_column_changed_signal);
1366 column->sort_column_changed_signal = 0;
1369 column->tree_view = NULL;
1370 column->button = NULL;
1374 _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
1378 for (list = column->cell_list; list; list = list->next)
1379 if (((PsppSheetViewColumnCellInfo *)list->data)->cell->mode ==
1380 GTK_CELL_RENDERER_MODE_EDITABLE)
1386 /* gets cell being edited */
1388 _pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
1392 for (list = column->cell_list; list; list = list->next)
1393 if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
1394 return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
1400 _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
1405 for (list = column->cell_list; list; list = list->next)
1407 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1409 if ((cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1410 cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
1411 cellinfo->cell->visible)
1419 _pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
1425 list = pspp_sheet_view_column_cell_first (column);
1426 for (; list; list = pspp_sheet_view_column_cell_next (column, list))
1428 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1429 if (current_x <= x && x <= current_x + cellinfo->real_width)
1430 return cellinfo->cell;
1431 current_x += cellinfo->real_width;
1437 /* Public Functions */
1441 * pspp_sheet_view_column_new:
1443 * Creates a new #PsppSheetViewColumn.
1445 * Return value: A newly created #PsppSheetViewColumn.
1447 PsppSheetViewColumn *
1448 pspp_sheet_view_column_new (void)
1450 PsppSheetViewColumn *tree_column;
1452 tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
1458 * pspp_sheet_view_column_new_with_attributes:
1459 * @title: The title to set the header to.
1460 * @cell: The #GtkCellRenderer.
1461 * @Varargs: A %NULL-terminated list of attributes.
1463 * Creates a new #PsppSheetViewColumn with a number of default values. This is
1464 * equivalent to calling pspp_sheet_view_column_set_title(),
1465 * pspp_sheet_view_column_pack_start(), and
1466 * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
1468 * Here's a simple example:
1470 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1473 * PsppSheetViewColumn *column;
1474 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
1476 * column = pspp_sheet_view_column_new_with_attributes ("Title",
1478 * "text", TEXT_COLUMN,
1479 * "foreground", COLOR_COLUMN,
1484 * Return value: A newly created #PsppSheetViewColumn.
1486 PsppSheetViewColumn *
1487 pspp_sheet_view_column_new_with_attributes (const gchar *title,
1488 GtkCellRenderer *cell,
1491 PsppSheetViewColumn *retval;
1494 retval = pspp_sheet_view_column_new ();
1496 pspp_sheet_view_column_set_title (retval, title);
1497 pspp_sheet_view_column_pack_start (retval, cell, TRUE);
1499 va_start (args, cell);
1500 pspp_sheet_view_column_set_attributesv (retval, cell, args);
1506 static PsppSheetViewColumnCellInfo *
1507 pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
1508 GtkCellRenderer *cell_renderer)
1511 for (list = tree_column->cell_list; list; list = list->next)
1512 if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
1513 return (PsppSheetViewColumnCellInfo *) list->data;
1519 * pspp_sheet_view_column_pack_start:
1520 * @tree_column: A #PsppSheetViewColumn.
1521 * @cell: The #GtkCellRenderer.
1522 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1524 * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
1525 * the @cell is allocated no more space than it needs. Any unused space is divided
1526 * evenly between cells for which @expand is %TRUE.
1529 pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
1530 GtkCellRenderer *cell,
1533 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
1537 * pspp_sheet_view_column_pack_end:
1538 * @tree_column: A #PsppSheetViewColumn.
1539 * @cell: The #GtkCellRenderer.
1540 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1542 * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
1543 * is allocated no more space than it needs. Any unused space is divided
1544 * evenly between cells for which @expand is %TRUE.
1547 pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
1548 GtkCellRenderer *cell,
1551 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
1555 * pspp_sheet_view_column_clear:
1556 * @tree_column: A #PsppSheetViewColumn
1558 * Unsets all the mappings on all renderers on the @tree_column.
1561 pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
1563 gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
1567 pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
1569 PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
1570 GList *retval = NULL, *list;
1572 g_return_val_if_fail (tree_column != NULL, NULL);
1574 for (list = tree_column->cell_list; list; list = list->next)
1576 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
1578 retval = g_list_append (retval, info->cell);
1585 * pspp_sheet_view_column_get_cell_renderers:
1586 * @tree_column: A #PsppSheetViewColumn
1588 * Returns a newly-allocated #GList of all the cell renderers in the column,
1589 * in no particular order. The list must be freed with g_list_free().
1591 * Return value: A list of #GtkCellRenderers
1593 * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
1596 pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
1598 return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
1602 * pspp_sheet_view_column_add_attribute:
1603 * @tree_column: A #PsppSheetViewColumn.
1604 * @cell_renderer: the #GtkCellRenderer to set attributes on
1605 * @attribute: An attribute on the renderer
1606 * @column: The column position on the model to get the attribute from.
1608 * Adds an attribute mapping to the list in @tree_column. The @column is the
1609 * column of the model to get a value from, and the @attribute is the
1610 * parameter on @cell_renderer to be set from the value. So for example
1611 * if column 2 of the model contains strings, you could have the
1612 * "text" attribute of a #GtkCellRendererText get its values from
1616 pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
1617 GtkCellRenderer *cell_renderer,
1618 const gchar *attribute,
1621 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
1622 cell_renderer, attribute, column);
1626 pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
1627 GtkCellRenderer *cell_renderer,
1633 attribute = va_arg (args, gchar *);
1635 pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
1637 while (attribute != NULL)
1639 column = va_arg (args, gint);
1640 pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1641 attribute = va_arg (args, gchar *);
1646 * pspp_sheet_view_column_set_attributes:
1647 * @tree_column: A #PsppSheetViewColumn.
1648 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1649 * @Varargs: A %NULL-terminated list of attributes.
1651 * Sets the attributes in the list as the attributes of @tree_column.
1652 * The attributes should be in attribute/column order, as in
1653 * pspp_sheet_view_column_add_attribute(). All existing attributes
1654 * are removed, and replaced with the new attributes.
1657 pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
1658 GtkCellRenderer *cell_renderer,
1663 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1664 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1665 g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
1667 va_start (args, cell_renderer);
1668 pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
1674 * pspp_sheet_view_column_set_cell_data_func:
1675 * @tree_column: A #PsppSheetViewColumn
1676 * @cell_renderer: A #GtkCellRenderer
1677 * @func: The #PsppSheetViewColumnFunc to use.
1678 * @func_data: The user data for @func.
1679 * @destroy: The destroy notification for @func_data
1681 * Sets the #PsppSheetViewColumnFunc to use for the column. This
1682 * function is used instead of the standard attributes mapping for
1683 * setting the column value, and should set the value of @tree_column's
1684 * cell renderer as appropriate. @func may be %NULL to remove an
1688 pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
1689 GtkCellRenderer *cell_renderer,
1690 PsppSheetCellDataFunc func,
1692 GDestroyNotify destroy)
1694 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
1696 (GtkCellLayoutDataFunc)func,
1697 func_data, destroy);
1702 * pspp_sheet_view_column_clear_attributes:
1703 * @tree_column: a #PsppSheetViewColumn
1704 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1706 * Clears all existing attributes previously set with
1707 * pspp_sheet_view_column_set_attributes().
1710 pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
1711 GtkCellRenderer *cell_renderer)
1713 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
1718 * pspp_sheet_view_column_set_spacing:
1719 * @tree_column: A #PsppSheetViewColumn.
1720 * @spacing: distance between cell renderers in pixels.
1722 * Sets the spacing field of @tree_column, which is the number of pixels to
1723 * place between cell renderers packed into it.
1726 pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
1729 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1730 g_return_if_fail (spacing >= 0);
1732 if (tree_column->spacing == spacing)
1735 tree_column->spacing = spacing;
1736 if (tree_column->tree_view)
1737 _pspp_sheet_view_column_cell_set_dirty (tree_column);
1741 * pspp_sheet_view_column_get_spacing:
1742 * @tree_column: A #PsppSheetViewColumn.
1744 * Returns the spacing of @tree_column.
1746 * Return value: the spacing of @tree_column.
1749 pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
1751 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
1753 return tree_column->spacing;
1756 /* Options for manipulating the columns */
1759 * pspp_sheet_view_column_set_visible:
1760 * @tree_column: A #PsppSheetViewColumn.
1761 * @visible: %TRUE if the @tree_column is visible.
1763 * Sets the visibility of @tree_column.
1766 pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
1769 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1771 visible = !! visible;
1773 if (tree_column->visible == visible)
1776 tree_column->visible = visible;
1778 if (tree_column->visible)
1779 _pspp_sheet_view_column_cell_set_dirty (tree_column);
1781 pspp_sheet_view_column_update_button (tree_column);
1782 g_object_notify (G_OBJECT (tree_column), "visible");
1786 * pspp_sheet_view_column_get_visible:
1787 * @tree_column: A #PsppSheetViewColumn.
1789 * Returns %TRUE if @tree_column is visible.
1791 * Return value: whether the column is visible or not. If it is visible, then
1792 * the tree will show the column.
1795 pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
1797 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
1799 return tree_column->visible;
1803 * pspp_sheet_view_column_set_resizable:
1804 * @tree_column: A #PsppSheetViewColumn
1805 * @resizable: %TRUE, if the column can be resized
1807 * If @resizable is %TRUE, then the user can explicitly resize the column by
1808 * grabbing the outer edge of the column button.
1811 pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
1814 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1816 resizable = !! resizable;
1818 if (tree_column->resizable == resizable)
1821 tree_column->resizable = resizable;
1823 pspp_sheet_view_column_update_button (tree_column);
1825 g_object_notify (G_OBJECT (tree_column), "resizable");
1829 * pspp_sheet_view_column_get_resizable:
1830 * @tree_column: A #PsppSheetViewColumn
1832 * Returns %TRUE if the @tree_column can be resized by the end user.
1834 * Return value: %TRUE, if the @tree_column can be resized.
1837 pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
1839 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
1841 return tree_column->resizable;
1846 * pspp_sheet_view_column_get_width:
1847 * @tree_column: A #PsppSheetViewColumn.
1849 * Returns the current size of @tree_column in pixels.
1851 * Return value: The current width of @tree_column.
1854 pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
1856 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
1858 return tree_column->width;
1862 * pspp_sheet_view_column_set_fixed_width:
1863 * @tree_column: A #PsppSheetViewColumn.
1864 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
1866 * Sets the size of the column in pixels. The size of the column is clamped to
1867 * the min/max width for the column. Please note that the min/max width of the
1868 * column doesn't actually affect the "fixed_width" property of the widget, just
1869 * the actual size when displayed.
1872 pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
1875 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1876 g_return_if_fail (fixed_width > 0);
1878 tree_column->fixed_width = fixed_width;
1879 tree_column->use_resized_width = FALSE;
1881 if (tree_column->tree_view &&
1882 gtk_widget_get_realized (tree_column->tree_view))
1884 gtk_widget_queue_resize (tree_column->tree_view);
1887 g_object_notify (G_OBJECT (tree_column), "fixed-width");
1891 * pspp_sheet_view_column_get_fixed_width:
1892 * @tree_column: a #PsppSheetViewColumn
1894 * Gets the fixed width of the column. This value is only meaning may not be
1895 * the actual width of the column on the screen, just what is requested.
1897 * Return value: the fixed width of the column
1900 pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
1902 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
1904 return tree_column->fixed_width;
1908 * pspp_sheet_view_column_set_min_width:
1909 * @tree_column: A #PsppSheetViewColumn.
1910 * @min_width: The minimum width of the column in pixels, or -1.
1912 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
1913 * minimum width is unset.
1916 pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
1919 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1920 g_return_if_fail (min_width >= -1);
1922 if (min_width == tree_column->min_width)
1925 if (tree_column->visible &&
1926 tree_column->tree_view != NULL &&
1927 gtk_widget_get_realized (tree_column->tree_view))
1929 if (min_width > tree_column->width)
1930 gtk_widget_queue_resize (tree_column->tree_view);
1933 tree_column->min_width = min_width;
1934 g_object_freeze_notify (G_OBJECT (tree_column));
1935 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
1937 tree_column->max_width = min_width;
1938 g_object_notify (G_OBJECT (tree_column), "max-width");
1940 g_object_notify (G_OBJECT (tree_column), "min-width");
1941 g_object_thaw_notify (G_OBJECT (tree_column));
1945 * pspp_sheet_view_column_get_min_width:
1946 * @tree_column: A #PsppSheetViewColumn.
1948 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
1951 * Return value: The minimum width of the @tree_column.
1954 pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
1956 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
1958 return tree_column->min_width;
1962 * pspp_sheet_view_column_set_max_width:
1963 * @tree_column: A #PsppSheetViewColumn.
1964 * @max_width: The maximum width of the column in pixels, or -1.
1966 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
1967 * maximum width is unset. Note, the column can actually be wider than max
1968 * width if it's the last column in a view. In this case, the column expands to
1969 * fill any extra space.
1972 pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
1975 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1976 g_return_if_fail (max_width >= -1);
1978 if (max_width == tree_column->max_width)
1981 if (tree_column->visible &&
1982 tree_column->tree_view != NULL &&
1983 gtk_widget_get_realized (tree_column->tree_view))
1985 if (max_width != -1 && max_width < tree_column->width)
1986 gtk_widget_queue_resize (tree_column->tree_view);
1989 tree_column->max_width = max_width;
1990 g_object_freeze_notify (G_OBJECT (tree_column));
1991 if (max_width != -1 && max_width < tree_column->min_width)
1993 tree_column->min_width = max_width;
1994 g_object_notify (G_OBJECT (tree_column), "min-width");
1996 g_object_notify (G_OBJECT (tree_column), "max-width");
1997 g_object_thaw_notify (G_OBJECT (tree_column));
2001 * pspp_sheet_view_column_get_max_width:
2002 * @tree_column: A #PsppSheetViewColumn.
2004 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
2007 * Return value: The maximum width of the @tree_column.
2010 pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
2012 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2014 return tree_column->max_width;
2018 * pspp_sheet_view_column_clicked:
2019 * @tree_column: a #PsppSheetViewColumn
2021 * Emits the "clicked" signal on the column. This function will only work if
2022 * @tree_column is clickable.
2025 pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
2027 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2029 if (tree_column->visible &&
2030 tree_column->button &&
2031 tree_column->clickable)
2032 gtk_button_clicked (GTK_BUTTON (tree_column->button));
2036 * pspp_sheet_view_column_set_title:
2037 * @tree_column: A #PsppSheetViewColumn.
2038 * @title: The title of the @tree_column.
2040 * Sets the title of the @tree_column. If a custom widget has been set, then
2041 * this value is ignored.
2044 pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
2049 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2051 new_title = g_strdup (title);
2052 g_free (tree_column->title);
2053 tree_column->title = new_title;
2055 pspp_sheet_view_column_update_button (tree_column);
2056 g_object_notify (G_OBJECT (tree_column), "title");
2060 * pspp_sheet_view_column_get_title:
2061 * @tree_column: A #PsppSheetViewColumn.
2063 * Returns the title of the widget.
2065 * Return value: the title of the column. This string should not be
2066 * modified or freed.
2068 G_CONST_RETURN gchar *
2069 pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
2071 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2073 return tree_column->title;
2077 * pspp_sheet_view_column_set_expand:
2078 * @tree_column: A #PsppSheetViewColumn
2079 * @expand: %TRUE if the column should take available extra space, %FALSE if not
2081 * Sets the column to take available extra space. This space is shared equally
2082 * amongst all columns that have the expand set to %TRUE. If no column has this
2083 * option set, then the last column gets all extra space. By default, every
2084 * column is created with this %FALSE.
2089 pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
2092 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2094 expand = expand?TRUE:FALSE;
2095 if (tree_column->expand == expand)
2097 tree_column->expand = expand;
2099 if (tree_column->visible &&
2100 tree_column->tree_view != NULL &&
2101 gtk_widget_get_realized (tree_column->tree_view))
2103 /* We want to continue using the original width of the
2104 * column that includes additional space added by the user
2105 * resizing the columns and possibly extra (expanded) space, which
2106 * are not included in the resized width.
2108 tree_column->use_resized_width = FALSE;
2110 gtk_widget_queue_resize (tree_column->tree_view);
2113 g_object_notify (G_OBJECT (tree_column), "expand");
2117 * pspp_sheet_view_column_get_expand:
2118 * @tree_column: a #PsppSheetViewColumn
2120 * Return %TRUE if the column expands to take any available space.
2122 * Return value: %TRUE, if the column expands
2127 pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
2129 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2131 return tree_column->expand;
2135 * pspp_sheet_view_column_set_clickable:
2136 * @tree_column: A #PsppSheetViewColumn.
2137 * @clickable: %TRUE if the header is active.
2139 * Sets the header to be active if @active is %TRUE. When the header is active,
2140 * then it can take keyboard focus, and can be clicked.
2143 pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
2146 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2148 clickable = !! clickable;
2149 if (tree_column->clickable == clickable)
2152 tree_column->clickable = clickable;
2153 pspp_sheet_view_column_update_button (tree_column);
2154 g_object_notify (G_OBJECT (tree_column), "clickable");
2158 * pspp_sheet_view_column_get_clickable:
2159 * @tree_column: a #PsppSheetViewColumn
2161 * Returns %TRUE if the user can click on the header for the column.
2163 * Return value: %TRUE if user can click the column header.
2166 pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
2168 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2170 return tree_column->clickable;
2174 * pspp_sheet_view_column_set_widget:
2175 * @tree_column: A #PsppSheetViewColumn.
2176 * @widget: (allow-none): A child #GtkWidget, or %NULL.
2178 * Sets the widget in the header to be @widget. If widget is %NULL, then the
2179 * header button is set with a #GtkLabel set to the title of @tree_column.
2182 pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
2185 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2186 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
2189 g_object_ref_sink (widget);
2191 if (tree_column->child)
2192 g_object_unref (tree_column->child);
2194 tree_column->child = widget;
2195 pspp_sheet_view_column_update_button (tree_column);
2196 g_object_notify (G_OBJECT (tree_column), "widget");
2200 * pspp_sheet_view_column_get_widget:
2201 * @tree_column: A #PsppSheetViewColumn.
2203 * Returns the #GtkWidget in the button on the column header. If a custom
2204 * widget has not been set then %NULL is returned.
2206 * Return value: The #GtkWidget in the column header, or %NULL
2209 pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
2211 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2213 return tree_column->child;
2217 * pspp_sheet_view_column_set_alignment:
2218 * @tree_column: A #PsppSheetViewColumn.
2219 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2221 * Sets the alignment of the title or custom widget inside the column header.
2222 * The alignment determines its location inside the button -- 0.0 for left, 0.5
2223 * for center, 1.0 for right.
2226 pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
2229 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2231 xalign = CLAMP (xalign, 0.0, 1.0);
2233 if (tree_column->xalign == xalign)
2236 tree_column->xalign = xalign;
2237 pspp_sheet_view_column_update_button (tree_column);
2238 g_object_notify (G_OBJECT (tree_column), "alignment");
2242 * pspp_sheet_view_column_get_alignment:
2243 * @tree_column: A #PsppSheetViewColumn.
2245 * Returns the current x alignment of @tree_column. This value can range
2246 * between 0.0 and 1.0.
2248 * Return value: The current alignent of @tree_column.
2251 pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
2253 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0.5);
2255 return tree_column->xalign;
2259 * pspp_sheet_view_column_set_reorderable:
2260 * @tree_column: A #PsppSheetViewColumn
2261 * @reorderable: %TRUE, if the column can be reordered.
2263 * If @reorderable is %TRUE, then the column can be reordered by the end user
2264 * dragging the header.
2267 pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
2268 gboolean reorderable)
2270 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2273 pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
2275 if (tree_column->reorderable == (reorderable?TRUE:FALSE))
2278 tree_column->reorderable = (reorderable?TRUE:FALSE);
2279 pspp_sheet_view_column_update_button (tree_column);
2280 g_object_notify (G_OBJECT (tree_column), "reorderable");
2284 * pspp_sheet_view_column_get_reorderable:
2285 * @tree_column: A #PsppSheetViewColumn
2287 * Returns %TRUE if the @tree_column can be reordered by the user.
2289 * Return value: %TRUE if the @tree_column can be reordered by the user.
2292 pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
2294 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2296 return tree_column->reorderable;
2301 * pspp_sheet_view_column_set_sort_column_id:
2302 * @tree_column: a #PsppSheetViewColumn
2303 * @sort_column_id: The @sort_column_id of the model to sort on.
2305 * Sets the logical @sort_column_id that this column sorts on when this column
2306 * is selected for sorting. Doing so makes the column header clickable.
2309 pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
2310 gint sort_column_id)
2312 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2313 g_return_if_fail (sort_column_id >= -1);
2315 if (tree_column->sort_column_id == sort_column_id)
2318 tree_column->sort_column_id = sort_column_id;
2320 /* Handle unsetting the id */
2321 if (sort_column_id == -1)
2323 GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
2325 if (tree_column->sort_clicked_signal)
2327 g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
2328 tree_column->sort_clicked_signal = 0;
2331 if (tree_column->sort_column_changed_signal)
2333 g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
2334 tree_column->sort_column_changed_signal = 0;
2337 pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2338 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
2339 pspp_sheet_view_column_set_clickable (tree_column, FALSE);
2340 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2344 pspp_sheet_view_column_set_clickable (tree_column, TRUE);
2346 if (! tree_column->sort_clicked_signal)
2347 tree_column->sort_clicked_signal = g_signal_connect (tree_column,
2349 G_CALLBACK (pspp_sheet_view_column_sort),
2352 pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
2353 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2357 * pspp_sheet_view_column_get_sort_column_id:
2358 * @tree_column: a #PsppSheetViewColumn
2360 * Gets the logical @sort_column_id that the model sorts on when this
2361 * column is selected for sorting.
2362 * See pspp_sheet_view_column_set_sort_column_id().
2364 * Return value: the current @sort_column_id for this column, or -1 if
2365 * this column can't be used for sorting.
2368 pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
2370 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2372 return tree_column->sort_column_id;
2376 * pspp_sheet_view_column_set_sort_indicator:
2377 * @tree_column: a #PsppSheetViewColumn
2378 * @setting: %TRUE to display an indicator that the column is sorted
2380 * Call this function with a @setting of %TRUE to display an arrow in
2381 * the header button indicating the column is sorted. Call
2382 * pspp_sheet_view_column_set_sort_order() to change the direction of
2387 pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
2390 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2392 setting = setting != FALSE;
2394 if (setting == tree_column->show_sort_indicator)
2397 tree_column->show_sort_indicator = setting;
2398 pspp_sheet_view_column_update_button (tree_column);
2399 g_object_notify (G_OBJECT (tree_column), "sort-indicator");
2403 * pspp_sheet_view_column_get_sort_indicator:
2404 * @tree_column: a #PsppSheetViewColumn
2406 * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
2408 * Return value: whether the sort indicator arrow is displayed
2411 pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column)
2413 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2415 return tree_column->show_sort_indicator;
2419 * pspp_sheet_view_column_set_sort_order:
2420 * @tree_column: a #PsppSheetViewColumn
2421 * @order: sort order that the sort indicator should indicate
2423 * Changes the appearance of the sort indicator.
2425 * This <emphasis>does not</emphasis> actually sort the model. Use
2426 * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
2427 * support. This function is primarily for custom sorting behavior, and should
2428 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2429 * that. For custom models, the mechanism will vary.
2431 * The sort indicator changes direction to indicate normal sort or reverse sort.
2432 * Note that you must have the sort indicator enabled to see anything when
2433 * calling this function; see pspp_sheet_view_column_set_sort_indicator().
2436 pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
2439 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2441 if (order == tree_column->sort_order)
2444 tree_column->sort_order = order;
2445 pspp_sheet_view_column_update_button (tree_column);
2446 g_object_notify (G_OBJECT (tree_column), "sort-order");
2450 * pspp_sheet_view_column_get_sort_order:
2451 * @tree_column: a #PsppSheetViewColumn
2453 * Gets the value set by pspp_sheet_view_column_set_sort_order().
2455 * Return value: the sort order the sort indicator is indicating
2458 pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column)
2460 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2462 return tree_column->sort_order;
2466 * pspp_sheet_view_column_cell_set_cell_data:
2467 * @tree_column: A #PsppSheetViewColumn.
2468 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2469 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2471 * Sets the cell renderer based on the @tree_model and @iter. That is, for
2472 * every attribute mapping in @tree_column, it will get a value from the set
2473 * column on the @iter, and use that value to set the attribute on the cell
2474 * renderer. This is used primarily by the #PsppSheetView.
2477 pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
2478 GtkTreeModel *tree_model,
2482 GValue value = { 0, };
2485 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2487 if (tree_model == NULL)
2490 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2492 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
2493 GObject *cell = (GObject *) info->cell;
2495 list = info->attributes;
2497 g_object_freeze_notify (cell);
2499 while (list && list->next)
2501 gtk_tree_model_get_value (tree_model, iter,
2502 GPOINTER_TO_INT (list->next->data),
2504 g_object_set_property (cell, (gchar *) list->data, &value);
2505 g_value_unset (&value);
2506 list = list->next->next;
2510 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2511 g_object_thaw_notify (G_OBJECT (info->cell));
2517 * pspp_sheet_view_column_cell_get_size:
2518 * @tree_column: A #PsppSheetViewColumn.
2519 * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
2520 * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
2521 * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
2522 * @width: (allow-none): location to return width needed to render a cell, or %NULL
2523 * @height: (allow-none): location to return height needed to render a cell, or %NULL
2525 * Obtains the width and height needed to render the column. This is used
2526 * primarily by the #PsppSheetView.
2529 pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
2530 const GdkRectangle *cell_area,
2537 gboolean first_cell = TRUE;
2538 gint focus_line_width;
2540 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2547 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
2549 for (list = tree_column->cell_list; list; list = list->next)
2551 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2553 gint new_height = 0;
2555 g_object_get (info->cell, "visible", &visible, NULL);
2557 if (visible == FALSE)
2560 if (first_cell == FALSE && width)
2561 *width += tree_column->spacing;
2563 gtk_cell_renderer_get_size (info->cell,
2564 tree_column->tree_view,
2572 * height = MAX (*height, new_height + focus_line_width * 2);
2573 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
2575 * width += info->requested_width;
2580 /* rendering, event handling and rendering focus are somewhat complicated, and
2581 * quite a bit of code. Rather than duplicate them, we put them together to
2582 * keep the code in one place.
2584 * To better understand what's going on, check out
2585 * docs/tree-column-sizing.png
2594 pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn *tree_column,
2596 const GdkRectangle *background_area,
2597 const GdkRectangle *cell_area,
2600 const GdkRectangle *expose_area, /* RENDER */
2601 GdkRectangle *focus_rectangle, /* FOCUS */
2602 GtkCellEditable **editable_widget, /* EVENT */
2603 GdkEvent *event, /* EVENT */
2604 gchar *path_string) /* EVENT */
2607 GdkRectangle real_cell_area;
2608 GdkRectangle real_background_area;
2609 GdkRectangle real_expose_area = *cell_area;
2611 gint expand_cell_count = 0;
2612 gint full_requested_width = 0;
2614 gint min_x, min_y, max_x, max_y;
2615 gint focus_line_width;
2617 gint horizontal_separator;
2618 gboolean cursor_row = FALSE;
2619 gboolean first_cell = TRUE;
2621 /* If we have rtl text, we need to transform our areas */
2622 GdkRectangle rtl_cell_area;
2623 GdkRectangle rtl_background_area;
2630 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
2631 special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
2633 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
2635 PsppSheetViewColumnCellInfo *info = NULL;
2636 gboolean found_has_focus = FALSE;
2638 /* one should have focus */
2639 for (list = tree_column->cell_list; list; list = list->next)
2642 if (info && info->has_focus)
2644 found_has_focus = TRUE;
2649 if (!found_has_focus)
2651 /* give the first one focus */
2652 info = pspp_sheet_view_column_cell_first (tree_column)->data;
2653 info->has_focus = TRUE;
2657 cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
2659 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
2660 "focus-line-width", &focus_line_width,
2661 "horizontal-separator", &horizontal_separator,
2664 real_cell_area = *cell_area;
2665 real_background_area = *background_area;
2668 real_cell_area.x += focus_line_width;
2669 real_cell_area.y += focus_line_width;
2670 real_cell_area.height -= 2 * focus_line_width;
2673 depth = real_background_area.width - real_cell_area.width;
2675 depth = real_cell_area.x - real_background_area.x;
2677 /* Find out how much extra space we have to allocate */
2678 for (list = tree_column->cell_list; list; list = list->next)
2680 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
2682 if (! info->cell->visible)
2685 if (info->expand == TRUE)
2686 expand_cell_count ++;
2687 full_requested_width += info->requested_width;
2690 full_requested_width += tree_column->spacing;
2695 extra_space = cell_area->width - full_requested_width;
2696 if (extra_space < 0)
2698 else if (extra_space > 0 && expand_cell_count > 0)
2699 extra_space /= expand_cell_count;
2701 /* iterate list for GTK_PACK_START cells */
2702 for (list = tree_column->cell_list; list; list = list->next)
2704 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2706 if (info->pack == GTK_PACK_END)
2709 if (! info->cell->visible)
2712 if ((info->has_focus || special_cells == 1) && cursor_row)
2713 flags |= GTK_CELL_RENDERER_FOCUSED;
2715 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2717 info->real_width = info->requested_width + (info->expand?extra_space:0);
2719 /* We constrain ourselves to only the width available */
2720 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
2722 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
2725 if (real_cell_area.x > cell_area->x + cell_area->width)
2728 real_cell_area.width = info->real_width;
2729 real_cell_area.width -= 2 * focus_line_width;
2733 real_background_area.width = info->real_width + depth;
2737 /* fill the rest of background for the last cell */
2738 real_background_area.width = background_area->x + background_area->width - real_background_area.x;
2741 rtl_cell_area = real_cell_area;
2742 rtl_background_area = real_background_area;
2746 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
2747 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
2751 if (action == CELL_ACTION_RENDER)
2753 gtk_cell_renderer_render (info->cell,
2755 tree_column->tree_view,
2756 &rtl_background_area,
2762 else if (action == CELL_ACTION_FOCUS)
2764 gint x_offset, y_offset, width, height;
2766 gtk_cell_renderer_get_size (info->cell,
2767 tree_column->tree_view,
2769 &x_offset, &y_offset,
2772 if (special_cells > 1)
2774 if (info->has_focus)
2776 min_x = rtl_cell_area.x + x_offset;
2777 max_x = min_x + width;
2778 min_y = rtl_cell_area.y + y_offset;
2779 max_y = min_y + height;
2784 if (min_x > (rtl_cell_area.x + x_offset))
2785 min_x = rtl_cell_area.x + x_offset;
2786 if (max_x < rtl_cell_area.x + x_offset + width)
2787 max_x = rtl_cell_area.x + x_offset + width;
2788 if (min_y > (rtl_cell_area.y + y_offset))
2789 min_y = rtl_cell_area.y + y_offset;
2790 if (max_y < rtl_cell_area.y + y_offset + height)
2791 max_y = rtl_cell_area.y + y_offset + height;
2795 else if (action == CELL_ACTION_EVENT)
2797 gboolean try_event = FALSE;
2801 if (special_cells == 1)
2803 /* only 1 activatable cell -> whole column can activate */
2804 if (cell_area->x <= ((GdkEventButton *)event)->x &&
2805 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
2808 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
2809 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
2810 /* only activate cell if the user clicked on an individual
2815 else if (special_cells > 1 && info->has_focus)
2817 else if (special_cells == 1)
2822 gboolean visible, mode;
2824 g_object_get (info->cell,
2825 "visible", &visible,
2828 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2830 if (gtk_cell_renderer_activate (info->cell,
2832 tree_column->tree_view,
2834 &rtl_background_area,
2838 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2842 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2845 gtk_cell_renderer_start_editing (info->cell,
2847 tree_column->tree_view,
2849 &rtl_background_area,
2853 if (*editable_widget != NULL)
2855 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2856 info->in_editing_mode = TRUE;
2857 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
2859 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2867 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2869 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
2870 real_background_area.x += real_background_area.width + tree_column->spacing;
2872 /* Only needed for first cell */
2876 /* iterate list for PACK_END cells */
2877 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
2879 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2881 if (info->pack == GTK_PACK_START)
2884 if (! info->cell->visible)
2887 if ((info->has_focus || special_cells == 1) && cursor_row)
2888 flags |= GTK_CELL_RENDERER_FOCUSED;
2890 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2892 info->real_width = info->requested_width + (info->expand?extra_space:0);
2894 /* We constrain ourselves to only the width available */
2895 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
2897 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
2900 if (real_cell_area.x > cell_area->x + cell_area->width)
2903 real_cell_area.width = info->real_width;
2904 real_cell_area.width -= 2 * focus_line_width;
2905 real_background_area.width = info->real_width + depth;
2907 rtl_cell_area = real_cell_area;
2908 rtl_background_area = real_background_area;
2911 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
2912 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
2916 if (action == CELL_ACTION_RENDER)
2918 gtk_cell_renderer_render (info->cell,
2920 tree_column->tree_view,
2921 &rtl_background_area,
2927 else if (action == CELL_ACTION_FOCUS)
2929 gint x_offset, y_offset, width, height;
2931 gtk_cell_renderer_get_size (info->cell,
2932 tree_column->tree_view,
2934 &x_offset, &y_offset,
2937 if (special_cells > 1)
2939 if (info->has_focus)
2941 min_x = rtl_cell_area.x + x_offset;
2942 max_x = min_x + width;
2943 min_y = rtl_cell_area.y + y_offset;
2944 max_y = min_y + height;
2949 if (min_x > (rtl_cell_area.x + x_offset))
2950 min_x = rtl_cell_area.x + x_offset;
2951 if (max_x < rtl_cell_area.x + x_offset + width)
2952 max_x = rtl_cell_area.x + x_offset + width;
2953 if (min_y > (rtl_cell_area.y + y_offset))
2954 min_y = rtl_cell_area.y + y_offset;
2955 if (max_y < rtl_cell_area.y + y_offset + height)
2956 max_y = rtl_cell_area.y + y_offset + height;
2960 else if (action == CELL_ACTION_EVENT)
2962 gboolean try_event = FALSE;
2966 if (special_cells == 1)
2968 /* only 1 activatable cell -> whole column can activate */
2969 if (cell_area->x <= ((GdkEventButton *)event)->x &&
2970 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
2973 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
2974 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
2975 /* only activate cell if the user clicked on an individual
2980 else if (special_cells > 1 && info->has_focus)
2982 else if (special_cells == 1)
2987 gboolean visible, mode;
2989 g_object_get (info->cell,
2990 "visible", &visible,
2993 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2995 if (gtk_cell_renderer_activate (info->cell,
2997 tree_column->tree_view,
2999 &rtl_background_area,
3003 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3007 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3010 gtk_cell_renderer_start_editing (info->cell,
3012 tree_column->tree_view,
3014 &rtl_background_area,
3018 if (*editable_widget != NULL)
3020 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3021 info->in_editing_mode = TRUE;
3022 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3024 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3031 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3033 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3034 real_background_area.x += (real_background_area.width + tree_column->spacing);
3036 /* Only needed for first cell */
3040 /* fill focus_rectangle when required */
3041 if (action == CELL_ACTION_FOCUS)
3043 if (min_x >= max_x || min_y >= max_y)
3045 *focus_rectangle = *cell_area;
3046 /* don't change the focus_rectangle, just draw it nicely inside
3051 focus_rectangle->x = min_x - focus_line_width;
3052 focus_rectangle->y = min_y - focus_line_width;
3053 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
3054 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
3062 * pspp_sheet_view_column_cell_render:
3063 * @tree_column: A #PsppSheetViewColumn.
3064 * @window: a #GdkDrawable to draw to
3065 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
3066 * @cell_area: area normally rendered by a cell renderer
3067 * @expose_area: area that actually needs updating
3068 * @flags: flags that affect rendering
3070 * Renders the cell contained by #tree_column. This is used primarily by the
3074 _pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
3076 const GdkRectangle *background_area,
3077 const GdkRectangle *cell_area,
3078 const GdkRectangle *expose_area,
3081 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3082 g_return_if_fail (background_area != NULL);
3083 g_return_if_fail (cell_area != NULL);
3084 g_return_if_fail (expose_area != NULL);
3086 pspp_sheet_view_column_cell_process_action (tree_column,
3093 NULL, NULL, NULL, NULL);
3097 _pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
3098 GtkCellEditable **editable_widget,
3101 const GdkRectangle *background_area,
3102 const GdkRectangle *cell_area,
3105 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3107 return pspp_sheet_view_column_cell_process_action (tree_column,
3120 _pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
3121 const GdkRectangle *background_area,
3122 const GdkRectangle *cell_area,
3123 GdkRectangle *focus_area)
3125 pspp_sheet_view_column_cell_process_action (tree_column,
3137 /* cell list manipulation */
3139 pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
3141 GList *list = tree_column->cell_list;
3143 /* first GTK_PACK_START cell we find */
3144 for ( ; list; list = list->next)
3146 PsppSheetViewColumnCellInfo *info = list->data;
3147 if (info->pack == GTK_PACK_START)
3151 /* hmm, else the *last* GTK_PACK_END cell */
3152 list = g_list_last (tree_column->cell_list);
3154 for ( ; list; list = list->prev)
3156 PsppSheetViewColumnCellInfo *info = list->data;
3157 if (info->pack == GTK_PACK_END)
3165 pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
3167 GList *list = tree_column->cell_list;
3169 /* *first* GTK_PACK_END cell we find */
3170 for ( ; list ; list = list->next)
3172 PsppSheetViewColumnCellInfo *info = list->data;
3173 if (info->pack == GTK_PACK_END)
3177 /* hmm, else the last GTK_PACK_START cell */
3178 list = g_list_last (tree_column->cell_list);
3180 for ( ; list; list = list->prev)
3182 PsppSheetViewColumnCellInfo *info = list->data;
3183 if (info->pack == GTK_PACK_START)
3191 pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
3195 PsppSheetViewColumnCellInfo *info = current->data;
3197 if (info->pack == GTK_PACK_START)
3199 for (list = current->next; list; list = list->next)
3201 PsppSheetViewColumnCellInfo *inf = list->data;
3202 if (inf->pack == GTK_PACK_START)
3206 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
3207 list = g_list_last (tree_column->cell_list);
3208 for (; list; list = list->prev)
3210 PsppSheetViewColumnCellInfo *inf = list->data;
3211 if (inf->pack == GTK_PACK_END)
3216 for (list = current->prev; list; list = list->prev)
3218 PsppSheetViewColumnCellInfo *inf = list->data;
3219 if (inf->pack == GTK_PACK_END)
3227 pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
3231 PsppSheetViewColumnCellInfo *info = current->data;
3233 if (info->pack == GTK_PACK_END)
3235 for (list = current->next; list; list = list->next)
3237 PsppSheetViewColumnCellInfo *inf = list->data;
3238 if (inf->pack == GTK_PACK_END)
3242 /* out of GTK_PACK_END, get last GTK_PACK_START one */
3243 list = g_list_last (tree_column->cell_list);
3244 for ( ; list; list = list->prev)
3246 PsppSheetViewColumnCellInfo *inf = list->data;
3247 if (inf->pack == GTK_PACK_START)
3252 for (list = current->prev; list; list = list->prev)
3254 PsppSheetViewColumnCellInfo *inf = list->data;
3255 if (inf->pack == GTK_PACK_START)
3263 _pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
3271 count = _pspp_sheet_view_column_count_special_cells (tree_column);
3272 rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
3274 /* if we are the current focus column and have multiple editable cells,
3275 * try to select the next one, else move the focus to the next column
3277 if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
3282 GList *list = tree_column->cell_list;
3283 PsppSheetViewColumnCellInfo *info = NULL;
3285 /* find current focussed cell */
3286 for ( ; list; list = list->next)
3289 if (info->has_focus)
3293 /* not a focussed cell in the focus column? */
3294 if (!list || !info || !info->has_focus)
3299 prev = pspp_sheet_view_column_cell_next (tree_column, list);
3300 next = pspp_sheet_view_column_cell_prev (tree_column, list);
3304 next = pspp_sheet_view_column_cell_next (tree_column, list);
3305 prev = pspp_sheet_view_column_cell_prev (tree_column, list);
3308 info->has_focus = FALSE;
3309 if (direction > 0 && next)
3312 info->has_focus = TRUE;
3315 else if (direction > 0 && !next && !right)
3317 /* keep focus on last cell */
3319 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3321 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3323 info->has_focus = TRUE;
3326 else if (direction < 0 && prev)
3329 info->has_focus = TRUE;
3332 else if (direction < 0 && !prev && !left)
3334 /* keep focus on first cell */
3336 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3338 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3340 info->has_focus = TRUE;
3347 /* we get focus, if we have multiple editable cells, give the correct one
3352 GList *list = tree_column->cell_list;
3354 /* clear focus first */
3355 for ( ; list ; list = list->next)
3357 PsppSheetViewColumnCellInfo *info = list->data;
3358 if (info->has_focus)
3359 info->has_focus = FALSE;
3366 list = pspp_sheet_view_column_cell_last (tree_column);
3367 else if (direction < 0)
3368 list = pspp_sheet_view_column_cell_first (tree_column);
3373 list = pspp_sheet_view_column_cell_first (tree_column);
3374 else if (direction < 0)
3375 list = pspp_sheet_view_column_cell_last (tree_column);
3379 ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
3386 _pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
3388 const GdkRectangle *background_area,
3389 const GdkRectangle *cell_area,
3390 const GdkRectangle *expose_area,
3393 gint focus_line_width;
3394 GtkStateType cell_state;
3396 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3397 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3398 "focus-line-width", &focus_line_width, NULL);
3399 if (tree_column->editable_widget)
3401 /* This function is only called on the editable row when editing.
3404 gtk_paint_focus (tree_column->tree_view->style,
3406 gtk_widget_get_state (tree_column->tree_view),
3408 tree_column->tree_view,
3410 cell_area->x - focus_line_width,
3411 cell_area->y - focus_line_width,
3412 cell_area->width + 2 * focus_line_width,
3413 cell_area->height + 2 * focus_line_width);
3418 GdkRectangle focus_rectangle;
3419 pspp_sheet_view_column_cell_process_action (tree_column,
3429 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3430 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3431 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3432 gtk_paint_focus (tree_column->tree_view->style,
3436 tree_column->tree_view,
3440 focus_rectangle.width,
3441 focus_rectangle.height);
3446 * pspp_sheet_view_column_cell_is_visible:
3447 * @tree_column: A #PsppSheetViewColumn
3449 * Returns %TRUE if any of the cells packed into the @tree_column are visible.
3450 * For this to be meaningful, you must first initialize the cells with
3451 * pspp_sheet_view_column_cell_set_cell_data()
3453 * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
3456 pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
3460 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3462 for (list = tree_column->cell_list; list; list = list->next)
3464 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3466 if (info->cell->visible)
3474 * pspp_sheet_view_column_focus_cell:
3475 * @tree_column: A #PsppSheetViewColumn
3476 * @cell: A #GtkCellRenderer
3478 * Sets the current keyboard focus to be at @cell, if the column contains
3479 * 2 or more editable and activatable cells.
3484 pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
3485 GtkCellRenderer *cell)
3488 gboolean found_cell = FALSE;
3490 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3491 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3493 if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
3496 for (list = tree_column->cell_list; list; list = list->next)
3498 PsppSheetViewColumnCellInfo *info = list->data;
3500 if (info->cell == cell)
3502 info->has_focus = TRUE;
3510 for (list = tree_column->cell_list; list; list = list->next)
3512 PsppSheetViewColumnCellInfo *info = list->data;
3514 if (info->cell != cell)
3515 info->has_focus = FALSE;
3518 /* FIXME: redraw? */
3523 _pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
3527 for (list = tree_column->cell_list; list; list = list->next)
3529 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3531 info->requested_width = 0;
3533 tree_column->dirty = TRUE;
3534 tree_column->requested_width = -1;
3535 tree_column->width = 0;
3537 if (tree_column->tree_view &&
3538 gtk_widget_get_realized (tree_column->tree_view))
3540 _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
3541 gtk_widget_queue_resize (tree_column->tree_view);
3546 _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
3547 GtkCellEditable *cell_editable)
3549 g_return_if_fail (tree_column->editable_widget == NULL);
3551 tree_column->editable_widget = cell_editable;
3555 _pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
3559 g_return_if_fail (tree_column->editable_widget != NULL);
3561 tree_column->editable_widget = NULL;
3562 for (list = tree_column->cell_list; list; list = list->next)
3563 ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
3567 _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
3568 GtkCellRenderer *cell,
3573 PsppSheetViewColumnCellInfo *info;
3579 list = pspp_sheet_view_column_cell_first (column);
3583 info = (PsppSheetViewColumnCellInfo *)list->data;
3585 list = pspp_sheet_view_column_cell_next (column, list);
3587 if (info->cell == cell)
3590 if (info->cell->visible)
3591 l += info->real_width + column->spacing;
3596 info = (PsppSheetViewColumnCellInfo *)list->data;
3598 list = pspp_sheet_view_column_cell_next (column, list);
3600 if (info->cell->visible)
3601 r += info->real_width + column->spacing;
3604 rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
3606 *left = rtl ? r : l;
3609 *right = rtl ? l : r;
3613 * pspp_sheet_view_column_cell_get_position:
3614 * @tree_column: a #PsppSheetViewColumn
3615 * @cell_renderer: a #GtkCellRenderer
3616 * @start_pos: return location for the horizontal position of @cell within
3617 * @tree_column, may be %NULL
3618 * @width: return location for the width of @cell, may be %NULL
3620 * Obtains the horizontal position and size of a cell in a column. If the
3621 * cell is not found in the column, @start_pos and @width are not changed and
3622 * %FALSE is returned.
3624 * Return value: %TRUE if @cell belongs to @tree_column.
3627 pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
3628 GtkCellRenderer *cell_renderer,
3634 gboolean found_cell = FALSE;
3635 PsppSheetViewColumnCellInfo *cellinfo = NULL;
3637 list = pspp_sheet_view_column_cell_first (tree_column);
3638 for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
3640 cellinfo = list->data;
3641 if (cellinfo->cell == cell_renderer)
3647 if (cellinfo->cell->visible)
3648 current_x += cellinfo->real_width;
3654 *start_pos = current_x;
3656 *width = cellinfo->real_width;
3663 * pspp_sheet_view_column_queue_resize:
3664 * @tree_column: A #PsppSheetViewColumn
3666 * Flags the column, and the cell renderers added to this column, to have
3667 * their sizes renegotiated.
3672 pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
3674 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3676 if (tree_column->tree_view)
3677 _pspp_sheet_view_column_cell_set_dirty (tree_column);
3681 * pspp_sheet_view_column_get_tree_view:
3682 * @tree_column: A #PsppSheetViewColumn
3684 * Returns the #PsppSheetView wherein @tree_column has been inserted. If
3685 * @column is currently not inserted in any tree view, %NULL is
3688 * Return value: The tree view wherein @column has been inserted if any,
3694 pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
3696 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
3698 return tree_column->tree_view;
3702 GtkCellLayout *cell_layout;
3703 GtkCellRenderer *renderer;
3705 } AttributesSubParserData;
3708 attributes_start_element (GMarkupParseContext *context,
3709 const gchar *element_name,
3710 const gchar **names,
3711 const gchar **values,
3715 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
3718 if (strcmp (element_name, "attribute") == 0)
3720 for (i = 0; names[i]; i++)
3721 if (strcmp (names[i], "name") == 0)
3722 parser_data->attr_name = g_strdup (values[i]);
3724 else if (strcmp (element_name, "attributes") == 0)
3727 g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
3731 attributes_text_element (GMarkupParseContext *context,
3737 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
3742 if (!parser_data->attr_name)
3746 string = g_strndup (text, text_len);
3747 l = strtol (string, &endptr, 0);
3748 if (errno || endptr == string)
3752 GTK_BUILDER_ERROR_INVALID_VALUE,
3753 "Could not parse integer `%s'",
3760 gtk_cell_layout_add_attribute (parser_data->cell_layout,
3761 parser_data->renderer,
3762 parser_data->attr_name, l);
3763 g_free (parser_data->attr_name);
3764 parser_data->attr_name = NULL;
3767 static const GMarkupParser attributes_parser =
3769 attributes_start_element,
3771 attributes_text_element,
3775 _gtk_cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
3776 GtkBuilder *builder,
3778 const gchar *tagname,
3779 GMarkupParser *parser,
3782 AttributesSubParserData *parser_data;
3787 if (strcmp (tagname, "attributes") == 0)
3789 parser_data = g_slice_new0 (AttributesSubParserData);
3790 parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
3791 parser_data->renderer = GTK_CELL_RENDERER (child);
3792 parser_data->attr_name = NULL;
3794 *parser = attributes_parser;
3795 *data = parser_data;
3803 _gtk_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
3804 GtkBuilder *builder,
3806 const gchar *tagname,
3809 AttributesSubParserData *parser_data;
3811 parser_data = (AttributesSubParserData*)data;
3812 g_assert (!parser_data->attr_name);
3813 g_slice_free (AttributesSubParserData, parser_data);
3817 _gtk_cell_layout_buildable_add_child (GtkBuildable *buildable,
3818 GtkBuilder *builder,
3822 GtkCellLayoutIface *iface;
3824 g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
3825 g_return_if_fail (GTK_IS_CELL_RENDERER (child));
3827 iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
3828 g_return_if_fail (iface->pack_start != NULL);
3829 iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);