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
80 typedef struct _PsppSheetViewColumnCellInfo PsppSheetViewColumnCellInfo;
81 struct _PsppSheetViewColumnCellInfo
83 GtkCellRenderer *cell;
85 PsppSheetCellDataFunc func;
87 GDestroyNotify destroy;
93 guint in_editing_mode : 1;
97 static void pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface);
100 static void pspp_sheet_view_column_set_property (GObject *object,
104 static void pspp_sheet_view_column_get_property (GObject *object,
108 static void pspp_sheet_view_column_finalize (GObject *object);
110 /* GtkCellLayout implementation */
111 static void pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
112 GtkCellRenderer *cell,
114 static void pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
115 GtkCellRenderer *cell,
117 static void pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout);
118 static void pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
119 GtkCellRenderer *cell,
120 const gchar *attribute,
122 static void pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
123 GtkCellRenderer *cell,
124 GtkCellLayoutDataFunc func,
126 GDestroyNotify destroy);
127 static void pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
128 GtkCellRenderer *cell);
129 static void pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
130 GtkCellRenderer *cell,
132 static GList *pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
134 /* Button handling code */
135 static void pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column);
136 static void pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
138 /* Button signal handlers */
139 static gint pspp_sheet_view_column_button_event (GtkWidget *widget,
142 static void pspp_sheet_view_column_button_clicked (GtkWidget *widget,
144 static gboolean pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
145 gboolean group_cycling,
148 /* Property handlers */
149 static void pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
150 PsppSheetViewColumn *tree_column);
152 /* Internal functions */
153 static void pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
155 static void pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column);
156 static void pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
157 GtkCellRenderer *cell_renderer,
159 static PsppSheetViewColumnCellInfo *pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
160 GtkCellRenderer *cell_renderer);
162 /* cell list manipulation */
163 static GList *pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column);
164 static GList *pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column);
165 static GList *pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
167 static GList *pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
169 static void pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
170 PsppSheetViewColumnCellInfo *info);
171 /* GtkBuildable implementation */
172 static void pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface);
174 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
176 G_DEFINE_TYPE_WITH_CODE (PsppSheetViewColumn, pspp_sheet_view_column, GTK_TYPE_OBJECT,
177 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
178 pspp_sheet_view_column_cell_layout_init)
179 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
180 pspp_sheet_view_column_buildable_init))
184 pspp_sheet_view_column_class_init (PsppSheetViewColumnClass *class)
186 GObjectClass *object_class;
188 object_class = (GObjectClass*) class;
190 class->clicked = NULL;
192 object_class->finalize = pspp_sheet_view_column_finalize;
193 object_class->set_property = pspp_sheet_view_column_set_property;
194 object_class->get_property = pspp_sheet_view_column_get_property;
196 tree_column_signals[CLICKED] =
197 g_signal_new ("clicked",
198 G_OBJECT_CLASS_TYPE (object_class),
200 G_STRUCT_OFFSET (PsppSheetViewColumnClass, clicked),
202 g_cclosure_marshal_VOID__VOID,
205 tree_column_signals[QUERY_TOOLTIP] =
206 g_signal_new ("query-tooltip",
207 G_OBJECT_CLASS_TYPE (object_class),
210 g_signal_accumulator_true_handled, NULL,
211 psppire_marshal_BOOLEAN__OBJECT,
215 g_object_class_install_property (object_class,
217 g_param_spec_boolean ("visible",
219 P_("Whether to display the column"),
221 GTK_PARAM_READWRITE));
223 g_object_class_install_property (object_class,
225 g_param_spec_boolean ("resizable",
227 P_("Column is user-resizable"),
229 GTK_PARAM_READWRITE));
231 g_object_class_install_property (object_class,
233 g_param_spec_int ("width",
235 P_("Current width of the column"),
239 GTK_PARAM_READABLE));
240 g_object_class_install_property (object_class,
242 g_param_spec_int ("spacing",
244 P_("Space which is inserted between cells"),
248 GTK_PARAM_READWRITE));
250 g_object_class_install_property (object_class,
252 g_param_spec_int ("fixed-width",
254 P_("Current fixed width of the column"),
258 GTK_PARAM_READWRITE));
260 g_object_class_install_property (object_class,
262 g_param_spec_int ("min-width",
264 P_("Minimum allowed width of the column"),
268 GTK_PARAM_READWRITE));
270 g_object_class_install_property (object_class,
272 g_param_spec_int ("max-width",
274 P_("Maximum allowed width of the column"),
278 GTK_PARAM_READWRITE));
280 g_object_class_install_property (object_class,
282 g_param_spec_string ("title",
284 P_("Title to appear in column header"),
286 GTK_PARAM_READWRITE));
288 g_object_class_install_property (object_class,
290 g_param_spec_boolean ("expand",
292 P_("Column gets share of extra width allocated to the widget"),
294 GTK_PARAM_READWRITE));
296 g_object_class_install_property (object_class,
298 g_param_spec_boolean ("clickable",
300 P_("Whether the header can be clicked"),
302 GTK_PARAM_READWRITE));
305 g_object_class_install_property (object_class,
307 g_param_spec_object ("widget",
309 P_("Widget to put in column header button instead of column title"),
311 GTK_PARAM_READWRITE));
313 g_object_class_install_property (object_class,
315 g_param_spec_float ("alignment",
317 P_("X Alignment of the column header text or widget"),
321 GTK_PARAM_READWRITE));
323 g_object_class_install_property (object_class,
325 g_param_spec_boolean ("reorderable",
327 P_("Whether the column can be reordered around the headers"),
329 GTK_PARAM_READWRITE));
331 g_object_class_install_property (object_class,
333 g_param_spec_boolean ("sort-indicator",
334 P_("Sort indicator"),
335 P_("Whether to show a sort indicator"),
337 GTK_PARAM_READWRITE));
339 g_object_class_install_property (object_class,
341 g_param_spec_enum ("sort-order",
343 P_("Sort direction the sort indicator should indicate"),
346 GTK_PARAM_READWRITE));
349 * PsppSheetViewColumn:sort-column-id:
351 * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
352 * clickable. Set to %-1 to make the column unsortable.
356 g_object_class_install_property (object_class,
358 g_param_spec_int ("sort-column-id",
359 P_("Sort column ID"),
360 P_("Logical sort column ID this column sorts on when selected for sorting"),
364 GTK_PARAM_READWRITE));
366 g_object_class_install_property (object_class,
368 g_param_spec_boolean ("quick-edit",
370 P_("If true, editing starts upon the first click in the column. If false, the first click selects the column and a second click is needed to begin editing. This has no effect on cells that are not editable."),
372 GTK_PARAM_READWRITE));
376 pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface)
378 iface->add_child = _gtk_cell_layout_buildable_add_child;
379 iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
380 iface->custom_tag_end = _gtk_cell_layout_buildable_custom_tag_end;
384 pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface)
386 iface->pack_start = pspp_sheet_view_column_cell_layout_pack_start;
387 iface->pack_end = pspp_sheet_view_column_cell_layout_pack_end;
388 iface->clear = pspp_sheet_view_column_cell_layout_clear;
389 iface->add_attribute = pspp_sheet_view_column_cell_layout_add_attribute;
390 iface->set_cell_data_func = pspp_sheet_view_column_cell_layout_set_cell_data_func;
391 iface->clear_attributes = pspp_sheet_view_column_cell_layout_clear_attributes;
392 iface->reorder = pspp_sheet_view_column_cell_layout_reorder;
393 iface->get_cells = pspp_sheet_view_column_cell_layout_get_cells;
397 pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column)
399 tree_column->button = NULL;
400 tree_column->xalign = 0.0;
401 tree_column->width = 0;
402 tree_column->spacing = 0;
403 tree_column->requested_width = -1;
404 tree_column->min_width = -1;
405 tree_column->max_width = -1;
406 tree_column->resized_width = 0;
407 tree_column->visible = TRUE;
408 tree_column->resizable = FALSE;
409 tree_column->expand = FALSE;
410 tree_column->clickable = FALSE;
411 tree_column->dirty = TRUE;
412 tree_column->sort_order = GTK_SORT_ASCENDING;
413 tree_column->show_sort_indicator = FALSE;
414 tree_column->property_changed_signal = 0;
415 tree_column->sort_clicked_signal = 0;
416 tree_column->sort_column_changed_signal = 0;
417 tree_column->sort_column_id = -1;
418 tree_column->reorderable = FALSE;
419 tree_column->maybe_reordered = FALSE;
420 tree_column->fixed_width = 1;
421 tree_column->use_resized_width = FALSE;
422 tree_column->title = g_strdup ("");
423 tree_column->quick_edit = TRUE;
427 pspp_sheet_view_column_finalize (GObject *object)
429 PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
432 for (list = tree_column->cell_list; list; list = list->next)
434 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
438 GDestroyNotify d = info->destroy;
440 info->destroy = NULL;
443 pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
444 g_object_unref (info->cell);
448 g_free (tree_column->title);
449 g_list_free (tree_column->cell_list);
451 if (tree_column->child)
452 g_object_unref (tree_column->child);
454 G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
458 pspp_sheet_view_column_set_property (GObject *object,
463 PsppSheetViewColumn *tree_column;
465 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
470 pspp_sheet_view_column_set_visible (tree_column,
471 g_value_get_boolean (value));
475 pspp_sheet_view_column_set_resizable (tree_column,
476 g_value_get_boolean (value));
479 case PROP_FIXED_WIDTH:
480 pspp_sheet_view_column_set_fixed_width (tree_column,
481 g_value_get_int (value));
485 pspp_sheet_view_column_set_min_width (tree_column,
486 g_value_get_int (value));
490 pspp_sheet_view_column_set_max_width (tree_column,
491 g_value_get_int (value));
495 pspp_sheet_view_column_set_spacing (tree_column,
496 g_value_get_int (value));
500 pspp_sheet_view_column_set_title (tree_column,
501 g_value_get_string (value));
505 pspp_sheet_view_column_set_expand (tree_column,
506 g_value_get_boolean (value));
510 pspp_sheet_view_column_set_clickable (tree_column,
511 g_value_get_boolean (value));
515 pspp_sheet_view_column_set_widget (tree_column,
516 (GtkWidget*) g_value_get_object (value));
520 pspp_sheet_view_column_set_alignment (tree_column,
521 g_value_get_float (value));
524 case PROP_REORDERABLE:
525 pspp_sheet_view_column_set_reorderable (tree_column,
526 g_value_get_boolean (value));
529 case PROP_SORT_INDICATOR:
530 pspp_sheet_view_column_set_sort_indicator (tree_column,
531 g_value_get_boolean (value));
534 case PROP_SORT_ORDER:
535 pspp_sheet_view_column_set_sort_order (tree_column,
536 g_value_get_enum (value));
539 case PROP_SORT_COLUMN_ID:
540 pspp_sheet_view_column_set_sort_column_id (tree_column,
541 g_value_get_int (value));
544 case PROP_QUICK_EDIT:
545 pspp_sheet_view_column_set_quick_edit (tree_column,
546 g_value_get_boolean (value));
550 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
556 pspp_sheet_view_column_get_property (GObject *object,
561 PsppSheetViewColumn *tree_column;
563 tree_column = PSPP_SHEET_VIEW_COLUMN (object);
568 g_value_set_boolean (value,
569 pspp_sheet_view_column_get_visible (tree_column));
573 g_value_set_boolean (value,
574 pspp_sheet_view_column_get_resizable (tree_column));
578 g_value_set_int (value,
579 pspp_sheet_view_column_get_width (tree_column));
583 g_value_set_int (value,
584 pspp_sheet_view_column_get_spacing (tree_column));
587 case PROP_FIXED_WIDTH:
588 g_value_set_int (value,
589 pspp_sheet_view_column_get_fixed_width (tree_column));
593 g_value_set_int (value,
594 pspp_sheet_view_column_get_min_width (tree_column));
598 g_value_set_int (value,
599 pspp_sheet_view_column_get_max_width (tree_column));
603 g_value_set_string (value,
604 pspp_sheet_view_column_get_title (tree_column));
608 g_value_set_boolean (value,
609 pspp_sheet_view_column_get_expand (tree_column));
613 g_value_set_boolean (value,
614 pspp_sheet_view_column_get_clickable (tree_column));
618 g_value_set_object (value,
619 (GObject*) pspp_sheet_view_column_get_widget (tree_column));
623 g_value_set_float (value,
624 pspp_sheet_view_column_get_alignment (tree_column));
627 case PROP_REORDERABLE:
628 g_value_set_boolean (value,
629 pspp_sheet_view_column_get_reorderable (tree_column));
632 case PROP_SORT_INDICATOR:
633 g_value_set_boolean (value,
634 pspp_sheet_view_column_get_sort_indicator (tree_column));
637 case PROP_SORT_ORDER:
638 g_value_set_enum (value,
639 pspp_sheet_view_column_get_sort_order (tree_column));
642 case PROP_SORT_COLUMN_ID:
643 g_value_set_int (value,
644 pspp_sheet_view_column_get_sort_column_id (tree_column));
647 case PROP_QUICK_EDIT:
648 g_value_set_boolean (value,
649 pspp_sheet_view_column_get_quick_edit (tree_column));
653 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
658 /* Implementation of GtkCellLayout interface
662 pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
663 GtkCellRenderer *cell,
666 PsppSheetViewColumn *column;
667 PsppSheetViewColumnCellInfo *cell_info;
669 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
670 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
671 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
673 g_object_ref_sink (cell);
675 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
676 cell_info->cell = cell;
677 cell_info->expand = expand ? TRUE : FALSE;
678 cell_info->pack = GTK_PACK_START;
679 cell_info->has_focus = 0;
680 cell_info->attributes = NULL;
682 column->cell_list = g_list_append (column->cell_list, cell_info);
686 pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
687 GtkCellRenderer *cell,
690 PsppSheetViewColumn *column;
691 PsppSheetViewColumnCellInfo *cell_info;
693 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
694 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
695 g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
697 g_object_ref_sink (cell);
699 cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
700 cell_info->cell = cell;
701 cell_info->expand = expand ? TRUE : FALSE;
702 cell_info->pack = GTK_PACK_END;
703 cell_info->has_focus = 0;
704 cell_info->attributes = NULL;
706 column->cell_list = g_list_append (column->cell_list, cell_info);
710 pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
712 PsppSheetViewColumn *column;
714 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
715 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
717 while (column->cell_list)
719 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
721 pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
722 g_object_unref (info->cell);
724 column->cell_list = g_list_delete_link (column->cell_list,
730 pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
731 GtkCellRenderer *cell,
732 const gchar *attribute,
735 PsppSheetViewColumn *tree_column;
736 PsppSheetViewColumnCellInfo *info;
738 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
739 tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
741 info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
742 g_return_if_fail (info != NULL);
744 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
745 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
747 if (tree_column->tree_view)
748 _pspp_sheet_view_column_cell_set_dirty (tree_column);
752 pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
753 GtkCellRenderer *cell,
754 GtkCellLayoutDataFunc func,
756 GDestroyNotify destroy)
758 PsppSheetViewColumn *column;
759 PsppSheetViewColumnCellInfo *info;
761 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
762 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
764 info = pspp_sheet_view_column_get_cell_info (column, cell);
765 g_return_if_fail (info != NULL);
769 GDestroyNotify d = info->destroy;
771 info->destroy = NULL;
775 info->func = (PsppSheetCellDataFunc)func;
776 info->func_data = func_data;
777 info->destroy = destroy;
779 if (column->tree_view)
780 _pspp_sheet_view_column_cell_set_dirty (column);
784 pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
785 GtkCellRenderer *cell_renderer)
787 PsppSheetViewColumn *column;
788 PsppSheetViewColumnCellInfo *info;
790 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
791 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
793 info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
795 pspp_sheet_view_column_clear_attributes_by_info (column, info);
799 pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
800 GtkCellRenderer *cell,
804 PsppSheetViewColumn *column;
805 PsppSheetViewColumnCellInfo *info;
807 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
808 column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
810 info = pspp_sheet_view_column_get_cell_info (column, cell);
812 g_return_if_fail (info != NULL);
813 g_return_if_fail (position >= 0);
815 link = g_list_find (column->cell_list, info);
817 g_return_if_fail (link != NULL);
819 column->cell_list = g_list_delete_link (column->cell_list, link);
820 column->cell_list = g_list_insert (column->cell_list, info, position);
822 if (column->tree_view)
823 gtk_widget_queue_draw (column->tree_view);
827 pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
828 PsppSheetViewColumnCellInfo *info)
832 list = info->attributes;
834 while (list && list->next)
837 list = list->next->next;
839 g_slist_free (info->attributes);
840 info->attributes = NULL;
842 if (tree_column->tree_view)
843 _pspp_sheet_view_column_cell_set_dirty (tree_column);
847 on_query_tooltip (GtkWidget *widget,
850 gboolean keyboard_mode,
854 PsppSheetViewColumn *tree_column = user_data;
857 g_signal_emit (tree_column, tree_column_signals[QUERY_TOOLTIP], 0,
865 /* Button handling code
868 pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
870 PsppSheetView *tree_view;
874 tree_view = (PsppSheetView *) tree_column->tree_view;
876 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
877 g_return_if_fail (tree_column->button == NULL);
879 gtk_widget_push_composite_child ();
880 tree_column->button = gtk_button_new ();
881 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
882 gtk_widget_pop_composite_child ();
884 /* make sure we own a reference to it as well. */
885 if (tree_view->priv->header_window)
886 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
887 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
889 g_signal_connect (tree_column->button, "event",
890 G_CALLBACK (pspp_sheet_view_column_button_event),
892 g_signal_connect (tree_column->button, "clicked",
893 G_CALLBACK (pspp_sheet_view_column_button_clicked),
896 g_signal_connect (tree_column->button, "query-tooltip",
897 G_CALLBACK (on_query_tooltip), tree_column);
898 g_object_set (tree_column->button, "has-tooltip", TRUE, NULL);
900 tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
902 hbox = gtk_hbox_new (FALSE, 2);
903 tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
905 if (tree_column->child)
906 child = tree_column->child;
909 child = gtk_label_new (tree_column->title);
910 gtk_widget_show (child);
913 g_signal_connect (child, "mnemonic-activate",
914 G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
917 if (tree_column->xalign <= 0.5)
918 gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
920 gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
922 gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
924 gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
925 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
927 gtk_widget_show (hbox);
928 gtk_widget_show (tree_column->alignment);
929 pspp_sheet_view_column_update_button (tree_column);
933 pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
935 gint sort_column_id = -1;
937 GtkWidget *alignment;
939 GtkWidget *current_child;
940 GtkArrowType arrow_type = GTK_ARROW_NONE;
943 if (tree_column->tree_view)
944 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
948 /* Create a button if necessary */
949 if (tree_column->visible &&
950 tree_column->button == NULL &&
951 tree_column->tree_view &&
952 gtk_widget_get_realized (tree_column->tree_view))
953 pspp_sheet_view_column_create_button (tree_column);
955 if (! tree_column->button)
958 hbox = GTK_BIN (tree_column->button)->child;
959 alignment = tree_column->alignment;
960 arrow = tree_column->arrow;
961 current_child = GTK_BIN (alignment)->child;
963 /* Set up the actual button */
964 gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
967 if (tree_column->child)
969 if (current_child != tree_column->child)
971 gtk_container_remove (GTK_CONTAINER (alignment),
973 gtk_container_add (GTK_CONTAINER (alignment),
979 if (current_child == NULL)
981 current_child = gtk_label_new (NULL);
982 gtk_widget_show (current_child);
983 gtk_container_add (GTK_CONTAINER (alignment),
987 g_return_if_fail (GTK_IS_LABEL (current_child));
989 if (tree_column->title)
990 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
993 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
997 if (GTK_IS_TREE_SORTABLE (model))
998 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1002 if (tree_column->show_sort_indicator)
1004 gboolean alternative;
1006 g_object_get (gtk_widget_get_settings (tree_column->tree_view),
1007 "gtk-alternative-sort-arrows", &alternative,
1010 switch (tree_column->sort_order)
1012 case GTK_SORT_ASCENDING:
1013 arrow_type = alternative ? GTK_ARROW_UP : GTK_ARROW_DOWN;
1016 case GTK_SORT_DESCENDING:
1017 arrow_type = alternative ? GTK_ARROW_DOWN : GTK_ARROW_UP;
1021 g_warning (G_STRLOC": bad sort order");
1026 gtk_arrow_set (GTK_ARROW (arrow),
1030 /* Put arrow on the right if the text is left-or-center justified, and on the
1031 * left otherwise; do this by packing boxes, so flipping text direction will
1034 g_object_ref (arrow);
1035 gtk_container_remove (GTK_CONTAINER (hbox), arrow);
1037 if (tree_column->xalign <= 0.5)
1039 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1043 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1044 /* move it to the front */
1045 gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
1047 g_object_unref (arrow);
1049 if (tree_column->show_sort_indicator
1050 || (GTK_IS_TREE_SORTABLE (model) && tree_column->sort_column_id >= 0))
1051 gtk_widget_show (arrow);
1053 gtk_widget_hide (arrow);
1055 /* It's always safe to hide the button. It isn't always safe to show it, as
1056 * if you show it before it's realized, it'll get the wrong window. */
1057 if (tree_column->button &&
1058 tree_column->tree_view != NULL &&
1059 gtk_widget_get_realized (tree_column->tree_view))
1061 if (tree_column->visible)
1063 gtk_widget_show_now (tree_column->button);
1064 if (tree_column->window)
1066 if (tree_column->resizable)
1068 gdk_window_show (tree_column->window);
1069 gdk_window_raise (tree_column->window);
1073 gdk_window_hide (tree_column->window);
1079 gtk_widget_hide (tree_column->button);
1080 if (tree_column->window)
1081 gdk_window_hide (tree_column->window);
1085 if (tree_column->reorderable || tree_column->clickable)
1087 gtk_widget_set_can_focus (tree_column->button, TRUE);
1091 gtk_widget_set_can_focus (tree_column->button, FALSE);
1092 if (gtk_widget_has_focus (tree_column->button))
1094 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
1095 if (gtk_widget_is_toplevel (toplevel))
1097 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
1101 /* Queue a resize on the assumption that we always want to catch all changes
1102 * and columns don't change all that often.
1104 if (gtk_widget_get_realized (tree_column->tree_view))
1105 gtk_widget_queue_resize (tree_column->tree_view);
1109 /* Button signal handlers
1113 pspp_sheet_view_column_button_event (GtkWidget *widget,
1117 PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
1119 g_return_val_if_fail (event != NULL, FALSE);
1121 if (event->type == GDK_BUTTON_PRESS &&
1122 column->reorderable &&
1123 ((GdkEventButton *)event)->button == 1)
1125 column->maybe_reordered = TRUE;
1126 gdk_window_get_pointer (GTK_BUTTON (widget)->event_window,
1130 gtk_widget_grab_focus (widget);
1133 if (event->type == GDK_BUTTON_RELEASE ||
1134 event->type == GDK_LEAVE_NOTIFY)
1135 column->maybe_reordered = FALSE;
1137 if (event->type == GDK_MOTION_NOTIFY &&
1138 column->maybe_reordered &&
1139 (gtk_drag_check_threshold (widget,
1142 (gint) ((GdkEventMotion *)event)->x,
1143 (gint) ((GdkEventMotion *)event)->y)))
1145 column->maybe_reordered = FALSE;
1146 _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
1149 if (column->clickable == FALSE)
1151 switch (event->type)
1153 case GDK_BUTTON_PRESS:
1154 case GDK_2BUTTON_PRESS:
1155 case GDK_3BUTTON_PRESS:
1156 case GDK_MOTION_NOTIFY:
1157 case GDK_BUTTON_RELEASE:
1158 case GDK_ENTER_NOTIFY:
1159 case GDK_LEAVE_NOTIFY:
1170 pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
1172 g_signal_emit_by_name (data, "clicked");
1176 pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
1177 gboolean group_cycling,
1180 PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
1182 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
1184 PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
1185 if (column->clickable)
1186 gtk_button_clicked (GTK_BUTTON (column->button));
1187 else if (gtk_widget_get_can_focus (column->button))
1188 gtk_widget_grab_focus (column->button);
1190 gtk_widget_grab_focus (column->tree_view);
1196 pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
1197 PsppSheetViewColumn *column)
1199 gint sort_column_id;
1202 if (gtk_tree_sortable_get_sort_column_id (sortable,
1206 if (sort_column_id == column->sort_column_id)
1208 pspp_sheet_view_column_set_sort_indicator (column, TRUE);
1209 pspp_sheet_view_column_set_sort_order (column, order);
1213 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1218 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1223 pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
1226 gint sort_column_id;
1228 gboolean has_sort_column;
1229 gboolean has_default_sort_func;
1231 g_return_if_fail (tree_column->tree_view != NULL);
1234 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1237 has_default_sort_func =
1238 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
1240 if (has_sort_column &&
1241 sort_column_id == tree_column->sort_column_id)
1243 if (order == GTK_SORT_ASCENDING)
1244 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1245 tree_column->sort_column_id,
1246 GTK_SORT_DESCENDING);
1247 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
1248 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1249 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1250 GTK_SORT_ASCENDING);
1252 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1253 tree_column->sort_column_id,
1254 GTK_SORT_ASCENDING);
1258 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
1259 tree_column->sort_column_id,
1260 GTK_SORT_ASCENDING);
1266 pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
1268 GtkTreeModel *model;
1270 if (tree_column->tree_view == NULL)
1273 model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
1278 if (GTK_IS_TREE_SORTABLE (model) &&
1279 tree_column->sort_column_id != -1)
1281 gint real_sort_column_id;
1282 GtkSortType real_order;
1284 if (tree_column->sort_column_changed_signal == 0)
1285 tree_column->sort_column_changed_signal =
1286 g_signal_connect (model, "sort-column-changed",
1287 G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
1290 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1291 &real_sort_column_id,
1293 (real_sort_column_id == tree_column->sort_column_id))
1295 pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
1296 pspp_sheet_view_column_set_sort_order (tree_column, real_order);
1300 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
1306 /* Exported Private Functions.
1307 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1311 _pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
1313 PsppSheetView *tree_view;
1315 guint attributes_mask;
1318 tree_view = (PsppSheetView *)column->tree_view;
1319 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
1321 g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
1322 g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
1323 g_return_if_fail (tree_view->priv->header_window != NULL);
1324 g_return_if_fail (column->button != NULL);
1326 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
1328 if (column->visible)
1329 gtk_widget_show (column->button);
1331 attr.window_type = GDK_WINDOW_CHILD;
1332 attr.wclass = GDK_INPUT_ONLY;
1333 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
1334 attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
1335 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
1336 (GDK_BUTTON_PRESS_MASK |
1337 GDK_BUTTON_RELEASE_MASK |
1338 GDK_POINTER_MOTION_MASK |
1339 GDK_POINTER_MOTION_HINT_MASK |
1340 GDK_KEY_PRESS_MASK);
1341 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
1342 attr.cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (tree_view->priv->header_window),
1343 GDK_SB_H_DOUBLE_ARROW);
1345 attr.width = TREE_VIEW_DRAG_WIDTH;
1346 attr.height = tree_view->priv->header_height;
1348 attr.x = (column->button->allocation.x + (rtl ? 0 : column->button->allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
1349 column->window = gdk_window_new (tree_view->priv->header_window,
1350 &attr, attributes_mask);
1351 gdk_window_set_user_data (column->window, tree_view);
1353 pspp_sheet_view_column_update_button (column);
1355 gdk_cursor_unref (attr.cursor);
1359 _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
1361 g_return_if_fail (column != NULL);
1362 g_return_if_fail (column->window != NULL);
1364 gdk_window_set_user_data (column->window, NULL);
1365 gdk_window_destroy (column->window);
1366 column->window = NULL;
1370 _pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
1371 GtkTreeModel *old_model)
1373 if (column->sort_column_changed_signal)
1375 g_signal_handler_disconnect (old_model,
1376 column->sort_column_changed_signal);
1377 column->sort_column_changed_signal = 0;
1379 pspp_sheet_view_column_set_sort_indicator (column, FALSE);
1383 _pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
1384 PsppSheetView *tree_view)
1386 g_assert (column->tree_view == NULL);
1388 column->tree_view = GTK_WIDGET (tree_view);
1389 pspp_sheet_view_column_create_button (column);
1391 column->property_changed_signal =
1392 g_signal_connect_swapped (tree_view,
1394 G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
1397 pspp_sheet_view_column_setup_sort_column_id_callback (column);
1401 _pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
1403 if (column->tree_view && column->button)
1405 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1407 if (column->property_changed_signal)
1409 g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
1410 column->property_changed_signal = 0;
1413 if (column->sort_column_changed_signal)
1415 g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
1416 column->sort_column_changed_signal);
1417 column->sort_column_changed_signal = 0;
1420 column->tree_view = NULL;
1421 column->button = NULL;
1425 _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
1429 for (list = column->cell_list; list; list = list->next)
1430 if (((PsppSheetViewColumnCellInfo *)list->data)->cell->mode ==
1431 GTK_CELL_RENDERER_MODE_EDITABLE)
1437 /* gets cell being edited */
1439 _pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
1443 for (list = column->cell_list; list; list = list->next)
1444 if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
1445 return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
1451 _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
1456 for (list = column->cell_list; list; list = list->next)
1458 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1460 if ((cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1461 cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
1462 cellinfo->cell->visible)
1470 _pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
1476 list = pspp_sheet_view_column_cell_first (column);
1477 for (; list; list = pspp_sheet_view_column_cell_next (column, list))
1479 PsppSheetViewColumnCellInfo *cellinfo = list->data;
1480 if (current_x <= x && x <= current_x + cellinfo->real_width)
1481 return cellinfo->cell;
1482 current_x += cellinfo->real_width;
1488 /* Public Functions */
1492 * pspp_sheet_view_column_new:
1494 * Creates a new #PsppSheetViewColumn.
1496 * Return value: A newly created #PsppSheetViewColumn.
1498 PsppSheetViewColumn *
1499 pspp_sheet_view_column_new (void)
1501 PsppSheetViewColumn *tree_column;
1503 tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
1509 * pspp_sheet_view_column_new_with_attributes:
1510 * @title: The title to set the header to.
1511 * @cell: The #GtkCellRenderer.
1512 * @Varargs: A %NULL-terminated list of attributes.
1514 * Creates a new #PsppSheetViewColumn with a number of default values. This is
1515 * equivalent to calling pspp_sheet_view_column_set_title(),
1516 * pspp_sheet_view_column_pack_start(), and
1517 * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
1519 * Here's a simple example:
1521 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1524 * PsppSheetViewColumn *column;
1525 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
1527 * column = pspp_sheet_view_column_new_with_attributes ("Title",
1529 * "text", TEXT_COLUMN,
1530 * "foreground", COLOR_COLUMN,
1535 * Return value: A newly created #PsppSheetViewColumn.
1537 PsppSheetViewColumn *
1538 pspp_sheet_view_column_new_with_attributes (const gchar *title,
1539 GtkCellRenderer *cell,
1542 PsppSheetViewColumn *retval;
1545 retval = pspp_sheet_view_column_new ();
1547 pspp_sheet_view_column_set_title (retval, title);
1548 pspp_sheet_view_column_pack_start (retval, cell, TRUE);
1550 va_start (args, cell);
1551 pspp_sheet_view_column_set_attributesv (retval, cell, args);
1557 static PsppSheetViewColumnCellInfo *
1558 pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
1559 GtkCellRenderer *cell_renderer)
1562 for (list = tree_column->cell_list; list; list = list->next)
1563 if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
1564 return (PsppSheetViewColumnCellInfo *) list->data;
1570 * pspp_sheet_view_column_pack_start:
1571 * @tree_column: A #PsppSheetViewColumn.
1572 * @cell: The #GtkCellRenderer.
1573 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1575 * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
1576 * the @cell is allocated no more space than it needs. Any unused space is divided
1577 * evenly between cells for which @expand is %TRUE.
1580 pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
1581 GtkCellRenderer *cell,
1584 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
1588 * pspp_sheet_view_column_pack_end:
1589 * @tree_column: A #PsppSheetViewColumn.
1590 * @cell: The #GtkCellRenderer.
1591 * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1593 * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
1594 * is allocated no more space than it needs. Any unused space is divided
1595 * evenly between cells for which @expand is %TRUE.
1598 pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
1599 GtkCellRenderer *cell,
1602 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
1606 * pspp_sheet_view_column_clear:
1607 * @tree_column: A #PsppSheetViewColumn
1609 * Unsets all the mappings on all renderers on the @tree_column.
1612 pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
1614 gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
1618 pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
1620 PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
1621 GList *retval = NULL, *list;
1623 g_return_val_if_fail (tree_column != NULL, NULL);
1625 for (list = tree_column->cell_list; list; list = list->next)
1627 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
1629 retval = g_list_append (retval, info->cell);
1636 * pspp_sheet_view_column_get_cell_renderers:
1637 * @tree_column: A #PsppSheetViewColumn
1639 * Returns a newly-allocated #GList of all the cell renderers in the column,
1640 * in no particular order. The list must be freed with g_list_free().
1642 * Return value: A list of #GtkCellRenderers
1644 * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
1647 pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
1649 return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
1653 * pspp_sheet_view_column_add_attribute:
1654 * @tree_column: A #PsppSheetViewColumn.
1655 * @cell_renderer: the #GtkCellRenderer to set attributes on
1656 * @attribute: An attribute on the renderer
1657 * @column: The column position on the model to get the attribute from.
1659 * Adds an attribute mapping to the list in @tree_column. The @column is the
1660 * column of the model to get a value from, and the @attribute is the
1661 * parameter on @cell_renderer to be set from the value. So for example
1662 * if column 2 of the model contains strings, you could have the
1663 * "text" attribute of a #GtkCellRendererText get its values from
1667 pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
1668 GtkCellRenderer *cell_renderer,
1669 const gchar *attribute,
1672 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
1673 cell_renderer, attribute, column);
1677 pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
1678 GtkCellRenderer *cell_renderer,
1684 attribute = va_arg (args, gchar *);
1686 pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
1688 while (attribute != NULL)
1690 column = va_arg (args, gint);
1691 pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1692 attribute = va_arg (args, gchar *);
1697 * pspp_sheet_view_column_set_attributes:
1698 * @tree_column: A #PsppSheetViewColumn.
1699 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1700 * @Varargs: A %NULL-terminated list of attributes.
1702 * Sets the attributes in the list as the attributes of @tree_column.
1703 * The attributes should be in attribute/column order, as in
1704 * pspp_sheet_view_column_add_attribute(). All existing attributes
1705 * are removed, and replaced with the new attributes.
1708 pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
1709 GtkCellRenderer *cell_renderer,
1714 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1715 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1716 g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
1718 va_start (args, cell_renderer);
1719 pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
1725 * pspp_sheet_view_column_set_cell_data_func:
1726 * @tree_column: A #PsppSheetViewColumn
1727 * @cell_renderer: A #GtkCellRenderer
1728 * @func: The #PsppSheetViewColumnFunc to use.
1729 * @func_data: The user data for @func.
1730 * @destroy: The destroy notification for @func_data
1732 * Sets the #PsppSheetViewColumnFunc to use for the column. This
1733 * function is used instead of the standard attributes mapping for
1734 * setting the column value, and should set the value of @tree_column's
1735 * cell renderer as appropriate. @func may be %NULL to remove an
1739 pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
1740 GtkCellRenderer *cell_renderer,
1741 PsppSheetCellDataFunc func,
1743 GDestroyNotify destroy)
1745 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
1747 (GtkCellLayoutDataFunc)func,
1748 func_data, destroy);
1753 * pspp_sheet_view_column_clear_attributes:
1754 * @tree_column: a #PsppSheetViewColumn
1755 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1757 * Clears all existing attributes previously set with
1758 * pspp_sheet_view_column_set_attributes().
1761 pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
1762 GtkCellRenderer *cell_renderer)
1764 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
1769 * pspp_sheet_view_column_set_spacing:
1770 * @tree_column: A #PsppSheetViewColumn.
1771 * @spacing: distance between cell renderers in pixels.
1773 * Sets the spacing field of @tree_column, which is the number of pixels to
1774 * place between cell renderers packed into it.
1777 pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
1780 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1781 g_return_if_fail (spacing >= 0);
1783 if (tree_column->spacing == spacing)
1786 tree_column->spacing = spacing;
1787 if (tree_column->tree_view)
1788 _pspp_sheet_view_column_cell_set_dirty (tree_column);
1792 * pspp_sheet_view_column_get_spacing:
1793 * @tree_column: A #PsppSheetViewColumn.
1795 * Returns the spacing of @tree_column.
1797 * Return value: the spacing of @tree_column.
1800 pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
1802 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
1804 return tree_column->spacing;
1807 /* Options for manipulating the columns */
1810 * pspp_sheet_view_column_set_visible:
1811 * @tree_column: A #PsppSheetViewColumn.
1812 * @visible: %TRUE if the @tree_column is visible.
1814 * Sets the visibility of @tree_column.
1817 pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
1820 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1822 visible = !! visible;
1824 if (tree_column->visible == visible)
1827 tree_column->visible = visible;
1829 if (tree_column->visible)
1830 _pspp_sheet_view_column_cell_set_dirty (tree_column);
1832 pspp_sheet_view_column_update_button (tree_column);
1833 g_object_notify (G_OBJECT (tree_column), "visible");
1837 * pspp_sheet_view_column_get_visible:
1838 * @tree_column: A #PsppSheetViewColumn.
1840 * Returns %TRUE if @tree_column is visible.
1842 * Return value: whether the column is visible or not. If it is visible, then
1843 * the tree will show the column.
1846 pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
1848 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
1850 return tree_column->visible;
1854 * pspp_sheet_view_column_set_resizable:
1855 * @tree_column: A #PsppSheetViewColumn
1856 * @resizable: %TRUE, if the column can be resized
1858 * If @resizable is %TRUE, then the user can explicitly resize the column by
1859 * grabbing the outer edge of the column button.
1862 pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
1865 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1867 resizable = !! resizable;
1869 if (tree_column->resizable == resizable)
1872 tree_column->resizable = resizable;
1874 pspp_sheet_view_column_update_button (tree_column);
1876 g_object_notify (G_OBJECT (tree_column), "resizable");
1880 * pspp_sheet_view_column_get_resizable:
1881 * @tree_column: A #PsppSheetViewColumn
1883 * Returns %TRUE if the @tree_column can be resized by the end user.
1885 * Return value: %TRUE, if the @tree_column can be resized.
1888 pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
1890 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
1892 return tree_column->resizable;
1897 * pspp_sheet_view_column_get_width:
1898 * @tree_column: A #PsppSheetViewColumn.
1900 * Returns the current size of @tree_column in pixels.
1902 * Return value: The current width of @tree_column.
1905 pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
1907 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
1909 return tree_column->width;
1913 * pspp_sheet_view_column_set_fixed_width:
1914 * @tree_column: A #PsppSheetViewColumn.
1915 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
1917 * Sets the size of the column in pixels. The size of the column is clamped to
1918 * the min/max width for the column. Please note that the min/max width of the
1919 * column doesn't actually affect the "fixed_width" property of the widget, just
1920 * the actual size when displayed.
1923 pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
1926 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1927 g_return_if_fail (fixed_width > 0);
1929 tree_column->fixed_width = fixed_width;
1930 tree_column->use_resized_width = FALSE;
1932 if (tree_column->tree_view &&
1933 gtk_widget_get_realized (tree_column->tree_view))
1935 gtk_widget_queue_resize (tree_column->tree_view);
1938 g_object_notify (G_OBJECT (tree_column), "fixed-width");
1942 * pspp_sheet_view_column_get_fixed_width:
1943 * @tree_column: a #PsppSheetViewColumn
1945 * Gets the fixed width of the column. This value is only meaning may not be
1946 * the actual width of the column on the screen, just what is requested.
1948 * Return value: the fixed width of the column
1951 pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
1953 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
1955 return tree_column->fixed_width;
1959 * pspp_sheet_view_column_set_min_width:
1960 * @tree_column: A #PsppSheetViewColumn.
1961 * @min_width: The minimum width of the column in pixels, or -1.
1963 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
1964 * minimum width is unset.
1967 pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
1970 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
1971 g_return_if_fail (min_width >= -1);
1973 if (min_width == tree_column->min_width)
1976 if (tree_column->visible &&
1977 tree_column->tree_view != NULL &&
1978 gtk_widget_get_realized (tree_column->tree_view))
1980 if (min_width > tree_column->width)
1981 gtk_widget_queue_resize (tree_column->tree_view);
1984 tree_column->min_width = min_width;
1985 g_object_freeze_notify (G_OBJECT (tree_column));
1986 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
1988 tree_column->max_width = min_width;
1989 g_object_notify (G_OBJECT (tree_column), "max-width");
1991 g_object_notify (G_OBJECT (tree_column), "min-width");
1992 g_object_thaw_notify (G_OBJECT (tree_column));
1996 * pspp_sheet_view_column_get_min_width:
1997 * @tree_column: A #PsppSheetViewColumn.
1999 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
2002 * Return value: The minimum width of the @tree_column.
2005 pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
2007 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2009 return tree_column->min_width;
2013 * pspp_sheet_view_column_set_max_width:
2014 * @tree_column: A #PsppSheetViewColumn.
2015 * @max_width: The maximum width of the column in pixels, or -1.
2017 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
2018 * maximum width is unset. Note, the column can actually be wider than max
2019 * width if it's the last column in a view. In this case, the column expands to
2020 * fill any extra space.
2023 pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
2026 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2027 g_return_if_fail (max_width >= -1);
2029 if (max_width == tree_column->max_width)
2032 if (tree_column->visible &&
2033 tree_column->tree_view != NULL &&
2034 gtk_widget_get_realized (tree_column->tree_view))
2036 if (max_width != -1 && max_width < tree_column->width)
2037 gtk_widget_queue_resize (tree_column->tree_view);
2040 tree_column->max_width = max_width;
2041 g_object_freeze_notify (G_OBJECT (tree_column));
2042 if (max_width != -1 && max_width < tree_column->min_width)
2044 tree_column->min_width = max_width;
2045 g_object_notify (G_OBJECT (tree_column), "min-width");
2047 g_object_notify (G_OBJECT (tree_column), "max-width");
2048 g_object_thaw_notify (G_OBJECT (tree_column));
2052 * pspp_sheet_view_column_get_max_width:
2053 * @tree_column: A #PsppSheetViewColumn.
2055 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
2058 * Return value: The maximum width of the @tree_column.
2061 pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
2063 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
2065 return tree_column->max_width;
2069 * pspp_sheet_view_column_clicked:
2070 * @tree_column: a #PsppSheetViewColumn
2072 * Emits the "clicked" signal on the column. This function will only work if
2073 * @tree_column is clickable.
2076 pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
2078 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2080 if (tree_column->visible &&
2081 tree_column->button &&
2082 tree_column->clickable)
2083 gtk_button_clicked (GTK_BUTTON (tree_column->button));
2087 * pspp_sheet_view_column_set_title:
2088 * @tree_column: A #PsppSheetViewColumn.
2089 * @title: The title of the @tree_column.
2091 * Sets the title of the @tree_column. If a custom widget has been set, then
2092 * this value is ignored.
2095 pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
2100 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2102 new_title = g_strdup (title);
2103 g_free (tree_column->title);
2104 tree_column->title = new_title;
2106 pspp_sheet_view_column_update_button (tree_column);
2107 g_object_notify (G_OBJECT (tree_column), "title");
2111 * pspp_sheet_view_column_get_title:
2112 * @tree_column: A #PsppSheetViewColumn.
2114 * Returns the title of the widget.
2116 * Return value: the title of the column. This string should not be
2117 * modified or freed.
2119 G_CONST_RETURN gchar *
2120 pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
2122 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2124 return tree_column->title;
2128 * pspp_sheet_view_column_set_expand:
2129 * @tree_column: A #PsppSheetViewColumn
2130 * @expand: %TRUE if the column should take available extra space, %FALSE if not
2132 * Sets the column to take available extra space. This space is shared equally
2133 * amongst all columns that have the expand set to %TRUE. If no column has this
2134 * option set, then the last column gets all extra space. By default, every
2135 * column is created with this %FALSE.
2140 pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
2143 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2145 expand = expand?TRUE:FALSE;
2146 if (tree_column->expand == expand)
2148 tree_column->expand = expand;
2150 if (tree_column->visible &&
2151 tree_column->tree_view != NULL &&
2152 gtk_widget_get_realized (tree_column->tree_view))
2154 /* We want to continue using the original width of the
2155 * column that includes additional space added by the user
2156 * resizing the columns and possibly extra (expanded) space, which
2157 * are not included in the resized width.
2159 tree_column->use_resized_width = FALSE;
2161 gtk_widget_queue_resize (tree_column->tree_view);
2164 g_object_notify (G_OBJECT (tree_column), "expand");
2168 * pspp_sheet_view_column_get_expand:
2169 * @tree_column: a #PsppSheetViewColumn
2171 * Return %TRUE if the column expands to take any available space.
2173 * Return value: %TRUE, if the column expands
2178 pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
2180 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2182 return tree_column->expand;
2186 * pspp_sheet_view_column_set_clickable:
2187 * @tree_column: A #PsppSheetViewColumn.
2188 * @clickable: %TRUE if the header is active.
2190 * Sets the header to be active if @active is %TRUE. When the header is active,
2191 * then it can take keyboard focus, and can be clicked.
2194 pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
2197 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2199 clickable = !! clickable;
2200 if (tree_column->clickable == clickable)
2203 tree_column->clickable = clickable;
2204 pspp_sheet_view_column_update_button (tree_column);
2205 g_object_notify (G_OBJECT (tree_column), "clickable");
2209 * pspp_sheet_view_column_get_clickable:
2210 * @tree_column: a #PsppSheetViewColumn
2212 * Returns %TRUE if the user can click on the header for the column.
2214 * Return value: %TRUE if user can click the column header.
2217 pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
2219 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2221 return tree_column->clickable;
2225 * pspp_sheet_view_column_set_widget:
2226 * @tree_column: A #PsppSheetViewColumn.
2227 * @widget: (allow-none): A child #GtkWidget, or %NULL.
2229 * Sets the widget in the header to be @widget. If widget is %NULL, then the
2230 * header button is set with a #GtkLabel set to the title of @tree_column.
2233 pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
2236 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2237 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
2240 g_object_ref_sink (widget);
2242 if (tree_column->child)
2243 g_object_unref (tree_column->child);
2245 tree_column->child = widget;
2246 pspp_sheet_view_column_update_button (tree_column);
2247 g_object_notify (G_OBJECT (tree_column), "widget");
2251 * pspp_sheet_view_column_get_widget:
2252 * @tree_column: A #PsppSheetViewColumn.
2254 * Returns the #GtkWidget in the button on the column header. If a custom
2255 * widget has not been set then %NULL is returned.
2257 * Return value: The #GtkWidget in the column header, or %NULL
2260 pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
2262 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
2264 return tree_column->child;
2268 * pspp_sheet_view_column_set_alignment:
2269 * @tree_column: A #PsppSheetViewColumn.
2270 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2272 * Sets the alignment of the title or custom widget inside the column header.
2273 * The alignment determines its location inside the button -- 0.0 for left, 0.5
2274 * for center, 1.0 for right.
2277 pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
2280 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2282 xalign = CLAMP (xalign, 0.0, 1.0);
2284 if (tree_column->xalign == xalign)
2287 tree_column->xalign = xalign;
2288 pspp_sheet_view_column_update_button (tree_column);
2289 g_object_notify (G_OBJECT (tree_column), "alignment");
2293 * pspp_sheet_view_column_get_alignment:
2294 * @tree_column: A #PsppSheetViewColumn.
2296 * Returns the current x alignment of @tree_column. This value can range
2297 * between 0.0 and 1.0.
2299 * Return value: The current alignent of @tree_column.
2302 pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
2304 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0.5);
2306 return tree_column->xalign;
2310 * pspp_sheet_view_column_set_reorderable:
2311 * @tree_column: A #PsppSheetViewColumn
2312 * @reorderable: %TRUE, if the column can be reordered.
2314 * If @reorderable is %TRUE, then the column can be reordered by the end user
2315 * dragging the header.
2318 pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
2319 gboolean reorderable)
2321 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2324 pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
2326 if (tree_column->reorderable == (reorderable?TRUE:FALSE))
2329 tree_column->reorderable = (reorderable?TRUE:FALSE);
2330 pspp_sheet_view_column_update_button (tree_column);
2331 g_object_notify (G_OBJECT (tree_column), "reorderable");
2335 * pspp_sheet_view_column_get_reorderable:
2336 * @tree_column: A #PsppSheetViewColumn
2338 * Returns %TRUE if the @tree_column can be reordered by the user.
2340 * Return value: %TRUE if the @tree_column can be reordered by the user.
2343 pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
2345 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2347 return tree_column->reorderable;
2351 * pspp_sheet_view_column_set_quick_edit:
2352 * @tree_column: A #PsppSheetViewColumn
2353 * @quick_edit: If true, editing starts upon the first click in the column. If
2354 * false, the first click selects the column and a second click is needed to
2355 * begin editing. This has no effect on cells that are not editable.
2358 pspp_sheet_view_column_set_quick_edit (PsppSheetViewColumn *tree_column,
2359 gboolean quick_edit)
2361 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2363 quick_edit = !!quick_edit;
2364 if (tree_column->quick_edit != quick_edit)
2366 tree_column->quick_edit = (quick_edit?TRUE:FALSE);
2367 g_object_notify (G_OBJECT (tree_column), "quick-edit");
2372 * pspp_sheet_view_column_get_quick_edit:
2373 * @tree_column: A #PsppSheetViewColumn
2375 * Returns %TRUE if editing starts upon the first click in the column. Returns
2376 * %FALSE, the first click selects the column and a second click is needed to
2377 * begin editing. This is not meaningful for cells that are not editable.
2379 * Return value: %TRUE if editing starts upon the first click.
2382 pspp_sheet_view_column_get_quick_edit (PsppSheetViewColumn *tree_column)
2384 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2386 return tree_column->quick_edit;
2391 * pspp_sheet_view_column_set_sort_column_id:
2392 * @tree_column: a #PsppSheetViewColumn
2393 * @sort_column_id: The @sort_column_id of the model to sort on.
2395 * Sets the logical @sort_column_id that this column sorts on when this column
2396 * is selected for sorting. Doing so makes the column header clickable.
2399 pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
2400 gint sort_column_id)
2402 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2403 g_return_if_fail (sort_column_id >= -1);
2405 if (tree_column->sort_column_id == sort_column_id)
2408 tree_column->sort_column_id = sort_column_id;
2410 /* Handle unsetting the id */
2411 if (sort_column_id == -1)
2413 GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
2415 if (tree_column->sort_clicked_signal)
2417 g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
2418 tree_column->sort_clicked_signal = 0;
2421 if (tree_column->sort_column_changed_signal)
2423 g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
2424 tree_column->sort_column_changed_signal = 0;
2427 pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2428 pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
2429 pspp_sheet_view_column_set_clickable (tree_column, FALSE);
2430 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2434 pspp_sheet_view_column_set_clickable (tree_column, TRUE);
2436 if (! tree_column->sort_clicked_signal)
2437 tree_column->sort_clicked_signal = g_signal_connect (tree_column,
2439 G_CALLBACK (pspp_sheet_view_column_sort),
2442 pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
2443 g_object_notify (G_OBJECT (tree_column), "sort-column-id");
2447 * pspp_sheet_view_column_get_sort_column_id:
2448 * @tree_column: a #PsppSheetViewColumn
2450 * Gets the logical @sort_column_id that the model sorts on when this
2451 * column is selected for sorting.
2452 * See pspp_sheet_view_column_set_sort_column_id().
2454 * Return value: the current @sort_column_id for this column, or -1 if
2455 * this column can't be used for sorting.
2458 pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
2460 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2462 return tree_column->sort_column_id;
2466 * pspp_sheet_view_column_set_sort_indicator:
2467 * @tree_column: a #PsppSheetViewColumn
2468 * @setting: %TRUE to display an indicator that the column is sorted
2470 * Call this function with a @setting of %TRUE to display an arrow in
2471 * the header button indicating the column is sorted. Call
2472 * pspp_sheet_view_column_set_sort_order() to change the direction of
2477 pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
2480 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2482 setting = setting != FALSE;
2484 if (setting == tree_column->show_sort_indicator)
2487 tree_column->show_sort_indicator = setting;
2488 pspp_sheet_view_column_update_button (tree_column);
2489 g_object_notify (G_OBJECT (tree_column), "sort-indicator");
2493 * pspp_sheet_view_column_get_sort_indicator:
2494 * @tree_column: a #PsppSheetViewColumn
2496 * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
2498 * Return value: whether the sort indicator arrow is displayed
2501 pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column)
2503 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
2505 return tree_column->show_sort_indicator;
2509 * pspp_sheet_view_column_set_sort_order:
2510 * @tree_column: a #PsppSheetViewColumn
2511 * @order: sort order that the sort indicator should indicate
2513 * Changes the appearance of the sort indicator.
2515 * This <emphasis>does not</emphasis> actually sort the model. Use
2516 * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
2517 * support. This function is primarily for custom sorting behavior, and should
2518 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2519 * that. For custom models, the mechanism will vary.
2521 * The sort indicator changes direction to indicate normal sort or reverse sort.
2522 * Note that you must have the sort indicator enabled to see anything when
2523 * calling this function; see pspp_sheet_view_column_set_sort_indicator().
2526 pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
2529 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2531 if (order == tree_column->sort_order)
2534 tree_column->sort_order = order;
2535 pspp_sheet_view_column_update_button (tree_column);
2536 g_object_notify (G_OBJECT (tree_column), "sort-order");
2540 * pspp_sheet_view_column_get_sort_order:
2541 * @tree_column: a #PsppSheetViewColumn
2543 * Gets the value set by pspp_sheet_view_column_set_sort_order().
2545 * Return value: the sort order the sort indicator is indicating
2548 pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column)
2550 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
2552 return tree_column->sort_order;
2556 * pspp_sheet_view_column_cell_set_cell_data:
2557 * @tree_column: A #PsppSheetViewColumn.
2558 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2559 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2561 * Sets the cell renderer based on the @tree_model and @iter. That is, for
2562 * every attribute mapping in @tree_column, it will get a value from the set
2563 * column on the @iter, and use that value to set the attribute on the cell
2564 * renderer. This is used primarily by the #PsppSheetView.
2567 pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
2568 GtkTreeModel *tree_model,
2572 GValue value = { 0, };
2575 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2577 if (tree_model == NULL)
2580 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2582 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
2583 GObject *cell = (GObject *) info->cell;
2585 list = info->attributes;
2587 g_object_freeze_notify (cell);
2589 while (list && list->next)
2591 gtk_tree_model_get_value (tree_model, iter,
2592 GPOINTER_TO_INT (list->next->data),
2594 g_object_set_property (cell, (gchar *) list->data, &value);
2595 g_value_unset (&value);
2596 list = list->next->next;
2600 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2601 g_object_thaw_notify (G_OBJECT (info->cell));
2607 * pspp_sheet_view_column_cell_get_size:
2608 * @tree_column: A #PsppSheetViewColumn.
2609 * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
2610 * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
2611 * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
2612 * @width: (allow-none): location to return width needed to render a cell, or %NULL
2613 * @height: (allow-none): location to return height needed to render a cell, or %NULL
2615 * Obtains the width and height needed to render the column. This is used
2616 * primarily by the #PsppSheetView.
2619 pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
2620 const GdkRectangle *cell_area,
2627 gboolean first_cell = TRUE;
2628 gint focus_line_width;
2630 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
2637 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
2639 for (list = tree_column->cell_list; list; list = list->next)
2641 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2643 gint new_height = 0;
2645 g_object_get (info->cell, "visible", &visible, NULL);
2647 if (visible == FALSE)
2650 if (first_cell == FALSE && width)
2651 *width += tree_column->spacing;
2653 gtk_cell_renderer_get_size (info->cell,
2654 tree_column->tree_view,
2662 * height = MAX (*height, new_height + focus_line_width * 2);
2663 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
2665 * width += info->requested_width;
2670 /* rendering, event handling and rendering focus are somewhat complicated, and
2671 * quite a bit of code. Rather than duplicate them, we put them together to
2672 * keep the code in one place.
2674 * To better understand what's going on, check out
2675 * docs/tree-column-sizing.png
2684 pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn *tree_column,
2686 const GdkRectangle *background_area,
2687 const GdkRectangle *cell_area,
2690 const GdkRectangle *expose_area, /* RENDER */
2691 GdkRectangle *focus_rectangle, /* FOCUS */
2692 GtkCellEditable **editable_widget, /* EVENT */
2693 GdkEvent *event, /* EVENT */
2694 gchar *path_string) /* EVENT */
2697 GdkRectangle real_cell_area;
2698 GdkRectangle real_background_area;
2699 GdkRectangle real_expose_area = *cell_area;
2701 gint expand_cell_count = 0;
2702 gint full_requested_width = 0;
2704 gint min_x, min_y, max_x, max_y;
2705 gint focus_line_width;
2707 gint horizontal_separator;
2708 gboolean cursor_row = FALSE;
2709 gboolean first_cell = TRUE;
2711 /* If we have rtl text, we need to transform our areas */
2712 GdkRectangle rtl_cell_area;
2713 GdkRectangle rtl_background_area;
2720 rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
2721 special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
2723 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
2725 PsppSheetViewColumnCellInfo *info = NULL;
2726 gboolean found_has_focus = FALSE;
2728 /* one should have focus */
2729 for (list = tree_column->cell_list; list; list = list->next)
2732 if (info && info->has_focus)
2734 found_has_focus = TRUE;
2739 if (!found_has_focus)
2741 /* give the first one focus */
2742 info = pspp_sheet_view_column_cell_first (tree_column)->data;
2743 info->has_focus = TRUE;
2747 cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
2749 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
2750 "focus-line-width", &focus_line_width,
2751 "horizontal-separator", &horizontal_separator,
2754 real_cell_area = *cell_area;
2755 real_background_area = *background_area;
2758 real_cell_area.x += focus_line_width;
2759 real_cell_area.y += focus_line_width;
2760 real_cell_area.height -= 2 * focus_line_width;
2763 depth = real_background_area.width - real_cell_area.width;
2765 depth = real_cell_area.x - real_background_area.x;
2767 /* Find out how much extra space we have to allocate */
2768 for (list = tree_column->cell_list; list; list = list->next)
2770 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
2772 if (! info->cell->visible)
2775 if (info->expand == TRUE)
2776 expand_cell_count ++;
2777 full_requested_width += info->requested_width;
2780 full_requested_width += tree_column->spacing;
2785 extra_space = cell_area->width - full_requested_width;
2786 if (extra_space < 0)
2788 else if (extra_space > 0 && expand_cell_count > 0)
2789 extra_space /= expand_cell_count;
2791 /* iterate list for GTK_PACK_START cells */
2792 for (list = tree_column->cell_list; list; list = list->next)
2794 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2796 if (info->pack == GTK_PACK_END)
2799 if (! info->cell->visible)
2802 if ((info->has_focus || special_cells == 1) && cursor_row)
2803 flags |= GTK_CELL_RENDERER_FOCUSED;
2805 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2807 info->real_width = info->requested_width + (info->expand?extra_space:0);
2809 /* We constrain ourselves to only the width available */
2810 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
2812 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
2815 if (real_cell_area.x > cell_area->x + cell_area->width)
2818 real_cell_area.width = info->real_width;
2819 real_cell_area.width -= 2 * focus_line_width;
2823 real_background_area.width = info->real_width + depth;
2827 /* fill the rest of background for the last cell */
2828 real_background_area.width = background_area->x + background_area->width - real_background_area.x;
2831 rtl_cell_area = real_cell_area;
2832 rtl_background_area = real_background_area;
2836 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
2837 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
2841 if (action == CELL_ACTION_RENDER)
2843 gtk_cell_renderer_render (info->cell,
2845 tree_column->tree_view,
2846 &rtl_background_area,
2852 else if (action == CELL_ACTION_FOCUS)
2854 gint x_offset, y_offset, width, height;
2856 gtk_cell_renderer_get_size (info->cell,
2857 tree_column->tree_view,
2859 &x_offset, &y_offset,
2862 if (special_cells > 1)
2864 if (info->has_focus)
2866 min_x = rtl_cell_area.x + x_offset;
2867 max_x = min_x + width;
2868 min_y = rtl_cell_area.y + y_offset;
2869 max_y = min_y + height;
2874 if (min_x > (rtl_cell_area.x + x_offset))
2875 min_x = rtl_cell_area.x + x_offset;
2876 if (max_x < rtl_cell_area.x + x_offset + width)
2877 max_x = rtl_cell_area.x + x_offset + width;
2878 if (min_y > (rtl_cell_area.y + y_offset))
2879 min_y = rtl_cell_area.y + y_offset;
2880 if (max_y < rtl_cell_area.y + y_offset + height)
2881 max_y = rtl_cell_area.y + y_offset + height;
2885 else if (action == CELL_ACTION_EVENT)
2887 gboolean try_event = FALSE;
2891 if (special_cells == 1)
2893 /* only 1 activatable cell -> whole column can activate */
2894 if (cell_area->x <= ((GdkEventButton *)event)->x &&
2895 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
2898 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
2899 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
2900 /* only activate cell if the user clicked on an individual
2905 else if (special_cells > 1 && info->has_focus)
2907 else if (special_cells == 1)
2912 gboolean visible, mode;
2914 g_object_get (info->cell,
2915 "visible", &visible,
2918 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2920 if (gtk_cell_renderer_activate (info->cell,
2922 tree_column->tree_view,
2924 &rtl_background_area,
2928 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2932 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2935 gtk_cell_renderer_start_editing (info->cell,
2937 tree_column->tree_view,
2939 &rtl_background_area,
2943 if (*editable_widget != NULL)
2945 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2946 info->in_editing_mode = TRUE;
2947 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
2949 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2957 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2959 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
2960 real_background_area.x += real_background_area.width + tree_column->spacing;
2962 /* Only needed for first cell */
2966 /* iterate list for PACK_END cells */
2967 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
2969 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
2971 if (info->pack == GTK_PACK_START)
2974 if (! info->cell->visible)
2977 if ((info->has_focus || special_cells == 1) && cursor_row)
2978 flags |= GTK_CELL_RENDERER_FOCUSED;
2980 flags &= ~GTK_CELL_RENDERER_FOCUSED;
2982 info->real_width = info->requested_width + (info->expand?extra_space:0);
2984 /* We constrain ourselves to only the width available */
2985 if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
2987 info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
2990 if (real_cell_area.x > cell_area->x + cell_area->width)
2993 real_cell_area.width = info->real_width;
2994 real_cell_area.width -= 2 * focus_line_width;
2995 real_background_area.width = info->real_width + depth;
2997 rtl_cell_area = real_cell_area;
2998 rtl_background_area = real_background_area;
3001 rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
3002 rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
3006 if (action == CELL_ACTION_RENDER)
3008 gtk_cell_renderer_render (info->cell,
3010 tree_column->tree_view,
3011 &rtl_background_area,
3017 else if (action == CELL_ACTION_FOCUS)
3019 gint x_offset, y_offset, width, height;
3021 gtk_cell_renderer_get_size (info->cell,
3022 tree_column->tree_view,
3024 &x_offset, &y_offset,
3027 if (special_cells > 1)
3029 if (info->has_focus)
3031 min_x = rtl_cell_area.x + x_offset;
3032 max_x = min_x + width;
3033 min_y = rtl_cell_area.y + y_offset;
3034 max_y = min_y + height;
3039 if (min_x > (rtl_cell_area.x + x_offset))
3040 min_x = rtl_cell_area.x + x_offset;
3041 if (max_x < rtl_cell_area.x + x_offset + width)
3042 max_x = rtl_cell_area.x + x_offset + width;
3043 if (min_y > (rtl_cell_area.y + y_offset))
3044 min_y = rtl_cell_area.y + y_offset;
3045 if (max_y < rtl_cell_area.y + y_offset + height)
3046 max_y = rtl_cell_area.y + y_offset + height;
3050 else if (action == CELL_ACTION_EVENT)
3052 gboolean try_event = FALSE;
3056 if (special_cells == 1)
3058 /* only 1 activatable cell -> whole column can activate */
3059 if (cell_area->x <= ((GdkEventButton *)event)->x &&
3060 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
3063 else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
3064 rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
3065 /* only activate cell if the user clicked on an individual
3070 else if (special_cells > 1 && info->has_focus)
3072 else if (special_cells == 1)
3077 gboolean visible, mode;
3079 g_object_get (info->cell,
3080 "visible", &visible,
3083 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
3085 if (gtk_cell_renderer_activate (info->cell,
3087 tree_column->tree_view,
3089 &rtl_background_area,
3093 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3097 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
3100 gtk_cell_renderer_start_editing (info->cell,
3102 tree_column->tree_view,
3104 &rtl_background_area,
3108 if (*editable_widget != NULL)
3110 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
3111 info->in_editing_mode = TRUE;
3112 pspp_sheet_view_column_focus_cell (tree_column, info->cell);
3114 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3121 flags &= ~GTK_CELL_RENDERER_FOCUSED;
3123 real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
3124 real_background_area.x += (real_background_area.width + tree_column->spacing);
3126 /* Only needed for first cell */
3130 /* fill focus_rectangle when required */
3131 if (action == CELL_ACTION_FOCUS)
3133 if (min_x >= max_x || min_y >= max_y)
3135 *focus_rectangle = *cell_area;
3136 /* don't change the focus_rectangle, just draw it nicely inside
3141 focus_rectangle->x = min_x - focus_line_width;
3142 focus_rectangle->y = min_y - focus_line_width;
3143 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
3144 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
3152 * pspp_sheet_view_column_cell_render:
3153 * @tree_column: A #PsppSheetViewColumn.
3154 * @window: a #GdkDrawable to draw to
3155 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
3156 * @cell_area: area normally rendered by a cell renderer
3157 * @expose_area: area that actually needs updating
3158 * @flags: flags that affect rendering
3160 * Renders the cell contained by #tree_column. This is used primarily by the
3164 _pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
3166 const GdkRectangle *background_area,
3167 const GdkRectangle *cell_area,
3168 const GdkRectangle *expose_area,
3171 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3172 g_return_if_fail (background_area != NULL);
3173 g_return_if_fail (cell_area != NULL);
3174 g_return_if_fail (expose_area != NULL);
3176 pspp_sheet_view_column_cell_process_action (tree_column,
3183 NULL, NULL, NULL, NULL);
3187 _pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
3188 GtkCellEditable **editable_widget,
3191 const GdkRectangle *background_area,
3192 const GdkRectangle *cell_area,
3195 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3197 return pspp_sheet_view_column_cell_process_action (tree_column,
3210 _pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
3211 const GdkRectangle *background_area,
3212 const GdkRectangle *cell_area,
3213 GdkRectangle *focus_area)
3215 pspp_sheet_view_column_cell_process_action (tree_column,
3227 /* cell list manipulation */
3229 pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
3231 GList *list = tree_column->cell_list;
3233 /* first GTK_PACK_START cell we find */
3234 for ( ; list; list = list->next)
3236 PsppSheetViewColumnCellInfo *info = list->data;
3237 if (info->pack == GTK_PACK_START)
3241 /* hmm, else the *last* GTK_PACK_END cell */
3242 list = g_list_last (tree_column->cell_list);
3244 for ( ; list; list = list->prev)
3246 PsppSheetViewColumnCellInfo *info = list->data;
3247 if (info->pack == GTK_PACK_END)
3255 pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
3257 GList *list = tree_column->cell_list;
3259 /* *first* GTK_PACK_END cell we find */
3260 for ( ; list ; list = list->next)
3262 PsppSheetViewColumnCellInfo *info = list->data;
3263 if (info->pack == GTK_PACK_END)
3267 /* hmm, else the last GTK_PACK_START cell */
3268 list = g_list_last (tree_column->cell_list);
3270 for ( ; list; list = list->prev)
3272 PsppSheetViewColumnCellInfo *info = list->data;
3273 if (info->pack == GTK_PACK_START)
3281 pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
3285 PsppSheetViewColumnCellInfo *info = current->data;
3287 if (info->pack == GTK_PACK_START)
3289 for (list = current->next; list; list = list->next)
3291 PsppSheetViewColumnCellInfo *inf = list->data;
3292 if (inf->pack == GTK_PACK_START)
3296 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
3297 list = g_list_last (tree_column->cell_list);
3298 for (; list; list = list->prev)
3300 PsppSheetViewColumnCellInfo *inf = list->data;
3301 if (inf->pack == GTK_PACK_END)
3306 for (list = current->prev; list; list = list->prev)
3308 PsppSheetViewColumnCellInfo *inf = list->data;
3309 if (inf->pack == GTK_PACK_END)
3317 pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
3321 PsppSheetViewColumnCellInfo *info = current->data;
3323 if (info->pack == GTK_PACK_END)
3325 for (list = current->next; list; list = list->next)
3327 PsppSheetViewColumnCellInfo *inf = list->data;
3328 if (inf->pack == GTK_PACK_END)
3332 /* out of GTK_PACK_END, get last GTK_PACK_START one */
3333 list = g_list_last (tree_column->cell_list);
3334 for ( ; list; list = list->prev)
3336 PsppSheetViewColumnCellInfo *inf = list->data;
3337 if (inf->pack == GTK_PACK_START)
3342 for (list = current->prev; list; list = list->prev)
3344 PsppSheetViewColumnCellInfo *inf = list->data;
3345 if (inf->pack == GTK_PACK_START)
3353 _pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
3361 count = _pspp_sheet_view_column_count_special_cells (tree_column);
3362 rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
3364 /* if we are the current focus column and have multiple editable cells,
3365 * try to select the next one, else move the focus to the next column
3367 if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
3372 GList *list = tree_column->cell_list;
3373 PsppSheetViewColumnCellInfo *info = NULL;
3375 /* find current focussed cell */
3376 for ( ; list; list = list->next)
3379 if (info->has_focus)
3383 /* not a focussed cell in the focus column? */
3384 if (!list || !info || !info->has_focus)
3389 prev = pspp_sheet_view_column_cell_next (tree_column, list);
3390 next = pspp_sheet_view_column_cell_prev (tree_column, list);
3394 next = pspp_sheet_view_column_cell_next (tree_column, list);
3395 prev = pspp_sheet_view_column_cell_prev (tree_column, list);
3398 info->has_focus = FALSE;
3399 if (direction > 0 && next)
3402 info->has_focus = TRUE;
3405 else if (direction > 0 && !next && !right)
3407 /* keep focus on last cell */
3409 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3411 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3413 info->has_focus = TRUE;
3416 else if (direction < 0 && prev)
3419 info->has_focus = TRUE;
3422 else if (direction < 0 && !prev && !left)
3424 /* keep focus on first cell */
3426 info = pspp_sheet_view_column_cell_last (tree_column)->data;
3428 info = pspp_sheet_view_column_cell_first (tree_column)->data;
3430 info->has_focus = TRUE;
3437 /* we get focus, if we have multiple editable cells, give the correct one
3442 GList *list = tree_column->cell_list;
3444 /* clear focus first */
3445 for ( ; list ; list = list->next)
3447 PsppSheetViewColumnCellInfo *info = list->data;
3448 if (info->has_focus)
3449 info->has_focus = FALSE;
3456 list = pspp_sheet_view_column_cell_last (tree_column);
3457 else if (direction < 0)
3458 list = pspp_sheet_view_column_cell_first (tree_column);
3463 list = pspp_sheet_view_column_cell_first (tree_column);
3464 else if (direction < 0)
3465 list = pspp_sheet_view_column_cell_last (tree_column);
3469 ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
3476 _pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
3478 const GdkRectangle *background_area,
3479 const GdkRectangle *cell_area,
3480 const GdkRectangle *expose_area,
3483 gint focus_line_width;
3484 GtkStateType cell_state;
3486 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3487 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3488 "focus-line-width", &focus_line_width, NULL);
3489 if (tree_column->editable_widget)
3491 /* This function is only called on the editable row when editing.
3494 gtk_paint_focus (tree_column->tree_view->style,
3496 gtk_widget_get_state (tree_column->tree_view),
3498 tree_column->tree_view,
3500 cell_area->x - focus_line_width,
3501 cell_area->y - focus_line_width,
3502 cell_area->width + 2 * focus_line_width,
3503 cell_area->height + 2 * focus_line_width);
3508 GdkRectangle focus_rectangle;
3509 pspp_sheet_view_column_cell_process_action (tree_column,
3519 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3520 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3521 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3522 gtk_paint_focus (tree_column->tree_view->style,
3526 tree_column->tree_view,
3530 focus_rectangle.width,
3531 focus_rectangle.height);
3536 * pspp_sheet_view_column_cell_is_visible:
3537 * @tree_column: A #PsppSheetViewColumn
3539 * Returns %TRUE if any of the cells packed into the @tree_column are visible.
3540 * For this to be meaningful, you must first initialize the cells with
3541 * pspp_sheet_view_column_cell_set_cell_data()
3543 * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
3546 pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
3550 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
3552 for (list = tree_column->cell_list; list; list = list->next)
3554 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3556 if (info->cell->visible)
3564 * pspp_sheet_view_column_focus_cell:
3565 * @tree_column: A #PsppSheetViewColumn
3566 * @cell: A #GtkCellRenderer
3568 * Sets the current keyboard focus to be at @cell, if the column contains
3569 * 2 or more editable and activatable cells.
3574 pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
3575 GtkCellRenderer *cell)
3578 gboolean found_cell = FALSE;
3580 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3581 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3583 if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
3586 for (list = tree_column->cell_list; list; list = list->next)
3588 PsppSheetViewColumnCellInfo *info = list->data;
3590 if (info->cell == cell)
3592 info->has_focus = TRUE;
3600 for (list = tree_column->cell_list; list; list = list->next)
3602 PsppSheetViewColumnCellInfo *info = list->data;
3604 if (info->cell != cell)
3605 info->has_focus = FALSE;
3608 /* FIXME: redraw? */
3613 _pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
3617 for (list = tree_column->cell_list; list; list = list->next)
3619 PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
3621 info->requested_width = 0;
3623 tree_column->dirty = TRUE;
3624 tree_column->requested_width = -1;
3625 tree_column->width = 0;
3627 if (tree_column->tree_view &&
3628 gtk_widget_get_realized (tree_column->tree_view))
3630 _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
3631 gtk_widget_queue_resize (tree_column->tree_view);
3636 _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
3637 GtkCellEditable *cell_editable)
3639 g_return_if_fail (tree_column->editable_widget == NULL);
3641 tree_column->editable_widget = cell_editable;
3645 _pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
3649 g_return_if_fail (tree_column->editable_widget != NULL);
3651 tree_column->editable_widget = NULL;
3652 for (list = tree_column->cell_list; list; list = list->next)
3653 ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
3657 _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
3658 GtkCellRenderer *cell,
3663 PsppSheetViewColumnCellInfo *info;
3669 list = pspp_sheet_view_column_cell_first (column);
3673 info = (PsppSheetViewColumnCellInfo *)list->data;
3675 list = pspp_sheet_view_column_cell_next (column, list);
3677 if (info->cell == cell)
3680 if (info->cell->visible)
3681 l += info->real_width + column->spacing;
3686 info = (PsppSheetViewColumnCellInfo *)list->data;
3688 list = pspp_sheet_view_column_cell_next (column, list);
3690 if (info->cell->visible)
3691 r += info->real_width + column->spacing;
3694 rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
3696 *left = rtl ? r : l;
3699 *right = rtl ? l : r;
3703 * pspp_sheet_view_column_cell_get_position:
3704 * @tree_column: a #PsppSheetViewColumn
3705 * @cell_renderer: a #GtkCellRenderer
3706 * @start_pos: return location for the horizontal position of @cell within
3707 * @tree_column, may be %NULL
3708 * @width: return location for the width of @cell, may be %NULL
3710 * Obtains the horizontal position and size of a cell in a column. If the
3711 * cell is not found in the column, @start_pos and @width are not changed and
3712 * %FALSE is returned.
3714 * Return value: %TRUE if @cell belongs to @tree_column.
3717 pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
3718 GtkCellRenderer *cell_renderer,
3724 gboolean found_cell = FALSE;
3725 PsppSheetViewColumnCellInfo *cellinfo = NULL;
3727 list = pspp_sheet_view_column_cell_first (tree_column);
3728 for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
3730 cellinfo = list->data;
3731 if (cellinfo->cell == cell_renderer)
3737 if (cellinfo->cell->visible)
3738 current_x += cellinfo->real_width;
3744 *start_pos = current_x;
3746 *width = cellinfo->real_width;
3753 * pspp_sheet_view_column_queue_resize:
3754 * @tree_column: A #PsppSheetViewColumn
3756 * Flags the column, and the cell renderers added to this column, to have
3757 * their sizes renegotiated.
3762 pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
3764 g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
3766 if (tree_column->tree_view)
3767 _pspp_sheet_view_column_cell_set_dirty (tree_column);
3771 * pspp_sheet_view_column_get_tree_view:
3772 * @tree_column: A #PsppSheetViewColumn
3774 * Returns the #PsppSheetView wherein @tree_column has been inserted. If
3775 * @column is currently not inserted in any tree view, %NULL is
3778 * Return value: The tree view wherein @column has been inserted if any,
3784 pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
3786 g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
3788 return tree_column->tree_view;
3792 GtkCellLayout *cell_layout;
3793 GtkCellRenderer *renderer;
3795 } AttributesSubParserData;
3798 attributes_start_element (GMarkupParseContext *context,
3799 const gchar *element_name,
3800 const gchar **names,
3801 const gchar **values,
3805 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
3808 if (strcmp (element_name, "attribute") == 0)
3810 for (i = 0; names[i]; i++)
3811 if (strcmp (names[i], "name") == 0)
3812 parser_data->attr_name = g_strdup (values[i]);
3814 else if (strcmp (element_name, "attributes") == 0)
3817 g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
3821 attributes_text_element (GMarkupParseContext *context,
3827 AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
3832 if (!parser_data->attr_name)
3836 string = g_strndup (text, text_len);
3837 l = strtol (string, &endptr, 0);
3838 if (errno || endptr == string)
3842 GTK_BUILDER_ERROR_INVALID_VALUE,
3843 "Could not parse integer `%s'",
3850 gtk_cell_layout_add_attribute (parser_data->cell_layout,
3851 parser_data->renderer,
3852 parser_data->attr_name, l);
3853 g_free (parser_data->attr_name);
3854 parser_data->attr_name = NULL;
3857 static const GMarkupParser attributes_parser =
3859 attributes_start_element,
3861 attributes_text_element,
3865 _gtk_cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
3866 GtkBuilder *builder,
3868 const gchar *tagname,
3869 GMarkupParser *parser,
3872 AttributesSubParserData *parser_data;
3877 if (strcmp (tagname, "attributes") == 0)
3879 parser_data = g_slice_new0 (AttributesSubParserData);
3880 parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
3881 parser_data->renderer = GTK_CELL_RENDERER (child);
3882 parser_data->attr_name = NULL;
3884 *parser = attributes_parser;
3885 *data = parser_data;
3893 _gtk_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
3894 GtkBuilder *builder,
3896 const gchar *tagname,
3899 AttributesSubParserData *parser_data;
3901 parser_data = (AttributesSubParserData*)data;
3902 g_assert (!parser_data->attr_name);
3903 g_slice_free (AttributesSubParserData, parser_data);
3907 _gtk_cell_layout_buildable_add_child (GtkBuildable *buildable,
3908 GtkBuilder *builder,
3912 GtkCellLayoutIface *iface;
3914 g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
3915 g_return_if_fail (GTK_IS_CELL_RENDERER (child));
3917 iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
3918 g_return_if_fail (iface->pack_start != NULL);
3919 iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);