[gtk+] GailTreeView: optimize a bit
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] GailTreeView: optimize a bit
- Date: Tue, 5 Jul 2011 20:25:29 +0000 (UTC)
commit 2deeab4c4f929ebd32d5f6141ea1cec572a76728
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Jun 22 22:27:10 2011 -0400
GailTreeView: optimize a bit
Avoid many unnecessary list iterations by using a hash table
to store cell infos, and caching row and column counts. Based
on patches by William Jon McCann, bug 554171.
tree-performance results:
before: (MINPERF:large tree test with a11y: 9.18531sec)
after: (MINPERF:large tree test with a11y: 0.923463sec)
for comparison, without accessibility:
(MINPERF:large tree test: 0.016179sec)
gtk/a11y/gailtreeview.c | 660 +++++++++++++++++++----------------------------
1 files changed, 270 insertions(+), 390 deletions(-)
---
diff --git a/gtk/a11y/gailtreeview.c b/gtk/a11y/gailtreeview.c
index 338e646..4ecf590 100644
--- a/gtk/a11y/gailtreeview.c
+++ b/gtk/a11y/gailtreeview.c
@@ -82,7 +82,6 @@ static AtkObject* gail_tree_view_table_ref_at (AtkTable
gint column);
static gint gail_tree_view_get_n_rows (AtkTable *table);
static gint gail_tree_view_get_n_columns (AtkTable *table);
-static gint get_n_actual_columns (GtkTreeView *tree_view);
static gboolean gail_tree_view_is_row_selected (AtkTable *table,
gint row);
static gboolean gail_tree_view_is_selected (AtkTable *table,
@@ -245,8 +244,6 @@ static GtkTreeIter* return_iter_nth_row (GtkTreeView
static void free_row_info (GArray *array,
gint array_idx,
gboolean shift);
-static void clean_cell_info (GailTreeView *tree_view,
- GList *list);
static void clean_rows (GailTreeView *tree_view);
static void clean_cols (GailTreeView *tree_view,
GtkTreeViewColumn *tv_col);
@@ -326,7 +323,6 @@ static gboolean get_next_node_with_child (GtkTreeModel
static gboolean get_tree_path_from_row_index (GtkTreeModel *model,
gint row_index,
GtkTreePath **tree_path);
-static gint get_row_count (GtkTreeModel *model);
static gboolean get_path_column_from_index (GtkTreeView *tree_view,
gint index,
GtkTreePath **path,
@@ -335,7 +331,6 @@ static void set_cell_expandable (GailCell
static GailTreeViewCellInfo* find_cell_info (GailTreeView *view,
GailCell *cell,
- GList** list,
gboolean live_only);
static AtkObject * get_header_from_column (GtkTreeViewColumn *tv_col);
static gboolean idle_garbage_collect_cell_data (gpointer data);
@@ -459,7 +454,6 @@ gail_tree_view_real_initialize (AtkObject *obj,
view->summary = NULL;
view->row_data = NULL;
view->col_data = NULL;
- view->cell_data = NULL;
view->focus_cell = NULL;
view->old_hadj = NULL;
view->old_vadj = NULL;
@@ -468,6 +462,8 @@ gail_tree_view_real_initialize (AtkObject *obj,
view->n_children_deleted = 0;
+ view->cell_info_by_index = g_hash_table_new (g_int_hash, g_int_equal);
+
widget = GTK_WIDGET (data);
g_signal_connect_after (widget,
"row-collapsed",
@@ -502,9 +498,12 @@ gail_tree_view_real_initialize (AtkObject *obj,
(GCallback) focus_out, NULL, NULL, 0);
view->tree_model = tree_model;
+ view->n_rows = 0;
+ view->n_cols = 0;
if (tree_model)
{
g_object_add_weak_pointer (G_OBJECT (view->tree_model), (gpointer *)&view->tree_model);
+ count_rows (tree_model, NULL, NULL, &view->n_rows, 0, G_MAXINT);
connect_model_signals (tree_view, view);
if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
@@ -537,6 +536,7 @@ gail_tree_view_real_initialize (AtkObject *obj,
for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
{
+ view->n_cols++;
g_signal_connect_data (tmp_list->data, "notify::visible",
(GCallback)column_visibility_changed,
tree_view, NULL, FALSE);
@@ -574,12 +574,14 @@ gail_tree_view_real_notify_gtk (GObject *obj,
disconnect_model_signals (gailview);
clear_cached_data (gailview);
gailview->tree_model = tree_model;
+ gailview->n_rows = 0;
/*
* if there is no model the GtkTreeView is probably being destroyed
*/
if (tree_model)
{
g_object_add_weak_pointer (G_OBJECT (gailview->tree_model), (gpointer *)&gailview->tree_model);
+ count_rows (tree_model, NULL, NULL, &gailview->n_rows, 0, G_MAXINT);
connect_model_signals (tree_view, gailview);
if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
@@ -650,6 +652,9 @@ gail_tree_view_finalize (GObject *object)
if (view->tree_model)
disconnect_model_signals (view);
+ if (view->cell_info_by_index)
+ g_hash_table_destroy (view->cell_info_by_index);
+
if (view->col_data)
{
GArray *array = view->col_data;
@@ -768,31 +773,14 @@ static gint
gail_tree_view_get_n_children (AtkObject *obj)
{
GtkWidget *widget;
- GtkTreeView *tree_view;
- GtkTreeModel *tree_model;
- gint n_rows, n_cols;
gail_return_val_if_fail (GAIL_IS_TREE_VIEW (obj), 0);
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
if (widget == NULL)
- /*
- * State is defunct
- */
return 0;
- tree_view = GTK_TREE_VIEW (widget);
- tree_model = gtk_tree_view_get_model (tree_view);
-
- /*
- * We get the total number of rows including those which are collapsed
- */
- n_rows = get_row_count (tree_model);
- /*
- * We get the total number of columns including those which are not visible
- */
- n_cols = get_n_actual_columns (tree_view);
- return (n_rows * n_cols);
+ return (GAIL_TREE_VIEW (obj)->n_rows + 1) * GAIL_TREE_VIEW (obj)->n_cols;
}
static AtkObject*
@@ -835,8 +823,9 @@ gail_tree_view_ref_child (AtkObject *obj,
if (i >= gail_tree_view_get_n_children (obj))
return NULL;
+ gailview = GAIL_TREE_VIEW (obj);
tree_view = GTK_TREE_VIEW (widget);
- if (i < get_n_actual_columns (tree_view))
+ if (i < gailview->n_cols)
{
tv_col = gtk_tree_view_get_column (tree_view, i);
child = get_header_from_column (tv_col);
@@ -845,7 +834,6 @@ gail_tree_view_ref_child (AtkObject *obj,
return child;
}
- gailview = GAIL_TREE_VIEW (obj);
/*
* Check whether the child is cached
*/
@@ -1034,10 +1022,8 @@ gail_tree_view_ref_child (AtkObject *obj,
else
{
gint parent_index;
- gint n_columns;
- n_columns = get_n_actual_columns (tree_view);
- parent_index = get_index (tree_view, path, i % n_columns);
+ parent_index = get_index (tree_view, path, i % gailview->n_cols);
parent_node = atk_object_ref_accessible_child (obj, parent_index);
}
accessible_array[0] = parent_node;
@@ -1208,7 +1194,7 @@ gail_tree_view_get_column_at_index (AtkTable *table,
return -1;
tree_view = GTK_TREE_VIEW (widget);
- n_columns = get_n_actual_columns (tree_view);
+ n_columns = GAIL_TREE_VIEW (table)->n_cols;
if (n_columns == 0)
return 0;
@@ -1274,11 +1260,10 @@ gail_tree_view_get_n_rows (AtkTable *table)
if (!tree_model)
n_rows = 0;
else if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
- /*
- * If working with a LIST store, then this is a faster way
- * to get the number of rows.
+ /*
+ * If working with a LIST store, then no rows are collapsed
*/
- n_rows = gtk_tree_model_iter_n_children (tree_model, NULL);
+ n_rows = GAIL_TREE_VIEW (table)->n_rows;
else
{
GtkTreePath *root_tree;
@@ -1293,23 +1278,7 @@ gail_tree_view_get_n_rows (AtkTable *table)
return n_rows;
}
-/*
- * The function get_n_actual_columns returns the number of columns in the
- * GtkTreeView. i.e. it include both visible and non-visible columns.
- */
-static gint
-get_n_actual_columns (GtkTreeView *tree_view)
-{
- GList *columns;
- gint n_cols;
-
- columns = gtk_tree_view_get_columns (tree_view);
- n_cols = g_list_length (columns);
- g_list_free (columns);
- return n_cols;
-}
-
-static gint
+static gint
gail_tree_view_get_n_columns (AtkTable *table)
{
GtkWidget *widget;
@@ -2094,7 +2063,7 @@ gail_tree_view_get_cell_area (GailCellParent *parent,
{
top_cell = cell;
}
- cell_info = find_cell_info (GAIL_TREE_VIEW (parent), top_cell, NULL, TRUE);
+ cell_info = find_cell_info (GAIL_TREE_VIEW (parent), top_cell, TRUE);
gail_return_if_fail (cell_info);
gail_return_if_fail (cell_info->cell_col_ref);
gail_return_if_fail (cell_info->cell_row_ref);
@@ -2178,7 +2147,7 @@ gail_tree_view_grab_cell_focus (GailCellParent *parent,
tree_view = GTK_TREE_VIEW (widget);
- cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+ cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, TRUE);
gail_return_val_if_fail (cell_info, FALSE);
gail_return_val_if_fail (cell_info->cell_col_ref, FALSE);
gail_return_val_if_fail (cell_info->cell_row_ref, FALSE);
@@ -2384,14 +2353,12 @@ gail_tree_view_changed_gtk (GtkTreeSelection *selection,
GailTreeView *gailview;
GtkTreeView *tree_view;
GtkWidget *widget;
- GList *cell_list;
- GList *l;
GailTreeViewCellInfo *info;
GtkTreeSelection *tree_selection;
GtkTreePath *path;
+ GHashTableIter iter;
gailview = GAIL_TREE_VIEW (data);
- cell_list = gailview->cell_data;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (gailview));
if (widget == NULL)
/*
@@ -2404,10 +2371,10 @@ gail_tree_view_changed_gtk (GtkTreeSelection *selection,
clean_rows (gailview);
- for (l = cell_list; l; l = l->next)
+ /* FIXME: clean rows iterates through all cells too */
+ g_hash_table_iter_init (&iter, gailview->cell_info_by_index);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&info))
{
- info = (GailTreeViewCellInfo *) (l->data);
-
if (info->in_use)
{
gail_cell_remove_state (info->cell, ATK_STATE_SELECTED, TRUE);
@@ -2440,6 +2407,7 @@ columns_changed (GtkTreeView *tree_view)
* gailview->col_data
*/
tv_cols = gtk_tree_view_get_columns (tree_view);
+ gailview->n_cols = g_list_length (tv_cols);
/* check for adds or moves */
for (tmp_list = tv_cols; tmp_list; tmp_list = tmp_list->next)
@@ -2480,7 +2448,7 @@ columns_changed (GtkTreeView *tree_view)
*/
if (!column_found)
{
- gint n_cols, n_rows, row;
+ gint row;
if (!stale_set)
{
@@ -2493,15 +2461,13 @@ columns_changed (GtkTreeView *tree_view)
g_signal_emit_by_name (atk_obj, "column_inserted", column_count, 1);
/* Generate children-changed signals */
- n_rows = get_row_count (gtk_tree_view_get_model (tree_view));
- n_cols = get_n_actual_columns (tree_view);
- for (row = 0; row < n_rows; row++)
+ for (row = 0; row < gailview->n_rows; row++)
{
/*
* Pass NULL as the child object, i.e. 4th argument.
*/
g_signal_emit_by_name (atk_obj, "children_changed::add",
- ((row * n_cols) + column_count), NULL, NULL);
+ ((row * gailview->n_cols) + column_count), NULL, NULL);
}
}
@@ -2530,7 +2496,7 @@ columns_changed (GtkTreeView *tree_view)
*/
if (!column_found)
{
- gint n_rows, n_cols, row;
+ gint row;
clean_cols (gailview,
(GtkTreeViewColumn *)g_array_index (gailview->col_data,
@@ -2547,15 +2513,13 @@ columns_changed (GtkTreeView *tree_view)
g_signal_emit_by_name (atk_obj, "column_deleted", i, 1);
/* Generate children-changed signals */
- n_rows = get_row_count (gtk_tree_view_get_model (tree_view));
- n_cols = get_n_actual_columns (tree_view);
- for (row = 0; row < n_rows; row++)
+ for (row = 0; row < gailview->n_rows; row++)
{
/*
* Pass NULL as the child object, 4th argument.
*/
g_signal_emit_by_name (atk_obj, "children_changed::remove",
- ((row * n_cols) + column_count), NULL, NULL);
+ ((row * gailview->n_cols) + column_count), NULL, NULL);
}
}
}
@@ -2696,17 +2660,17 @@ model_row_changed (GtkTreeModel *tree_model,
GtkTreeView *tree_view = GTK_TREE_VIEW(user_data);
GailTreeView *gailview;
GtkTreePath *cell_path;
- GList *l;
GailTreeViewCellInfo *cell_info;
-
+ GHashTableIter hash_iter;
+
gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view)));
/* Loop through our cached cells */
/* Must loop through them all */
- for (l = gailview->cell_data; l; l = l->next)
+ g_hash_table_iter_init (&hash_iter, gailview->cell_info_by_index);
+ while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer *)&cell_info))
{
- cell_info = (GailTreeViewCellInfo *) l->data;
- if (cell_info->in_use)
+ if (cell_info->in_use)
{
cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
@@ -2741,19 +2705,19 @@ column_visibility_changed (GObject *object,
*/
GtkTreeView *tree_view = (GtkTreeView *)user_data;
GailTreeView *gailview;
- GList *l;
GailTreeViewCellInfo *cell_info;
GtkTreeViewColumn *this_col = GTK_TREE_VIEW_COLUMN (object);
GtkTreeViewColumn *tv_col;
+ GHashTableIter iter;
gailview = GAIL_TREE_VIEW (gtk_widget_get_accessible (GTK_WIDGET (tree_view))
);
g_signal_emit_by_name (gailview, "model_changed");
- for (l = gailview->cell_data; l; l = l->next)
+ g_hash_table_iter_init (&iter, gailview->cell_info_by_index);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
{
- cell_info = (GailTreeViewCellInfo *) l->data;
- if (cell_info->in_use)
+ if (cell_info->in_use)
{
tv_col = cell_info->cell_col_ref;
if (tv_col == this_col)
@@ -2793,6 +2757,8 @@ model_row_inserted (GtkTreeModel *tree_model,
GailTreeView *gailview = GAIL_TREE_VIEW (atk_obj);
gint row, n_inserted, child_row;
+ gailview->n_rows++;
+
if (gailview->idle_expand_id)
{
g_source_remove (gailview->idle_expand_id);
@@ -2882,12 +2848,15 @@ model_row_deleted (GtkTreeModel *tree_model,
GtkTreePath *path_copy;
AtkObject *atk_obj;
GailTreeView *gailview;
- gint row, col, n_cols;
+ gint row, col;
tree_view = (GtkTreeView *)user_data;
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
gailview = GAIL_TREE_VIEW (atk_obj);
+ gailview->n_rows--;
+ g_assert (gailview->n_rows >= 0);
+
if (gailview->idle_expand_id)
{
g_source_remove (gailview->idle_expand_id);
@@ -2923,14 +2892,13 @@ model_row_deleted (GtkTreeModel *tree_model,
gailview->n_children_deleted = 0;
/* Generate children-changed signals */
- n_cols = get_n_actual_columns (tree_view);
- for (col = 0; col < n_cols; col++)
+ for (col = 0; col < gailview->n_cols; col++)
{
/*
* Pass NULL as the child object, 4th argument.
*/
g_signal_emit_by_name (atk_obj, "children_changed::remove",
- ((row * n_cols) + col), NULL, NULL);
+ ((row * gailview->n_cols) + col), NULL, NULL);
}
}
@@ -3104,7 +3072,7 @@ update_cell_value (GailRendererCell *renderer_cell,
prop_list = gail_renderer_cell_class->property_list;
cell = GAIL_CELL (renderer_cell);
- cell_info = find_cell_info (gailview, cell, NULL, TRUE);
+ cell_info = find_cell_info (gailview, cell, TRUE);
gail_return_val_if_fail (cell_info, FALSE);
gail_return_val_if_fail (cell_info->cell_col_ref, FALSE);
gail_return_val_if_fail (cell_info->cell_row_ref, FALSE);
@@ -3480,15 +3448,12 @@ iterate_thru_children(GtkTreeView *tree_view,
static void
clean_cell_info (GailTreeView *gailview,
- GList *list)
+ GailTreeViewCellInfo *cell_info)
{
- GailTreeViewCellInfo *cell_info;
GObject *obj;
g_assert (GAIL_IS_TREE_VIEW (gailview));
- cell_info = list->data;
-
if (cell_info->in_use) {
obj = G_OBJECT (cell_info->cell);
@@ -3508,6 +3473,8 @@ static void
clean_rows (GailTreeView *gailview)
{
GArray *array;
+ GailTreeViewCellInfo *cell_info;
+ GHashTableIter iter;
/* Clean GailTreeViewRowInfo data */
@@ -3536,70 +3503,48 @@ clean_rows (GailTreeView *gailview)
}
/* Clean GailTreeViewCellInfo data */
-
- if (gailview->cell_data != NULL)
+ g_hash_table_iter_init (&iter, gailview->cell_info_by_index);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
{
- GailTreeViewCellInfo *cell_info;
GtkTreePath *row_path;
- GList *cur_list;
- GList *temp_list;
- temp_list = gailview->cell_data;
-
- /* Must loop through them all */
- while (temp_list != NULL)
+ row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+ /*
+ * If the cell has become invalid because the row has been removed,
+ * then set the cell's state to ATK_STATE_DEFUNCT and schedule
+ * its removal. If row_path is NULL then the row has
+ * been removed.
+ */
+ if (row_path == NULL)
{
- cur_list = temp_list;
- cell_info = temp_list->data;
- temp_list = temp_list->next;
- row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
-
- /*
- * If the cell has become invalid because the row has been removed,
- * then set the cell's state to ATK_STATE_DEFUNCT and remove the cell
- * from gailview->cell_data. If row_path is NULL then the row has
- * been removed.
- */
- if (row_path == NULL)
- {
- clean_cell_info (gailview, cur_list);
- }
- else
- {
- gtk_tree_path_free (row_path);
- }
+ clean_cell_info (gailview, cell_info);
+ }
+ else
+ {
+ gtk_tree_path_free (row_path);
}
}
}
-static void
+static void
clean_cols (GailTreeView *gailview,
GtkTreeViewColumn *tv_col)
{
- /* Clean GailTreeViewCellInfo data */
+ GailTreeViewCellInfo *cell_info;
+ GHashTableIter iter;
- if (gailview->cell_data != NULL)
+ /* Clean GailTreeViewCellInfo data */
+ g_hash_table_iter_init (&iter, gailview->cell_info_by_index);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cell_info))
{
- GailTreeViewCellInfo *cell_info;
- GList *cur_list, *temp_list;
-
- temp_list = gailview->cell_data;
-
- while (temp_list != NULL)
+ /*
+ * If the cell has become invalid because the column tv_col
+ * has been removed, then set the cell's state to ATK_STATE_DEFUNCT
+ * and remove the cell from gailview->cell_data.
+ */
+ if (cell_info->cell_col_ref == tv_col)
{
- cur_list = temp_list;
- cell_info = temp_list->data;
- temp_list = temp_list->next;
-
- /*
- * If the cell has become invalid because the column tv_col
- * has been removed, then set the cell's state to ATK_STATE_DEFUNCT
- * and remove the cell from gailview->cell_data.
- */
- if (cell_info->cell_col_ref == tv_col)
- {
- clean_cell_info (gailview, cur_list);
- }
+ clean_cell_info (gailview, cell_info);
}
}
}
@@ -3631,12 +3576,11 @@ static gboolean
garbage_collect_cell_data (gpointer data)
{
GailTreeView *tree_view;
- GList *temp_list, *list;
GailTreeViewCellInfo *cell_info;
+ GHashTableIter iter;
g_assert (GAIL_IS_TREE_VIEW (data));
tree_view = (GailTreeView *)data;
- list = g_list_copy (tree_view->cell_data);
tree_view->garbage_collection_pending = FALSE;
if (tree_view->idle_garbage_collect_id != 0)
@@ -3646,22 +3590,18 @@ garbage_collect_cell_data (gpointer data)
}
/* Must loop through them all */
- temp_list = list;
- while (temp_list != NULL)
+ g_hash_table_iter_init (&iter, tree_view->cell_info_by_index);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
{
- cell_info = temp_list->data;
if (!cell_info->in_use)
{
/* g_object_unref (cell_info->cell); */
- tree_view->cell_data = g_list_remove (tree_view->cell_data,
- cell_info);
if (cell_info->cell_row_ref)
gtk_tree_row_reference_free (cell_info->cell_row_ref);
g_free (cell_info);
+ g_hash_table_iter_remove (&iter);
}
- temp_list = temp_list->next;
}
- g_list_free (list);
return tree_view->garbage_collection_pending;
}
@@ -3684,63 +3624,58 @@ traverse_cells (GailTreeView *tree_view,
gboolean set_stale,
gboolean inc_row)
{
- if (tree_view->cell_data != NULL)
- {
- GailTreeViewCellInfo *cell_info;
- GtkTreeView *gtk_tree_view;
- GList *temp_list;
- GtkWidget *widget;
+ GailTreeViewCellInfo *cell_info;
+ GtkTreeView *gtk_tree_view;
+ GtkWidget *widget;
+ GHashTableIter iter;
- g_assert (GTK_IS_ACCESSIBLE (tree_view));
+ g_assert (GTK_IS_ACCESSIBLE (tree_view));
- widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (tree_view));
- if (!widget)
- /* Widget is being deleted */
- return;
+ widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (tree_view));
+ if (!widget)
+ /* Widget is being deleted */
+ return;
- gtk_tree_view = GTK_TREE_VIEW (widget);
- temp_list = tree_view->cell_data;
+ gtk_tree_view = GTK_TREE_VIEW (widget);
- /* Must loop through them all */
- while (temp_list != NULL)
- {
- GtkTreePath *row_path;
- gboolean act_on_cell;
+ /* Must loop through them all */
+ g_hash_table_iter_init (&iter, tree_view->cell_info_by_index);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&cell_info))
+ {
+ GtkTreePath *row_path;
+ gboolean act_on_cell;
- cell_info = temp_list->data;
- temp_list = temp_list->next;
+ if (cell_info->in_use)
+ {
+ row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+ g_return_if_fail (row_path != NULL);
+ if (tree_path == NULL)
+ act_on_cell = TRUE;
+ else
+ {
+ gint comparison;
- if (cell_info->in_use)
- {
- row_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
- g_return_if_fail (row_path != NULL);
- if (tree_path == NULL)
- act_on_cell = TRUE;
- else
- {
- gint comparison;
-
- comparison = gtk_tree_path_compare (row_path, tree_path);
- if ((comparison > 0) ||
- (comparison == 0 && inc_row))
- act_on_cell = TRUE;
- else
- act_on_cell = FALSE;
- }
- if (!cell_info->in_use) g_warning ("warning: cell info destroyed during traversal");
- if (act_on_cell && cell_info->in_use)
- {
- if (set_stale)
- gail_cell_add_state (cell_info->cell, ATK_STATE_STALE, TRUE);
- set_cell_visibility (gtk_tree_view,
- cell_info->cell,
- cell_info->cell_col_ref,
- row_path, TRUE);
- }
- gtk_tree_path_free (row_path);
- }
- }
+ comparison = gtk_tree_path_compare (row_path, tree_path);
+ if ((comparison > 0) ||
+ (comparison == 0 && inc_row))
+ act_on_cell = TRUE;
+ else
+ act_on_cell = FALSE;
+ }
+ if (!cell_info->in_use) g_warning ("warning: cell info destroyed during traversal");
+ if (act_on_cell && cell_info->in_use)
+ {
+ if (set_stale)
+ gail_cell_add_state (cell_info->cell, ATK_STATE_STALE, TRUE);
+ set_cell_visibility (gtk_tree_view,
+ cell_info->cell,
+ cell_info->cell_col_ref,
+ row_path, TRUE);
+ }
+ gtk_tree_path_free (row_path);
+ }
}
+
g_signal_emit_by_name (tree_view, "visible-data-changed");
}
@@ -3783,95 +3718,85 @@ set_expand_state (GtkTreeView *tree_view,
GtkTreePath *tree_path,
gboolean set_on_ancestor)
{
- if (gailview->cell_data != NULL)
+ GtkTreeViewColumn *expander_tv;
+ GailTreeViewCellInfo *cell_info;
+ GtkTreePath *cell_path;
+ GtkTreeIter iter;
+ gboolean found;
+ GHashTableIter hash_iter;
+
+ g_hash_table_iter_init (&hash_iter, gailview->cell_info_by_index);
+ while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer *) &cell_info))
{
- GtkTreeViewColumn *expander_tv;
- GailTreeViewCellInfo *cell_info;
- GList *temp_list;
- GtkTreePath *cell_path;
- GtkTreeIter iter;
- gboolean found;
+ if (cell_info->in_use)
+ {
+ cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
+ found = FALSE;
- temp_list = gailview->cell_data;
+ if (cell_path != NULL)
+ {
+ GailCell *cell = GAIL_CELL (cell_info->cell);
- while (temp_list != NULL)
- {
- cell_info = temp_list->data;
- temp_list = temp_list->next;
- if (cell_info->in_use)
- {
- cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
- found = FALSE;
-
- if (cell_path != NULL)
- {
- GailCell *cell = GAIL_CELL (cell_info->cell);
-
- expander_tv = gtk_tree_view_get_expander_column (tree_view);
-
- /*
- * Only set state for the cell that is in the column with the
- * expander toggle
- */
- if (expander_tv == cell_info->cell_col_ref)
- {
- if (tree_path && gtk_tree_path_compare (cell_path, tree_path) == 0)
- found = TRUE;
- else if (set_on_ancestor &&
- gtk_tree_path_get_depth (cell_path) <
- gtk_tree_path_get_depth (tree_path) &&
- gtk_tree_path_is_ancestor (cell_path, tree_path) == 1)
- /* Only set if set_on_ancestor was passed in as TRUE */
- found = TRUE;
- }
-
- /*
- * Set ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED
- * for ancestors and found cells.
- */
- if (found)
- {
- /*
- * Must check against cell_path since cell_path
- * can be equal to or an ancestor of tree_path.
- */
- gtk_tree_model_get_iter (tree_model, &iter, cell_path);
-
- /* Set or unset ATK_STATE_EXPANDABLE as appropriate */
- if (gtk_tree_model_iter_has_child (tree_model, &iter))
- {
- set_cell_expandable (cell);
-
- if (gtk_tree_view_row_expanded (tree_view, cell_path))
- gail_cell_add_state (cell, ATK_STATE_EXPANDED, TRUE);
- else
- gail_cell_remove_state (cell,
- ATK_STATE_EXPANDED, TRUE);
- }
- else
- {
- gail_cell_remove_state (cell,
- ATK_STATE_EXPANDED, TRUE);
- if (gail_cell_remove_state (cell,
- ATK_STATE_EXPANDABLE, TRUE))
- /* The state may have been propagated to the container cell */
- if (!GAIL_IS_CONTAINER_CELL (cell))
- gail_cell_remove_action_by_name (cell,
- "expand or contract");
- }
-
- /*
- * We assume that each cell in the cache once and
- * a container cell is before its child cells so we are
- * finished if set_on_ancestor is not set to TRUE.
- */
- if (!set_on_ancestor)
- break;
- }
- }
- gtk_tree_path_free (cell_path);
- }
- }
+ expander_tv = gtk_tree_view_get_expander_column (tree_view);
+
+ /* Only set state for the cell that is in the column with the
+ * expander toggle
+ */
+ if (expander_tv == cell_info->cell_col_ref)
+ {
+ if (tree_path && gtk_tree_path_compare (cell_path, tree_path) == 0)
+ found = TRUE;
+ else if (set_on_ancestor &&
+ gtk_tree_path_get_depth (cell_path) <
+ gtk_tree_path_get_depth (tree_path) &&
+ gtk_tree_path_is_ancestor (cell_path, tree_path) == 1)
+ /* Only set if set_on_ancestor was passed in as TRUE */
+ found = TRUE;
+ }
+
+ /* Set ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED
+ * for ancestors and found cells.
+ */
+ if (found)
+ {
+ /* Must check against cell_path since cell_path
+ * can be equal to or an ancestor of tree_path.
+ */
+ gtk_tree_model_get_iter (tree_model, &iter, cell_path);
+
+ /* Set or unset ATK_STATE_EXPANDABLE as appropriate */
+ if (gtk_tree_model_iter_has_child (tree_model, &iter))
+ {
+ set_cell_expandable (cell);
+
+ if (gtk_tree_view_row_expanded (tree_view, cell_path))
+ gail_cell_add_state (cell, ATK_STATE_EXPANDED, TRUE);
+ else
+ gail_cell_remove_state (cell,
+ ATK_STATE_EXPANDED, TRUE);
+ }
+ else
+ {
+ gail_cell_remove_state (cell,
+ ATK_STATE_EXPANDED, TRUE);
+ if (gail_cell_remove_state (cell,
+ ATK_STATE_EXPANDABLE, TRUE))
+ /* The state may have been propagated to the container cell */
+ if (!GAIL_IS_CONTAINER_CELL (cell))
+ gail_cell_remove_action_by_name (cell,
+ "expand or contract");
+ }
+
+ /* We assume that each cell in the cache once and
+ * a container cell is before its child cells so we are
+ * finished if set_on_ancestor is not set to TRUE.
+ */
+ if (!set_on_ancestor)
+ break;
+ }
+ }
+ gtk_tree_path_free (cell_path);
+ }
}
}
@@ -3912,7 +3837,7 @@ toggle_cell_expanded (GailCell *cell)
if (GAIL_IS_CONTAINER_CELL (parent))
parent = atk_object_get_parent (parent);
- cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+ cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, TRUE);
gail_return_if_fail (cell_info);
gail_return_if_fail (cell_info->cell_col_ref);
gail_return_if_fail (cell_info->cell_row_ref);
@@ -3948,7 +3873,7 @@ toggle_cell_toggled (GailCell *cell)
parent = atk_object_get_parent (parent);
}
- cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+ cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, TRUE);
gail_return_if_fail (cell_info);
gail_return_if_fail (cell_info->cell_col_ref);
gail_return_if_fail (cell_info->cell_row_ref);
@@ -3996,7 +3921,7 @@ edit_cell (GailCell *cell)
if (GAIL_IS_CONTAINER_CELL (parent))
parent = atk_object_get_parent (parent);
- cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+ cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, TRUE);
gail_return_if_fail (cell_info);
gail_return_if_fail (cell_info->cell_col_ref);
gail_return_if_fail (cell_info->cell_row_ref);
@@ -4022,7 +3947,7 @@ activate_cell (GailCell *cell)
if (GAIL_IS_CONTAINER_CELL (parent))
parent = atk_object_get_parent (parent);
- cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+ cell_info = find_cell_info (GAIL_TREE_VIEW (parent), cell, TRUE);
gail_return_if_fail (cell_info);
gail_return_if_fail (cell_info->cell_col_ref);
gail_return_if_fail (cell_info->cell_row_ref);
@@ -4053,24 +3978,6 @@ cell_destroyed (gpointer data)
}
}
-#if 0
-static void
-cell_info_remove (GailTreeView *tree_view,
- GailCell *cell)
-{
- GailTreeViewCellInfo *info;
- GList *temp_list;
-
- info = find_cell_info (tree_view, cell, &temp_list, FALSE);
- if (info)
- {
- info->in_use = FALSE;
- return;
- }
- g_warning ("No cell removed in cell_info_remove\n");
-}
-#endif
-
static void
cell_info_get_index (GtkTreeView *tree_view,
GailTreeViewCellInfo *info,
@@ -4088,8 +3995,8 @@ cell_info_get_index (GtkTreeView *tree_view,
}
static void
-cell_info_new (GailTreeView *gailview,
- GtkTreeModel *tree_model,
+cell_info_new (GailTreeView *gailview,
+ GtkTreeModel *tree_model,
GtkTreePath *path,
GtkTreeViewColumn *tv_col,
GailCell *cell )
@@ -4105,8 +4012,8 @@ cell_info_new (GailTreeView *gailview,
cell_info->cell = cell;
cell_info->in_use = TRUE; /* if we've created it, assume it's in use */
cell_info->view = gailview;
- gailview->cell_data = g_list_append (gailview->cell_data, cell_info);
-
+ g_hash_table_insert (gailview->cell_info_by_index, &cell->index, cell_info);
+
/* Setup weak reference notification */
g_object_weak_ref (G_OBJECT (cell),
@@ -4119,35 +4026,11 @@ find_cell (GailTreeView *gailview,
gint index)
{
GailTreeViewCellInfo *info;
- GtkTreeView *tree_view;
- GList *cell_list;
- GList *l;
- gint real_index;
- gboolean needs_cleaning = FALSE;
GailCell *retval = NULL;
- tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (gailview)));
- cell_list = gailview->cell_data;
-
- for (l = cell_list; l; l = l->next)
- {
- info = (GailTreeViewCellInfo *) (l->data);
- if (info->in_use)
- {
- cell_info_get_index (tree_view, info, &real_index);
- if (index == real_index)
- {
- retval = info->cell;
- break;
- }
- }
- else
- {
- needs_cleaning = TRUE;
- }
- }
- if (needs_cleaning)
- garbage_collect_cell_data (gailview);
+ info = g_hash_table_lookup (gailview->cell_info_by_index, &index);
+ if (info != NULL)
+ retval = info->cell;
return retval;
}
@@ -4158,20 +4041,23 @@ refresh_cell_index (GailCell *cell)
GailTreeViewCellInfo *info;
AtkObject *parent;
GtkTreeView *tree_view;
+ GailTreeView *gailview;
gint index;
parent = atk_object_get_parent (ATK_OBJECT (cell));
gail_return_if_fail (GAIL_IS_TREE_VIEW (parent));
+ gailview = GAIL_TREE_VIEW (parent);
tree_view = GTK_TREE_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (parent)));
/* Find this cell in the GailTreeView's cache */
- info = find_cell_info (GAIL_TREE_VIEW (parent), cell, NULL, TRUE);
+ info = find_cell_info (gailview, cell, TRUE);
gail_return_if_fail (info);
cell_info_get_index (tree_view, info, &index);
cell->index = index;
+ g_hash_table_insert (gailview->cell_info_by_index, &index, info);
}
static void
@@ -4206,7 +4092,7 @@ connect_model_signals (GtkTreeView *view,
}
static void
-disconnect_model_signals (GailTreeView *view)
+disconnect_model_signals (GailTreeView *view)
{
GObject *obj;
GtkWidget *widget;
@@ -4222,7 +4108,8 @@ disconnect_model_signals (GailTreeView *view)
static void
clear_cached_data (GailTreeView *view)
{
- GList *temp_list;
+ GailTreeViewCellInfo *cell_info;
+ GHashTableIter iter;
if (view->row_data)
{
@@ -4230,7 +4117,7 @@ clear_cached_data (GailTreeView *view)
gint i;
/*
- * Since the third argument to free_row_info is FALSE, we don't remove
+ * Since the third argument to free_row_info is FALSE, we don't remove
* the element. Therefore it is safe to loop forward.
*/
for (i = 0; i < array->len; i++)
@@ -4241,19 +4128,15 @@ clear_cached_data (GailTreeView *view)
view->row_data = NULL;
}
- if (view->cell_data)
+ /* Must loop through them all */
+ g_hash_table_iter_init (&iter, view->cell_info_by_index);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cell_info))
{
- /* Must loop through them all */
- for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
- {
- clean_cell_info (view, temp_list);
- }
+ clean_cell_info (view, cell_info);
}
+
+ /* FIXME: seems pretty inefficient to loop again here */
garbage_collect_cell_data (view);
- if (view->cell_data)
- g_list_free (view->cell_data);
-
- view->cell_data = NULL;
}
/*
@@ -4269,37 +4152,45 @@ get_column_number (GtkTreeView *tree_view,
GtkTreeViewColumn *column,
gboolean visible)
{
- GList *temp_list, *column_list;
GtkTreeViewColumn *tv_column;
gint ret_val;
+ gint i;
+ AtkObject *atk_obj;
+ GailTreeView *gailview;
+
+ atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+ gailview = GAIL_TREE_VIEW (atk_obj);
- column_list = gtk_tree_view_get_columns (tree_view);
ret_val = 0;
- for (temp_list = column_list; temp_list; temp_list = temp_list->next)
+ for (i = 0; i < gailview->col_data->len; i++)
{
- tv_column = GTK_TREE_VIEW_COLUMN (temp_list->data);
+ tv_column = g_array_index (gailview->col_data, GtkTreeViewColumn *, i);
if (tv_column == column)
break;
if (!visible || gtk_tree_view_column_get_visible (tv_column))
ret_val++;
}
- if (temp_list == NULL)
+ if (i == gailview->col_data->len)
{
ret_val = -1;
}
- g_list_free (column_list);
+
return ret_val;
-}
+}
static gint
-get_index (GtkTreeView *tree_view,
- GtkTreePath *path,
- gint actual_column)
+get_index (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ gint actual_column)
{
+ AtkObject *atk_obj;
+ GailTreeView *gailview;
gint depth = 0;
gint index = 1;
gint *indices = NULL;
+ atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+ gailview = GAIL_TREE_VIEW (atk_obj);
if (path)
{
@@ -4321,7 +4212,7 @@ get_index (GtkTreeView *tree_view,
if (path)
index += indices[depth-1];
- index *= get_n_actual_columns (tree_view);
+ index *= gailview->n_cols;
index += actual_column;
return index;
}
@@ -4356,6 +4247,9 @@ count_rows (GtkTreeModel *model,
gtk_tree_path_to_string (gtk_tree_model_get_path (model, iter)));
#endif
+ if (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY)
+ return;
+
if (level >= depth)
return;
@@ -4527,20 +4421,7 @@ get_tree_path_from_row_index (GtkTreeModel *model,
*tree_path = NULL;
return FALSE;
}
- }
-}
-
-/*
- * This function returns the number of rows, including those which are collapsed
- */
-static gint
-get_row_count (GtkTreeModel *model)
-{
- gint n_rows = 1;
-
- count_rows (model, NULL, NULL, &n_rows, 0, G_MAXINT);
-
- return n_rows;
+ }
}
static gboolean
@@ -4550,14 +4431,17 @@ get_path_column_from_index (GtkTreeView *tree_view,
GtkTreeViewColumn **column)
{
GtkTreeModel *tree_model;
- gint n_columns;
+ AtkObject *atk_obj;
+ GailTreeView *gailview;
+
+ atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
+ gailview = GAIL_TREE_VIEW (atk_obj);
tree_model = gtk_tree_view_get_model (tree_view);
- n_columns = get_n_actual_columns (tree_view);
- if (n_columns == 0)
+ if (gailview->n_cols == 0)
return FALSE;
/* First row is the column headers */
- index -= n_columns;
+ index -= gailview->n_cols;
if (index < 0)
return FALSE;
@@ -4566,7 +4450,7 @@ get_path_column_from_index (GtkTreeView *tree_view,
gint row_index;
gboolean retval;
- row_index = index / n_columns;
+ row_index = index / gailview->n_cols;
retval = get_tree_path_from_row_index (tree_model, row_index, path);
gail_return_val_if_fail (retval, FALSE);
if (*path == NULL)
@@ -4575,7 +4459,7 @@ get_path_column_from_index (GtkTreeView *tree_view,
if (column)
{
- *column = gtk_tree_view_get_column (tree_view, index % n_columns);
+ *column = gtk_tree_view_get_column (tree_view, index % gailview->n_cols);
if (*column == NULL)
{
if (path)
@@ -4603,21 +4487,17 @@ set_cell_expandable (GailCell *cell)
static GailTreeViewCellInfo*
find_cell_info (GailTreeView *view,
GailCell *cell,
- GList** list,
- gboolean live_only)
+ gboolean live_only)
{
- GList *temp_list;
GailTreeViewCellInfo *cell_info;
+ GHashTableIter iter;
- for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
+ /* Clean GailTreeViewCellInfo data */
+ g_hash_table_iter_init (&iter, view->cell_info_by_index);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cell_info))
{
- cell_info = (GailTreeViewCellInfo *) temp_list->data;
if (cell_info->cell == cell && (!live_only || cell_info->in_use))
- {
- if (list)
- *list = temp_list;
- return cell_info;
- }
+ return cell_info;
}
return NULL;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]