1 /* GAIL - The GNOME Accessibility Implementation Library
2 * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library 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 GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #ifdef GDK_WINDOWING_X11
23 #include <gdk/x11/gdkx.h>
25 #include <gtk/gtktreeviewcolumn.h>
26 #include "gailtreeview.h"
27 #include "gailrenderercell.h"
28 #include "gailbooleancell.h"
29 #include "gailcontainercell.h"
30 #include "gailtextcell.h"
31 #include "gailcellparent.h"
32 #include "gail-private-macros.h"
34 typedef struct _GailTreeViewRowInfo GailTreeViewRowInfo;
35 typedef struct _GailTreeViewCellInfo GailTreeViewCellInfo;
37 static void gail_tree_view_class_init (GailTreeViewClass *klass);
38 static void gail_tree_view_real_initialize (AtkObject *obj,
40 static void gail_tree_view_real_notify_gtk (GObject *obj,
42 static void gail_tree_view_finalize (GObject *object);
44 static void gail_tree_view_connect_widget_destroyed
45 (GtkAccessible *accessible);
46 static void gail_tree_view_destroyed (GtkWidget *widget,
47 GtkAccessible *accessible);
50 static gint gail_tree_view_get_n_children (AtkObject *obj);
51 static AtkObject* gail_tree_view_ref_child (AtkObject *obj,
53 static AtkStateSet* gail_tree_view_ref_state_set (AtkObject *obj);
57 static void atk_component_interface_init (AtkComponentIface *iface);
59 static AtkObject* gail_tree_view_ref_accessible_at_point
60 (AtkComponent *component,
63 AtkCoordType coord_type);
67 static void atk_table_interface_init (AtkTableIface *iface);
69 static gint gail_tree_view_get_index_at (AtkTable *table,
72 static gint gail_tree_view_get_column_at_index
75 static gint gail_tree_view_get_row_at_index (AtkTable *table,
78 static AtkObject* gail_tree_view_table_ref_at (AtkTable *table,
81 static gint gail_tree_view_get_n_rows (AtkTable *table);
82 static gint gail_tree_view_get_n_columns (AtkTable *table);
83 static gint get_n_actual_columns (GtkTreeView *tree_view);
84 static gboolean gail_tree_view_is_row_selected (AtkTable *table,
86 static gboolean gail_tree_view_is_selected (AtkTable *table,
89 static gint gail_tree_view_get_selected_rows
92 static gboolean gail_tree_view_add_row_selection
95 static gboolean gail_tree_view_remove_row_selection
98 static AtkObject* gail_tree_view_get_row_header (AtkTable *table,
100 static AtkObject* gail_tree_view_get_column_header
103 static void gail_tree_view_set_row_header (AtkTable *table,
106 static void gail_tree_view_set_column_header
111 gail_tree_view_get_caption (AtkTable *table);
112 static void gail_tree_view_set_caption (AtkTable *table,
114 static AtkObject* gail_tree_view_get_summary (AtkTable *table);
115 static void gail_tree_view_set_summary (AtkTable *table,
116 AtkObject *accessible);
117 static G_CONST_RETURN gchar*
118 gail_tree_view_get_row_description
121 static void gail_tree_view_set_row_description
124 const gchar *description);
125 static G_CONST_RETURN gchar*
126 gail_tree_view_get_column_description
129 static void gail_tree_view_set_column_description
132 const gchar *description);
134 static void set_row_data (AtkTable *table,
137 const gchar *description,
139 static GailTreeViewRowInfo*
140 get_row_info (AtkTable *table,
145 static void atk_selection_interface_init (AtkSelectionIface *iface);
146 static gboolean gail_tree_view_add_selection (AtkSelection *selection,
148 static gboolean gail_tree_view_clear_selection (AtkSelection *selection);
149 static AtkObject* gail_tree_view_ref_selection (AtkSelection *selection,
151 static gint gail_tree_view_get_selection_count
152 (AtkSelection *selection);
153 static gboolean gail_tree_view_is_child_selected
154 (AtkSelection *selection,
157 /* gailcellparent.h */
159 static void gail_cell_parent_interface_init (GailCellParentIface *iface);
160 static void gail_tree_view_get_cell_extents (GailCellParent *parent,
166 AtkCoordType coord_type);
167 static void gail_tree_view_get_cell_area (GailCellParent *parent,
169 GdkRectangle *cell_rect);
170 static gboolean gail_tree_view_grab_cell_focus (GailCellParent *parent,
173 /* signal handling */
175 static gboolean gail_tree_view_expand_row_gtk (GtkTreeView *tree_view,
178 static gint idle_expand_row (gpointer data);
179 static gboolean gail_tree_view_collapse_row_gtk (GtkTreeView *tree_view,
182 static void gail_tree_view_size_allocate_gtk (GtkWidget *widget,
183 GtkAllocation *allocation);
184 static void gail_tree_view_set_scroll_adjustments
187 GtkAdjustment *vadj);
188 static void gail_tree_view_changed_gtk (GtkTreeSelection *selection,
191 static void columns_changed (GtkTreeView *tree_view);
192 static void cursor_changed (GtkTreeView *tree_view);
193 static gint idle_cursor_changed (gpointer data);
195 static void model_row_changed (GtkTreeModel *tree_model,
199 static void column_visibility_changed (GObject *object,
202 static void column_destroy (GtkObject *obj);
203 static void model_row_inserted (GtkTreeModel *tree_model,
207 static void model_row_deleted (GtkTreeModel *tree_model,
210 static void destroy_count_func (GtkTreeView *tree_view,
214 static void model_rows_reordered (GtkTreeModel *tree_model,
219 static void adjustment_changed (GtkAdjustment *adjustment,
220 GtkTreeView *tree_view);
224 static void set_iter_nth_row (GtkTreeView *tree_view,
227 static gint get_row_from_tree_path (GtkTreeView *tree_view,
229 static GtkTreeViewColumn* get_column (GtkTreeView *tree_view,
231 static gint get_actual_column_number (GtkTreeView *tree_view,
232 gint visible_column);
233 static gint get_visible_column_number (GtkTreeView *tree_view,
235 static void iterate_thru_children (GtkTreeView *tree_view,
236 GtkTreeModel *tree_model,
237 GtkTreePath *tree_path,
241 static GtkTreeIter* return_iter_nth_row (GtkTreeView *tree_view,
242 GtkTreeModel *tree_model,
246 static void free_row_info (GArray *array,
249 static void clean_cell_info (GailTreeView *tree_view,
251 static void clean_rows (GailTreeView *tree_view);
252 static void clean_cols (GailTreeView *tree_view,
253 GtkTreeViewColumn *tv_col);
254 static void traverse_cells (GailTreeView *tree_view,
255 GtkTreePath *tree_path,
258 static gboolean update_cell_value (GailRendererCell *renderer_cell,
259 GailTreeView *gailview,
260 gboolean emit_change_signal);
261 static void set_cell_visibility (GtkTreeView *tree_view,
263 GtkTreeViewColumn *tv_col,
264 GtkTreePath *tree_path,
265 gboolean emit_signal);
266 static gboolean is_cell_showing (GtkTreeView *tree_view,
267 GdkRectangle *cell_rect);
268 static void set_expand_state (GtkTreeView *tree_view,
269 GtkTreeModel *tree_model,
270 GailTreeView *gailview,
271 GtkTreePath *tree_path,
272 gboolean set_on_ancestor);
273 static void add_cell_actions (GailCell *cell,
276 static void toggle_cell_expanded (GailCell *cell);
277 static void toggle_cell_toggled (GailCell *cell);
278 static void edit_cell (GailCell *cell);
279 static void activate_cell (GailCell *cell);
280 static void cell_destroyed (gpointer data);
282 static void cell_info_remove (GailTreeView *tree_view,
285 static void cell_info_get_index (GtkTreeView *tree_view,
286 GailTreeViewCellInfo *info,
288 static void cell_info_new (GailTreeView *gailview,
289 GtkTreeModel *tree_model,
291 GtkTreeViewColumn *tv_col,
293 static GailCell* find_cell (GailTreeView *gailview,
295 static void refresh_cell_index (GailCell *cell);
296 static void get_selected_rows (GtkTreeModel *model,
300 static void connect_model_signals (GtkTreeView *view,
301 GailTreeView *gailview);
302 static void disconnect_model_signals (GailTreeView *gailview);
303 static void clear_cached_data (GailTreeView *view);
304 static gint get_column_number (GtkTreeView *tree_view,
305 GtkTreeViewColumn *column,
307 static gint get_focus_index (GtkTreeView *tree_view);
308 static gint get_index (GtkTreeView *tree_view,
311 static void count_rows (GtkTreeModel *model,
313 GtkTreePath *end_path,
318 static gboolean get_next_node_with_child_at_depth
319 (GtkTreeModel *model,
324 static gboolean get_next_node_with_child (GtkTreeModel *model,
326 GtkTreePath **return_path);
327 static gboolean get_tree_path_from_row_index (GtkTreeModel *model,
329 GtkTreePath **tree_path);
330 static gint get_row_count (GtkTreeModel *model);
331 static gboolean get_path_column_from_index (GtkTreeView *tree_view,
334 GtkTreeViewColumn **column);
335 static void set_cell_expandable (GailCell *cell);
337 static GailTreeViewCellInfo* find_cell_info (GailTreeView *view,
341 static AtkObject * get_header_from_column (GtkTreeViewColumn *tv_col);
342 static gboolean idle_garbage_collect_cell_data (gpointer data);
343 static gboolean garbage_collect_cell_data (gpointer data);
345 static GailWidgetClass *parent_class = NULL;
346 static GQuark quark_column_desc_object = 0;
347 static GQuark quark_column_header_object = 0;
348 static gboolean editing = FALSE;
349 static const gchar* hadjustment = "hadjustment";
350 static const gchar* vadjustment = "vadjustment";
352 struct _GailTreeViewRowInfo
354 GtkTreeRowReference *row_ref;
359 struct _GailTreeViewCellInfo
362 GtkTreeRowReference *cell_row_ref;
363 GtkTreeViewColumn *cell_col_ref;
369 gail_tree_view_get_type (void)
371 static GType type = 0;
375 static const GTypeInfo tinfo =
377 sizeof (GailTreeViewClass),
378 (GBaseInitFunc) NULL, /* base init */
379 (GBaseFinalizeFunc) NULL, /* base finalize */
380 (GClassInitFunc) gail_tree_view_class_init, /* class init */
381 (GClassFinalizeFunc) NULL, /* class finalize */
382 NULL, /* class data */
383 sizeof (GailTreeView), /* instance size */
384 0, /* nb preallocs */
385 (GInstanceInitFunc) NULL, /* instance init */
386 NULL /* value table */
389 static const GInterfaceInfo atk_table_info =
391 (GInterfaceInitFunc) atk_table_interface_init,
392 (GInterfaceFinalizeFunc) NULL,
396 static const GInterfaceInfo atk_selection_info =
398 (GInterfaceInitFunc) atk_selection_interface_init,
399 (GInterfaceFinalizeFunc) NULL,
403 static const GInterfaceInfo atk_component_info =
405 (GInterfaceInitFunc) atk_component_interface_init,
406 (GInterfaceFinalizeFunc) NULL,
410 static const GInterfaceInfo gail_cell_parent_info =
412 (GInterfaceInitFunc) gail_cell_parent_interface_init,
413 (GInterfaceFinalizeFunc) NULL,
417 type = g_type_register_static (GAIL_TYPE_CONTAINER,
418 "GailTreeView", &tinfo, 0);
420 g_type_add_interface_static (type, ATK_TYPE_TABLE,
422 g_type_add_interface_static (type, ATK_TYPE_SELECTION,
423 &atk_selection_info);
424 g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
425 &atk_component_info);
426 g_type_add_interface_static (type, GAIL_TYPE_CELL_PARENT,
427 &gail_cell_parent_info);
434 gail_tree_view_class_init (GailTreeViewClass *klass)
436 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
437 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
438 GtkAccessibleClass *accessible_class;
439 GailWidgetClass *widget_class;
440 GailContainerClass *container_class;
442 accessible_class = (GtkAccessibleClass*)klass;
443 widget_class = (GailWidgetClass*)klass;
444 container_class = (GailContainerClass*)klass;
446 parent_class = g_type_class_peek_parent (klass);
448 class->get_n_children = gail_tree_view_get_n_children;
449 class->ref_child = gail_tree_view_ref_child;
450 class->ref_state_set = gail_tree_view_ref_state_set;
451 class->initialize = gail_tree_view_real_initialize;
453 widget_class->notify_gtk = gail_tree_view_real_notify_gtk;
455 accessible_class->connect_widget_destroyed = gail_tree_view_connect_widget_destroyed;
458 * The children of a GtkTreeView are the buttons at the top of the columns
459 * we do not represent these as children so we do not want to report
460 * children added or deleted when these changed.
462 container_class->add_gtk = NULL;
463 container_class->remove_gtk = NULL;
465 gobject_class->finalize = gail_tree_view_finalize;
467 quark_column_desc_object = g_quark_from_static_string ("gtk-column-object");
468 quark_column_header_object = g_quark_from_static_string ("gtk-header-object");
472 gail_tree_view_real_initialize (AtkObject *obj,
476 GtkTreeView *tree_view;
477 GtkTreeModel *tree_model;
479 GList *tv_cols, *tmp_list;
482 ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
484 view = GAIL_TREE_VIEW (obj);
485 view->caption = NULL;
486 view->summary = NULL;
487 view->row_data = NULL;
488 view->col_data = NULL;
489 view->cell_data = NULL;
490 view->focus_cell = NULL;
491 view->old_hadj = NULL;
492 view->old_vadj = NULL;
493 view->idle_expand_id = 0;
494 view->idle_expand_path = NULL;
496 view->n_children_deleted = 0;
498 widget = GTK_WIDGET (data);
499 g_signal_connect_after (widget,
501 G_CALLBACK (gail_tree_view_collapse_row_gtk),
503 g_signal_connect (widget,
505 G_CALLBACK (gail_tree_view_expand_row_gtk),
507 g_signal_connect (widget,
509 G_CALLBACK (gail_tree_view_size_allocate_gtk),
512 tree_view = GTK_TREE_VIEW (widget);
513 tree_model = gtk_tree_view_get_model (tree_view);
515 /* Set up signal handling */
517 g_signal_connect_data (gtk_tree_view_get_selection (tree_view),
519 (GCallback) gail_tree_view_changed_gtk,
522 g_signal_connect_data (tree_view, "columns-changed",
523 (GCallback) columns_changed, NULL, NULL, 0);
524 g_signal_connect_data (tree_view, "cursor-changed",
525 (GCallback) cursor_changed, NULL, NULL, 0);
527 view->tree_model = tree_model;
530 g_object_add_weak_pointer (G_OBJECT (view->tree_model), (gpointer *)&view->tree_model);
531 connect_model_signals (tree_view, view);
533 if (GTK_IS_TREE_STORE (tree_model))
534 obj->role = ATK_ROLE_TREE_TABLE;
536 obj->role = ATK_ROLE_TABLE;
540 obj->role = ATK_ROLE_UNKNOWN;
543 /* adjustment callbacks */
545 g_object_get (tree_view, hadjustment, &adj, NULL);
546 view->old_hadj = adj;
547 g_object_add_weak_pointer (G_OBJECT (view->old_hadj), (gpointer *)&view->old_hadj);
548 g_signal_connect (adj,
550 G_CALLBACK (adjustment_changed),
553 g_object_get (tree_view, vadjustment, &adj, NULL);
554 view->old_vadj = adj;
555 g_object_add_weak_pointer (G_OBJECT (view->old_vadj), (gpointer *)&view->old_vadj);
556 g_signal_connect (adj,
558 G_CALLBACK (adjustment_changed),
560 g_signal_connect_after (widget,
561 "set_scroll_adjustments",
562 G_CALLBACK (gail_tree_view_set_scroll_adjustments),
565 view->col_data = g_array_sized_new (FALSE, TRUE,
566 sizeof(GtkTreeViewColumn *), 0);
568 tv_cols = gtk_tree_view_get_columns (tree_view);
570 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
572 g_signal_connect_data (tmp_list->data, "notify::visible",
573 (GCallback)column_visibility_changed,
574 tree_view, NULL, FALSE);
575 g_signal_connect_data (tmp_list->data, "destroy",
576 (GCallback)column_destroy,
578 g_array_append_val (view->col_data, tmp_list->data);
581 gtk_tree_view_set_destroy_count_func (tree_view,
584 g_list_free (tv_cols);
588 gail_tree_view_real_notify_gtk (GObject *obj,
593 GtkTreeView *tree_view;
594 GailTreeView *gailview;
597 widget = GTK_WIDGET (obj);
598 atk_obj = gtk_widget_get_accessible (widget);
599 tree_view = GTK_TREE_VIEW (widget);
600 gailview = GAIL_TREE_VIEW (atk_obj);
602 if (strcmp (pspec->name, "model") == 0)
604 GtkTreeModel *tree_model;
607 tree_model = gtk_tree_view_get_model (tree_view);
608 if (gailview->tree_model)
609 disconnect_model_signals (gailview);
610 clear_cached_data (gailview);
611 gailview->tree_model = tree_model;
613 * if there is no model the GtkTreeView is probably being destroyed
617 g_object_add_weak_pointer (G_OBJECT (gailview->tree_model), (gpointer *)&gailview->tree_model);
618 connect_model_signals (tree_view, gailview);
620 if (GTK_IS_TREE_STORE (tree_model))
621 role = ATK_ROLE_TREE_TABLE;
623 role = ATK_ROLE_TABLE;
627 role = ATK_ROLE_UNKNOWN;
629 atk_object_set_role (atk_obj, role);
630 g_object_freeze_notify (G_OBJECT (atk_obj));
631 g_signal_emit_by_name (atk_obj, "model_changed");
632 g_signal_emit_by_name (atk_obj, "visible_data_changed");
633 g_object_thaw_notify (G_OBJECT (atk_obj));
635 else if (strcmp (pspec->name, hadjustment) == 0)
637 g_object_get (tree_view, hadjustment, &adj, NULL);
638 g_signal_handlers_disconnect_by_func (gailview->old_hadj,
639 (gpointer) adjustment_changed,
641 gailview->old_hadj = adj;
642 g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_hadj);
643 g_signal_connect (adj,
645 G_CALLBACK (adjustment_changed),
648 else if (strcmp (pspec->name, vadjustment) == 0)
650 g_object_get (tree_view, vadjustment, &adj, NULL);
651 g_signal_handlers_disconnect_by_func (gailview->old_vadj,
652 (gpointer) adjustment_changed,
654 gailview->old_vadj = adj;
655 g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_vadj);
656 g_signal_connect (adj,
658 G_CALLBACK (adjustment_changed),
662 parent_class->notify_gtk (obj, pspec);
666 gail_tree_view_new (GtkWidget *widget)
669 AtkObject *accessible;
671 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), NULL);
673 object = g_object_new (GAIL_TYPE_TREE_VIEW, NULL);
675 accessible = ATK_OBJECT (object);
676 atk_object_initialize (accessible, widget);
682 gail_tree_view_finalize (GObject *object)
684 GailTreeView *view = GAIL_TREE_VIEW (object);
686 clear_cached_data (view);
688 /* remove any idle handlers still pending */
689 if (view->idle_garbage_collect_id)
690 g_source_remove (view->idle_garbage_collect_id);
691 if (view->idle_cursor_changed_id)
692 g_source_remove (view->idle_cursor_changed_id);
693 if (view->idle_expand_id)
694 g_source_remove (view->idle_expand_id);
697 g_object_unref (view->caption);
699 g_object_unref (view->summary);
701 if (view->tree_model)
702 disconnect_model_signals (view);
706 GArray *array = view->col_data;
709 * No need to free the contents of the array since it
710 * just contains pointers to the GtkTreeViewColumn
711 * objects that are in the GtkTreeView.
713 g_array_free (array, TRUE);
716 G_OBJECT_CLASS (parent_class)->finalize (object);
720 gail_tree_view_connect_widget_destroyed (GtkAccessible *accessible)
722 if (accessible->widget)
724 g_signal_connect_after (accessible->widget,
726 G_CALLBACK (gail_tree_view_destroyed),
729 GTK_ACCESSIBLE_CLASS (parent_class)->connect_widget_destroyed (accessible);
733 gail_tree_view_destroyed (GtkWidget *widget,
734 GtkAccessible *accessible)
737 GailTreeView *gailview;
739 gail_return_if_fail (GTK_IS_TREE_VIEW (widget));
741 gailview = GAIL_TREE_VIEW (accessible);
742 adj = gailview->old_hadj;
744 g_signal_handlers_disconnect_by_func (adj,
745 (gpointer) adjustment_changed,
747 adj = gailview->old_vadj;
749 g_signal_handlers_disconnect_by_func (adj,
750 (gpointer) adjustment_changed,
752 if (gailview->tree_model)
754 disconnect_model_signals (gailview);
755 gailview->tree_model = NULL;
757 if (gailview->focus_cell)
759 g_object_unref (gailview->focus_cell);
760 gailview->focus_cell = NULL;
762 if (gailview->idle_expand_id)
764 g_source_remove (gailview->idle_expand_id);
765 gailview->idle_expand_id = 0;
770 get_focus_index (GtkTreeView *tree_view)
772 GtkTreePath *focus_path;
773 GtkTreeViewColumn *focus_column;
776 gtk_tree_view_get_cursor (tree_view, &focus_path, &focus_column);
777 if (focus_path && focus_column)
780 index = get_index (tree_view, focus_path,
781 get_column_number (tree_view, focus_column, FALSE));
787 gtk_tree_path_free (focus_path);
793 gail_tree_view_ref_focus_cell (GtkTreeView *tree_view)
796 * This function returns a reference to the accessible object for the cell
797 * in the treeview which has focus, if a cell has focus.
799 AtkObject *focus_cell = NULL;
803 focus_index = get_focus_index (tree_view);
804 if (focus_index >= 0)
806 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
807 focus_cell = atk_object_ref_accessible_child (atk_obj, focus_index);
816 gail_tree_view_get_n_children (AtkObject *obj)
819 GtkTreeView *tree_view;
820 GtkTreeModel *tree_model;
823 gail_return_val_if_fail (GAIL_IS_TREE_VIEW (obj), 0);
825 widget = GTK_ACCESSIBLE (obj)->widget;
832 tree_view = GTK_TREE_VIEW (widget);
833 tree_model = gtk_tree_view_get_model (tree_view);
836 * We get the total number of rows including those which are collapsed
838 n_rows = get_row_count (tree_model);
840 * We get the total number of columns including those which are not visible
842 n_cols = get_n_actual_columns (tree_view);
843 return (n_rows * n_cols);
847 gail_tree_view_ref_child (AtkObject *obj,
851 GailTreeView *gailview;
853 GtkTreeView *tree_view;
854 GtkTreeModel *tree_model;
855 GtkCellRenderer *renderer;
857 GtkTreeViewColumn *tv_col;
858 GtkTreeSelection *selection;
860 AtkRegistry *default_registry;
861 AtkObjectFactory *factory;
864 GtkTreeViewColumn *expander_tv;
865 GList *renderer_list;
867 GailContainerCell *container = NULL;
868 GailRendererCell *renderer_cell;
869 gboolean is_expander, is_expanded, retval;
870 gboolean editable = FALSE;
873 g_return_val_if_fail (GAIL_IS_TREE_VIEW (obj), NULL);
874 g_return_val_if_fail (i >= 0, NULL);
876 widget = GTK_ACCESSIBLE (obj)->widget;
883 if (i >= gail_tree_view_get_n_children (obj))
886 tree_view = GTK_TREE_VIEW (widget);
887 if (i < get_n_actual_columns (tree_view))
889 tv_col = gtk_tree_view_get_column (tree_view, i);
890 child = get_header_from_column (tv_col);
892 g_object_ref (child);
896 gailview = GAIL_TREE_VIEW (obj);
898 * Check whether the child is cached
900 cell = find_cell (gailview, i);
904 return ATK_OBJECT (cell);
907 if (gailview->focus_cell == NULL)
908 focus_index = get_focus_index (tree_view);
912 * Find the TreePath and GtkTreeViewColumn for the index
914 if (!get_path_column_from_index (tree_view, i, &path, &tv_col))
917 tree_model = gtk_tree_view_get_model (tree_view);
918 retval = gtk_tree_model_get_iter (tree_model, &iter, path);
919 gail_return_val_if_fail (retval, NULL);
921 expander_tv = gtk_tree_view_get_expander_column (tree_view);
924 if (gtk_tree_model_iter_has_child (tree_model, &iter))
926 if (expander_tv == tv_col)
929 is_expanded = gtk_tree_view_row_expanded (tree_view, path);
932 gtk_tree_view_column_cell_set_cell_data (tv_col, tree_model, &iter,
933 is_expander, is_expanded);
935 renderer_list = gtk_tree_view_column_get_cell_renderers (tv_col);
937 /* If there are more than one renderer in the list, make a container */
939 if (renderer_list && renderer_list->next)
941 GailCell *container_cell;
943 container = gail_container_cell_new ();
944 gail_return_val_if_fail (container, NULL);
946 container_cell = GAIL_CELL (container);
947 gail_cell_init (container_cell,
948 widget, ATK_OBJECT (gailview),
951 * The GailTreeViewCellInfo structure for the container will be before
952 * the ones for the cells so that the first one we find for a position
953 * will be for the container
955 cell_info_new (gailview, tree_model, path, tv_col, container_cell);
956 container_cell->refresh_index = refresh_cell_index;
957 parent = ATK_OBJECT (container);
960 parent = ATK_OBJECT (gailview);
965 * Now we make a fake cell_renderer if there is no cell in renderer_list
968 if (renderer_list == NULL)
970 GtkCellRenderer *fake_renderer;
971 fake_renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL);
972 default_registry = atk_get_default_registry ();
973 factory = atk_registry_get_factory (default_registry,
974 GTK_OBJECT_TYPE (fake_renderer));
975 child = atk_object_factory_create_accessible (factory,
976 G_OBJECT (fake_renderer));
977 gail_return_val_if_fail (GAIL_IS_RENDERER_CELL (child), NULL);
978 cell = GAIL_CELL (child);
979 renderer_cell = GAIL_RENDERER_CELL (child);
980 renderer_cell->renderer = fake_renderer;
982 /* Create the GailTreeViewCellInfo structure for this cell */
983 cell_info_new (gailview, tree_model, path, tv_col, cell);
985 gail_cell_init (cell,
989 cell->refresh_index = refresh_cell_index;
991 /* set state if it is expandable */
994 set_cell_expandable (cell);
996 gail_cell_add_state (cell,
1001 for (l = renderer_list; l; l = l->next)
1003 renderer = GTK_CELL_RENDERER (l->data);
1005 if (GTK_IS_CELL_RENDERER_TEXT (renderer))
1006 g_object_get (G_OBJECT (renderer), "editable", &editable, NULL);
1008 default_registry = atk_get_default_registry ();
1009 factory = atk_registry_get_factory (default_registry,
1010 GTK_OBJECT_TYPE (renderer));
1011 child = atk_object_factory_create_accessible (factory,
1012 G_OBJECT (renderer));
1013 gail_return_val_if_fail (GAIL_IS_RENDERER_CELL (child), NULL);
1014 cell = GAIL_CELL (child);
1015 renderer_cell = GAIL_RENDERER_CELL (child);
1017 /* Create the GailTreeViewCellInfo structure for this cell */
1018 cell_info_new (gailview, tree_model, path, tv_col, cell);
1020 gail_cell_init (cell,
1025 gail_container_cell_add_child (container, cell);
1027 cell->refresh_index = refresh_cell_index;
1029 update_cell_value (renderer_cell, gailview, FALSE);
1030 /* Add the actions appropriate for this cell */
1031 add_cell_actions (cell, editable);
1033 /* set state if it is expandable */
1036 set_cell_expandable (cell);
1038 gail_cell_add_state (cell,
1043 * If the column is visible, sets the cell's state
1045 if (gtk_tree_view_column_get_visible (tv_col))
1046 set_cell_visibility (tree_view, cell, tv_col, path, FALSE);
1048 * If the row is selected, all cells on the row are selected
1050 selection = gtk_tree_view_get_selection (tree_view);
1052 if (gtk_tree_selection_path_is_selected (selection, path))
1053 gail_cell_add_state (cell, ATK_STATE_SELECTED, FALSE);
1055 gail_cell_add_state (cell, ATK_STATE_FOCUSABLE, FALSE);
1056 if (focus_index == i)
1058 gailview->focus_cell = g_object_ref (cell);
1059 gail_cell_add_state (cell, ATK_STATE_FOCUSED, FALSE);
1062 g_list_free (renderer_list);
1064 child = ATK_OBJECT (container);
1067 if (expander_tv == tv_col)
1069 AtkRelationSet *relation_set;
1070 AtkObject *accessible_array[1];
1071 AtkRelation* relation;
1072 AtkObject *parent_node;
1074 relation_set = atk_object_ref_relation_set (ATK_OBJECT (child));
1076 gtk_tree_path_up (path);
1077 if (gtk_tree_path_get_depth (path) == 0)
1084 n_columns = get_n_actual_columns (tree_view);
1085 parent_index = get_index (tree_view, path, i % n_columns);
1086 parent_node = atk_object_ref_accessible_child (obj, parent_index);
1088 accessible_array[0] = parent_node;
1089 relation = atk_relation_new (accessible_array, 1,
1090 ATK_RELATION_NODE_CHILD_OF);
1091 atk_relation_set_add (relation_set, relation);
1092 g_object_unref (relation);
1093 g_object_unref (relation_set);
1095 gtk_tree_path_free (path);
1098 * We do not increase the reference count here; when g_object_unref() is
1099 * called for the cell then cell_destroyed() is called and
1100 * this removes the cell from the cache.
1106 gail_tree_view_ref_state_set (AtkObject *obj)
1108 AtkStateSet *state_set;
1111 state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
1112 widget = GTK_ACCESSIBLE (obj)->widget;
1115 atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
1120 /* atkcomponent.h */
1123 atk_component_interface_init (AtkComponentIface *iface)
1125 g_return_if_fail (iface != NULL);
1127 iface->ref_accessible_at_point = gail_tree_view_ref_accessible_at_point;
1131 gail_tree_view_ref_accessible_at_point (AtkComponent *component,
1134 AtkCoordType coord_type)
1137 GtkTreeView *tree_view;
1139 GtkTreeViewColumn *tv_column;
1143 widget = GTK_ACCESSIBLE (component)->widget;
1145 /* State is defunct */
1148 tree_view = GTK_TREE_VIEW (widget);
1150 atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
1151 ret_val = gtk_tree_view_get_path_at_pos (tree_view,
1152 x - x_pos, y - y_pos,
1153 &path, &tv_column, NULL, NULL);
1158 column = get_column_number (tree_view, tv_column, FALSE);
1159 index = get_index (tree_view, path, column);
1160 gtk_tree_path_free (path);
1162 return gail_tree_view_ref_child (ATK_OBJECT (component), index);
1166 g_warning ("gail_tree_view_ref_accessible_at_point: gtk_tree_view_get_path_at_pos () failed\n");
1174 atk_table_interface_init (AtkTableIface *iface)
1176 g_return_if_fail (iface != NULL);
1177 iface->ref_at = gail_tree_view_table_ref_at;
1178 iface->get_n_rows = gail_tree_view_get_n_rows;
1179 iface->get_n_columns = gail_tree_view_get_n_columns;
1180 iface->get_index_at = gail_tree_view_get_index_at;
1181 iface->get_column_at_index = gail_tree_view_get_column_at_index;
1182 iface->get_row_at_index = gail_tree_view_get_row_at_index;
1183 iface->is_row_selected = gail_tree_view_is_row_selected;
1184 iface->is_selected = gail_tree_view_is_selected;
1185 iface->get_selected_rows = gail_tree_view_get_selected_rows;
1186 iface->add_row_selection = gail_tree_view_add_row_selection;
1187 iface->remove_row_selection = gail_tree_view_remove_row_selection;
1188 iface->get_column_extent_at = NULL;
1189 iface->get_row_extent_at = NULL;
1190 iface->get_row_header = gail_tree_view_get_row_header;
1191 iface->set_row_header = gail_tree_view_set_row_header;
1192 iface->get_column_header = gail_tree_view_get_column_header;
1193 iface->set_column_header = gail_tree_view_set_column_header;
1194 iface->get_caption = gail_tree_view_get_caption;
1195 iface->set_caption = gail_tree_view_set_caption;
1196 iface->get_summary = gail_tree_view_get_summary;
1197 iface->set_summary = gail_tree_view_set_summary;
1198 iface->get_row_description = gail_tree_view_get_row_description;
1199 iface->set_row_description = gail_tree_view_set_row_description;
1200 iface->get_column_description = gail_tree_view_get_column_description;
1201 iface->set_column_description = gail_tree_view_set_column_description;
1205 gail_tree_view_get_index_at (AtkTable *table,
1210 GtkTreeView *tree_view;
1212 gint n_cols, n_rows;
1217 n_cols = atk_table_get_n_columns (table);
1218 n_rows = atk_table_get_n_rows (table);
1220 if (row >= n_rows ||
1224 widget = GTK_ACCESSIBLE (table)->widget;
1226 /* State is defunct */
1229 tree_view = GTK_TREE_VIEW (widget);
1230 actual_column = get_actual_column_number (tree_view, column);
1232 set_iter_nth_row (tree_view, &iter, row);
1233 path = gtk_tree_model_get_path (gtk_tree_view_get_model (tree_view), &iter);
1235 index = get_index (tree_view, path, actual_column);
1236 gtk_tree_path_free (path);
1242 gail_tree_view_get_column_at_index (AtkTable *table,
1246 GtkTreeView *tree_view;
1249 widget = GTK_ACCESSIBLE (table)->widget;
1251 /* State is defunct */
1254 tree_view = GTK_TREE_VIEW (widget);
1255 n_columns = get_n_actual_columns (tree_view);
1259 index = index % n_columns;
1261 return get_visible_column_number (tree_view, index);
1265 gail_tree_view_get_row_at_index (AtkTable *table,
1269 GtkTreeView *tree_view;
1272 widget = GTK_ACCESSIBLE (table)->widget;
1274 /* State is defunct */
1277 tree_view = GTK_TREE_VIEW (widget);
1278 if (get_path_column_from_index (tree_view, index, &path, NULL))
1280 gint row = get_row_from_tree_path (tree_view, path);
1281 gtk_tree_path_free (path);
1289 gail_tree_view_table_ref_at (AtkTable *table,
1295 index = gail_tree_view_get_index_at (table, row, column);
1299 return gail_tree_view_ref_child (ATK_OBJECT (table), index);
1303 gail_tree_view_get_n_rows (AtkTable *table)
1306 GtkTreeView *tree_view;
1307 GtkTreeModel *tree_model;
1310 widget = GTK_ACCESSIBLE (table)->widget;
1312 /* State is defunct */
1315 tree_view = GTK_TREE_VIEW (widget);
1316 tree_model = gtk_tree_view_get_model (tree_view);
1318 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
1320 * If working with a LIST store, then this is a faster way
1321 * to get the number of rows.
1323 n_rows = gtk_tree_model_iter_n_children (tree_model, NULL);
1326 GtkTreePath *root_tree;
1329 root_tree = gtk_tree_path_new_root ();
1330 iterate_thru_children (tree_view, tree_model,
1331 root_tree, NULL, &n_rows, 0);
1339 * The function get_n_actual_columns returns the number of columns in the
1340 * GtkTreeView. i.e. it include both visible and non-visible columns.
1343 get_n_actual_columns (GtkTreeView *tree_view)
1348 columns = gtk_tree_view_get_columns (tree_view);
1349 n_cols = g_list_length (columns);
1350 g_list_free (columns);
1355 gail_tree_view_get_n_columns (AtkTable *table)
1358 GtkTreeView *tree_view;
1359 GtkTreeViewColumn *tv_col;
1363 widget = GTK_ACCESSIBLE (table)->widget;
1365 /* State is defunct */
1368 tree_view = GTK_TREE_VIEW (widget);
1369 tv_col = gtk_tree_view_get_column (tree_view, i);
1371 while (tv_col != NULL)
1373 if (gtk_tree_view_column_get_visible (tv_col))
1377 tv_col = gtk_tree_view_get_column (tree_view, i);
1384 gail_tree_view_is_row_selected (AtkTable *table,
1388 GtkTreeView *tree_view;
1389 GtkTreeSelection *selection;
1392 widget = GTK_ACCESSIBLE (table)->widget;
1394 /* State is defunct */
1400 tree_view = GTK_TREE_VIEW (widget);
1402 selection = gtk_tree_view_get_selection (tree_view);
1404 set_iter_nth_row (tree_view, &iter, row);
1406 return gtk_tree_selection_iter_is_selected (selection, &iter);
1410 gail_tree_view_is_selected (AtkTable *table,
1414 return gail_tree_view_is_row_selected (table, row);
1418 gail_tree_view_get_selected_rows (AtkTable *table,
1419 gint **rows_selected)
1422 GtkTreeView *tree_view;
1423 GtkTreeModel *tree_model;
1425 GtkTreeSelection *selection;
1426 GtkTreePath *tree_path;
1429 widget = GTK_ACCESSIBLE (table)->widget;
1431 /* State is defunct */
1434 tree_view = GTK_TREE_VIEW (widget);
1436 selection = gtk_tree_view_get_selection (tree_view);
1438 switch (selection->type)
1440 case GTK_SELECTION_SINGLE:
1441 case GTK_SELECTION_BROWSE:
1442 if (gtk_tree_selection_get_selected (selection, &tree_model, &iter))
1448 *rows_selected = (gint *)g_malloc (sizeof(gint));
1449 tree_path = gtk_tree_model_get_path (tree_model, &iter);
1450 row = get_row_from_tree_path (tree_view, tree_path);
1451 gtk_tree_path_free (tree_path);
1453 /* shouldn't ever happen */
1454 g_return_val_if_fail (row != -1, 0);
1456 *rows_selected[0] = row;
1461 case GTK_SELECTION_MULTIPLE:
1463 GPtrArray *array = g_ptr_array_new();
1465 gtk_tree_selection_selected_foreach (selection,
1468 ret_val = array->len;
1470 if (rows_selected && ret_val)
1473 *rows_selected = (gint *) g_malloc (ret_val * sizeof (gint));
1475 for (i = 0; i < ret_val; i++)
1479 tree_path = (GtkTreePath *) g_ptr_array_index (array, i);
1480 row = get_row_from_tree_path (tree_view, tree_path);
1481 gtk_tree_path_free (tree_path);
1482 (*rows_selected)[i] = row;
1485 g_ptr_array_free (array, FALSE);
1488 case GTK_SELECTION_NONE:
1495 gail_tree_view_add_row_selection (AtkTable *table,
1499 GtkTreeView *tree_view;
1500 GtkTreeModel *tree_model;
1501 GtkTreeSelection *selection;
1502 GtkTreePath *tree_path;
1503 GtkTreeIter iter_to_row;
1505 widget = GTK_ACCESSIBLE (table)->widget;
1507 /* State is defunct */
1510 if (!gail_tree_view_is_row_selected (table, row))
1512 tree_view = GTK_TREE_VIEW (widget);
1513 tree_model = gtk_tree_view_get_model (tree_view);
1514 selection = gtk_tree_view_get_selection (tree_view);
1516 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
1518 tree_path = gtk_tree_path_new ();
1519 gtk_tree_path_append_index (tree_path, row);
1520 gtk_tree_selection_select_path (selection,tree_path);
1521 gtk_tree_path_free (tree_path);
1525 set_iter_nth_row (tree_view, &iter_to_row, row);
1526 if (&iter_to_row != NULL)
1527 gtk_tree_selection_select_iter (selection, &iter_to_row);
1533 return gail_tree_view_is_row_selected (table, row);
1537 gail_tree_view_remove_row_selection (AtkTable *table,
1541 GtkTreeView *tree_view;
1542 GtkTreeSelection *selection;
1544 widget = GTK_ACCESSIBLE (table)->widget;
1546 /* State is defunct */
1549 tree_view = GTK_TREE_VIEW (widget);
1551 selection = gtk_tree_view_get_selection (tree_view);
1553 if (gail_tree_view_is_row_selected (table, row))
1555 gtk_tree_selection_unselect_all (selection);
1562 gail_tree_view_get_row_header (AtkTable *table,
1565 GailTreeViewRowInfo *row_info;
1567 row_info = get_row_info (table, row);
1569 return row_info->header;
1575 gail_tree_view_set_row_header (AtkTable *table,
1579 set_row_data (table, row, header, NULL, TRUE);
1583 gail_tree_view_get_column_header (AtkTable *table,
1587 GtkTreeView *tree_view;
1588 GtkTreeViewColumn *tv_col;
1590 widget = GTK_ACCESSIBLE (table)->widget;
1592 /* State is defunct */
1595 tree_view = GTK_TREE_VIEW (widget);
1596 tv_col = get_column (tree_view, in_col);
1597 return get_header_from_column (tv_col);
1601 gail_tree_view_set_column_header (AtkTable *table,
1606 GtkTreeView *tree_view;
1607 GtkTreeViewColumn *tv_col;
1609 AtkPropertyValues values = { NULL };
1611 widget = GTK_ACCESSIBLE (table)->widget;
1613 /* State is defunct */
1616 tree_view = GTK_TREE_VIEW (widget);
1617 tv_col = get_column (tree_view, in_col);
1621 rc = g_object_get_qdata (G_OBJECT (tv_col),
1622 quark_column_header_object);
1624 g_object_unref (rc);
1626 g_object_set_qdata (G_OBJECT (tv_col),
1627 quark_column_header_object,
1630 g_object_ref (header);
1631 g_value_init (&values.new_value, G_TYPE_INT);
1632 g_value_set_int (&values.new_value, in_col);
1634 values.property_name = "accessible-table-column-header";
1635 g_signal_emit_by_name (table,
1636 "property_change::accessible-table-column-header",
1641 gail_tree_view_get_caption (AtkTable *table)
1643 GailTreeView* obj = GAIL_TREE_VIEW (table);
1645 return obj->caption;
1649 gail_tree_view_set_caption (AtkTable *table,
1652 GailTreeView* obj = GAIL_TREE_VIEW (table);
1653 AtkPropertyValues values = { NULL };
1654 AtkObject *old_caption;
1656 old_caption = obj->caption;
1657 obj->caption = caption;
1659 g_object_ref (obj->caption);
1660 g_value_init (&values.old_value, G_TYPE_POINTER);
1661 g_value_set_pointer (&values.old_value, old_caption);
1662 g_value_init (&values.new_value, G_TYPE_POINTER);
1663 g_value_set_pointer (&values.new_value, obj->caption);
1665 values.property_name = "accessible-table-caption-object";
1666 g_signal_emit_by_name (table,
1667 "property_change::accessible-table-caption-object",
1670 g_object_unref (old_caption);
1673 static G_CONST_RETURN gchar*
1674 gail_tree_view_get_column_description (AtkTable *table,
1678 GtkTreeView *tree_view;
1679 GtkTreeViewColumn *tv_col;
1682 widget = GTK_ACCESSIBLE (table)->widget;
1684 /* State is defunct */
1687 tree_view = GTK_TREE_VIEW (widget);
1688 tv_col = get_column (tree_view, in_col);
1692 rc = g_object_get_qdata (G_OBJECT (tv_col),
1693 quark_column_desc_object);
1701 g_object_get (tv_col, "title", &title_text, NULL);
1707 gail_tree_view_set_column_description (AtkTable *table,
1709 const gchar *description)
1712 GtkTreeView *tree_view;
1713 GtkTreeViewColumn *tv_col;
1714 AtkPropertyValues values = { NULL };
1716 widget = GTK_ACCESSIBLE (table)->widget;
1718 /* State is defunct */
1721 tree_view = GTK_TREE_VIEW (widget);
1722 tv_col = get_column (tree_view, in_col);
1726 g_object_set_qdata (G_OBJECT (tv_col),
1727 quark_column_desc_object,
1728 g_strdup (description));
1729 g_value_init (&values.new_value, G_TYPE_INT);
1730 g_value_set_int (&values.new_value, in_col);
1732 values.property_name = "accessible-table-column-description";
1733 g_signal_emit_by_name (table,
1734 "property_change::accessible-table-column-description",
1738 static G_CONST_RETURN gchar*
1739 gail_tree_view_get_row_description (AtkTable *table,
1742 GailTreeViewRowInfo *row_info;
1744 row_info = get_row_info (table, row);
1746 return row_info->description;
1752 gail_tree_view_set_row_description (AtkTable *table,
1754 const gchar *description)
1756 set_row_data (table, row, NULL, description, FALSE);
1760 gail_tree_view_get_summary (AtkTable *table)
1762 GailTreeView* obj = GAIL_TREE_VIEW (table);
1764 return obj->summary;
1768 gail_tree_view_set_summary (AtkTable *table,
1769 AtkObject *accessible)
1771 GailTreeView* obj = GAIL_TREE_VIEW (table);
1772 AtkPropertyValues values = { NULL };
1773 AtkObject *old_summary;
1775 old_summary = obj->summary;
1776 obj->summary = accessible;
1778 g_object_ref (obj->summary);
1779 g_value_init (&values.old_value, G_TYPE_POINTER);
1780 g_value_set_pointer (&values.old_value, old_summary);
1781 g_value_init (&values.new_value, G_TYPE_POINTER);
1782 g_value_set_pointer (&values.new_value, obj->summary);
1784 values.property_name = "accessible-table-summary";
1785 g_signal_emit_by_name (table,
1786 "property_change::accessible-table-ummary",
1789 g_object_unref (old_summary);
1793 set_row_data (AtkTable *table,
1796 const gchar *description,
1800 GtkTreeView *tree_view;
1801 GtkTreeModel *tree_model;
1802 GailTreeView* obj = GAIL_TREE_VIEW (table);
1803 GailTreeViewRowInfo* row_info;
1807 gboolean found = FALSE;
1809 AtkPropertyValues values = { NULL };
1812 widget = GTK_ACCESSIBLE (table)->widget;
1814 /* State is defunct */
1817 tree_view = GTK_TREE_VIEW (widget);
1818 tree_model = gtk_tree_view_get_model (tree_view);
1820 set_iter_nth_row (tree_view, &iter, row);
1821 path = gtk_tree_model_get_path (tree_model, &iter);
1823 if (obj->row_data == NULL)
1824 obj->row_data = g_array_sized_new (FALSE, TRUE,
1825 sizeof(GailTreeViewRowInfo *), 0);
1827 array = obj->row_data;
1829 for (i = 0; i < array->len; i++)
1831 GtkTreePath *row_path;
1833 row_info = g_array_index (array, GailTreeViewRowInfo*, i);
1834 row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
1836 if (row_path != NULL)
1838 if (path && gtk_tree_path_compare (row_path, path) == 0)
1841 gtk_tree_path_free (row_path);
1847 if (row_info->header)
1848 g_object_unref (row_info->header);
1849 row_info->header = header;
1850 if (row_info->header)
1851 g_object_ref (row_info->header);
1855 g_free (row_info->description);
1856 row_info->description = g_strdup (description);
1866 row_info = g_malloc (sizeof(GailTreeViewRowInfo));
1867 row_info->row_ref = gtk_tree_row_reference_new (tree_model, path);
1870 row_info->header = header;
1871 if (row_info->header)
1872 g_object_ref (row_info->header);
1873 row_info->description = NULL;
1877 row_info->header = NULL;
1878 row_info->description = g_strdup (description);
1880 g_array_append_val (array, row_info);
1882 g_value_init (&values.new_value, G_TYPE_INT);
1883 g_value_set_int (&values.new_value, row);
1887 values.property_name = "accessible-table-row-header";
1888 signal_name = "property_change::accessible-table-row-header";
1892 values.property_name = "accessible-table-row-description";
1893 signal_name = "property-change::accessible-table-row-description";
1895 g_signal_emit_by_name (table,
1899 gtk_tree_path_free (path);
1903 static GailTreeViewRowInfo*
1904 get_row_info (AtkTable *table,
1908 GtkTreeView *tree_view;
1909 GtkTreeModel *tree_model;
1910 GailTreeView* obj = GAIL_TREE_VIEW (table);
1914 GailTreeViewRowInfo *rc = NULL;
1916 widget = GTK_ACCESSIBLE (table)->widget;
1918 /* State is defunct */
1921 tree_view = GTK_TREE_VIEW (widget);
1922 tree_model = gtk_tree_view_get_model (tree_view);
1924 set_iter_nth_row (tree_view, &iter, row);
1925 path = gtk_tree_model_get_path (tree_model, &iter);
1926 array = obj->row_data;
1930 GailTreeViewRowInfo *row_info;
1931 GtkTreePath *row_path;
1934 for (i = 0; i < array->len; i++)
1936 row_info = g_array_index (array, GailTreeViewRowInfo*, i);
1937 row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
1938 if (row_path != NULL)
1940 if (path && gtk_tree_path_compare (row_path, path) == 0)
1943 gtk_tree_path_free (row_path);
1951 gtk_tree_path_free (path);
1954 /* atkselection.h */
1956 static void atk_selection_interface_init (AtkSelectionIface *iface)
1958 g_return_if_fail (iface != NULL);
1959 iface->add_selection = gail_tree_view_add_selection;
1960 iface->clear_selection = gail_tree_view_clear_selection;
1961 iface->ref_selection = gail_tree_view_ref_selection;
1962 iface->get_selection_count = gail_tree_view_get_selection_count;
1963 iface->is_child_selected = gail_tree_view_is_child_selected;
1967 gail_tree_view_add_selection (AtkSelection *selection,
1974 table = ATK_TABLE (selection);
1975 n_columns = gail_tree_view_get_n_columns (table);
1979 row = gail_tree_view_get_row_at_index (table, i);
1980 return gail_tree_view_add_row_selection (table, row);
1984 gail_tree_view_clear_selection (AtkSelection *selection)
1987 GtkTreeView *tree_view;
1988 GtkTreeSelection *tree_selection;
1990 widget = GTK_ACCESSIBLE (selection)->widget;
1992 /* State is defunct */
1995 tree_view = GTK_TREE_VIEW (widget);
1997 tree_selection = gtk_tree_view_get_selection (tree_view);
1998 gtk_tree_selection_unselect_all (tree_selection);
2004 gail_tree_view_ref_selection (AtkSelection *selection,
2013 table = ATK_TABLE (selection);
2014 n_columns = gail_tree_view_get_n_columns (table);
2015 n_selected = gail_tree_view_get_selected_rows (table, &selected);
2016 if (i >= n_columns * n_selected)
2019 row = selected[i / n_columns];
2022 return gail_tree_view_table_ref_at (table, row, i % n_columns);
2026 gail_tree_view_get_selection_count (AtkSelection *selection)
2031 table = ATK_TABLE (selection);
2032 n_selected = gail_tree_view_get_selected_rows (table, NULL);
2034 n_selected *= gail_tree_view_get_n_columns (table);
2039 gail_tree_view_is_child_selected (AtkSelection *selection,
2045 widget = GTK_ACCESSIBLE (selection)->widget;
2047 /* State is defunct */
2050 row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
2052 return gail_tree_view_is_row_selected (ATK_TABLE (selection), row);
2056 static void gail_cell_parent_interface_init (GailCellParentIface *iface)
2058 g_return_if_fail (iface);
2060 iface->get_cell_extents = gail_tree_view_get_cell_extents;
2061 iface->get_cell_area = gail_tree_view_get_cell_area;
2062 iface->grab_focus = gail_tree_view_grab_cell_focus;
2066 gail_tree_view_get_cell_extents (GailCellParent *parent,
2072 AtkCoordType coord_type)
2075 GtkTreeView *tree_view;
2076 GdkWindow *bin_window;
2077 GdkRectangle cell_rect;
2080 widget = GTK_ACCESSIBLE (parent)->widget;
2082 /* State is defunct */
2085 tree_view = GTK_TREE_VIEW (widget);
2086 gail_tree_view_get_cell_area (parent, cell, &cell_rect);
2087 bin_window = gtk_tree_view_get_bin_window (tree_view);
2088 gdk_window_get_origin (bin_window, &w_x, &w_y);
2090 if (coord_type == ATK_XY_WINDOW)
2093 gint x_toplevel, y_toplevel;
2095 window = gdk_window_get_toplevel (bin_window);
2096 gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
2102 *width = cell_rect.width;
2103 *height = cell_rect.height;
2104 if (is_cell_showing (tree_view, &cell_rect))
2106 *x = cell_rect.x + w_x;
2107 *y = cell_rect.y + w_y;
2116 #define EXTRA_EXPANDER_PADDING 4
2119 gail_tree_view_get_cell_area (GailCellParent *parent,
2121 GdkRectangle *cell_rect)
2124 GtkTreeView *tree_view;
2125 GtkTreeViewColumn *tv_col;
2127 AtkObject *parent_cell;
2128 GailTreeViewCellInfo *cell_info;
2131 widget = GTK_ACCESSIBLE (parent)->widget;
2133 /* State is defunct */
2136 tree_view = GTK_TREE_VIEW (widget);
2137 parent_cell = atk_object_get_parent (ATK_OBJECT (cell));
2138 if (parent_cell != ATK_OBJECT (parent))
2141 * GailCell is in a GailContainerCell
2143 top_cell = GAIL_CELL (parent_cell);
2149 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), top_cell, NULL, TRUE);
2150 gail_return_if_fail (cell_info);
2151 gail_return_if_fail (cell_info->cell_col_ref);
2152 gail_return_if_fail (cell_info->cell_row_ref);
2153 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2154 tv_col = cell_info->cell_col_ref;
2155 if (path && cell_info->in_use)
2157 GtkTreeViewColumn *expander_column;
2158 gint focus_line_width;
2160 gtk_tree_view_get_cell_area (tree_view, path, tv_col, cell_rect);
2161 expander_column = gtk_tree_view_get_expander_column (tree_view);
2162 if (expander_column == tv_col)
2166 gtk_widget_style_get (widget,
2167 "expander_size", &expander_size,
2170 cell_rect->x += expander_size + EXTRA_EXPANDER_PADDING;
2171 cell_rect->width -= expander_size + EXTRA_EXPANDER_PADDING;
2173 gtk_widget_style_get (widget,
2174 "focus-line-width", &focus_line_width,
2177 cell_rect->x += focus_line_width;
2178 cell_rect->width -= 2 * focus_line_width;
2180 gtk_tree_path_free (path);
2183 * A column has more than one renderer so we find the position and width
2186 if (top_cell != cell)
2193 GtkCellRenderer *renderer;
2195 cell_index = atk_object_get_index_in_parent (ATK_OBJECT (cell));
2196 renderers = gtk_tree_view_column_get_cell_renderers (tv_col);
2197 renderer = g_list_nth_data (renderers, cell_index);
2199 found = gtk_tree_view_column_cell_get_position (tv_col, renderer, &cell_start, &cell_width);
2202 cell_rect->x += cell_start;
2203 cell_rect->width = cell_width;
2205 g_list_free (renderers);
2212 gail_tree_view_grab_cell_focus (GailCellParent *parent,
2216 GtkTreeView *tree_view;
2217 GtkTreeViewColumn *tv_col;
2219 AtkObject *parent_cell;
2220 AtkObject *cell_object;
2221 GailTreeViewCellInfo *cell_info;
2222 GtkCellRenderer *renderer = NULL;
2223 GtkWidget *toplevel;
2226 widget = GTK_ACCESSIBLE (parent)->widget;
2228 /* State is defunct */
2231 tree_view = GTK_TREE_VIEW (widget);
2233 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
2234 gail_return_val_if_fail (cell_info, FALSE);
2235 gail_return_val_if_fail (cell_info->cell_col_ref, FALSE);
2236 gail_return_val_if_fail (cell_info->cell_row_ref, FALSE);
2237 cell_object = ATK_OBJECT (cell);
2238 parent_cell = atk_object_get_parent (cell_object);
2239 tv_col = cell_info->cell_col_ref;
2240 if (parent_cell != ATK_OBJECT (parent))
2243 * GailCell is in a GailContainerCell.
2244 * The GtkTreeViewColumn has multiple renderers;
2245 * find the corresponding one.
2249 renderers = gtk_tree_view_column_get_cell_renderers (tv_col);
2250 if (cell_info->in_use) {
2251 index = atk_object_get_index_in_parent (cell_object);
2252 renderer = g_list_nth_data (renderers, index);
2254 g_list_free (renderers);
2256 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2257 if (path && cell_info->in_use)
2260 gtk_tree_view_set_cursor_on_cell (tree_view, path, tv_col, renderer, FALSE);
2262 gtk_tree_view_set_cursor (tree_view, path, tv_col, FALSE);
2264 gtk_tree_path_free (path);
2265 gtk_widget_grab_focus (widget);
2266 toplevel = gtk_widget_get_toplevel (widget);
2267 if (GTK_WIDGET_TOPLEVEL (toplevel))
2269 #ifdef GDK_WINDOWING_X11
2270 gtk_window_present_with_time (GTK_WINDOW (toplevel), gdk_x11_get_server_time (widget->window));
2272 gtk_window_present (GTK_WINDOW (toplevel));
2282 /* signal handling */
2285 gail_tree_view_expand_row_gtk (GtkTreeView *tree_view,
2290 GailTreeView *gailview;
2292 g_assert (GTK_IS_TREE_VIEW (tree_view));
2294 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2296 g_assert (GAIL_IS_TREE_VIEW (atk_obj));
2298 gailview = GAIL_TREE_VIEW (atk_obj);
2301 * The visible rectangle has not been updated when this signal is emitted
2302 * so we process the signal when the GTK processing is completed
2304 /* this seems wrong since it overwrites any other pending expand handlers... */
2305 gailview->idle_expand_path = gtk_tree_path_copy (path);
2306 if (gailview->idle_expand_id)
2307 g_source_remove (gailview->idle_expand_id);
2308 gailview->idle_expand_id = gdk_threads_add_idle (idle_expand_row, gailview);
2313 idle_expand_row (gpointer data)
2315 GailTreeView *gailview = data;
2317 GtkTreeView *tree_view;
2319 GtkTreeModel *tree_model;
2320 gint n_inserted, row;
2322 gailview->idle_expand_id = 0;
2324 path = gailview->idle_expand_path;
2325 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
2327 g_assert (GTK_IS_TREE_VIEW (tree_view));
2329 tree_model = gtk_tree_view_get_model(tree_view);
2333 if (!path || !gtk_tree_model_get_iter (tree_model, &iter, path))
2337 * Update visibility of cells below expansion row
2339 traverse_cells (gailview, path, FALSE, FALSE);
2341 * Figure out number of visible children, the following test
2344 if (gtk_tree_model_iter_has_child (tree_model, &iter))
2346 GtkTreePath *path_copy;
2349 * By passing path into this function, we find the number of
2350 * visible children of path.
2352 path_copy = gtk_tree_path_copy (path);
2353 gtk_tree_path_append_index(path_copy, 0);
2356 iterate_thru_children (tree_view, tree_model,
2357 path_copy, NULL, &n_inserted, 0);
2358 gtk_tree_path_free (path_copy);
2362 /* We can get here if the row expanded callback deleted the row */
2366 /* Set expand state */
2367 set_expand_state (tree_view, tree_model, gailview, path, TRUE);
2369 row = get_row_from_tree_path (tree_view, path);
2371 /* shouldn't ever happen */
2373 g_assert_not_reached ();
2375 /* Must add 1 because the "added rows" are below the row being expanded */
2378 g_signal_emit_by_name (gailview, "row_inserted", row, n_inserted);
2380 gailview->idle_expand_path = NULL;
2382 gtk_tree_path_free (path);
2388 gail_tree_view_collapse_row_gtk (GtkTreeView *tree_view,
2392 GtkTreeModel *tree_model;
2393 AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2394 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2397 tree_model = gtk_tree_view_get_model (tree_view);
2399 clean_rows (gailview);
2402 * Update visibility of cells below collapsed row
2404 traverse_cells (gailview, path, FALSE, FALSE);
2405 /* Set collapse state */
2406 set_expand_state (tree_view, tree_model, gailview, path, FALSE);
2408 gail_return_val_if_fail (gailview->n_children_deleted, FALSE);
2409 row = get_row_from_tree_path (tree_view, path);
2410 gail_return_val_if_fail (row != -1, FALSE);
2411 g_signal_emit_by_name (atk_obj, "row_deleted", row,
2412 gailview->n_children_deleted);
2413 gailview->n_children_deleted = 0;
2418 gail_tree_view_size_allocate_gtk (GtkWidget *widget,
2419 GtkAllocation *allocation)
2421 AtkObject *atk_obj = gtk_widget_get_accessible (widget);
2422 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2425 * If the size allocation changes, the visibility of cells may change so
2426 * update the cells visibility.
2428 traverse_cells (gailview, NULL, FALSE, FALSE);
2432 gail_tree_view_set_scroll_adjustments (GtkWidget *widget,
2433 GtkAdjustment *hadj,
2434 GtkAdjustment *vadj)
2436 AtkObject *atk_obj = gtk_widget_get_accessible (widget);
2437 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2440 g_object_get (widget, hadjustment, &adj, NULL);
2441 if (gailview->old_hadj != adj)
2443 g_signal_handlers_disconnect_by_func (gailview->old_hadj,
2444 (gpointer) adjustment_changed,
2446 gailview->old_hadj = adj;
2447 g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_hadj);
2448 g_signal_connect (adj,
2450 G_CALLBACK (adjustment_changed),
2453 g_object_get (widget, vadjustment, &adj, NULL);
2454 if (gailview->old_vadj != adj)
2456 g_signal_handlers_disconnect_by_func (gailview->old_vadj,
2457 (gpointer) adjustment_changed,
2459 gailview->old_vadj = adj;
2460 g_object_add_weak_pointer (G_OBJECT (gailview->old_vadj), (gpointer *)&gailview->old_vadj);
2461 g_signal_connect (adj,
2463 G_CALLBACK (adjustment_changed),
2469 gail_tree_view_changed_gtk (GtkTreeSelection *selection,
2472 GailTreeView *gailview;
2473 GtkTreeView *tree_view;
2477 GailTreeViewCellInfo *info;
2478 GtkTreeSelection *tree_selection;
2481 gailview = GAIL_TREE_VIEW (data);
2482 cell_list = gailview->cell_data;
2483 widget = GTK_ACCESSIBLE (gailview)->widget;
2486 * destroy signal emitted for widget
2489 tree_view = GTK_TREE_VIEW (widget);
2491 tree_selection = gtk_tree_view_get_selection (tree_view);
2493 for (l = cell_list; l; l = l->next)
2495 info = (GailTreeViewCellInfo *) (l->data);
2499 gail_cell_remove_state (info->cell, ATK_STATE_SELECTED, TRUE);
2501 path = gtk_tree_row_reference_get_path (info->cell_row_ref);
2502 if (path && gtk_tree_selection_path_is_selected (tree_selection, path))
2503 gail_cell_add_state (info->cell, ATK_STATE_SELECTED, TRUE);
2504 gtk_tree_path_free (path);
2507 if (GTK_WIDGET_REALIZED (widget))
2508 g_signal_emit_by_name (gailview, "selection_changed");
2512 columns_changed (GtkTreeView *tree_view)
2514 AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET(tree_view));
2515 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2516 GList *tv_cols, *tmp_list;
2517 gboolean column_found;
2518 gboolean move_found = FALSE;
2519 gboolean stale_set = FALSE;
2520 gint column_count = 0;
2524 * This function must determine if the change is an add, delete or
2525 * a move based upon its cache of TreeViewColumns in
2526 * gailview->col_data
2528 tv_cols = gtk_tree_view_get_columns (tree_view);
2530 /* check for adds or moves */
2531 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
2533 column_found = FALSE;
2535 for (i = 0; i < gailview->col_data->len; i++)
2538 if ((GtkTreeViewColumn *)tmp_list->data ==
2539 (GtkTreeViewColumn *)g_array_index (gailview->col_data,
2540 GtkTreeViewColumn *, i))
2542 column_found = TRUE;
2544 /* If the column isn't in the same position, a move happened */
2545 if (!move_found && i != column_count)
2549 /* Set all rows to ATK_STATE_STALE */
2550 traverse_cells (gailview, NULL, TRUE, FALSE);
2554 /* Just emit one column reordered signal when a move happens */
2555 g_signal_emit_by_name (atk_obj, "column_reordered");
2564 * If column_found is FALSE, then an insert happened for column
2565 * number column_count
2569 gint n_cols, n_rows, row;
2573 /* Set all rows to ATK_STATE_STALE */
2574 traverse_cells (gailview, NULL, TRUE, FALSE);
2578 /* Generate column-inserted signal */
2579 g_signal_emit_by_name (atk_obj, "column_inserted", column_count, 1);
2581 /* Generate children-changed signals */
2582 n_rows = get_row_count (gtk_tree_view_get_model (tree_view));
2583 n_cols = get_n_actual_columns (tree_view);
2584 for (row = 0; row < n_rows; row++)
2587 * Pass NULL as the child object, i.e. 4th argument.
2589 g_signal_emit_by_name (atk_obj, "children_changed::add",
2590 ((row * n_cols) + column_count), NULL, NULL);
2597 /* check for deletes */
2598 for (i = 0; i < gailview->col_data->len; i++)
2600 column_found = FALSE;
2602 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
2604 if ((GtkTreeViewColumn *)tmp_list->data ==
2605 (GtkTreeViewColumn *)g_array_index (gailview->col_data,
2606 GtkTreeViewColumn *, i))
2608 column_found = TRUE;
2614 * If column_found is FALSE, then a delete happened for column
2619 gint n_rows, n_cols, row;
2621 clean_cols (gailview,
2622 (GtkTreeViewColumn *)g_array_index (gailview->col_data,
2623 GtkTreeViewColumn *, i));
2627 /* Set all rows to ATK_STATE_STALE */
2628 traverse_cells (gailview, NULL, TRUE, FALSE);
2632 /* Generate column-deleted signal */
2633 g_signal_emit_by_name (atk_obj, "column_deleted", i, 1);
2635 /* Generate children-changed signals */
2636 n_rows = get_row_count (gtk_tree_view_get_model (tree_view));
2637 n_cols = get_n_actual_columns (tree_view);
2638 for (row = 0; row < n_rows; row++)
2641 * Pass NULL as the child object, 4th argument.
2643 g_signal_emit_by_name (atk_obj, "children_changed::remove",
2644 ((row * n_cols) + column_count), NULL, NULL);
2649 /* rebuild the array */
2651 g_array_free (gailview->col_data, TRUE);
2652 gailview->col_data = g_array_sized_new (FALSE, TRUE,
2653 sizeof(GtkTreeViewColumn *), 0);
2655 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
2656 g_array_append_val (gailview->col_data, tmp_list->data);
2657 g_list_free (tv_cols);
2661 cursor_changed (GtkTreeView *tree_view)
2663 GailTreeView *gailview;
2665 gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
2666 if (gailview->idle_cursor_changed_id != 0)
2670 * We notify the focus change in a idle handler so that the processing
2671 * of the cursor change is completed when the focus handler is called.
2672 * This will allow actions to be called in the focus handler
2674 gailview->idle_cursor_changed_id = gdk_threads_add_idle (idle_cursor_changed, gailview);
2678 idle_cursor_changed (gpointer data)
2680 GailTreeView *gail_tree_view = GAIL_TREE_VIEW (data);
2681 GtkTreeView *tree_view;
2685 gail_tree_view->idle_cursor_changed_id = 0;
2687 widget = GTK_ACCESSIBLE (gail_tree_view)->widget;
2689 * Widget has been deleted
2694 tree_view = GTK_TREE_VIEW (widget);
2696 cell = gail_tree_view_ref_focus_cell (tree_view);
2699 if (cell != gail_tree_view->focus_cell)
2701 if (gail_tree_view->focus_cell)
2703 gail_cell_remove_state (GAIL_CELL (gail_tree_view->focus_cell), ATK_STATE_ACTIVE, FALSE);
2704 g_object_unref (gail_tree_view->focus_cell);
2706 gail_tree_view->focus_cell = cell;
2708 if (GTK_WIDGET_HAS_FOCUS (widget))
2709 gail_cell_add_state (GAIL_CELL (cell), ATK_STATE_ACTIVE, FALSE);
2710 g_signal_emit_by_name (gail_tree_view,
2711 "active-descendant-changed",
2715 g_object_unref (cell);
2722 model_row_changed (GtkTreeModel *tree_model,
2727 GtkTreeView *tree_view = GTK_TREE_VIEW(user_data);
2728 GailTreeView *gailview;
2729 GtkTreePath *cell_path;
2731 GailTreeViewCellInfo *cell_info;
2733 gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
2735 /* Loop through our cached cells */
2736 /* Must loop through them all */
2737 for (l = gailview->cell_data; l; l = l->next)
2739 cell_info = (GailTreeViewCellInfo *) l->data;
2740 if (cell_info->in_use)
2742 cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2744 if (cell_path != NULL)
2746 if (path && gtk_tree_path_compare (cell_path, path) == 0)
2748 if (GAIL_IS_RENDERER_CELL (cell_info->cell))
2750 update_cell_value (GAIL_RENDERER_CELL (cell_info->cell),
2754 gtk_tree_path_free (cell_path);
2758 g_signal_emit_by_name (gailview, "visible-data-changed");
2762 column_visibility_changed (GObject *object,
2766 if (strcmp (pspec->name, "visible") == 0)
2769 * A column has been made visible or invisible
2771 * We update our cache of cells and emit model_changed signal
2773 GtkTreeView *tree_view = (GtkTreeView *)user_data;
2774 GailTreeView *gailview;
2776 GailTreeViewCellInfo *cell_info;
2777 GtkTreeViewColumn *this_col = GTK_TREE_VIEW_COLUMN (object);
2778 GtkTreeViewColumn *tv_col;
2780 gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view))
2782 g_signal_emit_by_name (gailview, "model_changed");
2784 for (l = gailview->cell_data; l; l = l->next)
2786 cell_info = (GailTreeViewCellInfo *) l->data;
2787 if (cell_info->in_use)
2789 tv_col = cell_info->cell_col_ref;
2790 if (tv_col == this_col)
2792 GtkTreePath *row_path;
2793 row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2794 if (GAIL_IS_RENDERER_CELL (cell_info->cell))
2796 if (gtk_tree_view_column_get_visible (tv_col))
2797 set_cell_visibility (tree_view,
2799 tv_col, row_path, FALSE);
2802 gail_cell_remove_state (cell_info->cell,
2803 ATK_STATE_VISIBLE, TRUE);
2804 gail_cell_remove_state (cell_info->cell,
2805 ATK_STATE_SHOWING, TRUE);
2808 gtk_tree_path_free (row_path);
2816 * This is the signal handler for the "destroy" signal for a GtkTreeViewColumn
2818 * We check whether we have stored column description or column header
2819 * and if so we get rid of it.
2822 column_destroy (GtkObject *obj)
2824 GtkTreeViewColumn *tv_col = GTK_TREE_VIEW_COLUMN (obj);
2828 header = g_object_get_qdata (G_OBJECT (tv_col),
2829 quark_column_header_object);
2831 g_object_unref (header);
2832 desc = g_object_get_qdata (G_OBJECT (tv_col),
2833 quark_column_desc_object);
2838 model_row_inserted (GtkTreeModel *tree_model,
2843 GtkTreeView *tree_view = (GtkTreeView *)user_data;
2844 GtkTreePath *path_copy;
2845 AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2846 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2847 gint row, n_inserted, child_row;
2849 if (gailview->idle_expand_id)
2851 g_source_remove (gailview->idle_expand_id);
2852 gailview->idle_expand_id = 0;
2854 /* don't do this if the insertion precedes the idle path, since it will now be invalid */
2855 if (path && gailview->idle_expand_path &&
2856 (gtk_tree_path_compare (path, gailview->idle_expand_path) > 0))
2857 set_expand_state (tree_view, tree_model, gailview, gailview->idle_expand_path, FALSE);
2858 if (gailview->idle_expand_path)
2859 gtk_tree_path_free (gailview->idle_expand_path);
2861 /* Check to see if row is visible */
2862 row = get_row_from_tree_path (tree_view, path);
2865 * A row insert is not necessarily visible. For example,
2866 * a row can be draged & dropped into another row, which
2867 * causes an insert on the model that isn't visible in the
2868 * view. Only generate a signal if the inserted row is
2876 gtk_tree_model_get_iter (tree_model, &iter, path);
2878 /* Figure out number of visible children. */
2879 if (gtk_tree_model_iter_has_child (tree_model, &iter))
2882 * By passing path into this function, we find the number of
2883 * visible children of path.
2886 iterate_thru_children (tree_view, tree_model,
2887 path, NULL, &n_inserted, 0);
2889 /* Must add one to include the row that is being added */
2895 /* Set rows below the inserted row to ATK_STATE_STALE */
2896 traverse_cells (gailview, path, TRUE, TRUE);
2898 /* Generate row-inserted signal */
2899 g_signal_emit_by_name (atk_obj, "row_inserted", row, n_inserted);
2901 /* Generate children-changed signals */
2902 n_cols = gail_tree_view_get_n_columns (ATK_TABLE (atk_obj));
2903 for (child_row = row; child_row < (row + n_inserted); child_row++)
2905 for (col = 0; col < n_cols; col++)
2908 * Pass NULL as the child object, i.e. 4th argument
2910 g_signal_emit_by_name (atk_obj, "children_changed::add",
2911 ((row * n_cols) + col), NULL, NULL);
2918 * The row has been inserted inside another row. This can
2919 * cause a row that previously couldn't be expanded to now
2922 path_copy = gtk_tree_path_copy (path);
2923 gtk_tree_path_up (path_copy);
2924 set_expand_state (tree_view, tree_model, gailview, path_copy, TRUE);
2925 gtk_tree_path_free (path_copy);
2930 model_row_deleted (GtkTreeModel *tree_model,
2934 GtkTreeView *tree_view;
2935 GtkTreePath *path_copy;
2937 GailTreeView *gailview;
2940 tree_view = (GtkTreeView *)user_data;
2941 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2942 gailview = GAIL_TREE_VIEW (atk_obj);
2944 if (gailview->idle_expand_id)
2946 g_source_remove (gailview->idle_expand_id);
2947 gtk_tree_path_free (gailview->idle_expand_path);
2948 gailview->idle_expand_id = 0;
2950 /* Check to see if row is visible */
2951 clean_rows (gailview);
2953 /* Set rows at or below the specified row to ATK_STATE_STALE */
2954 traverse_cells (gailview, path, TRUE, TRUE);
2957 * If deleting a row with a depth > 1, then this may affect the
2958 * expansion/contraction of its parent(s). Make sure this is
2961 if (gtk_tree_path_get_depth (path) > 1)
2963 path_copy = gtk_tree_path_copy (path);
2964 gtk_tree_path_up (path_copy);
2965 set_expand_state (tree_view, tree_model, gailview, path_copy, TRUE);
2966 gtk_tree_path_free (path_copy);
2968 row = get_row_from_tree_path (tree_view, path);
2970 * If the row which is deleted is not visible because it is a child of
2971 * a collapsed row then row will be -1
2974 g_signal_emit_by_name (atk_obj, "row_deleted", row,
2975 gailview->n_children_deleted + 1);
2976 gailview->n_children_deleted = 0;
2980 * This function gets called when a row is deleted or when rows are
2981 * removed from the view due to a collapse event. Note that the
2982 * count is the number of visible *children* of the deleted row,
2983 * so it does not include the row being deleted.
2985 * As this function is called before the rows are removed we just note the
2986 * number of rows and then deal with it when we get a notification that
2987 * rows were deleted or collapsed.
2990 destroy_count_func (GtkTreeView *tree_view,
2995 AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2996 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2998 gail_return_if_fail (gailview->n_children_deleted == 0);
2999 gailview->n_children_deleted = count;
3003 model_rows_reordered (GtkTreeModel *tree_model,
3009 GtkTreeView *tree_view = (GtkTreeView *)user_data;
3010 AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
3011 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
3013 if (gailview->idle_expand_id)
3015 g_source_remove (gailview->idle_expand_id);
3016 gtk_tree_path_free (gailview->idle_expand_path);
3017 gailview->idle_expand_id = 0;
3019 traverse_cells (gailview, NULL, TRUE, FALSE);
3021 g_signal_emit_by_name (atk_obj, "row_reordered");
3025 adjustment_changed (GtkAdjustment *adjustment,
3026 GtkTreeView *tree_view)
3032 * The scrollbars have changed
3034 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
3035 obj = GAIL_TREE_VIEW (atk_obj);
3037 traverse_cells (obj, NULL, FALSE, FALSE);
3041 set_cell_visibility (GtkTreeView *tree_view,
3043 GtkTreeViewColumn *tv_col,
3044 GtkTreePath *tree_path,
3045 gboolean emit_signal)
3047 GdkRectangle cell_rect;
3049 /* Get these three values in tree coords */
3050 if (GTK_WIDGET_REALIZED (GTK_WIDGET (tree_view)))
3051 gtk_tree_view_get_cell_area (tree_view, tree_path, tv_col, &cell_rect);
3053 cell_rect.height = 0;
3055 if (cell_rect.height > 0)
3058 * The height will be zero for a cell for which an antecedent is not
3061 gail_cell_add_state (cell, ATK_STATE_VISIBLE, emit_signal);
3062 if (is_cell_showing (tree_view, &cell_rect))
3063 gail_cell_add_state (cell, ATK_STATE_SHOWING, emit_signal);
3065 gail_cell_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
3069 gail_cell_remove_state (cell, ATK_STATE_VISIBLE, emit_signal);
3070 gail_cell_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
3075 is_cell_showing (GtkTreeView *tree_view,
3076 GdkRectangle *cell_rect)
3078 GdkRectangle rect, *visible_rect;
3079 GdkRectangle rect1, *tree_cell_rect;
3080 gboolean is_showing;
3082 * A cell is considered "SHOWING" if any part of the cell is in the visible
3083 * area. Other ways we could do this is by a cell's midpoint or if the cell
3084 * is fully in the visible range. Since we have the cell_rect x,y,width,height
3085 * of the cell, any of these is easy to compute.
3087 * It is assumed that cell's rectangle is in widget coordinates so we
3088 * must transform to tree cordinates.
3090 visible_rect = ▭
3091 tree_cell_rect = &rect1;
3092 tree_cell_rect->x = cell_rect->x;
3093 tree_cell_rect->width = cell_rect->width;
3094 tree_cell_rect->height = cell_rect->height;
3096 gtk_tree_view_get_visible_rect (tree_view, visible_rect);
3097 gtk_tree_view_widget_to_tree_coords (tree_view, cell_rect->x, cell_rect->y,
3100 if (((tree_cell_rect->x + tree_cell_rect->width) < visible_rect->x) ||
3101 ((tree_cell_rect->y + tree_cell_rect->height) < (visible_rect->y)) ||
3102 (tree_cell_rect->x > (visible_rect->x + visible_rect->width)) ||
3103 (tree_cell_rect->y > (visible_rect->y + visible_rect->height)))
3114 * This function is called when a cell's flyweight is created in
3115 * gail_tree_view_table_ref_at with emit_change_signal set to FALSE
3116 * and in model_row_changed() on receipt of "row-changed" signal when
3117 * emit_change_signal is set to TRUE
3120 update_cell_value (GailRendererCell *renderer_cell,
3121 GailTreeView *gailview,
3122 gboolean emit_change_signal)
3124 GailTreeViewCellInfo *cell_info;
3125 GtkTreeView *tree_view;
3126 GtkTreeModel *tree_model;
3129 GList *renderers, *cur_renderer;
3131 GailRendererCellClass *gail_renderer_cell_class;
3132 GtkCellRendererClass *gtk_cell_renderer_class;
3136 gboolean is_expander, is_expanded;
3138 gail_renderer_cell_class = GAIL_RENDERER_CELL_GET_CLASS (renderer_cell);
3139 if (renderer_cell->renderer)
3140 gtk_cell_renderer_class = GTK_CELL_RENDERER_GET_CLASS (renderer_cell->renderer);
3142 gtk_cell_renderer_class = NULL;
3144 prop_list = gail_renderer_cell_class->property_list;
3146 cell = GAIL_CELL (renderer_cell);
3147 cell_info = find_cell_info (gailview, cell, NULL, TRUE);
3148 gail_return_val_if_fail (cell_info, FALSE);
3149 gail_return_val_if_fail (cell_info->cell_col_ref, FALSE);
3150 gail_return_val_if_fail (cell_info->cell_row_ref, FALSE);
3152 if (emit_change_signal && cell_info->in_use)
3154 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
3155 tree_model = gtk_tree_view_get_model (tree_view);
3156 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3160 gtk_tree_model_get_iter (tree_model, &iter, path);
3161 is_expander = FALSE;
3162 is_expanded = FALSE;
3163 if (gtk_tree_model_iter_has_child (tree_model, &iter))
3165 GtkTreeViewColumn *expander_tv;
3167 expander_tv = gtk_tree_view_get_expander_column (tree_view);
3168 if (expander_tv == cell_info->cell_col_ref)
3171 is_expanded = gtk_tree_view_row_expanded (tree_view, path);
3174 gtk_tree_path_free (path);
3175 gtk_tree_view_column_cell_set_cell_data (cell_info->cell_col_ref,
3176 tree_model, &iter, is_expander, is_expanded);
3178 renderers = gtk_tree_view_column_get_cell_renderers (cell_info->cell_col_ref);
3179 gail_return_val_if_fail (renderers, FALSE);
3182 * If the cell is in a container, it's index is used to find the renderer
3187 * Otherwise, we assume that the cell is represented by the first renderer
3191 if (cell_info->in_use) {
3192 parent = atk_object_get_parent (ATK_OBJECT (cell));
3193 if (!ATK_IS_OBJECT (cell)) g_on_error_query (NULL);
3194 if (GAIL_IS_CONTAINER_CELL (parent))
3195 cur_renderer = g_list_nth (renderers, cell->index);
3197 cur_renderer = renderers;
3203 gail_return_val_if_fail (cur_renderer != NULL, FALSE);
3205 if (gtk_cell_renderer_class)
3209 spec = g_object_class_find_property
3210 (G_OBJECT_CLASS (gtk_cell_renderer_class), *prop_list);
3214 GValue value = { 0, };
3216 g_value_init (&value, spec->value_type);
3217 g_object_get_property (cur_renderer->data, *prop_list, &value);
3218 g_object_set_property (G_OBJECT (renderer_cell->renderer),
3219 *prop_list, &value);
3220 g_value_unset(&value);
3223 g_warning ("Invalid property: %s\n", *prop_list);
3227 g_list_free (renderers);
3228 return gail_renderer_cell_update_cache (renderer_cell, emit_change_signal);
3232 set_iter_nth_row (GtkTreeView *tree_view,
3236 GtkTreeModel *tree_model;
3238 tree_model = gtk_tree_view_get_model (tree_view);
3239 gtk_tree_model_get_iter_root (tree_model, iter);
3240 iter = return_iter_nth_row (tree_view, tree_model, iter, 0 , row);
3244 get_row_from_tree_path (GtkTreeView *tree_view,
3247 GtkTreeModel *tree_model;
3248 GtkTreePath *root_tree;
3251 tree_model = gtk_tree_view_get_model (tree_view);
3253 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
3254 row = gtk_tree_path_get_indices (path)[0];
3257 root_tree = gtk_tree_path_new_root ();
3259 iterate_thru_children (tree_view, tree_model, root_tree, path, &row, 0);
3260 gtk_tree_path_free (root_tree);
3269 * Get the specified GtkTreeViewColumn in the GtkTreeView.
3270 * Only visible columns are considered.
3272 static GtkTreeViewColumn*
3273 get_column (GtkTreeView *tree_view,
3276 GtkTreeViewColumn *tv_col;
3282 g_warning ("Request for invalid column %d\n", in_col);
3286 tv_col = gtk_tree_view_get_column (tree_view, i);
3288 while (tv_col != NULL)
3290 if (gtk_tree_view_column_get_visible (tv_col))
3292 if (in_col == n_cols)
3294 tv_col = gtk_tree_view_get_column (tree_view, ++i);
3297 if (in_col != n_cols)
3299 g_warning ("Request for invalid column %d\n", in_col);
3306 get_actual_column_number (GtkTreeView *tree_view,
3307 gint visible_column)
3309 GtkTreeViewColumn *tv_col;
3310 gint actual_column = 0;
3311 gint visible_columns = -1;
3313 * This function calculates the column number which corresponds to the
3314 * specified visible column number
3316 tv_col = gtk_tree_view_get_column (tree_view, actual_column);
3318 while (tv_col != NULL)
3320 if (gtk_tree_view_column_get_visible (tv_col))
3322 if (visible_columns == visible_column)
3323 return actual_column;
3324 tv_col = gtk_tree_view_get_column (tree_view, ++actual_column);
3326 g_warning ("get_actual_column_number failed for %d\n", visible_column);
3331 get_visible_column_number (GtkTreeView *tree_view,
3334 GtkTreeViewColumn *tv_col;
3336 gint visible_columns = -1;
3338 * This function calculates the visible column number which corresponds to the
3339 * specified actual column number
3341 tv_col = gtk_tree_view_get_column (tree_view, column);
3343 while (tv_col != NULL)
3345 if (gtk_tree_view_column_get_visible (tv_col))
3348 if (actual_column == column)
3349 return visible_columns;
3352 if (actual_column == column)
3354 tv_col = gtk_tree_view_get_column (tree_view, ++column);
3356 g_warning ("get_visible_column_number failed for %d\n", actual_column);
3361 * Helper recursive function that returns GtkTreeIter pointer to nth row.
3364 return_iter_nth_row(GtkTreeView *tree_view,
3365 GtkTreeModel *tree_model,
3370 GtkTreePath *current_path = gtk_tree_model_get_path (tree_model, iter);
3371 GtkTreeIter new_iter;
3372 gboolean row_expanded;
3374 if (increment == row) {
3375 gtk_tree_path_free (current_path);
3379 row_expanded = gtk_tree_view_row_expanded (tree_view, current_path);
3380 gtk_tree_path_free (current_path);
3383 if ((row_expanded && gtk_tree_model_iter_children (tree_model, iter, &new_iter)) ||
3384 (gtk_tree_model_iter_next (tree_model, iter)) ||
3385 (gtk_tree_model_iter_parent (tree_model, iter, &new_iter) &&
3386 (gtk_tree_model_iter_next (tree_model, iter))))
3387 return return_iter_nth_row (tree_view, tree_model, iter,
3394 * Recursively called until the row specified by orig is found.
3396 * *count will be set to the visible row number of the child
3397 * relative to the row that was initially passed in as tree_path.
3399 * *count will be -1 if orig is not found as a child (a row that is
3400 * not visible will not be found, e.g. if the row is inside a
3401 * collapsed row). If NULL is passed in as orig, *count will
3402 * be a count of the visible children.
3404 * NOTE: the value for depth must be 0 when this recursive function
3405 * is initially called, or it may not function as expected.
3408 iterate_thru_children(GtkTreeView *tree_view,
3409 GtkTreeModel *tree_model,
3410 GtkTreePath *tree_path,
3417 if (!gtk_tree_model_get_iter (tree_model, &iter, tree_path))
3420 if (tree_path && orig && !gtk_tree_path_compare (tree_path, orig))
3424 if (tree_path && orig && gtk_tree_path_compare (tree_path, orig) > 0)
3426 /* Past it, so return -1 */
3430 else if (gtk_tree_view_row_expanded (tree_view, tree_path) &&
3431 gtk_tree_model_iter_has_child (tree_model, &iter))
3434 gtk_tree_path_append_index (tree_path, 0);
3435 iterate_thru_children (tree_view, tree_model, tree_path,
3436 orig, count, (depth + 1));
3439 else if (gtk_tree_model_iter_next (tree_model, &iter))
3442 tree_path = gtk_tree_model_get_path (tree_model, &iter);
3445 iterate_thru_children (tree_view, tree_model, tree_path,
3446 orig, count, depth);
3447 gtk_tree_path_free (tree_path);
3451 else if (gtk_tree_path_up (tree_path))
3453 GtkTreeIter temp_iter;
3454 gboolean exit_loop = FALSE;
3455 gint new_depth = depth - 1;
3460 * Make sure that we back up until we find a row
3461 * where gtk_tree_path_next does not return NULL.
3465 if (gtk_tree_path_get_depth (tree_path) == 0)
3466 /* depth is now zero so */
3468 gtk_tree_path_next (tree_path);
3470 /* Verify that the next row is a valid row! */
3471 exit_loop = gtk_tree_model_get_iter (tree_model, &temp_iter, tree_path);
3475 /* Keep going up until we find a row that has a valid next */
3476 if (gtk_tree_path_get_depth(tree_path) > 1)
3479 gtk_tree_path_up (tree_path);
3484 * If depth is 1 and gtk_tree_model_get_iter returns FALSE,
3485 * then we are at the last row, so just return.
3496 * This guarantees that we will stop when we hit the end of the
3502 iterate_thru_children (tree_view, tree_model, tree_path,
3503 orig, count, new_depth);
3508 * If it gets here, then the path wasn't found. Situations
3509 * that would cause this would be if the path passed in is
3510 * invalid or contained within the last row, but not visible
3511 * because the last row is not expanded. If NULL was passed
3512 * in then a row count is desired, so only set count to -1
3513 * if orig is not NULL.
3522 clean_cell_info (GailTreeView *gailview,
3525 GailTreeViewCellInfo *cell_info;
3528 g_assert (GAIL_IS_TREE_VIEW (gailview));
3530 cell_info = list->data;
3532 if (cell_info->in_use) {
3533 obj = G_OBJECT (cell_info->cell);
3535 gail_cell_add_state (cell_info->cell, ATK_STATE_DEFUNCT, TRUE);
3536 g_object_weak_unref (obj, (GWeakNotify) cell_destroyed, cell_info);
3537 cell_info->in_use = FALSE;
3538 if (!gailview->garbage_collection_pending) {
3539 gailview->garbage_collection_pending = TRUE;
3540 g_assert (gailview->idle_garbage_collect_id == 0);
3541 gailview->idle_garbage_collect_id =
3542 gdk_threads_add_idle (idle_garbage_collect_cell_data, gailview);
3548 clean_rows (GailTreeView *gailview)
3552 /* Clean GailTreeViewRowInfo data */
3554 array = gailview->row_data;
3557 GailTreeViewRowInfo *row_info;
3558 GtkTreePath *row_path;
3562 * Loop backwards so that calls to free_row_info
3563 * do not affect the index numbers
3565 for (i = (array->len - 1); i >= 0; i --)
3567 row_info = g_array_index (array, GailTreeViewRowInfo*, i);
3568 row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
3570 /* Remove any rows that have become invalid */
3571 if (row_path == NULL)
3572 free_row_info (array, i, TRUE);
3574 gtk_tree_path_free (row_path);
3578 /* Clean GailTreeViewCellInfo data */
3580 if (gailview->cell_data != NULL)
3582 GailTreeViewCellInfo *cell_info;
3583 GtkTreePath *row_path;
3587 temp_list = gailview->cell_data;
3589 /* Must loop through them all */
3590 while (temp_list != NULL)
3592 cur_list = temp_list;
3593 cell_info = temp_list->data;
3594 temp_list = temp_list->next;
3595 row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3598 * If the cell has become invalid because the row has been removed,
3599 * then set the cell's state to ATK_STATE_DEFUNCT and remove the cell
3600 * from gailview->cell_data. If row_path is NULL then the row has
3603 if (row_path == NULL)
3605 clean_cell_info (gailview, cur_list);
3609 gtk_tree_path_free (row_path);
3616 clean_cols (GailTreeView *gailview,
3617 GtkTreeViewColumn *tv_col)
3619 /* Clean GailTreeViewCellInfo data */
3621 if (gailview->cell_data != NULL)
3623 GailTreeViewCellInfo *cell_info;
3624 GList *cur_list, *temp_list;
3626 temp_list = gailview->cell_data;
3628 while (temp_list != NULL)
3630 cur_list = temp_list;
3631 cell_info = temp_list->data;
3632 temp_list = temp_list->next;
3635 * If the cell has become invalid because the column tv_col
3636 * has been removed, then set the cell's state to ATK_STATE_DEFUNCT
3637 * and remove the cell from gailview->cell_data.
3639 if (cell_info->cell_col_ref == tv_col)
3641 clean_cell_info (gailview, cur_list);
3648 idle_garbage_collect_cell_data (gpointer data)
3650 GailTreeView *tree_view;
3652 g_assert (GAIL_IS_TREE_VIEW (data));
3653 tree_view = (GailTreeView *)data;
3655 /* this is the idle handler (only one instance allowed), so
3656 * we can safely delete it.
3658 tree_view->garbage_collection_pending = FALSE;
3659 tree_view->idle_garbage_collect_id = 0;
3661 tree_view->garbage_collection_pending = garbage_collect_cell_data (data);
3663 /* N.B.: if for some reason another handler has re-enterantly been queued
3664 * while this handler was being serviced, it has its own gsource, therefore this handler
3665 * should always return FALSE.
3671 garbage_collect_cell_data (gpointer data)
3673 GailTreeView *tree_view;
3675 GailTreeViewCellInfo *cell_info;
3677 g_assert (GAIL_IS_TREE_VIEW (data));
3678 tree_view = (GailTreeView *)data;
3679 temp_list = g_list_copy (tree_view->cell_data);
3681 tree_view->garbage_collection_pending = FALSE;
3682 if (tree_view->idle_garbage_collect_id != 0)
3684 g_source_remove (tree_view->idle_garbage_collect_id);
3685 tree_view->idle_garbage_collect_id = 0;
3688 /* Must loop through them all */
3689 while (temp_list != NULL)
3691 cell_info = temp_list->data;
3692 if (!cell_info->in_use)
3694 /* g_object_unref (cell_info->cell); */
3695 tree_view->cell_data = g_list_remove (tree_view->cell_data,
3697 if (cell_info->cell_row_ref)
3698 gtk_tree_row_reference_free (cell_info->cell_row_ref);
3701 temp_list = temp_list->next;
3703 g_list_free (temp_list);
3705 return tree_view->garbage_collection_pending;
3709 * If tree_path is passed in as NULL, then all cells are acted on.
3710 * Otherwise, just act on those cells that are on a row greater than
3711 * the specified tree_path. If inc_row is passed in as TRUE, then rows
3712 * greater and equal to the specified tree_path are acted on.
3714 * if set_stale is set the ATK_STATE_STALE is set on cells which are to be
3717 * The function set_cell_visibility() is called on all cells to be
3718 * acted on to update the visibility of the cell.
3721 traverse_cells (GailTreeView *tree_view,
3722 GtkTreePath *tree_path,
3726 if (tree_view->cell_data != NULL)
3728 GailTreeViewCellInfo *cell_info;
3729 GtkTreeView *gtk_tree_view;
3733 g_assert (GTK_IS_ACCESSIBLE (tree_view));
3735 widget = GTK_ACCESSIBLE (tree_view)->widget;
3737 /* Widget is being deleted */
3740 gtk_tree_view = GTK_TREE_VIEW (widget);
3741 temp_list = tree_view->cell_data;
3743 /* Must loop through them all */
3744 while (temp_list != NULL)
3746 GtkTreePath *row_path;
3747 gboolean act_on_cell;
3749 cell_info = temp_list->data;
3750 temp_list = temp_list->next;
3752 if (cell_info->in_use)
3754 row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3755 g_assert (row_path != NULL);
3756 if (tree_path == NULL)
3762 comparison = gtk_tree_path_compare (row_path, tree_path);
3763 if ((comparison > 0) ||
3764 (comparison == 0 && inc_row))
3767 act_on_cell = FALSE;
3769 if (!cell_info->in_use) g_warning ("warning: cell info destroyed during traversal");
3770 if (act_on_cell && cell_info->in_use)
3773 gail_cell_add_state (cell_info->cell, ATK_STATE_STALE, TRUE);
3774 set_cell_visibility (gtk_tree_view,
3776 cell_info->cell_col_ref,
3779 gtk_tree_path_free (row_path);
3783 g_signal_emit_by_name (tree_view, "visible-data-changed");
3787 free_row_info (GArray *array,
3791 GailTreeViewRowInfo* obj;
3793 obj = g_array_index (array, GailTreeViewRowInfo*, array_idx);
3795 g_free (obj->description);
3796 if (obj->row_ref != NULL)
3797 gtk_tree_row_reference_free (obj->row_ref);
3799 g_object_unref (obj->header);
3803 g_array_remove_index (array, array_idx);
3807 * If the tree_path passed in has children, then
3808 * ATK_STATE_EXPANDABLE is set. If the row is expanded
3809 * ATK_STATE_EXPANDED is turned on. If the row is
3810 * collapsed, then ATK_STATE_EXPANDED is removed.
3812 * If the tree_path passed in has no children, then
3813 * ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED are removed.
3815 * If set_on_ancestor is TRUE, then this function will also
3816 * update all cells that are ancestors of the tree_path.
3819 set_expand_state (GtkTreeView *tree_view,
3820 GtkTreeModel *tree_model,
3821 GailTreeView *gailview,
3822 GtkTreePath *tree_path,
3823 gboolean set_on_ancestor)
3825 if (gailview->cell_data != NULL)
3827 GtkTreeViewColumn *expander_tv;
3828 GailTreeViewCellInfo *cell_info;
3830 GtkTreePath *cell_path;
3834 temp_list = gailview->cell_data;
3836 while (temp_list != NULL)
3838 cell_info = temp_list->data;
3839 temp_list = temp_list->next;
3840 if (cell_info->in_use)
3842 cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3845 if (cell_path != NULL)
3847 GailCell *cell = GAIL_CELL (cell_info->cell);
3849 expander_tv = gtk_tree_view_get_expander_column (tree_view);
3852 * Only set state for the cell that is in the column with the
3855 if (expander_tv == cell_info->cell_col_ref)
3857 if (tree_path && gtk_tree_path_compare (cell_path, tree_path) == 0)
3859 else if (set_on_ancestor &&
3860 gtk_tree_path_get_depth (cell_path) <
3861 gtk_tree_path_get_depth (tree_path) &&
3862 gtk_tree_path_is_ancestor (cell_path, tree_path) == 1)
3863 /* Only set if set_on_ancestor was passed in as TRUE */
3868 * Set ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED
3869 * for ancestors and found cells.
3874 * Must check against cell_path since cell_path
3875 * can be equal to or an ancestor of tree_path.
3877 gtk_tree_model_get_iter (tree_model, &iter, cell_path);
3879 /* Set or unset ATK_STATE_EXPANDABLE as appropriate */
3880 if (gtk_tree_model_iter_has_child (tree_model, &iter))
3882 set_cell_expandable (cell);
3884 if (gtk_tree_view_row_expanded (tree_view, cell_path))
3885 gail_cell_add_state (cell, ATK_STATE_EXPANDED, TRUE);
3887 gail_cell_remove_state (cell,
3888 ATK_STATE_EXPANDED, TRUE);
3892 gail_cell_remove_state (cell,
3893 ATK_STATE_EXPANDED, TRUE);
3894 if (gail_cell_remove_state (cell,
3895 ATK_STATE_EXPANDABLE, TRUE))
3896 /* The state may have been propagated to the container cell */
3897 if (!GAIL_IS_CONTAINER_CELL (cell))
3898 gail_cell_remove_action_by_name (cell,
3899 "expand or contract");
3903 * We assume that each cell in the cache once and
3904 * a container cell is before its child cells so we are
3905 * finished if set_on_ancestor is not set to TRUE.
3907 if (!set_on_ancestor)
3911 gtk_tree_path_free (cell_path);
3919 add_cell_actions (GailCell *cell,
3922 if (GAIL_IS_BOOLEAN_CELL (cell))
3923 gail_cell_add_action (cell,
3925 "toggles the cell", /* action description */
3927 toggle_cell_toggled);
3929 gail_cell_add_action (cell,
3931 "creates a widget in which the contents of the cell can be edited",
3934 gail_cell_add_action (cell,
3936 "activate the cell",
3942 toggle_cell_expanded (GailCell *cell)
3944 GailTreeViewCellInfo *cell_info;
3945 GtkTreeView *tree_view;
3948 AtkStateSet *stateset;
3950 parent = atk_object_get_parent (ATK_OBJECT (cell));
3951 if (GAIL_IS_CONTAINER_CELL (parent))
3952 parent = atk_object_get_parent (parent);
3954 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
3955 gail_return_if_fail (cell_info);
3956 gail_return_if_fail (cell_info->cell_col_ref);
3957 gail_return_if_fail (cell_info->cell_row_ref);
3959 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
3960 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3961 gail_return_if_fail (path);
3963 stateset = atk_object_ref_state_set (ATK_OBJECT (cell));
3964 if (atk_state_set_contains_state (stateset, ATK_STATE_EXPANDED))
3965 gtk_tree_view_collapse_row (tree_view, path);
3967 gtk_tree_view_expand_row (tree_view, path, TRUE);
3968 g_object_unref (stateset);
3969 gtk_tree_path_free (path);
3974 toggle_cell_toggled (GailCell *cell)
3976 GailTreeViewCellInfo *cell_info;
3977 GtkTreeView *tree_view;
3980 GList *renderers, *cur_renderer;
3982 gboolean is_container_cell = FALSE;
3984 parent = atk_object_get_parent (ATK_OBJECT (cell));
3985 if (GAIL_IS_CONTAINER_CELL (parent))
3987 is_container_cell = TRUE;
3988 parent = atk_object_get_parent (parent);
3991 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
3992 gail_return_if_fail (cell_info);
3993 gail_return_if_fail (cell_info->cell_col_ref);
3994 gail_return_if_fail (cell_info->cell_row_ref);
3996 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
3997 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3998 gail_return_if_fail (path);
3999 pathstring = gtk_tree_path_to_string (path);
4001 renderers = gtk_tree_view_column_get_cell_renderers (cell_info->cell_col_ref);
4002 gail_return_if_fail (renderers);
4005 * if the cell is in a container, it's index is used to find the
4006 * renderer in the list
4009 if (is_container_cell)
4010 cur_renderer = g_list_nth (renderers, cell->index);
4013 * Otherwise, we assume that the cell is represented by the first
4014 * renderer in the list
4016 cur_renderer = renderers;
4018 gail_return_if_fail (cur_renderer);
4020 g_signal_emit_by_name (cur_renderer->data, "toggled", pathstring);
4021 g_list_free (renderers);
4022 g_free (pathstring);
4023 gtk_tree_path_free (path);
4028 edit_cell (GailCell *cell)
4030 GailTreeViewCellInfo *cell_info;
4031 GtkTreeView *tree_view;
4034 gboolean is_container_cell = FALSE;
4037 parent = atk_object_get_parent (ATK_OBJECT (cell));
4038 if (GAIL_IS_CONTAINER_CELL (parent))
4040 is_container_cell = TRUE;
4041 parent = atk_object_get_parent (parent);
4044 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
4045 gail_return_if_fail (cell_info);
4046 gail_return_if_fail (cell_info->cell_col_ref);
4047 gail_return_if_fail (cell_info->cell_row_ref);
4049 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
4050 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
4051 gail_return_if_fail (path);
4052 gtk_tree_view_set_cursor (tree_view, path, cell_info->cell_col_ref, TRUE);
4053 gtk_tree_path_free (path);
4058 activate_cell (GailCell *cell)
4060 GailTreeViewCellInfo *cell_info;
4061 GtkTreeView *tree_view;
4064 gboolean is_container_cell = FALSE;
4067 parent = atk_object_get_parent (ATK_OBJECT (cell));
4068 if (GAIL_IS_CONTAINER_CELL (parent))
4070 is_container_cell = TRUE;
4071 parent = atk_object_get_parent (parent);
4074 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
4075 gail_return_if_fail (cell_info);
4076 gail_return_if_fail (cell_info->cell_col_ref);
4077 gail_return_if_fail (cell_info->cell_row_ref);
4079 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
4080 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
4081 gail_return_if_fail (path);
4082 gtk_tree_view_row_activated (tree_view, path, cell_info->cell_col_ref);
4083 gtk_tree_path_free (path);
4088 cell_destroyed (gpointer data)
4090 GailTreeViewCellInfo *cell_info = data;
4092 gail_return_if_fail (cell_info);
4093 if (cell_info->in_use) {
4094 cell_info->in_use = FALSE;
4096 g_assert (GAIL_IS_TREE_VIEW (cell_info->view));
4097 if (!cell_info->view->garbage_collection_pending) {
4098 cell_info->view->garbage_collection_pending = TRUE;
4099 cell_info->view->idle_garbage_collect_id =
4100 gdk_threads_add_idle (idle_garbage_collect_cell_data, cell_info->view);
4107 cell_info_remove (GailTreeView *tree_view,
4110 GailTreeViewCellInfo *info;
4113 info = find_cell_info (tree_view, cell, &temp_list, FALSE);
4116 info->in_use = FALSE;
4119 g_warning ("No cell removed in cell_info_remove\n");
4124 cell_info_get_index (GtkTreeView *tree_view,
4125 GailTreeViewCellInfo *info,
4131 path = gtk_tree_row_reference_get_path (info->cell_row_ref);
4132 gail_return_if_fail (path);
4134 column_number = get_column_number (tree_view, info->cell_col_ref, FALSE);
4135 *index = get_index (tree_view, path, column_number);
4136 gtk_tree_path_free (path);
4140 cell_info_new (GailTreeView *gailview,
4141 GtkTreeModel *tree_model,
4143 GtkTreeViewColumn *tv_col,
4146 GailTreeViewCellInfo *cell_info;
4148 g_assert (GAIL_IS_TREE_VIEW (gailview));
4150 cell_info = g_new (GailTreeViewCellInfo, 1);
4151 cell_info->cell_row_ref = gtk_tree_row_reference_new (tree_model, path);
4153 cell_info->cell_col_ref = tv_col;
4154 cell_info->cell = cell;
4155 cell_info->in_use = TRUE; /* if we've created it, assume it's in use */
4156 cell_info->view = gailview;
4157 gailview->cell_data = g_list_append (gailview->cell_data, cell_info);
4159 /* Setup weak reference notification */
4161 g_object_weak_ref (G_OBJECT (cell),
4162 (GWeakNotify) cell_destroyed,
4167 find_cell (GailTreeView *gailview,
4170 GailTreeViewCellInfo *info;
4171 GtkTreeView *tree_view;
4175 gboolean needs_cleaning = FALSE;
4176 GailCell *retval = NULL;
4178 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
4179 cell_list = gailview->cell_data;
4181 for (l = cell_list; l; l = l->next)
4183 info = (GailTreeViewCellInfo *) (l->data);
4186 cell_info_get_index (tree_view, info, &real_index);
4187 if (index == real_index)
4189 retval = info->cell;
4195 needs_cleaning = TRUE;
4199 garbage_collect_cell_data (gailview);
4205 refresh_cell_index (GailCell *cell)
4207 GailTreeViewCellInfo *info;
4209 GtkTreeView *tree_view;
4212 parent = atk_object_get_parent (ATK_OBJECT (cell));
4213 gail_return_if_fail (GAIL_IS_TREE_VIEW (parent));
4215 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
4217 /* Find this cell in the GailTreeView's cache */
4219 info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
4220 gail_return_if_fail (info);
4222 cell_info_get_index (tree_view, info, &index);
4223 cell->index = index;
4227 get_selected_rows (GtkTreeModel *model,
4232 GPtrArray *array = (GPtrArray *)data;
4234 g_ptr_array_add (array, gtk_tree_path_copy (path));
4238 connect_model_signals (GtkTreeView *view,
4239 GailTreeView *gailview)
4243 obj = G_OBJECT (gailview->tree_model);
4244 g_signal_connect_data (obj, "row-changed",
4245 (GCallback) model_row_changed, view, NULL, 0);
4246 g_signal_connect_data (obj, "row-inserted",
4247 (GCallback) model_row_inserted, view, NULL,
4249 g_signal_connect_data (obj, "row-deleted",
4250 (GCallback) model_row_deleted, view, NULL,
4252 g_signal_connect_data (obj, "rows-reordered",
4253 (GCallback) model_rows_reordered, view, NULL,
4258 disconnect_model_signals (GailTreeView *view)
4263 obj = G_OBJECT (view->tree_model);
4264 widget = GTK_ACCESSIBLE (view)->widget;
4265 g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_changed, widget);
4266 g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_inserted, widget);
4267 g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_deleted, widget);
4268 g_signal_handlers_disconnect_by_func (obj, (gpointer) model_rows_reordered, widget);
4272 clear_cached_data (GailTreeView *view)
4278 GArray *array = view->row_data;
4282 * Since the third argument to free_row_info is FALSE, we don't remove
4283 * the element. Therefore it is safe to loop forward.
4285 for (i = 0; i < array->len; i++)
4286 free_row_info (array, i, FALSE);
4288 g_array_free (array, TRUE);
4290 view->row_data = NULL;
4293 if (view->cell_data)
4295 /* Must loop through them all */
4296 for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
4298 clean_cell_info (view, temp_list);
4301 garbage_collect_cell_data (view);
4302 if (view->cell_data)
4303 g_list_free (view->cell_data);
4305 view->cell_data = NULL;
4309 * Returns the column number of the specified GtkTreeViewColumn
4311 * If visible is set, the value returned will be the visible column number,
4312 * i.e. suitable for use in AtkTable function. If visible is not set, the
4313 * value returned is the actual column number, which is suitable for use in
4314 * getting an index value.
4317 get_column_number (GtkTreeView *tree_view,
4318 GtkTreeViewColumn *column,
4321 GList *temp_list, *column_list;
4322 GtkTreeViewColumn *tv_column;
4325 column_list = gtk_tree_view_get_columns (tree_view);
4327 for (temp_list = column_list; temp_list; temp_list = temp_list->next)
4329 tv_column = GTK_TREE_VIEW_COLUMN (temp_list->data);
4330 if (tv_column == column)
4332 if (!visible || gtk_tree_view_column_get_visible (tv_column))
4335 if (temp_list == NULL)
4339 g_list_free (column_list);
4344 get_index (GtkTreeView *tree_view,
4350 gint *indices = NULL;
4355 depth = gtk_tree_path_get_depth (path);
4356 indices = gtk_tree_path_get_indices (path);
4361 GtkTreePath *copy_path;
4362 GtkTreeModel *model;
4364 model = gtk_tree_view_get_model (tree_view);
4365 copy_path = gtk_tree_path_copy (path);
4366 gtk_tree_path_up (copy_path);
4367 count_rows (model, NULL, copy_path, &index, 0, depth);
4368 gtk_tree_path_free (copy_path);
4372 index += indices[depth-1];
4373 index *= get_n_actual_columns (tree_view);
4374 index += actual_column;
4379 * The function count_rows counts the number of rows starting at iter and ending
4380 * at end_path. The value of level is the depth of iter and the value of depth
4381 * is the depth of end_path. Rows at depth before end_path are counted.
4382 * This functions counts rows which are not visible because an ancestor is
4386 count_rows (GtkTreeModel *model,
4388 GtkTreePath *end_path,
4393 GtkTreeIter child_iter;
4399 *count += gtk_tree_model_iter_n_children (model, iter);
4402 g_print ("count_rows : %d level: %d depth: %d\n", *count, level, depth);
4404 g_print ("path: %s\n",
4405 gtk_tree_path_to_string (gtk_tree_model_get_path (model, iter)));
4411 if (gtk_tree_model_iter_children (model, &child_iter, iter))
4413 gboolean ret_val = TRUE;
4417 if (level == depth - 1)
4419 GtkTreePath *iter_path;
4420 gboolean finished = FALSE;
4422 iter_path = gtk_tree_model_get_path (model, &child_iter);
4423 if (end_path && gtk_tree_path_compare (iter_path, end_path) >= 0)
4425 gtk_tree_path_free (iter_path);
4429 if (gtk_tree_model_iter_has_child (model, &child_iter))
4430 count_rows (model, &child_iter, end_path, count, level, depth);
4431 ret_val = gtk_tree_model_iter_next (model, &child_iter);
4437 * Find the next node, which has children, at the specified depth below
4438 * the specified iter. The level is the depth of the current iter.
4439 * The position of the node is returned in path and the return value of TRUE
4440 * means that a node was found.
4443 gboolean get_next_node_with_child_at_depth (GtkTreeModel *model,
4449 GtkTreeIter child_iter;
4453 if (gtk_tree_model_iter_children (model, &child_iter, iter))
4459 while (!gtk_tree_model_iter_has_child (model, &child_iter))
4461 if (!gtk_tree_model_iter_next (model, &child_iter))
4466 /* We have found what we were looking for */
4468 *path = gtk_tree_model_get_path (model, &child_iter);
4472 if (get_next_node_with_child_at_depth (model, &child_iter, path,
4476 if (!gtk_tree_model_iter_next (model, &child_iter))
4484 * Find the next node, which has children, at the same depth as
4485 * the specified GtkTreePath.
4488 get_next_node_with_child (GtkTreeModel *model,
4490 GtkTreePath **return_path)
4495 gtk_tree_model_get_iter (model, &iter, path);
4497 while (gtk_tree_model_iter_next (model, &iter))
4499 if (gtk_tree_model_iter_has_child (model, &iter))
4501 *return_path = gtk_tree_model_get_path (model, &iter);
4505 depth = gtk_tree_path_get_depth (path);
4506 while (gtk_tree_path_up (path))
4508 if (gtk_tree_path_get_depth (path) == 0)
4511 gtk_tree_model_get_iter (model, &iter, path);
4512 while (gtk_tree_model_iter_next (model, &iter))
4513 if (get_next_node_with_child_at_depth (model, &iter, return_path,
4514 gtk_tree_path_get_depth (path), depth))
4517 *return_path = NULL;
4522 get_tree_path_from_row_index (GtkTreeModel *model,
4524 GtkTreePath **tree_path)
4530 count = gtk_tree_model_iter_n_children (model, NULL);
4531 if (count > row_index)
4533 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, row_index))
4535 *tree_path = gtk_tree_model_get_path (model, &iter);
4549 if (get_next_node_with_child_at_depth (model, NULL, tree_path, 0, depth))
4551 GtkTreePath *next_path;
4555 gtk_tree_model_get_iter (model, &iter, *tree_path);
4556 count = gtk_tree_model_iter_n_children (model, &iter);
4557 if (count > row_index)
4559 gtk_tree_path_append_index (*tree_path, row_index);
4565 if (!get_next_node_with_child (model, *tree_path, &next_path))
4568 gtk_tree_path_free (*tree_path);
4569 *tree_path = next_path;
4574 g_warning ("Index value is too large\n");
4575 gtk_tree_path_free (*tree_path);
4583 * This function returns the number of rows, including those which are collapsed
4586 get_row_count (GtkTreeModel *model)
4590 count_rows (model, NULL, NULL, &n_rows, 0, G_MAXINT);
4596 get_path_column_from_index (GtkTreeView *tree_view,
4599 GtkTreeViewColumn **column)
4601 GtkTreeModel *tree_model;
4604 tree_model = gtk_tree_view_get_model (tree_view);
4605 n_columns = get_n_actual_columns (tree_view);
4608 /* First row is the column headers */
4618 row_index = index / n_columns;
4619 retval = get_tree_path_from_row_index (tree_model, row_index, path);
4620 gail_return_val_if_fail (retval, FALSE);
4627 *column = gtk_tree_view_get_column (tree_view, index % n_columns);
4628 if (*column == NULL)
4631 gtk_tree_path_free (*path);
4639 set_cell_expandable (GailCell *cell)
4641 if (gail_cell_add_state (cell,
4642 ATK_STATE_EXPANDABLE,
4644 gail_cell_add_action (cell,
4645 "expand or contract", /* action name */
4646 "expands or contracts the row in the tree view "
4647 "containing this cell", /* description */
4648 NULL, /* Keybinding */
4649 toggle_cell_expanded);
4652 static GailTreeViewCellInfo*
4653 find_cell_info (GailTreeView *view,
4659 GailTreeViewCellInfo *cell_info;
4661 for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
4663 cell_info = (GailTreeViewCellInfo *) temp_list->data;
4664 if (cell_info->cell == cell && (!live_only || cell_info->in_use))
4675 get_header_from_column (GtkTreeViewColumn *tv_col)
4678 GtkWidget *header_widget;
4683 /* If the user has set a header object, use that */
4685 rc = g_object_get_qdata (G_OBJECT (tv_col), quark_column_header_object);
4689 /* If the user has not set a header object, grab the column */
4690 /* header object defined by the GtkTreeView */
4692 header_widget = tv_col->button;
4696 rc = gtk_widget_get_accessible (header_widget);