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_init (GailTreeView *view);
39 static void gail_tree_view_real_initialize (AtkObject *obj,
41 static void gail_tree_view_real_notify_gtk (GObject *obj,
43 static void gail_tree_view_finalize (GObject *object);
45 static void gail_tree_view_connect_widget_destroyed
46 (GtkAccessible *accessible);
47 static void gail_tree_view_destroyed (GtkWidget *widget,
48 GtkAccessible *accessible);
51 static gint gail_tree_view_get_n_children (AtkObject *obj);
52 static AtkObject* gail_tree_view_ref_child (AtkObject *obj,
54 static AtkStateSet* gail_tree_view_ref_state_set (AtkObject *obj);
58 static void atk_component_interface_init (AtkComponentIface *iface);
60 static AtkObject* gail_tree_view_ref_accessible_at_point
61 (AtkComponent *component,
64 AtkCoordType coord_type);
68 static void atk_table_interface_init (AtkTableIface *iface);
70 static gint gail_tree_view_get_index_at (AtkTable *table,
73 static gint gail_tree_view_get_column_at_index
76 static gint gail_tree_view_get_row_at_index (AtkTable *table,
79 static AtkObject* gail_tree_view_table_ref_at (AtkTable *table,
82 static gint gail_tree_view_get_n_rows (AtkTable *table);
83 static gint gail_tree_view_get_n_columns (AtkTable *table);
84 static gint get_n_actual_columns (GtkTreeView *tree_view);
85 static gboolean gail_tree_view_is_row_selected (AtkTable *table,
87 static gboolean gail_tree_view_is_selected (AtkTable *table,
90 static gint gail_tree_view_get_selected_rows
93 static gboolean gail_tree_view_add_row_selection
96 static gboolean gail_tree_view_remove_row_selection
99 static AtkObject* gail_tree_view_get_row_header (AtkTable *table,
101 static AtkObject* gail_tree_view_get_column_header
104 static void gail_tree_view_set_row_header (AtkTable *table,
107 static void gail_tree_view_set_column_header
112 gail_tree_view_get_caption (AtkTable *table);
113 static void gail_tree_view_set_caption (AtkTable *table,
115 static AtkObject* gail_tree_view_get_summary (AtkTable *table);
116 static void gail_tree_view_set_summary (AtkTable *table,
117 AtkObject *accessible);
118 static G_CONST_RETURN gchar*
119 gail_tree_view_get_row_description
122 static void gail_tree_view_set_row_description
125 const gchar *description);
126 static G_CONST_RETURN gchar*
127 gail_tree_view_get_column_description
130 static void gail_tree_view_set_column_description
133 const gchar *description);
135 static void set_row_data (AtkTable *table,
138 const gchar *description,
140 static GailTreeViewRowInfo*
141 get_row_info (AtkTable *table,
146 static void atk_selection_interface_init (AtkSelectionIface *iface);
147 static gboolean gail_tree_view_add_selection (AtkSelection *selection,
149 static gboolean gail_tree_view_clear_selection (AtkSelection *selection);
150 static AtkObject* gail_tree_view_ref_selection (AtkSelection *selection,
152 static gint gail_tree_view_get_selection_count
153 (AtkSelection *selection);
154 static gboolean gail_tree_view_is_child_selected
155 (AtkSelection *selection,
158 /* gailcellparent.h */
160 static void gail_cell_parent_interface_init (GailCellParentIface *iface);
161 static void gail_tree_view_get_cell_extents (GailCellParent *parent,
167 AtkCoordType coord_type);
168 static void gail_tree_view_get_cell_area (GailCellParent *parent,
170 GdkRectangle *cell_rect);
171 static gboolean gail_tree_view_grab_cell_focus (GailCellParent *parent,
174 /* signal handling */
176 static gboolean gail_tree_view_expand_row_gtk (GtkTreeView *tree_view,
179 static gint idle_expand_row (gpointer data);
180 static gboolean gail_tree_view_collapse_row_gtk (GtkTreeView *tree_view,
183 static void gail_tree_view_size_allocate_gtk (GtkWidget *widget,
184 GtkAllocation *allocation);
185 static void gail_tree_view_set_scroll_adjustments
188 GtkAdjustment *vadj);
189 static void gail_tree_view_changed_gtk (GtkTreeSelection *selection,
192 static void columns_changed (GtkTreeView *tree_view);
193 static void cursor_changed (GtkTreeView *tree_view);
194 static gint idle_cursor_changed (gpointer data);
196 static void model_row_changed (GtkTreeModel *tree_model,
200 static void column_visibility_changed (GObject *object,
203 static void column_destroy (GtkObject *obj);
204 static void model_row_inserted (GtkTreeModel *tree_model,
208 static void model_row_deleted (GtkTreeModel *tree_model,
211 static void destroy_count_func (GtkTreeView *tree_view,
215 static void model_rows_reordered (GtkTreeModel *tree_model,
220 static void adjustment_changed (GtkAdjustment *adjustment,
221 GtkTreeView *tree_view);
225 static void set_iter_nth_row (GtkTreeView *tree_view,
228 static gint get_row_from_tree_path (GtkTreeView *tree_view,
230 static GtkTreeViewColumn* get_column (GtkTreeView *tree_view,
232 static gint get_actual_column_number (GtkTreeView *tree_view,
233 gint visible_column);
234 static gint get_visible_column_number (GtkTreeView *tree_view,
236 static void iterate_thru_children (GtkTreeView *tree_view,
237 GtkTreeModel *tree_model,
238 GtkTreePath *tree_path,
242 static GtkTreeIter* return_iter_nth_row (GtkTreeView *tree_view,
243 GtkTreeModel *tree_model,
247 static void free_row_info (GArray *array,
250 static void clean_cell_info (GailTreeView *tree_view,
252 static void clean_rows (GailTreeView *tree_view);
253 static void clean_cols (GailTreeView *tree_view,
254 GtkTreeViewColumn *tv_col);
255 static void traverse_cells (GailTreeView *tree_view,
256 GtkTreePath *tree_path,
259 static gboolean update_cell_value (GailRendererCell *renderer_cell,
260 GailTreeView *gailview,
261 gboolean emit_change_signal);
262 static void set_cell_visibility (GtkTreeView *tree_view,
264 GtkTreeViewColumn *tv_col,
265 GtkTreePath *tree_path,
266 gboolean emit_signal);
267 static gboolean is_cell_showing (GtkTreeView *tree_view,
268 GdkRectangle *cell_rect);
269 static void set_expand_state (GtkTreeView *tree_view,
270 GtkTreeModel *tree_model,
271 GailTreeView *gailview,
272 GtkTreePath *tree_path,
273 gboolean set_on_ancestor);
274 static void add_cell_actions (GailCell *cell,
277 static void toggle_cell_expanded (GailCell *cell);
278 static void toggle_cell_toggled (GailCell *cell);
279 static void edit_cell (GailCell *cell);
280 static void activate_cell (GailCell *cell);
281 static void cell_destroyed (gpointer data);
283 static void cell_info_remove (GailTreeView *tree_view,
286 static void cell_info_get_index (GtkTreeView *tree_view,
287 GailTreeViewCellInfo *info,
289 static void cell_info_new (GailTreeView *gailview,
290 GtkTreeModel *tree_model,
292 GtkTreeViewColumn *tv_col,
294 static GailCell* find_cell (GailTreeView *gailview,
296 static void refresh_cell_index (GailCell *cell);
297 static void get_selected_rows (GtkTreeModel *model,
301 static void connect_model_signals (GtkTreeView *view,
302 GailTreeView *gailview);
303 static void disconnect_model_signals (GailTreeView *gailview);
304 static void clear_cached_data (GailTreeView *view);
305 static gint get_column_number (GtkTreeView *tree_view,
306 GtkTreeViewColumn *column,
308 static gint get_focus_index (GtkTreeView *tree_view);
309 static gint get_index (GtkTreeView *tree_view,
312 static void count_rows (GtkTreeModel *model,
314 GtkTreePath *end_path,
319 static gboolean get_next_node_with_child_at_depth
320 (GtkTreeModel *model,
325 static gboolean get_next_node_with_child (GtkTreeModel *model,
327 GtkTreePath **return_path);
328 static gboolean get_tree_path_from_row_index (GtkTreeModel *model,
330 GtkTreePath **tree_path);
331 static gint get_row_count (GtkTreeModel *model);
332 static gboolean get_path_column_from_index (GtkTreeView *tree_view,
335 GtkTreeViewColumn **column);
336 static void set_cell_expandable (GailCell *cell);
338 static GailTreeViewCellInfo* find_cell_info (GailTreeView *view,
342 static AtkObject * get_header_from_column (GtkTreeViewColumn *tv_col);
343 static gboolean idle_garbage_collect_cell_data (gpointer data);
344 static gboolean garbage_collect_cell_data (gpointer data);
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;
368 G_DEFINE_TYPE_WITH_CODE (GailTreeView, gail_tree_view, GAIL_TYPE_CONTAINER,
369 G_IMPLEMENT_INTERFACE (ATK_TYPE_TABLE, atk_table_interface_init)
370 G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init)
371 G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init)
372 G_IMPLEMENT_INTERFACE (GAIL_TYPE_CELL_PARENT, gail_cell_parent_interface_init))
375 gail_tree_view_class_init (GailTreeViewClass *klass)
377 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
378 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
379 GtkAccessibleClass *accessible_class;
380 GailWidgetClass *widget_class;
381 GailContainerClass *container_class;
383 accessible_class = (GtkAccessibleClass*)klass;
384 widget_class = (GailWidgetClass*)klass;
385 container_class = (GailContainerClass*)klass;
387 class->get_n_children = gail_tree_view_get_n_children;
388 class->ref_child = gail_tree_view_ref_child;
389 class->ref_state_set = gail_tree_view_ref_state_set;
390 class->initialize = gail_tree_view_real_initialize;
392 widget_class->notify_gtk = gail_tree_view_real_notify_gtk;
394 accessible_class->connect_widget_destroyed = gail_tree_view_connect_widget_destroyed;
397 * The children of a GtkTreeView are the buttons at the top of the columns
398 * we do not represent these as children so we do not want to report
399 * children added or deleted when these changed.
401 container_class->add_gtk = NULL;
402 container_class->remove_gtk = NULL;
404 gobject_class->finalize = gail_tree_view_finalize;
406 quark_column_desc_object = g_quark_from_static_string ("gtk-column-object");
407 quark_column_header_object = g_quark_from_static_string ("gtk-header-object");
411 gail_tree_view_init (GailTreeView *view)
416 gail_tree_view_real_initialize (AtkObject *obj,
420 GtkTreeView *tree_view;
421 GtkTreeModel *tree_model;
423 GList *tv_cols, *tmp_list;
426 ATK_OBJECT_CLASS (gail_tree_view_parent_class)->initialize (obj, data);
428 view = GAIL_TREE_VIEW (obj);
429 view->caption = NULL;
430 view->summary = NULL;
431 view->row_data = NULL;
432 view->col_data = NULL;
433 view->cell_data = NULL;
434 view->focus_cell = NULL;
435 view->old_hadj = NULL;
436 view->old_vadj = NULL;
437 view->idle_expand_id = 0;
438 view->idle_expand_path = NULL;
440 view->n_children_deleted = 0;
442 widget = GTK_WIDGET (data);
443 g_signal_connect_after (widget,
445 G_CALLBACK (gail_tree_view_collapse_row_gtk),
447 g_signal_connect (widget,
449 G_CALLBACK (gail_tree_view_expand_row_gtk),
451 g_signal_connect (widget,
453 G_CALLBACK (gail_tree_view_size_allocate_gtk),
456 tree_view = GTK_TREE_VIEW (widget);
457 tree_model = gtk_tree_view_get_model (tree_view);
459 /* Set up signal handling */
461 g_signal_connect_data (gtk_tree_view_get_selection (tree_view),
463 (GCallback) gail_tree_view_changed_gtk,
466 g_signal_connect_data (tree_view, "columns-changed",
467 (GCallback) columns_changed, NULL, NULL, 0);
468 g_signal_connect_data (tree_view, "cursor-changed",
469 (GCallback) cursor_changed, NULL, NULL, 0);
471 view->tree_model = tree_model;
474 g_object_add_weak_pointer (G_OBJECT (view->tree_model), (gpointer *)&view->tree_model);
475 connect_model_signals (tree_view, view);
477 if (GTK_IS_TREE_STORE (tree_model))
478 obj->role = ATK_ROLE_TREE_TABLE;
480 obj->role = ATK_ROLE_TABLE;
484 obj->role = ATK_ROLE_UNKNOWN;
487 /* adjustment callbacks */
489 g_object_get (tree_view, hadjustment, &adj, NULL);
490 view->old_hadj = adj;
491 g_object_add_weak_pointer (G_OBJECT (view->old_hadj), (gpointer *)&view->old_hadj);
492 g_signal_connect (adj,
494 G_CALLBACK (adjustment_changed),
497 g_object_get (tree_view, vadjustment, &adj, NULL);
498 view->old_vadj = adj;
499 g_object_add_weak_pointer (G_OBJECT (view->old_vadj), (gpointer *)&view->old_vadj);
500 g_signal_connect (adj,
502 G_CALLBACK (adjustment_changed),
504 g_signal_connect_after (widget,
505 "set_scroll_adjustments",
506 G_CALLBACK (gail_tree_view_set_scroll_adjustments),
509 view->col_data = g_array_sized_new (FALSE, TRUE,
510 sizeof(GtkTreeViewColumn *), 0);
512 tv_cols = gtk_tree_view_get_columns (tree_view);
514 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
516 g_signal_connect_data (tmp_list->data, "notify::visible",
517 (GCallback)column_visibility_changed,
518 tree_view, NULL, FALSE);
519 g_signal_connect_data (tmp_list->data, "destroy",
520 (GCallback)column_destroy,
522 g_array_append_val (view->col_data, tmp_list->data);
525 gtk_tree_view_set_destroy_count_func (tree_view,
528 g_list_free (tv_cols);
532 gail_tree_view_real_notify_gtk (GObject *obj,
537 GtkTreeView *tree_view;
538 GailTreeView *gailview;
541 widget = GTK_WIDGET (obj);
542 atk_obj = gtk_widget_get_accessible (widget);
543 tree_view = GTK_TREE_VIEW (widget);
544 gailview = GAIL_TREE_VIEW (atk_obj);
546 if (strcmp (pspec->name, "model") == 0)
548 GtkTreeModel *tree_model;
551 tree_model = gtk_tree_view_get_model (tree_view);
552 if (gailview->tree_model)
553 disconnect_model_signals (gailview);
554 clear_cached_data (gailview);
555 gailview->tree_model = tree_model;
557 * if there is no model the GtkTreeView is probably being destroyed
561 g_object_add_weak_pointer (G_OBJECT (gailview->tree_model), (gpointer *)&gailview->tree_model);
562 connect_model_signals (tree_view, gailview);
564 if (GTK_IS_TREE_STORE (tree_model))
565 role = ATK_ROLE_TREE_TABLE;
567 role = ATK_ROLE_TABLE;
571 role = ATK_ROLE_UNKNOWN;
573 atk_object_set_role (atk_obj, role);
574 g_object_freeze_notify (G_OBJECT (atk_obj));
575 g_signal_emit_by_name (atk_obj, "model_changed");
576 g_signal_emit_by_name (atk_obj, "visible_data_changed");
577 g_object_thaw_notify (G_OBJECT (atk_obj));
579 else if (strcmp (pspec->name, hadjustment) == 0)
581 g_object_get (tree_view, hadjustment, &adj, NULL);
582 g_signal_handlers_disconnect_by_func (gailview->old_hadj,
583 (gpointer) adjustment_changed,
585 gailview->old_hadj = adj;
586 g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_hadj);
587 g_signal_connect (adj,
589 G_CALLBACK (adjustment_changed),
592 else if (strcmp (pspec->name, vadjustment) == 0)
594 g_object_get (tree_view, vadjustment, &adj, NULL);
595 g_signal_handlers_disconnect_by_func (gailview->old_vadj,
596 (gpointer) adjustment_changed,
598 gailview->old_vadj = adj;
599 g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_vadj);
600 g_signal_connect (adj,
602 G_CALLBACK (adjustment_changed),
606 GAIL_WIDGET_CLASS (gail_tree_view_parent_class)->notify_gtk (obj, pspec);
610 gail_tree_view_new (GtkWidget *widget)
613 AtkObject *accessible;
615 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), NULL);
617 object = g_object_new (GAIL_TYPE_TREE_VIEW, NULL);
619 accessible = ATK_OBJECT (object);
620 atk_object_initialize (accessible, widget);
626 gail_tree_view_finalize (GObject *object)
628 GailTreeView *view = GAIL_TREE_VIEW (object);
630 clear_cached_data (view);
632 /* remove any idle handlers still pending */
633 if (view->idle_garbage_collect_id)
634 g_source_remove (view->idle_garbage_collect_id);
635 if (view->idle_cursor_changed_id)
636 g_source_remove (view->idle_cursor_changed_id);
637 if (view->idle_expand_id)
638 g_source_remove (view->idle_expand_id);
641 g_object_unref (view->caption);
643 g_object_unref (view->summary);
645 if (view->tree_model)
646 disconnect_model_signals (view);
650 GArray *array = view->col_data;
653 * No need to free the contents of the array since it
654 * just contains pointers to the GtkTreeViewColumn
655 * objects that are in the GtkTreeView.
657 g_array_free (array, TRUE);
660 G_OBJECT_CLASS (gail_tree_view_parent_class)->finalize (object);
664 gail_tree_view_connect_widget_destroyed (GtkAccessible *accessible)
666 if (accessible->widget)
668 g_signal_connect_after (accessible->widget,
670 G_CALLBACK (gail_tree_view_destroyed),
673 GTK_ACCESSIBLE_CLASS (gail_tree_view_parent_class)->connect_widget_destroyed (accessible);
677 gail_tree_view_destroyed (GtkWidget *widget,
678 GtkAccessible *accessible)
681 GailTreeView *gailview;
683 gail_return_if_fail (GTK_IS_TREE_VIEW (widget));
685 gailview = GAIL_TREE_VIEW (accessible);
686 adj = gailview->old_hadj;
688 g_signal_handlers_disconnect_by_func (adj,
689 (gpointer) adjustment_changed,
691 adj = gailview->old_vadj;
693 g_signal_handlers_disconnect_by_func (adj,
694 (gpointer) adjustment_changed,
696 if (gailview->tree_model)
698 disconnect_model_signals (gailview);
699 gailview->tree_model = NULL;
701 if (gailview->focus_cell)
703 g_object_unref (gailview->focus_cell);
704 gailview->focus_cell = NULL;
706 if (gailview->idle_expand_id)
708 g_source_remove (gailview->idle_expand_id);
709 gailview->idle_expand_id = 0;
714 get_focus_index (GtkTreeView *tree_view)
716 GtkTreePath *focus_path;
717 GtkTreeViewColumn *focus_column;
720 gtk_tree_view_get_cursor (tree_view, &focus_path, &focus_column);
721 if (focus_path && focus_column)
724 index = get_index (tree_view, focus_path,
725 get_column_number (tree_view, focus_column, FALSE));
731 gtk_tree_path_free (focus_path);
737 gail_tree_view_ref_focus_cell (GtkTreeView *tree_view)
740 * This function returns a reference to the accessible object for the cell
741 * in the treeview which has focus, if a cell has focus.
743 AtkObject *focus_cell = NULL;
747 focus_index = get_focus_index (tree_view);
748 if (focus_index >= 0)
750 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
751 focus_cell = atk_object_ref_accessible_child (atk_obj, focus_index);
760 gail_tree_view_get_n_children (AtkObject *obj)
763 GtkTreeView *tree_view;
764 GtkTreeModel *tree_model;
767 gail_return_val_if_fail (GAIL_IS_TREE_VIEW (obj), 0);
769 widget = GTK_ACCESSIBLE (obj)->widget;
776 tree_view = GTK_TREE_VIEW (widget);
777 tree_model = gtk_tree_view_get_model (tree_view);
780 * We get the total number of rows including those which are collapsed
782 n_rows = get_row_count (tree_model);
784 * We get the total number of columns including those which are not visible
786 n_cols = get_n_actual_columns (tree_view);
787 return (n_rows * n_cols);
791 gail_tree_view_ref_child (AtkObject *obj,
795 GailTreeView *gailview;
797 GtkTreeView *tree_view;
798 GtkTreeModel *tree_model;
799 GtkCellRenderer *renderer;
801 GtkTreeViewColumn *tv_col;
802 GtkTreeSelection *selection;
804 AtkRegistry *default_registry;
805 AtkObjectFactory *factory;
808 GtkTreeViewColumn *expander_tv;
809 GList *renderer_list;
811 GailContainerCell *container = NULL;
812 GailRendererCell *renderer_cell;
813 gboolean is_expander, is_expanded, retval;
814 gboolean editable = FALSE;
817 g_return_val_if_fail (GAIL_IS_TREE_VIEW (obj), NULL);
818 g_return_val_if_fail (i >= 0, NULL);
820 widget = GTK_ACCESSIBLE (obj)->widget;
827 if (i >= gail_tree_view_get_n_children (obj))
830 tree_view = GTK_TREE_VIEW (widget);
831 if (i < get_n_actual_columns (tree_view))
833 tv_col = gtk_tree_view_get_column (tree_view, i);
834 child = get_header_from_column (tv_col);
836 g_object_ref (child);
840 gailview = GAIL_TREE_VIEW (obj);
842 * Check whether the child is cached
844 cell = find_cell (gailview, i);
848 return ATK_OBJECT (cell);
851 if (gailview->focus_cell == NULL)
852 focus_index = get_focus_index (tree_view);
856 * Find the TreePath and GtkTreeViewColumn for the index
858 if (!get_path_column_from_index (tree_view, i, &path, &tv_col))
861 tree_model = gtk_tree_view_get_model (tree_view);
862 retval = gtk_tree_model_get_iter (tree_model, &iter, path);
863 gail_return_val_if_fail (retval, NULL);
865 expander_tv = gtk_tree_view_get_expander_column (tree_view);
868 if (gtk_tree_model_iter_has_child (tree_model, &iter))
870 if (expander_tv == tv_col)
873 is_expanded = gtk_tree_view_row_expanded (tree_view, path);
876 gtk_tree_view_column_cell_set_cell_data (tv_col, tree_model, &iter,
877 is_expander, is_expanded);
879 renderer_list = gtk_tree_view_column_get_cell_renderers (tv_col);
881 /* If there are more than one renderer in the list, make a container */
883 if (renderer_list && renderer_list->next)
885 GailCell *container_cell;
887 container = gail_container_cell_new ();
888 gail_return_val_if_fail (container, NULL);
890 container_cell = GAIL_CELL (container);
891 gail_cell_initialise (container_cell,
892 widget, ATK_OBJECT (gailview),
895 * The GailTreeViewCellInfo structure for the container will be before
896 * the ones for the cells so that the first one we find for a position
897 * will be for the container
899 cell_info_new (gailview, tree_model, path, tv_col, container_cell);
900 container_cell->refresh_index = refresh_cell_index;
901 parent = ATK_OBJECT (container);
904 parent = ATK_OBJECT (gailview);
909 * Now we make a fake cell_renderer if there is no cell in renderer_list
912 if (renderer_list == NULL)
914 GtkCellRenderer *fake_renderer;
915 fake_renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL);
916 default_registry = atk_get_default_registry ();
917 factory = atk_registry_get_factory (default_registry,
918 GTK_OBJECT_TYPE (fake_renderer));
919 child = atk_object_factory_create_accessible (factory,
920 G_OBJECT (fake_renderer));
921 gail_return_val_if_fail (GAIL_IS_RENDERER_CELL (child), NULL);
922 cell = GAIL_CELL (child);
923 renderer_cell = GAIL_RENDERER_CELL (child);
924 renderer_cell->renderer = fake_renderer;
926 /* Create the GailTreeViewCellInfo structure for this cell */
927 cell_info_new (gailview, tree_model, path, tv_col, cell);
929 gail_cell_initialise (cell,
933 cell->refresh_index = refresh_cell_index;
935 /* set state if it is expandable */
938 set_cell_expandable (cell);
940 gail_cell_add_state (cell,
945 for (l = renderer_list; l; l = l->next)
947 renderer = GTK_CELL_RENDERER (l->data);
949 if (GTK_IS_CELL_RENDERER_TEXT (renderer))
950 g_object_get (G_OBJECT (renderer), "editable", &editable, NULL);
952 default_registry = atk_get_default_registry ();
953 factory = atk_registry_get_factory (default_registry,
954 GTK_OBJECT_TYPE (renderer));
955 child = atk_object_factory_create_accessible (factory,
956 G_OBJECT (renderer));
957 gail_return_val_if_fail (GAIL_IS_RENDERER_CELL (child), NULL);
958 cell = GAIL_CELL (child);
959 renderer_cell = GAIL_RENDERER_CELL (child);
961 /* Create the GailTreeViewCellInfo structure for this cell */
962 cell_info_new (gailview, tree_model, path, tv_col, cell);
964 gail_cell_initialise (cell,
969 gail_container_cell_add_child (container, cell);
971 cell->refresh_index = refresh_cell_index;
973 update_cell_value (renderer_cell, gailview, FALSE);
974 /* Add the actions appropriate for this cell */
975 add_cell_actions (cell, editable);
977 /* set state if it is expandable */
980 set_cell_expandable (cell);
982 gail_cell_add_state (cell,
987 * If the column is visible, sets the cell's state
989 if (gtk_tree_view_column_get_visible (tv_col))
990 set_cell_visibility (tree_view, cell, tv_col, path, FALSE);
992 * If the row is selected, all cells on the row are selected
994 selection = gtk_tree_view_get_selection (tree_view);
996 if (gtk_tree_selection_path_is_selected (selection, path))
997 gail_cell_add_state (cell, ATK_STATE_SELECTED, FALSE);
999 gail_cell_add_state (cell, ATK_STATE_FOCUSABLE, FALSE);
1000 if (focus_index == i)
1002 gailview->focus_cell = g_object_ref (cell);
1003 gail_cell_add_state (cell, ATK_STATE_FOCUSED, FALSE);
1006 g_list_free (renderer_list);
1008 child = ATK_OBJECT (container);
1011 if (expander_tv == tv_col)
1013 AtkRelationSet *relation_set;
1014 AtkObject *accessible_array[1];
1015 AtkRelation* relation;
1016 AtkObject *parent_node;
1018 relation_set = atk_object_ref_relation_set (ATK_OBJECT (child));
1020 gtk_tree_path_up (path);
1021 if (gtk_tree_path_get_depth (path) == 0)
1028 n_columns = get_n_actual_columns (tree_view);
1029 parent_index = get_index (tree_view, path, i % n_columns);
1030 parent_node = atk_object_ref_accessible_child (obj, parent_index);
1032 accessible_array[0] = parent_node;
1033 relation = atk_relation_new (accessible_array, 1,
1034 ATK_RELATION_NODE_CHILD_OF);
1035 atk_relation_set_add (relation_set, relation);
1036 g_object_unref (relation);
1037 g_object_unref (relation_set);
1039 gtk_tree_path_free (path);
1042 * We do not increase the reference count here; when g_object_unref() is
1043 * called for the cell then cell_destroyed() is called and
1044 * this removes the cell from the cache.
1050 gail_tree_view_ref_state_set (AtkObject *obj)
1052 AtkStateSet *state_set;
1055 state_set = ATK_OBJECT_CLASS (gail_tree_view_parent_class)->ref_state_set (obj);
1056 widget = GTK_ACCESSIBLE (obj)->widget;
1059 atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
1064 /* atkcomponent.h */
1067 atk_component_interface_init (AtkComponentIface *iface)
1069 iface->ref_accessible_at_point = gail_tree_view_ref_accessible_at_point;
1073 gail_tree_view_ref_accessible_at_point (AtkComponent *component,
1076 AtkCoordType coord_type)
1079 GtkTreeView *tree_view;
1081 GtkTreeViewColumn *tv_column;
1085 widget = GTK_ACCESSIBLE (component)->widget;
1087 /* State is defunct */
1090 tree_view = GTK_TREE_VIEW (widget);
1092 atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
1093 ret_val = gtk_tree_view_get_path_at_pos (tree_view,
1094 x - x_pos, y - y_pos,
1095 &path, &tv_column, NULL, NULL);
1100 column = get_column_number (tree_view, tv_column, FALSE);
1101 index = get_index (tree_view, path, column);
1102 gtk_tree_path_free (path);
1104 return gail_tree_view_ref_child (ATK_OBJECT (component), index);
1108 g_warning ("gail_tree_view_ref_accessible_at_point: gtk_tree_view_get_path_at_pos () failed\n");
1116 atk_table_interface_init (AtkTableIface *iface)
1118 iface->ref_at = gail_tree_view_table_ref_at;
1119 iface->get_n_rows = gail_tree_view_get_n_rows;
1120 iface->get_n_columns = gail_tree_view_get_n_columns;
1121 iface->get_index_at = gail_tree_view_get_index_at;
1122 iface->get_column_at_index = gail_tree_view_get_column_at_index;
1123 iface->get_row_at_index = gail_tree_view_get_row_at_index;
1124 iface->is_row_selected = gail_tree_view_is_row_selected;
1125 iface->is_selected = gail_tree_view_is_selected;
1126 iface->get_selected_rows = gail_tree_view_get_selected_rows;
1127 iface->add_row_selection = gail_tree_view_add_row_selection;
1128 iface->remove_row_selection = gail_tree_view_remove_row_selection;
1129 iface->get_column_extent_at = NULL;
1130 iface->get_row_extent_at = NULL;
1131 iface->get_row_header = gail_tree_view_get_row_header;
1132 iface->set_row_header = gail_tree_view_set_row_header;
1133 iface->get_column_header = gail_tree_view_get_column_header;
1134 iface->set_column_header = gail_tree_view_set_column_header;
1135 iface->get_caption = gail_tree_view_get_caption;
1136 iface->set_caption = gail_tree_view_set_caption;
1137 iface->get_summary = gail_tree_view_get_summary;
1138 iface->set_summary = gail_tree_view_set_summary;
1139 iface->get_row_description = gail_tree_view_get_row_description;
1140 iface->set_row_description = gail_tree_view_set_row_description;
1141 iface->get_column_description = gail_tree_view_get_column_description;
1142 iface->set_column_description = gail_tree_view_set_column_description;
1146 gail_tree_view_get_index_at (AtkTable *table,
1151 GtkTreeView *tree_view;
1153 gint n_cols, n_rows;
1158 n_cols = atk_table_get_n_columns (table);
1159 n_rows = atk_table_get_n_rows (table);
1161 if (row >= n_rows ||
1165 widget = GTK_ACCESSIBLE (table)->widget;
1167 /* State is defunct */
1170 tree_view = GTK_TREE_VIEW (widget);
1171 actual_column = get_actual_column_number (tree_view, column);
1173 set_iter_nth_row (tree_view, &iter, row);
1174 path = gtk_tree_model_get_path (gtk_tree_view_get_model (tree_view), &iter);
1176 index = get_index (tree_view, path, actual_column);
1177 gtk_tree_path_free (path);
1183 gail_tree_view_get_column_at_index (AtkTable *table,
1187 GtkTreeView *tree_view;
1190 widget = GTK_ACCESSIBLE (table)->widget;
1192 /* State is defunct */
1195 tree_view = GTK_TREE_VIEW (widget);
1196 n_columns = get_n_actual_columns (tree_view);
1200 index = index % n_columns;
1202 return get_visible_column_number (tree_view, index);
1206 gail_tree_view_get_row_at_index (AtkTable *table,
1210 GtkTreeView *tree_view;
1213 widget = GTK_ACCESSIBLE (table)->widget;
1215 /* State is defunct */
1218 tree_view = GTK_TREE_VIEW (widget);
1219 if (get_path_column_from_index (tree_view, index, &path, NULL))
1221 gint row = get_row_from_tree_path (tree_view, path);
1222 gtk_tree_path_free (path);
1230 gail_tree_view_table_ref_at (AtkTable *table,
1236 index = gail_tree_view_get_index_at (table, row, column);
1240 return gail_tree_view_ref_child (ATK_OBJECT (table), index);
1244 gail_tree_view_get_n_rows (AtkTable *table)
1247 GtkTreeView *tree_view;
1248 GtkTreeModel *tree_model;
1251 widget = GTK_ACCESSIBLE (table)->widget;
1253 /* State is defunct */
1256 tree_view = GTK_TREE_VIEW (widget);
1257 tree_model = gtk_tree_view_get_model (tree_view);
1259 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
1261 * If working with a LIST store, then this is a faster way
1262 * to get the number of rows.
1264 n_rows = gtk_tree_model_iter_n_children (tree_model, NULL);
1267 GtkTreePath *root_tree;
1270 root_tree = gtk_tree_path_new_root ();
1271 iterate_thru_children (tree_view, tree_model,
1272 root_tree, NULL, &n_rows, 0);
1280 * The function get_n_actual_columns returns the number of columns in the
1281 * GtkTreeView. i.e. it include both visible and non-visible columns.
1284 get_n_actual_columns (GtkTreeView *tree_view)
1289 columns = gtk_tree_view_get_columns (tree_view);
1290 n_cols = g_list_length (columns);
1291 g_list_free (columns);
1296 gail_tree_view_get_n_columns (AtkTable *table)
1299 GtkTreeView *tree_view;
1300 GtkTreeViewColumn *tv_col;
1304 widget = GTK_ACCESSIBLE (table)->widget;
1306 /* State is defunct */
1309 tree_view = GTK_TREE_VIEW (widget);
1310 tv_col = gtk_tree_view_get_column (tree_view, i);
1312 while (tv_col != NULL)
1314 if (gtk_tree_view_column_get_visible (tv_col))
1318 tv_col = gtk_tree_view_get_column (tree_view, i);
1325 gail_tree_view_is_row_selected (AtkTable *table,
1329 GtkTreeView *tree_view;
1330 GtkTreeSelection *selection;
1333 widget = GTK_ACCESSIBLE (table)->widget;
1335 /* State is defunct */
1341 tree_view = GTK_TREE_VIEW (widget);
1343 selection = gtk_tree_view_get_selection (tree_view);
1345 set_iter_nth_row (tree_view, &iter, row);
1347 return gtk_tree_selection_iter_is_selected (selection, &iter);
1351 gail_tree_view_is_selected (AtkTable *table,
1355 return gail_tree_view_is_row_selected (table, row);
1359 gail_tree_view_get_selected_rows (AtkTable *table,
1360 gint **rows_selected)
1363 GtkTreeView *tree_view;
1364 GtkTreeModel *tree_model;
1366 GtkTreeSelection *selection;
1367 GtkTreePath *tree_path;
1370 widget = GTK_ACCESSIBLE (table)->widget;
1372 /* State is defunct */
1375 tree_view = GTK_TREE_VIEW (widget);
1377 selection = gtk_tree_view_get_selection (tree_view);
1379 switch (selection->type)
1381 case GTK_SELECTION_SINGLE:
1382 case GTK_SELECTION_BROWSE:
1383 if (gtk_tree_selection_get_selected (selection, &tree_model, &iter))
1389 *rows_selected = (gint *)g_malloc (sizeof(gint));
1390 tree_path = gtk_tree_model_get_path (tree_model, &iter);
1391 row = get_row_from_tree_path (tree_view, tree_path);
1392 gtk_tree_path_free (tree_path);
1394 /* shouldn't ever happen */
1395 g_return_val_if_fail (row != -1, 0);
1397 *rows_selected[0] = row;
1402 case GTK_SELECTION_MULTIPLE:
1404 GPtrArray *array = g_ptr_array_new();
1406 gtk_tree_selection_selected_foreach (selection,
1409 ret_val = array->len;
1411 if (rows_selected && ret_val)
1414 *rows_selected = (gint *) g_malloc (ret_val * sizeof (gint));
1416 for (i = 0; i < ret_val; i++)
1420 tree_path = (GtkTreePath *) g_ptr_array_index (array, i);
1421 row = get_row_from_tree_path (tree_view, tree_path);
1422 gtk_tree_path_free (tree_path);
1423 (*rows_selected)[i] = row;
1426 g_ptr_array_free (array, FALSE);
1429 case GTK_SELECTION_NONE:
1436 gail_tree_view_add_row_selection (AtkTable *table,
1440 GtkTreeView *tree_view;
1441 GtkTreeModel *tree_model;
1442 GtkTreeSelection *selection;
1443 GtkTreePath *tree_path;
1444 GtkTreeIter iter_to_row;
1446 widget = GTK_ACCESSIBLE (table)->widget;
1448 /* State is defunct */
1451 if (!gail_tree_view_is_row_selected (table, row))
1453 tree_view = GTK_TREE_VIEW (widget);
1454 tree_model = gtk_tree_view_get_model (tree_view);
1455 selection = gtk_tree_view_get_selection (tree_view);
1457 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
1459 tree_path = gtk_tree_path_new ();
1460 gtk_tree_path_append_index (tree_path, row);
1461 gtk_tree_selection_select_path (selection,tree_path);
1462 gtk_tree_path_free (tree_path);
1466 set_iter_nth_row (tree_view, &iter_to_row, row);
1467 if (&iter_to_row != NULL)
1468 gtk_tree_selection_select_iter (selection, &iter_to_row);
1474 return gail_tree_view_is_row_selected (table, row);
1478 gail_tree_view_remove_row_selection (AtkTable *table,
1482 GtkTreeView *tree_view;
1483 GtkTreeSelection *selection;
1485 widget = GTK_ACCESSIBLE (table)->widget;
1487 /* State is defunct */
1490 tree_view = GTK_TREE_VIEW (widget);
1492 selection = gtk_tree_view_get_selection (tree_view);
1494 if (gail_tree_view_is_row_selected (table, row))
1496 gtk_tree_selection_unselect_all (selection);
1503 gail_tree_view_get_row_header (AtkTable *table,
1506 GailTreeViewRowInfo *row_info;
1508 row_info = get_row_info (table, row);
1510 return row_info->header;
1516 gail_tree_view_set_row_header (AtkTable *table,
1520 set_row_data (table, row, header, NULL, TRUE);
1524 gail_tree_view_get_column_header (AtkTable *table,
1528 GtkTreeView *tree_view;
1529 GtkTreeViewColumn *tv_col;
1531 widget = GTK_ACCESSIBLE (table)->widget;
1533 /* State is defunct */
1536 tree_view = GTK_TREE_VIEW (widget);
1537 tv_col = get_column (tree_view, in_col);
1538 return get_header_from_column (tv_col);
1542 gail_tree_view_set_column_header (AtkTable *table,
1547 GtkTreeView *tree_view;
1548 GtkTreeViewColumn *tv_col;
1550 AtkPropertyValues values = { NULL };
1552 widget = GTK_ACCESSIBLE (table)->widget;
1554 /* State is defunct */
1557 tree_view = GTK_TREE_VIEW (widget);
1558 tv_col = get_column (tree_view, in_col);
1562 rc = g_object_get_qdata (G_OBJECT (tv_col),
1563 quark_column_header_object);
1565 g_object_unref (rc);
1567 g_object_set_qdata (G_OBJECT (tv_col),
1568 quark_column_header_object,
1571 g_object_ref (header);
1572 g_value_init (&values.new_value, G_TYPE_INT);
1573 g_value_set_int (&values.new_value, in_col);
1575 values.property_name = "accessible-table-column-header";
1576 g_signal_emit_by_name (table,
1577 "property_change::accessible-table-column-header",
1582 gail_tree_view_get_caption (AtkTable *table)
1584 GailTreeView* obj = GAIL_TREE_VIEW (table);
1586 return obj->caption;
1590 gail_tree_view_set_caption (AtkTable *table,
1593 GailTreeView* obj = GAIL_TREE_VIEW (table);
1594 AtkPropertyValues values = { NULL };
1595 AtkObject *old_caption;
1597 old_caption = obj->caption;
1598 obj->caption = caption;
1600 g_object_ref (obj->caption);
1601 g_value_init (&values.old_value, G_TYPE_POINTER);
1602 g_value_set_pointer (&values.old_value, old_caption);
1603 g_value_init (&values.new_value, G_TYPE_POINTER);
1604 g_value_set_pointer (&values.new_value, obj->caption);
1606 values.property_name = "accessible-table-caption-object";
1607 g_signal_emit_by_name (table,
1608 "property_change::accessible-table-caption-object",
1611 g_object_unref (old_caption);
1614 static G_CONST_RETURN gchar*
1615 gail_tree_view_get_column_description (AtkTable *table,
1619 GtkTreeView *tree_view;
1620 GtkTreeViewColumn *tv_col;
1623 widget = GTK_ACCESSIBLE (table)->widget;
1625 /* State is defunct */
1628 tree_view = GTK_TREE_VIEW (widget);
1629 tv_col = get_column (tree_view, in_col);
1633 rc = g_object_get_qdata (G_OBJECT (tv_col),
1634 quark_column_desc_object);
1642 g_object_get (tv_col, "title", &title_text, NULL);
1648 gail_tree_view_set_column_description (AtkTable *table,
1650 const gchar *description)
1653 GtkTreeView *tree_view;
1654 GtkTreeViewColumn *tv_col;
1655 AtkPropertyValues values = { NULL };
1657 widget = GTK_ACCESSIBLE (table)->widget;
1659 /* State is defunct */
1662 tree_view = GTK_TREE_VIEW (widget);
1663 tv_col = get_column (tree_view, in_col);
1667 g_object_set_qdata (G_OBJECT (tv_col),
1668 quark_column_desc_object,
1669 g_strdup (description));
1670 g_value_init (&values.new_value, G_TYPE_INT);
1671 g_value_set_int (&values.new_value, in_col);
1673 values.property_name = "accessible-table-column-description";
1674 g_signal_emit_by_name (table,
1675 "property_change::accessible-table-column-description",
1679 static G_CONST_RETURN gchar*
1680 gail_tree_view_get_row_description (AtkTable *table,
1683 GailTreeViewRowInfo *row_info;
1685 row_info = get_row_info (table, row);
1687 return row_info->description;
1693 gail_tree_view_set_row_description (AtkTable *table,
1695 const gchar *description)
1697 set_row_data (table, row, NULL, description, FALSE);
1701 gail_tree_view_get_summary (AtkTable *table)
1703 GailTreeView* obj = GAIL_TREE_VIEW (table);
1705 return obj->summary;
1709 gail_tree_view_set_summary (AtkTable *table,
1710 AtkObject *accessible)
1712 GailTreeView* obj = GAIL_TREE_VIEW (table);
1713 AtkPropertyValues values = { NULL };
1714 AtkObject *old_summary;
1716 old_summary = obj->summary;
1717 obj->summary = accessible;
1719 g_object_ref (obj->summary);
1720 g_value_init (&values.old_value, G_TYPE_POINTER);
1721 g_value_set_pointer (&values.old_value, old_summary);
1722 g_value_init (&values.new_value, G_TYPE_POINTER);
1723 g_value_set_pointer (&values.new_value, obj->summary);
1725 values.property_name = "accessible-table-summary";
1726 g_signal_emit_by_name (table,
1727 "property_change::accessible-table-ummary",
1730 g_object_unref (old_summary);
1734 set_row_data (AtkTable *table,
1737 const gchar *description,
1741 GtkTreeView *tree_view;
1742 GtkTreeModel *tree_model;
1743 GailTreeView* obj = GAIL_TREE_VIEW (table);
1744 GailTreeViewRowInfo* row_info;
1748 gboolean found = FALSE;
1750 AtkPropertyValues values = { NULL };
1753 widget = GTK_ACCESSIBLE (table)->widget;
1755 /* State is defunct */
1758 tree_view = GTK_TREE_VIEW (widget);
1759 tree_model = gtk_tree_view_get_model (tree_view);
1761 set_iter_nth_row (tree_view, &iter, row);
1762 path = gtk_tree_model_get_path (tree_model, &iter);
1764 if (obj->row_data == NULL)
1765 obj->row_data = g_array_sized_new (FALSE, TRUE,
1766 sizeof(GailTreeViewRowInfo *), 0);
1768 array = obj->row_data;
1770 for (i = 0; i < array->len; i++)
1772 GtkTreePath *row_path;
1774 row_info = g_array_index (array, GailTreeViewRowInfo*, i);
1775 row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
1777 if (row_path != NULL)
1779 if (path && gtk_tree_path_compare (row_path, path) == 0)
1782 gtk_tree_path_free (row_path);
1788 if (row_info->header)
1789 g_object_unref (row_info->header);
1790 row_info->header = header;
1791 if (row_info->header)
1792 g_object_ref (row_info->header);
1796 g_free (row_info->description);
1797 row_info->description = g_strdup (description);
1807 row_info = g_malloc (sizeof(GailTreeViewRowInfo));
1808 row_info->row_ref = gtk_tree_row_reference_new (tree_model, path);
1811 row_info->header = header;
1812 if (row_info->header)
1813 g_object_ref (row_info->header);
1814 row_info->description = NULL;
1818 row_info->header = NULL;
1819 row_info->description = g_strdup (description);
1821 g_array_append_val (array, row_info);
1823 g_value_init (&values.new_value, G_TYPE_INT);
1824 g_value_set_int (&values.new_value, row);
1828 values.property_name = "accessible-table-row-header";
1829 signal_name = "property_change::accessible-table-row-header";
1833 values.property_name = "accessible-table-row-description";
1834 signal_name = "property-change::accessible-table-row-description";
1836 g_signal_emit_by_name (table,
1840 gtk_tree_path_free (path);
1844 static GailTreeViewRowInfo*
1845 get_row_info (AtkTable *table,
1849 GtkTreeView *tree_view;
1850 GtkTreeModel *tree_model;
1851 GailTreeView* obj = GAIL_TREE_VIEW (table);
1855 GailTreeViewRowInfo *rc = NULL;
1857 widget = GTK_ACCESSIBLE (table)->widget;
1859 /* State is defunct */
1862 tree_view = GTK_TREE_VIEW (widget);
1863 tree_model = gtk_tree_view_get_model (tree_view);
1865 set_iter_nth_row (tree_view, &iter, row);
1866 path = gtk_tree_model_get_path (tree_model, &iter);
1867 array = obj->row_data;
1871 GailTreeViewRowInfo *row_info;
1872 GtkTreePath *row_path;
1875 for (i = 0; i < array->len; i++)
1877 row_info = g_array_index (array, GailTreeViewRowInfo*, i);
1878 row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
1879 if (row_path != NULL)
1881 if (path && gtk_tree_path_compare (row_path, path) == 0)
1884 gtk_tree_path_free (row_path);
1892 gtk_tree_path_free (path);
1895 /* atkselection.h */
1897 static void atk_selection_interface_init (AtkSelectionIface *iface)
1899 iface->add_selection = gail_tree_view_add_selection;
1900 iface->clear_selection = gail_tree_view_clear_selection;
1901 iface->ref_selection = gail_tree_view_ref_selection;
1902 iface->get_selection_count = gail_tree_view_get_selection_count;
1903 iface->is_child_selected = gail_tree_view_is_child_selected;
1907 gail_tree_view_add_selection (AtkSelection *selection,
1914 table = ATK_TABLE (selection);
1915 n_columns = gail_tree_view_get_n_columns (table);
1919 row = gail_tree_view_get_row_at_index (table, i);
1920 return gail_tree_view_add_row_selection (table, row);
1924 gail_tree_view_clear_selection (AtkSelection *selection)
1927 GtkTreeView *tree_view;
1928 GtkTreeSelection *tree_selection;
1930 widget = GTK_ACCESSIBLE (selection)->widget;
1932 /* State is defunct */
1935 tree_view = GTK_TREE_VIEW (widget);
1937 tree_selection = gtk_tree_view_get_selection (tree_view);
1938 gtk_tree_selection_unselect_all (tree_selection);
1944 gail_tree_view_ref_selection (AtkSelection *selection,
1953 table = ATK_TABLE (selection);
1954 n_columns = gail_tree_view_get_n_columns (table);
1955 n_selected = gail_tree_view_get_selected_rows (table, &selected);
1956 if (i >= n_columns * n_selected)
1959 row = selected[i / n_columns];
1962 return gail_tree_view_table_ref_at (table, row, i % n_columns);
1966 gail_tree_view_get_selection_count (AtkSelection *selection)
1971 table = ATK_TABLE (selection);
1972 n_selected = gail_tree_view_get_selected_rows (table, NULL);
1974 n_selected *= gail_tree_view_get_n_columns (table);
1979 gail_tree_view_is_child_selected (AtkSelection *selection,
1985 widget = GTK_ACCESSIBLE (selection)->widget;
1987 /* State is defunct */
1990 row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
1992 return gail_tree_view_is_row_selected (ATK_TABLE (selection), row);
1996 static void gail_cell_parent_interface_init (GailCellParentIface *iface)
1998 iface->get_cell_extents = gail_tree_view_get_cell_extents;
1999 iface->get_cell_area = gail_tree_view_get_cell_area;
2000 iface->grab_focus = gail_tree_view_grab_cell_focus;
2004 gail_tree_view_get_cell_extents (GailCellParent *parent,
2010 AtkCoordType coord_type)
2013 GtkTreeView *tree_view;
2014 GdkWindow *bin_window;
2015 GdkRectangle cell_rect;
2018 widget = GTK_ACCESSIBLE (parent)->widget;
2020 /* State is defunct */
2023 tree_view = GTK_TREE_VIEW (widget);
2024 gail_tree_view_get_cell_area (parent, cell, &cell_rect);
2025 bin_window = gtk_tree_view_get_bin_window (tree_view);
2026 gdk_window_get_origin (bin_window, &w_x, &w_y);
2028 if (coord_type == ATK_XY_WINDOW)
2031 gint x_toplevel, y_toplevel;
2033 window = gdk_window_get_toplevel (bin_window);
2034 gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
2040 *width = cell_rect.width;
2041 *height = cell_rect.height;
2042 if (is_cell_showing (tree_view, &cell_rect))
2044 *x = cell_rect.x + w_x;
2045 *y = cell_rect.y + w_y;
2054 #define EXTRA_EXPANDER_PADDING 4
2057 gail_tree_view_get_cell_area (GailCellParent *parent,
2059 GdkRectangle *cell_rect)
2062 GtkTreeView *tree_view;
2063 GtkTreeViewColumn *tv_col;
2065 AtkObject *parent_cell;
2066 GailTreeViewCellInfo *cell_info;
2069 widget = GTK_ACCESSIBLE (parent)->widget;
2071 /* State is defunct */
2074 tree_view = GTK_TREE_VIEW (widget);
2075 parent_cell = atk_object_get_parent (ATK_OBJECT (cell));
2076 if (parent_cell != ATK_OBJECT (parent))
2079 * GailCell is in a GailContainerCell
2081 top_cell = GAIL_CELL (parent_cell);
2087 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), top_cell, NULL, TRUE);
2088 gail_return_if_fail (cell_info);
2089 gail_return_if_fail (cell_info->cell_col_ref);
2090 gail_return_if_fail (cell_info->cell_row_ref);
2091 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2092 tv_col = cell_info->cell_col_ref;
2093 if (path && cell_info->in_use)
2095 GtkTreeViewColumn *expander_column;
2096 gint focus_line_width;
2098 gtk_tree_view_get_cell_area (tree_view, path, tv_col, cell_rect);
2099 expander_column = gtk_tree_view_get_expander_column (tree_view);
2100 if (expander_column == tv_col)
2104 gtk_widget_style_get (widget,
2105 "expander_size", &expander_size,
2108 cell_rect->x += expander_size + EXTRA_EXPANDER_PADDING;
2109 cell_rect->width -= expander_size + EXTRA_EXPANDER_PADDING;
2111 gtk_widget_style_get (widget,
2112 "focus-line-width", &focus_line_width,
2115 cell_rect->x += focus_line_width;
2116 cell_rect->width -= 2 * focus_line_width;
2118 gtk_tree_path_free (path);
2121 * A column has more than one renderer so we find the position and width
2124 if (top_cell != cell)
2131 GtkCellRenderer *renderer;
2133 cell_index = atk_object_get_index_in_parent (ATK_OBJECT (cell));
2134 renderers = gtk_tree_view_column_get_cell_renderers (tv_col);
2135 renderer = g_list_nth_data (renderers, cell_index);
2137 found = gtk_tree_view_column_cell_get_position (tv_col, renderer, &cell_start, &cell_width);
2140 cell_rect->x += cell_start;
2141 cell_rect->width = cell_width;
2143 g_list_free (renderers);
2150 gail_tree_view_grab_cell_focus (GailCellParent *parent,
2154 GtkTreeView *tree_view;
2155 GtkTreeViewColumn *tv_col;
2157 AtkObject *parent_cell;
2158 AtkObject *cell_object;
2159 GailTreeViewCellInfo *cell_info;
2160 GtkCellRenderer *renderer = NULL;
2161 GtkWidget *toplevel;
2164 widget = GTK_ACCESSIBLE (parent)->widget;
2166 /* State is defunct */
2169 tree_view = GTK_TREE_VIEW (widget);
2171 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
2172 gail_return_val_if_fail (cell_info, FALSE);
2173 gail_return_val_if_fail (cell_info->cell_col_ref, FALSE);
2174 gail_return_val_if_fail (cell_info->cell_row_ref, FALSE);
2175 cell_object = ATK_OBJECT (cell);
2176 parent_cell = atk_object_get_parent (cell_object);
2177 tv_col = cell_info->cell_col_ref;
2178 if (parent_cell != ATK_OBJECT (parent))
2181 * GailCell is in a GailContainerCell.
2182 * The GtkTreeViewColumn has multiple renderers;
2183 * find the corresponding one.
2187 renderers = gtk_tree_view_column_get_cell_renderers (tv_col);
2188 if (cell_info->in_use) {
2189 index = atk_object_get_index_in_parent (cell_object);
2190 renderer = g_list_nth_data (renderers, index);
2192 g_list_free (renderers);
2194 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2195 if (path && cell_info->in_use)
2198 gtk_tree_view_set_cursor_on_cell (tree_view, path, tv_col, renderer, FALSE);
2200 gtk_tree_view_set_cursor (tree_view, path, tv_col, FALSE);
2202 gtk_tree_path_free (path);
2203 gtk_widget_grab_focus (widget);
2204 toplevel = gtk_widget_get_toplevel (widget);
2205 if (GTK_WIDGET_TOPLEVEL (toplevel))
2207 #ifdef GDK_WINDOWING_X11
2208 gtk_window_present_with_time (GTK_WINDOW (toplevel), gdk_x11_get_server_time (widget->window));
2210 gtk_window_present (GTK_WINDOW (toplevel));
2220 /* signal handling */
2223 gail_tree_view_expand_row_gtk (GtkTreeView *tree_view,
2228 GailTreeView *gailview;
2230 g_assert (GTK_IS_TREE_VIEW (tree_view));
2232 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2234 g_assert (GAIL_IS_TREE_VIEW (atk_obj));
2236 gailview = GAIL_TREE_VIEW (atk_obj);
2239 * The visible rectangle has not been updated when this signal is emitted
2240 * so we process the signal when the GTK processing is completed
2242 /* this seems wrong since it overwrites any other pending expand handlers... */
2243 gailview->idle_expand_path = gtk_tree_path_copy (path);
2244 if (gailview->idle_expand_id)
2245 g_source_remove (gailview->idle_expand_id);
2246 gailview->idle_expand_id = gdk_threads_add_idle (idle_expand_row, gailview);
2251 idle_expand_row (gpointer data)
2253 GailTreeView *gailview = data;
2255 GtkTreeView *tree_view;
2257 GtkTreeModel *tree_model;
2258 gint n_inserted, row;
2260 gailview->idle_expand_id = 0;
2262 path = gailview->idle_expand_path;
2263 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
2265 g_assert (GTK_IS_TREE_VIEW (tree_view));
2267 tree_model = gtk_tree_view_get_model(tree_view);
2271 if (!path || !gtk_tree_model_get_iter (tree_model, &iter, path))
2275 * Update visibility of cells below expansion row
2277 traverse_cells (gailview, path, FALSE, FALSE);
2279 * Figure out number of visible children, the following test
2282 if (gtk_tree_model_iter_has_child (tree_model, &iter))
2284 GtkTreePath *path_copy;
2287 * By passing path into this function, we find the number of
2288 * visible children of path.
2290 path_copy = gtk_tree_path_copy (path);
2291 gtk_tree_path_append_index(path_copy, 0);
2294 iterate_thru_children (tree_view, tree_model,
2295 path_copy, NULL, &n_inserted, 0);
2296 gtk_tree_path_free (path_copy);
2300 /* We can get here if the row expanded callback deleted the row */
2304 /* Set expand state */
2305 set_expand_state (tree_view, tree_model, gailview, path, TRUE);
2307 row = get_row_from_tree_path (tree_view, path);
2309 /* shouldn't ever happen */
2311 g_assert_not_reached ();
2313 /* Must add 1 because the "added rows" are below the row being expanded */
2316 g_signal_emit_by_name (gailview, "row_inserted", row, n_inserted);
2318 gailview->idle_expand_path = NULL;
2320 gtk_tree_path_free (path);
2326 gail_tree_view_collapse_row_gtk (GtkTreeView *tree_view,
2330 GtkTreeModel *tree_model;
2331 AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2332 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2335 tree_model = gtk_tree_view_get_model (tree_view);
2337 clean_rows (gailview);
2340 * Update visibility of cells below collapsed row
2342 traverse_cells (gailview, path, FALSE, FALSE);
2343 /* Set collapse state */
2344 set_expand_state (tree_view, tree_model, gailview, path, FALSE);
2346 gail_return_val_if_fail (gailview->n_children_deleted, FALSE);
2347 row = get_row_from_tree_path (tree_view, path);
2348 gail_return_val_if_fail (row != -1, FALSE);
2349 g_signal_emit_by_name (atk_obj, "row_deleted", row,
2350 gailview->n_children_deleted);
2351 gailview->n_children_deleted = 0;
2356 gail_tree_view_size_allocate_gtk (GtkWidget *widget,
2357 GtkAllocation *allocation)
2359 AtkObject *atk_obj = gtk_widget_get_accessible (widget);
2360 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2363 * If the size allocation changes, the visibility of cells may change so
2364 * update the cells visibility.
2366 traverse_cells (gailview, NULL, FALSE, FALSE);
2370 gail_tree_view_set_scroll_adjustments (GtkWidget *widget,
2371 GtkAdjustment *hadj,
2372 GtkAdjustment *vadj)
2374 AtkObject *atk_obj = gtk_widget_get_accessible (widget);
2375 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2378 g_object_get (widget, hadjustment, &adj, NULL);
2379 if (gailview->old_hadj != adj)
2381 g_signal_handlers_disconnect_by_func (gailview->old_hadj,
2382 (gpointer) adjustment_changed,
2384 gailview->old_hadj = adj;
2385 g_object_add_weak_pointer (G_OBJECT (gailview->old_hadj), (gpointer *)&gailview->old_hadj);
2386 g_signal_connect (adj,
2388 G_CALLBACK (adjustment_changed),
2391 g_object_get (widget, vadjustment, &adj, NULL);
2392 if (gailview->old_vadj != adj)
2394 g_signal_handlers_disconnect_by_func (gailview->old_vadj,
2395 (gpointer) adjustment_changed,
2397 gailview->old_vadj = adj;
2398 g_object_add_weak_pointer (G_OBJECT (gailview->old_vadj), (gpointer *)&gailview->old_vadj);
2399 g_signal_connect (adj,
2401 G_CALLBACK (adjustment_changed),
2407 gail_tree_view_changed_gtk (GtkTreeSelection *selection,
2410 GailTreeView *gailview;
2411 GtkTreeView *tree_view;
2415 GailTreeViewCellInfo *info;
2416 GtkTreeSelection *tree_selection;
2419 gailview = GAIL_TREE_VIEW (data);
2420 cell_list = gailview->cell_data;
2421 widget = GTK_ACCESSIBLE (gailview)->widget;
2424 * destroy signal emitted for widget
2427 tree_view = GTK_TREE_VIEW (widget);
2429 tree_selection = gtk_tree_view_get_selection (tree_view);
2431 for (l = cell_list; l; l = l->next)
2433 info = (GailTreeViewCellInfo *) (l->data);
2437 gail_cell_remove_state (info->cell, ATK_STATE_SELECTED, TRUE);
2439 path = gtk_tree_row_reference_get_path (info->cell_row_ref);
2440 if (path && gtk_tree_selection_path_is_selected (tree_selection, path))
2441 gail_cell_add_state (info->cell, ATK_STATE_SELECTED, TRUE);
2442 gtk_tree_path_free (path);
2445 if (GTK_WIDGET_REALIZED (widget))
2446 g_signal_emit_by_name (gailview, "selection_changed");
2450 columns_changed (GtkTreeView *tree_view)
2452 AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET(tree_view));
2453 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2454 GList *tv_cols, *tmp_list;
2455 gboolean column_found;
2456 gboolean move_found = FALSE;
2457 gboolean stale_set = FALSE;
2458 gint column_count = 0;
2462 * This function must determine if the change is an add, delete or
2463 * a move based upon its cache of TreeViewColumns in
2464 * gailview->col_data
2466 tv_cols = gtk_tree_view_get_columns (tree_view);
2468 /* check for adds or moves */
2469 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
2471 column_found = FALSE;
2473 for (i = 0; i < gailview->col_data->len; i++)
2476 if ((GtkTreeViewColumn *)tmp_list->data ==
2477 (GtkTreeViewColumn *)g_array_index (gailview->col_data,
2478 GtkTreeViewColumn *, i))
2480 column_found = TRUE;
2482 /* If the column isn't in the same position, a move happened */
2483 if (!move_found && i != column_count)
2487 /* Set all rows to ATK_STATE_STALE */
2488 traverse_cells (gailview, NULL, TRUE, FALSE);
2492 /* Just emit one column reordered signal when a move happens */
2493 g_signal_emit_by_name (atk_obj, "column_reordered");
2502 * If column_found is FALSE, then an insert happened for column
2503 * number column_count
2507 gint n_cols, n_rows, row;
2511 /* Set all rows to ATK_STATE_STALE */
2512 traverse_cells (gailview, NULL, TRUE, FALSE);
2516 /* Generate column-inserted signal */
2517 g_signal_emit_by_name (atk_obj, "column_inserted", column_count, 1);
2519 /* Generate children-changed signals */
2520 n_rows = get_row_count (gtk_tree_view_get_model (tree_view));
2521 n_cols = get_n_actual_columns (tree_view);
2522 for (row = 0; row < n_rows; row++)
2525 * Pass NULL as the child object, i.e. 4th argument.
2527 g_signal_emit_by_name (atk_obj, "children_changed::add",
2528 ((row * n_cols) + column_count), NULL, NULL);
2535 /* check for deletes */
2536 for (i = 0; i < gailview->col_data->len; i++)
2538 column_found = FALSE;
2540 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
2542 if ((GtkTreeViewColumn *)tmp_list->data ==
2543 (GtkTreeViewColumn *)g_array_index (gailview->col_data,
2544 GtkTreeViewColumn *, i))
2546 column_found = TRUE;
2552 * If column_found is FALSE, then a delete happened for column
2557 gint n_rows, n_cols, row;
2559 clean_cols (gailview,
2560 (GtkTreeViewColumn *)g_array_index (gailview->col_data,
2561 GtkTreeViewColumn *, i));
2565 /* Set all rows to ATK_STATE_STALE */
2566 traverse_cells (gailview, NULL, TRUE, FALSE);
2570 /* Generate column-deleted signal */
2571 g_signal_emit_by_name (atk_obj, "column_deleted", i, 1);
2573 /* Generate children-changed signals */
2574 n_rows = get_row_count (gtk_tree_view_get_model (tree_view));
2575 n_cols = get_n_actual_columns (tree_view);
2576 for (row = 0; row < n_rows; row++)
2579 * Pass NULL as the child object, 4th argument.
2581 g_signal_emit_by_name (atk_obj, "children_changed::remove",
2582 ((row * n_cols) + column_count), NULL, NULL);
2587 /* rebuild the array */
2589 g_array_free (gailview->col_data, TRUE);
2590 gailview->col_data = g_array_sized_new (FALSE, TRUE,
2591 sizeof(GtkTreeViewColumn *), 0);
2593 for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
2594 g_array_append_val (gailview->col_data, tmp_list->data);
2595 g_list_free (tv_cols);
2599 cursor_changed (GtkTreeView *tree_view)
2601 GailTreeView *gailview;
2603 gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
2604 if (gailview->idle_cursor_changed_id != 0)
2608 * We notify the focus change in a idle handler so that the processing
2609 * of the cursor change is completed when the focus handler is called.
2610 * This will allow actions to be called in the focus handler
2612 gailview->idle_cursor_changed_id = gdk_threads_add_idle (idle_cursor_changed, gailview);
2616 idle_cursor_changed (gpointer data)
2618 GailTreeView *gail_tree_view = GAIL_TREE_VIEW (data);
2619 GtkTreeView *tree_view;
2623 gail_tree_view->idle_cursor_changed_id = 0;
2625 widget = GTK_ACCESSIBLE (gail_tree_view)->widget;
2627 * Widget has been deleted
2632 tree_view = GTK_TREE_VIEW (widget);
2634 cell = gail_tree_view_ref_focus_cell (tree_view);
2637 if (cell != gail_tree_view->focus_cell)
2639 if (gail_tree_view->focus_cell)
2641 gail_cell_remove_state (GAIL_CELL (gail_tree_view->focus_cell), ATK_STATE_ACTIVE, FALSE);
2642 g_object_unref (gail_tree_view->focus_cell);
2644 gail_tree_view->focus_cell = cell;
2646 if (GTK_WIDGET_HAS_FOCUS (widget))
2647 gail_cell_add_state (GAIL_CELL (cell), ATK_STATE_ACTIVE, FALSE);
2648 g_signal_emit_by_name (gail_tree_view,
2649 "active-descendant-changed",
2653 g_object_unref (cell);
2660 model_row_changed (GtkTreeModel *tree_model,
2665 GtkTreeView *tree_view = GTK_TREE_VIEW(user_data);
2666 GailTreeView *gailview;
2667 GtkTreePath *cell_path;
2669 GailTreeViewCellInfo *cell_info;
2671 gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
2673 /* Loop through our cached cells */
2674 /* Must loop through them all */
2675 for (l = gailview->cell_data; l; l = l->next)
2677 cell_info = (GailTreeViewCellInfo *) l->data;
2678 if (cell_info->in_use)
2680 cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2682 if (cell_path != NULL)
2684 if (path && gtk_tree_path_compare (cell_path, path) == 0)
2686 if (GAIL_IS_RENDERER_CELL (cell_info->cell))
2688 update_cell_value (GAIL_RENDERER_CELL (cell_info->cell),
2692 gtk_tree_path_free (cell_path);
2696 g_signal_emit_by_name (gailview, "visible-data-changed");
2700 column_visibility_changed (GObject *object,
2704 if (strcmp (pspec->name, "visible") == 0)
2707 * A column has been made visible or invisible
2709 * We update our cache of cells and emit model_changed signal
2711 GtkTreeView *tree_view = (GtkTreeView *)user_data;
2712 GailTreeView *gailview;
2714 GailTreeViewCellInfo *cell_info;
2715 GtkTreeViewColumn *this_col = GTK_TREE_VIEW_COLUMN (object);
2716 GtkTreeViewColumn *tv_col;
2718 gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view))
2720 g_signal_emit_by_name (gailview, "model_changed");
2722 for (l = gailview->cell_data; l; l = l->next)
2724 cell_info = (GailTreeViewCellInfo *) l->data;
2725 if (cell_info->in_use)
2727 tv_col = cell_info->cell_col_ref;
2728 if (tv_col == this_col)
2730 GtkTreePath *row_path;
2731 row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
2732 if (GAIL_IS_RENDERER_CELL (cell_info->cell))
2734 if (gtk_tree_view_column_get_visible (tv_col))
2735 set_cell_visibility (tree_view,
2737 tv_col, row_path, FALSE);
2740 gail_cell_remove_state (cell_info->cell,
2741 ATK_STATE_VISIBLE, TRUE);
2742 gail_cell_remove_state (cell_info->cell,
2743 ATK_STATE_SHOWING, TRUE);
2746 gtk_tree_path_free (row_path);
2754 * This is the signal handler for the "destroy" signal for a GtkTreeViewColumn
2756 * We check whether we have stored column description or column header
2757 * and if so we get rid of it.
2760 column_destroy (GtkObject *obj)
2762 GtkTreeViewColumn *tv_col = GTK_TREE_VIEW_COLUMN (obj);
2766 header = g_object_get_qdata (G_OBJECT (tv_col),
2767 quark_column_header_object);
2769 g_object_unref (header);
2770 desc = g_object_get_qdata (G_OBJECT (tv_col),
2771 quark_column_desc_object);
2776 model_row_inserted (GtkTreeModel *tree_model,
2781 GtkTreeView *tree_view = (GtkTreeView *)user_data;
2782 GtkTreePath *path_copy;
2783 AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2784 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2785 gint row, n_inserted, child_row;
2787 if (gailview->idle_expand_id)
2789 g_source_remove (gailview->idle_expand_id);
2790 gailview->idle_expand_id = 0;
2792 /* don't do this if the insertion precedes the idle path, since it will now be invalid */
2793 if (path && gailview->idle_expand_path &&
2794 (gtk_tree_path_compare (path, gailview->idle_expand_path) > 0))
2795 set_expand_state (tree_view, tree_model, gailview, gailview->idle_expand_path, FALSE);
2796 if (gailview->idle_expand_path)
2797 gtk_tree_path_free (gailview->idle_expand_path);
2799 /* Check to see if row is visible */
2800 row = get_row_from_tree_path (tree_view, path);
2803 * A row insert is not necessarily visible. For example,
2804 * a row can be draged & dropped into another row, which
2805 * causes an insert on the model that isn't visible in the
2806 * view. Only generate a signal if the inserted row is
2814 gtk_tree_model_get_iter (tree_model, &iter, path);
2816 /* Figure out number of visible children. */
2817 if (gtk_tree_model_iter_has_child (tree_model, &iter))
2820 * By passing path into this function, we find the number of
2821 * visible children of path.
2824 iterate_thru_children (tree_view, tree_model,
2825 path, NULL, &n_inserted, 0);
2827 /* Must add one to include the row that is being added */
2833 /* Set rows below the inserted row to ATK_STATE_STALE */
2834 traverse_cells (gailview, path, TRUE, TRUE);
2836 /* Generate row-inserted signal */
2837 g_signal_emit_by_name (atk_obj, "row_inserted", row, n_inserted);
2839 /* Generate children-changed signals */
2840 n_cols = gail_tree_view_get_n_columns (ATK_TABLE (atk_obj));
2841 for (child_row = row; child_row < (row + n_inserted); child_row++)
2843 for (col = 0; col < n_cols; col++)
2846 * Pass NULL as the child object, i.e. 4th argument
2848 g_signal_emit_by_name (atk_obj, "children_changed::add",
2849 ((row * n_cols) + col), NULL, NULL);
2856 * The row has been inserted inside another row. This can
2857 * cause a row that previously couldn't be expanded to now
2860 path_copy = gtk_tree_path_copy (path);
2861 gtk_tree_path_up (path_copy);
2862 set_expand_state (tree_view, tree_model, gailview, path_copy, TRUE);
2863 gtk_tree_path_free (path_copy);
2868 model_row_deleted (GtkTreeModel *tree_model,
2872 GtkTreeView *tree_view;
2873 GtkTreePath *path_copy;
2875 GailTreeView *gailview;
2878 tree_view = (GtkTreeView *)user_data;
2879 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2880 gailview = GAIL_TREE_VIEW (atk_obj);
2882 if (gailview->idle_expand_id)
2884 g_source_remove (gailview->idle_expand_id);
2885 gtk_tree_path_free (gailview->idle_expand_path);
2886 gailview->idle_expand_id = 0;
2888 /* Check to see if row is visible */
2889 clean_rows (gailview);
2891 /* Set rows at or below the specified row to ATK_STATE_STALE */
2892 traverse_cells (gailview, path, TRUE, TRUE);
2895 * If deleting a row with a depth > 1, then this may affect the
2896 * expansion/contraction of its parent(s). Make sure this is
2899 if (gtk_tree_path_get_depth (path) > 1)
2901 path_copy = gtk_tree_path_copy (path);
2902 gtk_tree_path_up (path_copy);
2903 set_expand_state (tree_view, tree_model, gailview, path_copy, TRUE);
2904 gtk_tree_path_free (path_copy);
2906 row = get_row_from_tree_path (tree_view, path);
2908 * If the row which is deleted is not visible because it is a child of
2909 * a collapsed row then row will be -1
2912 g_signal_emit_by_name (atk_obj, "row_deleted", row,
2913 gailview->n_children_deleted + 1);
2914 gailview->n_children_deleted = 0;
2918 * This function gets called when a row is deleted or when rows are
2919 * removed from the view due to a collapse event. Note that the
2920 * count is the number of visible *children* of the deleted row,
2921 * so it does not include the row being deleted.
2923 * As this function is called before the rows are removed we just note the
2924 * number of rows and then deal with it when we get a notification that
2925 * rows were deleted or collapsed.
2928 destroy_count_func (GtkTreeView *tree_view,
2933 AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2934 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2936 gail_return_if_fail (gailview->n_children_deleted == 0);
2937 gailview->n_children_deleted = count;
2941 model_rows_reordered (GtkTreeModel *tree_model,
2947 GtkTreeView *tree_view = (GtkTreeView *)user_data;
2948 AtkObject *atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2949 GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
2951 if (gailview->idle_expand_id)
2953 g_source_remove (gailview->idle_expand_id);
2954 gtk_tree_path_free (gailview->idle_expand_path);
2955 gailview->idle_expand_id = 0;
2957 traverse_cells (gailview, NULL, TRUE, FALSE);
2959 g_signal_emit_by_name (atk_obj, "row_reordered");
2963 adjustment_changed (GtkAdjustment *adjustment,
2964 GtkTreeView *tree_view)
2970 * The scrollbars have changed
2972 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
2973 obj = GAIL_TREE_VIEW (atk_obj);
2975 traverse_cells (obj, NULL, FALSE, FALSE);
2979 set_cell_visibility (GtkTreeView *tree_view,
2981 GtkTreeViewColumn *tv_col,
2982 GtkTreePath *tree_path,
2983 gboolean emit_signal)
2985 GdkRectangle cell_rect;
2987 /* Get these three values in tree coords */
2988 if (GTK_WIDGET_REALIZED (GTK_WIDGET (tree_view)))
2989 gtk_tree_view_get_cell_area (tree_view, tree_path, tv_col, &cell_rect);
2991 cell_rect.height = 0;
2993 if (cell_rect.height > 0)
2996 * The height will be zero for a cell for which an antecedent is not
2999 gail_cell_add_state (cell, ATK_STATE_VISIBLE, emit_signal);
3000 if (is_cell_showing (tree_view, &cell_rect))
3001 gail_cell_add_state (cell, ATK_STATE_SHOWING, emit_signal);
3003 gail_cell_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
3007 gail_cell_remove_state (cell, ATK_STATE_VISIBLE, emit_signal);
3008 gail_cell_remove_state (cell, ATK_STATE_SHOWING, emit_signal);
3013 is_cell_showing (GtkTreeView *tree_view,
3014 GdkRectangle *cell_rect)
3016 GdkRectangle rect, *visible_rect;
3017 GdkRectangle rect1, *tree_cell_rect;
3018 gboolean is_showing;
3020 * A cell is considered "SHOWING" if any part of the cell is in the visible
3021 * area. Other ways we could do this is by a cell's midpoint or if the cell
3022 * is fully in the visible range. Since we have the cell_rect x,y,width,height
3023 * of the cell, any of these is easy to compute.
3025 * It is assumed that cell's rectangle is in widget coordinates so we
3026 * must transform to tree cordinates.
3028 visible_rect = ▭
3029 tree_cell_rect = &rect1;
3030 tree_cell_rect->x = cell_rect->x;
3031 tree_cell_rect->width = cell_rect->width;
3032 tree_cell_rect->height = cell_rect->height;
3034 gtk_tree_view_get_visible_rect (tree_view, visible_rect);
3035 gtk_tree_view_widget_to_tree_coords (tree_view, cell_rect->x, cell_rect->y,
3038 if (((tree_cell_rect->x + tree_cell_rect->width) < visible_rect->x) ||
3039 ((tree_cell_rect->y + tree_cell_rect->height) < (visible_rect->y)) ||
3040 (tree_cell_rect->x > (visible_rect->x + visible_rect->width)) ||
3041 (tree_cell_rect->y > (visible_rect->y + visible_rect->height)))
3052 * This function is called when a cell's flyweight is created in
3053 * gail_tree_view_table_ref_at with emit_change_signal set to FALSE
3054 * and in model_row_changed() on receipt of "row-changed" signal when
3055 * emit_change_signal is set to TRUE
3058 update_cell_value (GailRendererCell *renderer_cell,
3059 GailTreeView *gailview,
3060 gboolean emit_change_signal)
3062 GailTreeViewCellInfo *cell_info;
3063 GtkTreeView *tree_view;
3064 GtkTreeModel *tree_model;
3067 GList *renderers, *cur_renderer;
3069 GailRendererCellClass *gail_renderer_cell_class;
3070 GtkCellRendererClass *gtk_cell_renderer_class;
3074 gboolean is_expander, is_expanded;
3076 gail_renderer_cell_class = GAIL_RENDERER_CELL_GET_CLASS (renderer_cell);
3077 if (renderer_cell->renderer)
3078 gtk_cell_renderer_class = GTK_CELL_RENDERER_GET_CLASS (renderer_cell->renderer);
3080 gtk_cell_renderer_class = NULL;
3082 prop_list = gail_renderer_cell_class->property_list;
3084 cell = GAIL_CELL (renderer_cell);
3085 cell_info = find_cell_info (gailview, cell, NULL, TRUE);
3086 gail_return_val_if_fail (cell_info, FALSE);
3087 gail_return_val_if_fail (cell_info->cell_col_ref, FALSE);
3088 gail_return_val_if_fail (cell_info->cell_row_ref, FALSE);
3090 if (emit_change_signal && cell_info->in_use)
3092 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
3093 tree_model = gtk_tree_view_get_model (tree_view);
3094 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3098 gtk_tree_model_get_iter (tree_model, &iter, path);
3099 is_expander = FALSE;
3100 is_expanded = FALSE;
3101 if (gtk_tree_model_iter_has_child (tree_model, &iter))
3103 GtkTreeViewColumn *expander_tv;
3105 expander_tv = gtk_tree_view_get_expander_column (tree_view);
3106 if (expander_tv == cell_info->cell_col_ref)
3109 is_expanded = gtk_tree_view_row_expanded (tree_view, path);
3112 gtk_tree_path_free (path);
3113 gtk_tree_view_column_cell_set_cell_data (cell_info->cell_col_ref,
3114 tree_model, &iter, is_expander, is_expanded);
3116 renderers = gtk_tree_view_column_get_cell_renderers (cell_info->cell_col_ref);
3117 gail_return_val_if_fail (renderers, FALSE);
3120 * If the cell is in a container, it's index is used to find the renderer
3125 * Otherwise, we assume that the cell is represented by the first renderer
3129 if (cell_info->in_use) {
3130 parent = atk_object_get_parent (ATK_OBJECT (cell));
3131 if (!ATK_IS_OBJECT (cell)) g_on_error_query (NULL);
3132 if (GAIL_IS_CONTAINER_CELL (parent))
3133 cur_renderer = g_list_nth (renderers, cell->index);
3135 cur_renderer = renderers;
3141 gail_return_val_if_fail (cur_renderer != NULL, FALSE);
3143 if (gtk_cell_renderer_class)
3147 spec = g_object_class_find_property
3148 (G_OBJECT_CLASS (gtk_cell_renderer_class), *prop_list);
3152 GValue value = { 0, };
3154 g_value_init (&value, spec->value_type);
3155 g_object_get_property (cur_renderer->data, *prop_list, &value);
3156 g_object_set_property (G_OBJECT (renderer_cell->renderer),
3157 *prop_list, &value);
3158 g_value_unset(&value);
3161 g_warning ("Invalid property: %s\n", *prop_list);
3165 g_list_free (renderers);
3166 return gail_renderer_cell_update_cache (renderer_cell, emit_change_signal);
3170 set_iter_nth_row (GtkTreeView *tree_view,
3174 GtkTreeModel *tree_model;
3176 tree_model = gtk_tree_view_get_model (tree_view);
3177 gtk_tree_model_get_iter_root (tree_model, iter);
3178 iter = return_iter_nth_row (tree_view, tree_model, iter, 0 , row);
3182 get_row_from_tree_path (GtkTreeView *tree_view,
3185 GtkTreeModel *tree_model;
3186 GtkTreePath *root_tree;
3189 tree_model = gtk_tree_view_get_model (tree_view);
3191 if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
3192 row = gtk_tree_path_get_indices (path)[0];
3195 root_tree = gtk_tree_path_new_root ();
3197 iterate_thru_children (tree_view, tree_model, root_tree, path, &row, 0);
3198 gtk_tree_path_free (root_tree);
3207 * Get the specified GtkTreeViewColumn in the GtkTreeView.
3208 * Only visible columns are considered.
3210 static GtkTreeViewColumn*
3211 get_column (GtkTreeView *tree_view,
3214 GtkTreeViewColumn *tv_col;
3220 g_warning ("Request for invalid column %d\n", in_col);
3224 tv_col = gtk_tree_view_get_column (tree_view, i);
3226 while (tv_col != NULL)
3228 if (gtk_tree_view_column_get_visible (tv_col))
3230 if (in_col == n_cols)
3232 tv_col = gtk_tree_view_get_column (tree_view, ++i);
3235 if (in_col != n_cols)
3237 g_warning ("Request for invalid column %d\n", in_col);
3244 get_actual_column_number (GtkTreeView *tree_view,
3245 gint visible_column)
3247 GtkTreeViewColumn *tv_col;
3248 gint actual_column = 0;
3249 gint visible_columns = -1;
3251 * This function calculates the column number which corresponds to the
3252 * specified visible column number
3254 tv_col = gtk_tree_view_get_column (tree_view, actual_column);
3256 while (tv_col != NULL)
3258 if (gtk_tree_view_column_get_visible (tv_col))
3260 if (visible_columns == visible_column)
3261 return actual_column;
3262 tv_col = gtk_tree_view_get_column (tree_view, ++actual_column);
3264 g_warning ("get_actual_column_number failed for %d\n", visible_column);
3269 get_visible_column_number (GtkTreeView *tree_view,
3272 GtkTreeViewColumn *tv_col;
3274 gint visible_columns = -1;
3276 * This function calculates the visible column number which corresponds to the
3277 * specified actual column number
3279 tv_col = gtk_tree_view_get_column (tree_view, column);
3281 while (tv_col != NULL)
3283 if (gtk_tree_view_column_get_visible (tv_col))
3286 if (actual_column == column)
3287 return visible_columns;
3290 if (actual_column == column)
3292 tv_col = gtk_tree_view_get_column (tree_view, ++column);
3294 g_warning ("get_visible_column_number failed for %d\n", actual_column);
3299 * Helper recursive function that returns GtkTreeIter pointer to nth row.
3302 return_iter_nth_row(GtkTreeView *tree_view,
3303 GtkTreeModel *tree_model,
3308 GtkTreePath *current_path = gtk_tree_model_get_path (tree_model, iter);
3309 GtkTreeIter new_iter;
3310 gboolean row_expanded;
3312 if (increment == row) {
3313 gtk_tree_path_free (current_path);
3317 row_expanded = gtk_tree_view_row_expanded (tree_view, current_path);
3318 gtk_tree_path_free (current_path);
3321 if ((row_expanded && gtk_tree_model_iter_children (tree_model, iter, &new_iter)) ||
3322 (gtk_tree_model_iter_next (tree_model, iter)) ||
3323 (gtk_tree_model_iter_parent (tree_model, iter, &new_iter) &&
3324 (gtk_tree_model_iter_next (tree_model, iter))))
3325 return return_iter_nth_row (tree_view, tree_model, iter,
3332 * Recursively called until the row specified by orig is found.
3334 * *count will be set to the visible row number of the child
3335 * relative to the row that was initially passed in as tree_path.
3337 * *count will be -1 if orig is not found as a child (a row that is
3338 * not visible will not be found, e.g. if the row is inside a
3339 * collapsed row). If NULL is passed in as orig, *count will
3340 * be a count of the visible children.
3342 * NOTE: the value for depth must be 0 when this recursive function
3343 * is initially called, or it may not function as expected.
3346 iterate_thru_children(GtkTreeView *tree_view,
3347 GtkTreeModel *tree_model,
3348 GtkTreePath *tree_path,
3355 if (!gtk_tree_model_get_iter (tree_model, &iter, tree_path))
3358 if (tree_path && orig && !gtk_tree_path_compare (tree_path, orig))
3362 if (tree_path && orig && gtk_tree_path_compare (tree_path, orig) > 0)
3364 /* Past it, so return -1 */
3368 else if (gtk_tree_view_row_expanded (tree_view, tree_path) &&
3369 gtk_tree_model_iter_has_child (tree_model, &iter))
3372 gtk_tree_path_append_index (tree_path, 0);
3373 iterate_thru_children (tree_view, tree_model, tree_path,
3374 orig, count, (depth + 1));
3377 else if (gtk_tree_model_iter_next (tree_model, &iter))
3380 tree_path = gtk_tree_model_get_path (tree_model, &iter);
3383 iterate_thru_children (tree_view, tree_model, tree_path,
3384 orig, count, depth);
3385 gtk_tree_path_free (tree_path);
3389 else if (gtk_tree_path_up (tree_path))
3391 GtkTreeIter temp_iter;
3392 gboolean exit_loop = FALSE;
3393 gint new_depth = depth - 1;
3398 * Make sure that we back up until we find a row
3399 * where gtk_tree_path_next does not return NULL.
3403 if (gtk_tree_path_get_depth (tree_path) == 0)
3404 /* depth is now zero so */
3406 gtk_tree_path_next (tree_path);
3408 /* Verify that the next row is a valid row! */
3409 exit_loop = gtk_tree_model_get_iter (tree_model, &temp_iter, tree_path);
3413 /* Keep going up until we find a row that has a valid next */
3414 if (gtk_tree_path_get_depth(tree_path) > 1)
3417 gtk_tree_path_up (tree_path);
3422 * If depth is 1 and gtk_tree_model_get_iter returns FALSE,
3423 * then we are at the last row, so just return.
3434 * This guarantees that we will stop when we hit the end of the
3440 iterate_thru_children (tree_view, tree_model, tree_path,
3441 orig, count, new_depth);
3446 * If it gets here, then the path wasn't found. Situations
3447 * that would cause this would be if the path passed in is
3448 * invalid or contained within the last row, but not visible
3449 * because the last row is not expanded. If NULL was passed
3450 * in then a row count is desired, so only set count to -1
3451 * if orig is not NULL.
3460 clean_cell_info (GailTreeView *gailview,
3463 GailTreeViewCellInfo *cell_info;
3466 g_assert (GAIL_IS_TREE_VIEW (gailview));
3468 cell_info = list->data;
3470 if (cell_info->in_use) {
3471 obj = G_OBJECT (cell_info->cell);
3473 gail_cell_add_state (cell_info->cell, ATK_STATE_DEFUNCT, TRUE);
3474 g_object_weak_unref (obj, (GWeakNotify) cell_destroyed, cell_info);
3475 cell_info->in_use = FALSE;
3476 if (!gailview->garbage_collection_pending) {
3477 gailview->garbage_collection_pending = TRUE;
3478 g_assert (gailview->idle_garbage_collect_id == 0);
3479 gailview->idle_garbage_collect_id =
3480 gdk_threads_add_idle (idle_garbage_collect_cell_data, gailview);
3486 clean_rows (GailTreeView *gailview)
3490 /* Clean GailTreeViewRowInfo data */
3492 array = gailview->row_data;
3495 GailTreeViewRowInfo *row_info;
3496 GtkTreePath *row_path;
3500 * Loop backwards so that calls to free_row_info
3501 * do not affect the index numbers
3503 for (i = (array->len - 1); i >= 0; i --)
3505 row_info = g_array_index (array, GailTreeViewRowInfo*, i);
3506 row_path = gtk_tree_row_reference_get_path (row_info->row_ref);
3508 /* Remove any rows that have become invalid */
3509 if (row_path == NULL)
3510 free_row_info (array, i, TRUE);
3512 gtk_tree_path_free (row_path);
3516 /* Clean GailTreeViewCellInfo data */
3518 if (gailview->cell_data != NULL)
3520 GailTreeViewCellInfo *cell_info;
3521 GtkTreePath *row_path;
3525 temp_list = gailview->cell_data;
3527 /* Must loop through them all */
3528 while (temp_list != NULL)
3530 cur_list = temp_list;
3531 cell_info = temp_list->data;
3532 temp_list = temp_list->next;
3533 row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3536 * If the cell has become invalid because the row has been removed,
3537 * then set the cell's state to ATK_STATE_DEFUNCT and remove the cell
3538 * from gailview->cell_data. If row_path is NULL then the row has
3541 if (row_path == NULL)
3543 clean_cell_info (gailview, cur_list);
3547 gtk_tree_path_free (row_path);
3554 clean_cols (GailTreeView *gailview,
3555 GtkTreeViewColumn *tv_col)
3557 /* Clean GailTreeViewCellInfo data */
3559 if (gailview->cell_data != NULL)
3561 GailTreeViewCellInfo *cell_info;
3562 GList *cur_list, *temp_list;
3564 temp_list = gailview->cell_data;
3566 while (temp_list != NULL)
3568 cur_list = temp_list;
3569 cell_info = temp_list->data;
3570 temp_list = temp_list->next;
3573 * If the cell has become invalid because the column tv_col
3574 * has been removed, then set the cell's state to ATK_STATE_DEFUNCT
3575 * and remove the cell from gailview->cell_data.
3577 if (cell_info->cell_col_ref == tv_col)
3579 clean_cell_info (gailview, cur_list);
3586 idle_garbage_collect_cell_data (gpointer data)
3588 GailTreeView *tree_view;
3590 g_assert (GAIL_IS_TREE_VIEW (data));
3591 tree_view = (GailTreeView *)data;
3593 /* this is the idle handler (only one instance allowed), so
3594 * we can safely delete it.
3596 tree_view->garbage_collection_pending = FALSE;
3597 tree_view->idle_garbage_collect_id = 0;
3599 tree_view->garbage_collection_pending = garbage_collect_cell_data (data);
3601 /* N.B.: if for some reason another handler has re-enterantly been queued
3602 * while this handler was being serviced, it has its own gsource, therefore this handler
3603 * should always return FALSE.
3609 garbage_collect_cell_data (gpointer data)
3611 GailTreeView *tree_view;
3613 GailTreeViewCellInfo *cell_info;
3615 g_assert (GAIL_IS_TREE_VIEW (data));
3616 tree_view = (GailTreeView *)data;
3617 temp_list = g_list_copy (tree_view->cell_data);
3619 tree_view->garbage_collection_pending = FALSE;
3620 if (tree_view->idle_garbage_collect_id != 0)
3622 g_source_remove (tree_view->idle_garbage_collect_id);
3623 tree_view->idle_garbage_collect_id = 0;
3626 /* Must loop through them all */
3627 while (temp_list != NULL)
3629 cell_info = temp_list->data;
3630 if (!cell_info->in_use)
3632 /* g_object_unref (cell_info->cell); */
3633 tree_view->cell_data = g_list_remove (tree_view->cell_data,
3635 if (cell_info->cell_row_ref)
3636 gtk_tree_row_reference_free (cell_info->cell_row_ref);
3639 temp_list = temp_list->next;
3641 g_list_free (temp_list);
3643 return tree_view->garbage_collection_pending;
3647 * If tree_path is passed in as NULL, then all cells are acted on.
3648 * Otherwise, just act on those cells that are on a row greater than
3649 * the specified tree_path. If inc_row is passed in as TRUE, then rows
3650 * greater and equal to the specified tree_path are acted on.
3652 * if set_stale is set the ATK_STATE_STALE is set on cells which are to be
3655 * The function set_cell_visibility() is called on all cells to be
3656 * acted on to update the visibility of the cell.
3659 traverse_cells (GailTreeView *tree_view,
3660 GtkTreePath *tree_path,
3664 if (tree_view->cell_data != NULL)
3666 GailTreeViewCellInfo *cell_info;
3667 GtkTreeView *gtk_tree_view;
3671 g_assert (GTK_IS_ACCESSIBLE (tree_view));
3673 widget = GTK_ACCESSIBLE (tree_view)->widget;
3675 /* Widget is being deleted */
3678 gtk_tree_view = GTK_TREE_VIEW (widget);
3679 temp_list = tree_view->cell_data;
3681 /* Must loop through them all */
3682 while (temp_list != NULL)
3684 GtkTreePath *row_path;
3685 gboolean act_on_cell;
3687 cell_info = temp_list->data;
3688 temp_list = temp_list->next;
3690 if (cell_info->in_use)
3692 row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3693 g_assert (row_path != NULL);
3694 if (tree_path == NULL)
3700 comparison = gtk_tree_path_compare (row_path, tree_path);
3701 if ((comparison > 0) ||
3702 (comparison == 0 && inc_row))
3705 act_on_cell = FALSE;
3707 if (!cell_info->in_use) g_warning ("warning: cell info destroyed during traversal");
3708 if (act_on_cell && cell_info->in_use)
3711 gail_cell_add_state (cell_info->cell, ATK_STATE_STALE, TRUE);
3712 set_cell_visibility (gtk_tree_view,
3714 cell_info->cell_col_ref,
3717 gtk_tree_path_free (row_path);
3721 g_signal_emit_by_name (tree_view, "visible-data-changed");
3725 free_row_info (GArray *array,
3729 GailTreeViewRowInfo* obj;
3731 obj = g_array_index (array, GailTreeViewRowInfo*, array_idx);
3733 g_free (obj->description);
3734 if (obj->row_ref != NULL)
3735 gtk_tree_row_reference_free (obj->row_ref);
3737 g_object_unref (obj->header);
3741 g_array_remove_index (array, array_idx);
3745 * If the tree_path passed in has children, then
3746 * ATK_STATE_EXPANDABLE is set. If the row is expanded
3747 * ATK_STATE_EXPANDED is turned on. If the row is
3748 * collapsed, then ATK_STATE_EXPANDED is removed.
3750 * If the tree_path passed in has no children, then
3751 * ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED are removed.
3753 * If set_on_ancestor is TRUE, then this function will also
3754 * update all cells that are ancestors of the tree_path.
3757 set_expand_state (GtkTreeView *tree_view,
3758 GtkTreeModel *tree_model,
3759 GailTreeView *gailview,
3760 GtkTreePath *tree_path,
3761 gboolean set_on_ancestor)
3763 if (gailview->cell_data != NULL)
3765 GtkTreeViewColumn *expander_tv;
3766 GailTreeViewCellInfo *cell_info;
3768 GtkTreePath *cell_path;
3772 temp_list = gailview->cell_data;
3774 while (temp_list != NULL)
3776 cell_info = temp_list->data;
3777 temp_list = temp_list->next;
3778 if (cell_info->in_use)
3780 cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3783 if (cell_path != NULL)
3785 GailCell *cell = GAIL_CELL (cell_info->cell);
3787 expander_tv = gtk_tree_view_get_expander_column (tree_view);
3790 * Only set state for the cell that is in the column with the
3793 if (expander_tv == cell_info->cell_col_ref)
3795 if (tree_path && gtk_tree_path_compare (cell_path, tree_path) == 0)
3797 else if (set_on_ancestor &&
3798 gtk_tree_path_get_depth (cell_path) <
3799 gtk_tree_path_get_depth (tree_path) &&
3800 gtk_tree_path_is_ancestor (cell_path, tree_path) == 1)
3801 /* Only set if set_on_ancestor was passed in as TRUE */
3806 * Set ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED
3807 * for ancestors and found cells.
3812 * Must check against cell_path since cell_path
3813 * can be equal to or an ancestor of tree_path.
3815 gtk_tree_model_get_iter (tree_model, &iter, cell_path);
3817 /* Set or unset ATK_STATE_EXPANDABLE as appropriate */
3818 if (gtk_tree_model_iter_has_child (tree_model, &iter))
3820 set_cell_expandable (cell);
3822 if (gtk_tree_view_row_expanded (tree_view, cell_path))
3823 gail_cell_add_state (cell, ATK_STATE_EXPANDED, TRUE);
3825 gail_cell_remove_state (cell,
3826 ATK_STATE_EXPANDED, TRUE);
3830 gail_cell_remove_state (cell,
3831 ATK_STATE_EXPANDED, TRUE);
3832 if (gail_cell_remove_state (cell,
3833 ATK_STATE_EXPANDABLE, TRUE))
3834 /* The state may have been propagated to the container cell */
3835 if (!GAIL_IS_CONTAINER_CELL (cell))
3836 gail_cell_remove_action_by_name (cell,
3837 "expand or contract");
3841 * We assume that each cell in the cache once and
3842 * a container cell is before its child cells so we are
3843 * finished if set_on_ancestor is not set to TRUE.
3845 if (!set_on_ancestor)
3849 gtk_tree_path_free (cell_path);
3857 add_cell_actions (GailCell *cell,
3860 if (GAIL_IS_BOOLEAN_CELL (cell))
3861 gail_cell_add_action (cell,
3863 "toggles the cell", /* action description */
3865 toggle_cell_toggled);
3867 gail_cell_add_action (cell,
3869 "creates a widget in which the contents of the cell can be edited",
3872 gail_cell_add_action (cell,
3874 "activate the cell",
3880 toggle_cell_expanded (GailCell *cell)
3882 GailTreeViewCellInfo *cell_info;
3883 GtkTreeView *tree_view;
3886 AtkStateSet *stateset;
3888 parent = atk_object_get_parent (ATK_OBJECT (cell));
3889 if (GAIL_IS_CONTAINER_CELL (parent))
3890 parent = atk_object_get_parent (parent);
3892 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
3893 gail_return_if_fail (cell_info);
3894 gail_return_if_fail (cell_info->cell_col_ref);
3895 gail_return_if_fail (cell_info->cell_row_ref);
3897 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
3898 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3899 gail_return_if_fail (path);
3901 stateset = atk_object_ref_state_set (ATK_OBJECT (cell));
3902 if (atk_state_set_contains_state (stateset, ATK_STATE_EXPANDED))
3903 gtk_tree_view_collapse_row (tree_view, path);
3905 gtk_tree_view_expand_row (tree_view, path, TRUE);
3906 g_object_unref (stateset);
3907 gtk_tree_path_free (path);
3912 toggle_cell_toggled (GailCell *cell)
3914 GailTreeViewCellInfo *cell_info;
3915 GtkTreeView *tree_view;
3918 GList *renderers, *cur_renderer;
3920 gboolean is_container_cell = FALSE;
3922 parent = atk_object_get_parent (ATK_OBJECT (cell));
3923 if (GAIL_IS_CONTAINER_CELL (parent))
3925 is_container_cell = TRUE;
3926 parent = atk_object_get_parent (parent);
3929 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
3930 gail_return_if_fail (cell_info);
3931 gail_return_if_fail (cell_info->cell_col_ref);
3932 gail_return_if_fail (cell_info->cell_row_ref);
3934 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
3935 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3936 gail_return_if_fail (path);
3937 pathstring = gtk_tree_path_to_string (path);
3939 renderers = gtk_tree_view_column_get_cell_renderers (cell_info->cell_col_ref);
3940 gail_return_if_fail (renderers);
3943 * if the cell is in a container, it's index is used to find the
3944 * renderer in the list
3947 if (is_container_cell)
3948 cur_renderer = g_list_nth (renderers, cell->index);
3951 * Otherwise, we assume that the cell is represented by the first
3952 * renderer in the list
3954 cur_renderer = renderers;
3956 gail_return_if_fail (cur_renderer);
3958 g_signal_emit_by_name (cur_renderer->data, "toggled", pathstring);
3959 g_list_free (renderers);
3960 g_free (pathstring);
3961 gtk_tree_path_free (path);
3966 edit_cell (GailCell *cell)
3968 GailTreeViewCellInfo *cell_info;
3969 GtkTreeView *tree_view;
3972 gboolean is_container_cell = FALSE;
3975 parent = atk_object_get_parent (ATK_OBJECT (cell));
3976 if (GAIL_IS_CONTAINER_CELL (parent))
3978 is_container_cell = TRUE;
3979 parent = atk_object_get_parent (parent);
3982 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
3983 gail_return_if_fail (cell_info);
3984 gail_return_if_fail (cell_info->cell_col_ref);
3985 gail_return_if_fail (cell_info->cell_row_ref);
3987 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
3988 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
3989 gail_return_if_fail (path);
3990 gtk_tree_view_set_cursor (tree_view, path, cell_info->cell_col_ref, TRUE);
3991 gtk_tree_path_free (path);
3996 activate_cell (GailCell *cell)
3998 GailTreeViewCellInfo *cell_info;
3999 GtkTreeView *tree_view;
4002 gboolean is_container_cell = FALSE;
4005 parent = atk_object_get_parent (ATK_OBJECT (cell));
4006 if (GAIL_IS_CONTAINER_CELL (parent))
4008 is_container_cell = TRUE;
4009 parent = atk_object_get_parent (parent);
4012 cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
4013 gail_return_if_fail (cell_info);
4014 gail_return_if_fail (cell_info->cell_col_ref);
4015 gail_return_if_fail (cell_info->cell_row_ref);
4017 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
4018 path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
4019 gail_return_if_fail (path);
4020 gtk_tree_view_row_activated (tree_view, path, cell_info->cell_col_ref);
4021 gtk_tree_path_free (path);
4026 cell_destroyed (gpointer data)
4028 GailTreeViewCellInfo *cell_info = data;
4030 gail_return_if_fail (cell_info);
4031 if (cell_info->in_use) {
4032 cell_info->in_use = FALSE;
4034 g_assert (GAIL_IS_TREE_VIEW (cell_info->view));
4035 if (!cell_info->view->garbage_collection_pending) {
4036 cell_info->view->garbage_collection_pending = TRUE;
4037 cell_info->view->idle_garbage_collect_id =
4038 gdk_threads_add_idle (idle_garbage_collect_cell_data, cell_info->view);
4045 cell_info_remove (GailTreeView *tree_view,
4048 GailTreeViewCellInfo *info;
4051 info = find_cell_info (tree_view, cell, &temp_list, FALSE);
4054 info->in_use = FALSE;
4057 g_warning ("No cell removed in cell_info_remove\n");
4062 cell_info_get_index (GtkTreeView *tree_view,
4063 GailTreeViewCellInfo *info,
4069 path = gtk_tree_row_reference_get_path (info->cell_row_ref);
4070 gail_return_if_fail (path);
4072 column_number = get_column_number (tree_view, info->cell_col_ref, FALSE);
4073 *index = get_index (tree_view, path, column_number);
4074 gtk_tree_path_free (path);
4078 cell_info_new (GailTreeView *gailview,
4079 GtkTreeModel *tree_model,
4081 GtkTreeViewColumn *tv_col,
4084 GailTreeViewCellInfo *cell_info;
4086 g_assert (GAIL_IS_TREE_VIEW (gailview));
4088 cell_info = g_new (GailTreeViewCellInfo, 1);
4089 cell_info->cell_row_ref = gtk_tree_row_reference_new (tree_model, path);
4091 cell_info->cell_col_ref = tv_col;
4092 cell_info->cell = cell;
4093 cell_info->in_use = TRUE; /* if we've created it, assume it's in use */
4094 cell_info->view = gailview;
4095 gailview->cell_data = g_list_append (gailview->cell_data, cell_info);
4097 /* Setup weak reference notification */
4099 g_object_weak_ref (G_OBJECT (cell),
4100 (GWeakNotify) cell_destroyed,
4105 find_cell (GailTreeView *gailview,
4108 GailTreeViewCellInfo *info;
4109 GtkTreeView *tree_view;
4113 gboolean needs_cleaning = FALSE;
4114 GailCell *retval = NULL;
4116 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (gailview)->widget);
4117 cell_list = gailview->cell_data;
4119 for (l = cell_list; l; l = l->next)
4121 info = (GailTreeViewCellInfo *) (l->data);
4124 cell_info_get_index (tree_view, info, &real_index);
4125 if (index == real_index)
4127 retval = info->cell;
4133 needs_cleaning = TRUE;
4137 garbage_collect_cell_data (gailview);
4143 refresh_cell_index (GailCell *cell)
4145 GailTreeViewCellInfo *info;
4147 GtkTreeView *tree_view;
4150 parent = atk_object_get_parent (ATK_OBJECT (cell));
4151 gail_return_if_fail (GAIL_IS_TREE_VIEW (parent));
4153 tree_view = GTK_TREE_VIEW (GTK_ACCESSIBLE (parent)->widget);
4155 /* Find this cell in the GailTreeView's cache */
4157 info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
4158 gail_return_if_fail (info);
4160 cell_info_get_index (tree_view, info, &index);
4161 cell->index = index;
4165 get_selected_rows (GtkTreeModel *model,
4170 GPtrArray *array = (GPtrArray *)data;
4172 g_ptr_array_add (array, gtk_tree_path_copy (path));
4176 connect_model_signals (GtkTreeView *view,
4177 GailTreeView *gailview)
4181 obj = G_OBJECT (gailview->tree_model);
4182 g_signal_connect_data (obj, "row-changed",
4183 (GCallback) model_row_changed, view, NULL, 0);
4184 g_signal_connect_data (obj, "row-inserted",
4185 (GCallback) model_row_inserted, view, NULL,
4187 g_signal_connect_data (obj, "row-deleted",
4188 (GCallback) model_row_deleted, view, NULL,
4190 g_signal_connect_data (obj, "rows-reordered",
4191 (GCallback) model_rows_reordered, view, NULL,
4196 disconnect_model_signals (GailTreeView *view)
4201 obj = G_OBJECT (view->tree_model);
4202 widget = GTK_ACCESSIBLE (view)->widget;
4203 g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_changed, widget);
4204 g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_inserted, widget);
4205 g_signal_handlers_disconnect_by_func (obj, (gpointer) model_row_deleted, widget);
4206 g_signal_handlers_disconnect_by_func (obj, (gpointer) model_rows_reordered, widget);
4210 clear_cached_data (GailTreeView *view)
4216 GArray *array = view->row_data;
4220 * Since the third argument to free_row_info is FALSE, we don't remove
4221 * the element. Therefore it is safe to loop forward.
4223 for (i = 0; i < array->len; i++)
4224 free_row_info (array, i, FALSE);
4226 g_array_free (array, TRUE);
4228 view->row_data = NULL;
4231 if (view->cell_data)
4233 /* Must loop through them all */
4234 for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
4236 clean_cell_info (view, temp_list);
4239 garbage_collect_cell_data (view);
4240 if (view->cell_data)
4241 g_list_free (view->cell_data);
4243 view->cell_data = NULL;
4247 * Returns the column number of the specified GtkTreeViewColumn
4249 * If visible is set, the value returned will be the visible column number,
4250 * i.e. suitable for use in AtkTable function. If visible is not set, the
4251 * value returned is the actual column number, which is suitable for use in
4252 * getting an index value.
4255 get_column_number (GtkTreeView *tree_view,
4256 GtkTreeViewColumn *column,
4259 GList *temp_list, *column_list;
4260 GtkTreeViewColumn *tv_column;
4263 column_list = gtk_tree_view_get_columns (tree_view);
4265 for (temp_list = column_list; temp_list; temp_list = temp_list->next)
4267 tv_column = GTK_TREE_VIEW_COLUMN (temp_list->data);
4268 if (tv_column == column)
4270 if (!visible || gtk_tree_view_column_get_visible (tv_column))
4273 if (temp_list == NULL)
4277 g_list_free (column_list);
4282 get_index (GtkTreeView *tree_view,
4288 gint *indices = NULL;
4293 depth = gtk_tree_path_get_depth (path);
4294 indices = gtk_tree_path_get_indices (path);
4299 GtkTreePath *copy_path;
4300 GtkTreeModel *model;
4302 model = gtk_tree_view_get_model (tree_view);
4303 copy_path = gtk_tree_path_copy (path);
4304 gtk_tree_path_up (copy_path);
4305 count_rows (model, NULL, copy_path, &index, 0, depth);
4306 gtk_tree_path_free (copy_path);
4310 index += indices[depth-1];
4311 index *= get_n_actual_columns (tree_view);
4312 index += actual_column;
4317 * The function count_rows counts the number of rows starting at iter and ending
4318 * at end_path. The value of level is the depth of iter and the value of depth
4319 * is the depth of end_path. Rows at depth before end_path are counted.
4320 * This functions counts rows which are not visible because an ancestor is
4324 count_rows (GtkTreeModel *model,
4326 GtkTreePath *end_path,
4331 GtkTreeIter child_iter;
4337 *count += gtk_tree_model_iter_n_children (model, iter);
4340 g_print ("count_rows : %d level: %d depth: %d\n", *count, level, depth);
4342 g_print ("path: %s\n",
4343 gtk_tree_path_to_string (gtk_tree_model_get_path (model, iter)));
4349 if (gtk_tree_model_iter_children (model, &child_iter, iter))
4351 gboolean ret_val = TRUE;
4355 if (level == depth - 1)
4357 GtkTreePath *iter_path;
4358 gboolean finished = FALSE;
4360 iter_path = gtk_tree_model_get_path (model, &child_iter);
4361 if (end_path && gtk_tree_path_compare (iter_path, end_path) >= 0)
4363 gtk_tree_path_free (iter_path);
4367 if (gtk_tree_model_iter_has_child (model, &child_iter))
4368 count_rows (model, &child_iter, end_path, count, level, depth);
4369 ret_val = gtk_tree_model_iter_next (model, &child_iter);
4375 * Find the next node, which has children, at the specified depth below
4376 * the specified iter. The level is the depth of the current iter.
4377 * The position of the node is returned in path and the return value of TRUE
4378 * means that a node was found.
4381 gboolean get_next_node_with_child_at_depth (GtkTreeModel *model,
4387 GtkTreeIter child_iter;
4391 if (gtk_tree_model_iter_children (model, &child_iter, iter))
4397 while (!gtk_tree_model_iter_has_child (model, &child_iter))
4399 if (!gtk_tree_model_iter_next (model, &child_iter))
4404 /* We have found what we were looking for */
4406 *path = gtk_tree_model_get_path (model, &child_iter);
4410 if (get_next_node_with_child_at_depth (model, &child_iter, path,
4414 if (!gtk_tree_model_iter_next (model, &child_iter))
4422 * Find the next node, which has children, at the same depth as
4423 * the specified GtkTreePath.
4426 get_next_node_with_child (GtkTreeModel *model,
4428 GtkTreePath **return_path)
4433 gtk_tree_model_get_iter (model, &iter, path);
4435 while (gtk_tree_model_iter_next (model, &iter))
4437 if (gtk_tree_model_iter_has_child (model, &iter))
4439 *return_path = gtk_tree_model_get_path (model, &iter);
4443 depth = gtk_tree_path_get_depth (path);
4444 while (gtk_tree_path_up (path))
4446 if (gtk_tree_path_get_depth (path) == 0)
4449 gtk_tree_model_get_iter (model, &iter, path);
4450 while (gtk_tree_model_iter_next (model, &iter))
4451 if (get_next_node_with_child_at_depth (model, &iter, return_path,
4452 gtk_tree_path_get_depth (path), depth))
4455 *return_path = NULL;
4460 get_tree_path_from_row_index (GtkTreeModel *model,
4462 GtkTreePath **tree_path)
4468 count = gtk_tree_model_iter_n_children (model, NULL);
4469 if (count > row_index)
4471 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, row_index))
4473 *tree_path = gtk_tree_model_get_path (model, &iter);
4487 if (get_next_node_with_child_at_depth (model, NULL, tree_path, 0, depth))
4489 GtkTreePath *next_path;
4493 gtk_tree_model_get_iter (model, &iter, *tree_path);
4494 count = gtk_tree_model_iter_n_children (model, &iter);
4495 if (count > row_index)
4497 gtk_tree_path_append_index (*tree_path, row_index);
4503 if (!get_next_node_with_child (model, *tree_path, &next_path))
4506 gtk_tree_path_free (*tree_path);
4507 *tree_path = next_path;
4512 g_warning ("Index value is too large\n");
4513 gtk_tree_path_free (*tree_path);
4521 * This function returns the number of rows, including those which are collapsed
4524 get_row_count (GtkTreeModel *model)
4528 count_rows (model, NULL, NULL, &n_rows, 0, G_MAXINT);
4534 get_path_column_from_index (GtkTreeView *tree_view,
4537 GtkTreeViewColumn **column)
4539 GtkTreeModel *tree_model;
4542 tree_model = gtk_tree_view_get_model (tree_view);
4543 n_columns = get_n_actual_columns (tree_view);
4546 /* First row is the column headers */
4556 row_index = index / n_columns;
4557 retval = get_tree_path_from_row_index (tree_model, row_index, path);
4558 gail_return_val_if_fail (retval, FALSE);
4565 *column = gtk_tree_view_get_column (tree_view, index % n_columns);
4566 if (*column == NULL)
4569 gtk_tree_path_free (*path);
4577 set_cell_expandable (GailCell *cell)
4579 if (gail_cell_add_state (cell,
4580 ATK_STATE_EXPANDABLE,
4582 gail_cell_add_action (cell,
4583 "expand or contract", /* action name */
4584 "expands or contracts the row in the tree view "
4585 "containing this cell", /* description */
4586 NULL, /* Keybinding */
4587 toggle_cell_expanded);
4590 static GailTreeViewCellInfo*
4591 find_cell_info (GailTreeView *view,
4597 GailTreeViewCellInfo *cell_info;
4599 for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
4601 cell_info = (GailTreeViewCellInfo *) temp_list->data;
4602 if (cell_info->cell == cell && (!live_only || cell_info->in_use))
4613 get_header_from_column (GtkTreeViewColumn *tv_col)
4616 GtkWidget *header_widget;
4621 /* If the user has set a header object, use that */
4623 rc = g_object_get_qdata (G_OBJECT (tv_col), quark_column_header_object);
4627 /* If the user has not set a header object, grab the column */
4628 /* header object defined by the GtkTreeView */
4630 header_widget = tv_col->button;
4634 rc = gtk_widget_get_accessible (header_widget);