aboutsummaryrefslogtreecommitdiffstats
path: root/a11y
diff options
context:
space:
mode:
Diffstat (limited to 'a11y')
-rw-r--r--a11y/e-table/gal-a11y-e-table-item.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/a11y/e-table/gal-a11y-e-table-item.c b/a11y/e-table/gal-a11y-e-table-item.c
index c67428ffb9..4884a95ba6 100644
--- a/a11y/e-table/gal-a11y-e-table-item.c
+++ b/a11y/e-table/gal-a11y-e-table-item.c
@@ -38,6 +38,7 @@ struct _GalA11yETableItemPrivate {
gpointer *cell_data;
int selection_change_id;
int cursor_change_id;
+ ETableCol ** columns;
};
#if 0
@@ -91,6 +92,11 @@ eti_dispose (GObject *object)
priv->cell_data = NULL;
}
+ if (priv->columns) {
+ g_free(priv->columns);
+ priv->columns = NULL;
+ }
+
if (parent_class->dispose)
parent_class->dispose (object);
}
@@ -706,6 +712,150 @@ eti_rows_deleted (ETableModel * model, int row, int count,
g_signal_emit_by_name (table_item, "visible-data-changed");
}
+enum {
+ ETI_HEADER_UNCHANGED = 0,
+ ETI_HEADER_REORDERED,
+ ETI_HEADER_NEW_ADDED,
+ ETI_HEADER_REMOVED,
+};
+
+/*
+ * 1. Check what actually happened: column reorder, remove or add
+ * 2. Update cache
+ * 3. Emit signals
+ */
+static void
+eti_header_structure_changed (ETableHeader *eth, AtkObject *a11y)
+{
+
+ gboolean reorder_found=FALSE, added_found=FALSE, removed_found=FALSE;
+ GalA11yETableItem * a11y_item;
+ ETableCol ** cols, **prev_cols;
+ GalA11yETableItemPrivate *priv;
+ gint *state = NULL, *prev_state = NULL, *reorder = NULL;
+ gint i,j,n_rows,n_cols, prev_n_cols;
+ gpointer * cell_data, * tmp;
+
+ a11y_item = GAL_A11Y_E_TABLE_ITEM (a11y);
+ priv = GET_PRIVATE (a11y_item);
+
+ g_return_if_fail (priv && priv->cell_data);
+ cell_data = priv->cell_data ;
+
+ /* Assume rows do not changed. */
+ n_rows = priv->rows;
+
+ prev_n_cols = priv->cols;
+ prev_cols = priv->columns;
+
+ cols = e_table_header_get_columns (eth);
+ n_cols = eth->col_count;
+
+ g_return_if_fail (cols && prev_cols && n_cols > 0);
+
+ /* Init to ETI_HEADER_UNCHANGED. */
+ state = g_malloc0 (sizeof (gint) * n_cols);
+ prev_state = g_malloc0 (sizeof (gint) * prev_n_cols);
+ reorder = g_malloc0 (sizeof (gint) * n_cols);
+
+ /* Compare with previously saved column headers. */
+ for ( i = 0 ; i < n_cols && cols[i]; i ++ ) {
+ for ( j = 0 ; j < prev_n_cols && prev_cols[j]; j ++ ) {
+ if ( prev_cols [j] == cols[i] && i != j ) {
+
+ reorder_found = TRUE;
+ state [i] = ETI_HEADER_REORDERED;
+ reorder [i] = j;
+
+ break;
+ } else if (prev_cols[j] == cols[i]) {
+ /* OK, this column is not changed. */
+ break;
+ }
+ }
+
+ /* cols[i] is new added column. */
+ if ( j == prev_n_cols ) {
+ gint row;
+
+ added_found = TRUE;
+ state[i] = ETI_HEADER_NEW_ADDED;
+ }
+ }
+
+ /* Now try to find if there are removed columns. */
+ for (i = 0 ; i < prev_n_cols && prev_cols[i]; i ++) {
+ for (j = 0 ; j < n_cols && cols[j]; j ++)
+ if ( prev_cols [j] == cols[i] )
+ break;
+
+ /* Removed columns found. */
+ if ( j == n_cols ) {
+ removed_found = TRUE;
+ prev_state[j] = ETI_HEADER_REMOVED;
+ }
+ }
+
+ /* If nothing interesting just return. */
+ if (!reorder_found && !added_found && !removed_found)
+ return;
+
+ /* Now update our cache. */
+ tmp = g_malloc0 (n_rows*n_cols*sizeof(gpointer));
+ g_return_if_fail (tmp);
+
+ for (i = 0 ; i < n_rows; i ++) {
+ for ( j = 0 ; j < n_cols; j ++ ) {
+ if ( state[j] == ETI_HEADER_REORDERED ) {
+ tmp [i*n_cols+j] = cell_data[i*prev_n_cols+reorder[j]];
+ if (tmp[i*n_cols+j] && ATK_IS_OBJECT(tmp[i*n_cols+j])) {
+ GAL_A11Y_E_CELL(tmp[i*n_cols+j])->view_col = j;
+ }
+ } else if (state[j] == ETI_HEADER_UNCHANGED) {
+ tmp [i*n_cols+j] = cell_data[i*prev_n_cols+j];
+ } /* else: new added, keep NULL. */
+ }
+ }
+
+ g_free (cell_data);
+ priv->cell_data = tmp;
+
+ /* Emit signals */
+ if (reorder_found)
+ g_signal_emit_by_name (G_OBJECT(a11y_item), "column_reordered");
+
+
+ if (removed_found) {
+ for (i = 0; i < prev_n_cols; i ++ ) {
+ if (prev_state[i] == ETI_HEADER_REMOVED) {
+ g_signal_emit_by_name (G_OBJECT(a11y_item), "column-deleted", i, 1);
+ for (j = 0 ; j < n_rows; j ++)
+ g_signal_emit_by_name (G_OBJECT(a11y_item), "children_changed::remove", (j*prev_n_cols+i), NULL, NULL);
+ }
+ }
+ }
+
+ if (added_found) {
+ for ( i = 0; i < n_cols; i ++ ) {
+ if (state[i] == ETI_HEADER_NEW_ADDED) {
+ g_signal_emit_by_name (G_OBJECT(a11y_item), "column-inserted", i, 1);
+ for (j = 0 ; j < n_rows; j ++)
+ g_signal_emit_by_name (G_OBJECT(a11y_item), "children_changed::add", (j*n_cols+i), NULL, NULL);
+ }
+ }
+ }
+
+ priv->cols = n_cols;
+
+ g_free (state);
+ g_free (reorder);
+ g_free (prev_state);
+
+ g_free (priv->columns);
+ priv->columns = cols;
+}
+
+
static void
eti_real_initialize (AtkObject *obj,
gpointer data)
@@ -724,6 +874,9 @@ eti_real_initialize (AtkObject *obj,
g_signal_connect (model, "model-rows-deleted",
G_CALLBACK (eti_rows_deleted),
obj);
+ g_signal_connect (G_OBJECT (eti->header), "structure_change",
+ G_CALLBACK (eti_header_structure_changed), obj);
+
}
static void
@@ -869,6 +1022,10 @@ gal_a11y_e_table_item_new (AtkObject *parent,
if ( GET_PRIVATE (a11y) == NULL)
return NULL;
+ GET_PRIVATE (a11y)->columns = e_table_header_get_columns (item->header);
+ if ( GET_PRIVATE (a11y)->columns == NULL)
+ return NULL;
+
if (item) {
g_signal_connect (G_OBJECT(item), "selection_model_removed",
G_CALLBACK (eti_a11y_selection_model_removed_cb), NULL);