mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-06 19:00:12 +00:00
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)
This commit is contained in:
parent
23bc606c79
commit
2deeab4c4f
@ -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;
|
||||
@ -1275,10 +1261,9 @@ gail_tree_view_get_n_rows (AtkTable *table)
|
||||
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,22 +1278,6 @@ 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
|
||||
gail_tree_view_get_n_columns (AtkTable *table)
|
||||
{
|
||||
@ -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,16 +2660,16 @@ 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)
|
||||
{
|
||||
cell_path = gtk_tree_row_reference_get_path (cell_info->cell_row_ref);
|
||||
@ -2741,18 +2705,18 @@ 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)
|
||||
{
|
||||
tv_col = cell_info->cell_col_ref;
|
||||
@ -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,33 +3503,21 @@ 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)
|
||||
{
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
clean_cell_info (gailview, cur_list);
|
||||
clean_cell_info (gailview, cell_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3570,27 +3525,18 @@ clean_rows (GailTreeView *gailview)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clean_cols (GailTreeView *gailview,
|
||||
GtkTreeViewColumn *tv_col)
|
||||
{
|
||||
/* Clean GailTreeViewCellInfo data */
|
||||
|
||||
if (gailview->cell_data != NULL)
|
||||
{
|
||||
GailTreeViewCellInfo *cell_info;
|
||||
GList *cur_list, *temp_list;
|
||||
GHashTableIter iter;
|
||||
|
||||
temp_list = gailview->cell_data;
|
||||
|
||||
while (temp_list != 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))
|
||||
{
|
||||
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
|
||||
@ -3598,8 +3544,7 @@ clean_cols (GailTreeView *gailview,
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@ -3683,13 +3623,11 @@ traverse_cells (GailTreeView *tree_view,
|
||||
GtkTreePath *tree_path,
|
||||
gboolean set_stale,
|
||||
gboolean inc_row)
|
||||
{
|
||||
if (tree_view->cell_data != NULL)
|
||||
{
|
||||
GailTreeViewCellInfo *cell_info;
|
||||
GtkTreeView *gtk_tree_view;
|
||||
GList *temp_list;
|
||||
GtkWidget *widget;
|
||||
GHashTableIter iter;
|
||||
|
||||
g_assert (GTK_IS_ACCESSIBLE (tree_view));
|
||||
|
||||
@ -3699,17 +3637,14 @@ traverse_cells (GailTreeView *tree_view,
|
||||
return;
|
||||
|
||||
gtk_tree_view = GTK_TREE_VIEW (widget);
|
||||
temp_list = tree_view->cell_data;
|
||||
|
||||
/* Must loop through them all */
|
||||
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))
|
||||
{
|
||||
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);
|
||||
@ -3740,7 +3675,7 @@ traverse_cells (GailTreeView *tree_view,
|
||||
gtk_tree_path_free (row_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_emit_by_name (tree_view, "visible-data-changed");
|
||||
}
|
||||
|
||||
@ -3782,22 +3717,17 @@ set_expand_state (GtkTreeView *tree_view,
|
||||
GailTreeView *gailview,
|
||||
GtkTreePath *tree_path,
|
||||
gboolean set_on_ancestor)
|
||||
{
|
||||
if (gailview->cell_data != NULL)
|
||||
{
|
||||
GtkTreeViewColumn *expander_tv;
|
||||
GailTreeViewCellInfo *cell_info;
|
||||
GList *temp_list;
|
||||
GtkTreePath *cell_path;
|
||||
GtkTreeIter iter;
|
||||
gboolean found;
|
||||
GHashTableIter hash_iter;
|
||||
|
||||
temp_list = gailview->cell_data;
|
||||
|
||||
while (temp_list != NULL)
|
||||
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 = 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);
|
||||
@ -3809,8 +3739,7 @@ set_expand_state (GtkTreeView *tree_view,
|
||||
|
||||
expander_tv = gtk_tree_view_get_expander_column (tree_view);
|
||||
|
||||
/*
|
||||
* Only set state for the cell that is in the column with the
|
||||
/* Only set state for the cell that is in the column with the
|
||||
* expander toggle
|
||||
*/
|
||||
if (expander_tv == cell_info->cell_col_ref)
|
||||
@ -3825,14 +3754,12 @@ set_expand_state (GtkTreeView *tree_view,
|
||||
found = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED
|
||||
/* Set ATK_STATE_EXPANDABLE and ATK_STATE_EXPANDED
|
||||
* for ancestors and found cells.
|
||||
*/
|
||||
if (found)
|
||||
{
|
||||
/*
|
||||
* Must check against cell_path since cell_path
|
||||
/* 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);
|
||||
@ -3860,8 +3787,7 @@ set_expand_state (GtkTreeView *tree_view,
|
||||
"expand or contract");
|
||||
}
|
||||
|
||||
/*
|
||||
* We assume that each cell in the cache once and
|
||||
/* 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.
|
||||
*/
|
||||
@ -3873,7 +3799,6 @@ set_expand_state (GtkTreeView *tree_view,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
@ -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,
|
||||
@ -4105,7 +4012,7 @@ 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 */
|
||||
|
||||
@ -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)
|
||||
{
|
||||
info = g_hash_table_lookup (gailview->cell_info_by_index, &index);
|
||||
if (info != NULL)
|
||||
retval = info->cell;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
needs_cleaning = TRUE;
|
||||
}
|
||||
}
|
||||
if (needs_cleaning)
|
||||
garbage_collect_cell_data (gailview);
|
||||
|
||||
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
|
||||
@ -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)
|
||||
{
|
||||
@ -4241,19 +4128,15 @@ clear_cached_data (GailTreeView *view)
|
||||
view->row_data = NULL;
|
||||
}
|
||||
|
||||
if (view->cell_data)
|
||||
{
|
||||
/* Must loop through them all */
|
||||
for (temp_list = view->cell_data; temp_list; temp_list = temp_list->next)
|
||||
g_hash_table_iter_init (&iter, view->cell_info_by_index);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cell_info))
|
||||
{
|
||||
clean_cell_info (view, temp_list);
|
||||
clean_cell_info (view, cell_info);
|
||||
}
|
||||
}
|
||||
garbage_collect_cell_data (view);
|
||||
if (view->cell_data)
|
||||
g_list_free (view->cell_data);
|
||||
|
||||
view->cell_data = NULL;
|
||||
/* FIXME: seems pretty inefficient to loop again here */
|
||||
garbage_collect_cell_data (view);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4269,25 +4152,29 @@ 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;
|
||||
}
|
||||
|
||||
@ -4296,10 +4183,14 @@ 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;
|
||||
|
||||
@ -4530,19 +4424,6 @@ get_tree_path_from_row_index (GtkTreeModel *model,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
get_path_column_from_index (GtkTreeView *tree_view,
|
||||
gint index,
|
||||
@ -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,22 +4487,18 @@ set_cell_expandable (GailCell *cell)
|
||||
static GailTreeViewCellInfo*
|
||||
find_cell_info (GailTreeView *view,
|
||||
GailCell *cell,
|
||||
GList** list,
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user