evolution-3.6.4/widgets/table/gal-a11y-e-table-item.c

No issues found

   1 /*
   2  * This program is free software; you can redistribute it and/or
   3  * modify it under the terms of the GNU Lesser General Public
   4  * License as published by the Free Software Foundation; either
   5  * version 2 of the License, or (at your option) version 3.
   6  *
   7  * This program is distributed in the hope that it will be useful,
   8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10  * Lesser General Public License for more details.
  11  *
  12  * You should have received a copy of the GNU Lesser General Public
  13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  14  *
  15  *
  16  * Authors:
  17  *		Christopher James Lahey <clahey@ximian.com>
  18  *		Bolian Yin <bolian.yin@sun.com>
  19  *
  20  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  21  *
  22  */
  23 
  24 #ifdef HAVE_CONFIG_H
  25 #include <config.h>
  26 #endif
  27 
  28 #include <string.h>
  29 
  30 #include <atk/atk.h>
  31 
  32 #include "a11y/gal-a11y-util.h"
  33 #include "table/e-table-click-to-add.h"
  34 #include "table/e-table-subset.h"
  35 #include "table/e-table.h"
  36 #include "table/e-tree.h"
  37 #include "misc/e-canvas.h"
  38 #include "misc/e-selection-model.h"
  39 
  40 #include "gal-a11y-e-table-item.h"
  41 #include "gal-a11y-e-table-item-factory.h"
  42 #include "gal-a11y-e-table-click-to-add.h"
  43 #include "gal-a11y-e-cell-registry.h"
  44 #include "gal-a11y-e-cell.h"
  45 #include "gal-a11y-e-table-column-header.h"
  46 
  47 static GObjectClass *parent_class;
  48 static AtkComponentIface *component_parent_iface;
  49 static GType parent_type;
  50 static gint priv_offset;
  51 static GQuark		quark_accessible_object = 0;
  52 #define GET_PRIVATE(object) \
  53 	((GalA11yETableItemPrivate *) (((gchar *) object) + priv_offset))
  54 #define PARENT_TYPE (parent_type)
  55 
  56 struct _GalA11yETableItemPrivate {
  57 	ETableItem *item;
  58 	gint cols;
  59 	gint rows;
  60 	gint selection_change_id;
  61 	gint cursor_change_id;
  62 	ETableCol ** columns;
  63 	ESelectionModel *selection;
  64 	AtkStateSet *state_set;
  65 	GtkWidget *widget;
  66 };
  67 
  68 static gboolean gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y,
  69 						     ESelectionModel *selection);
  70 static gboolean gal_a11y_e_table_item_unref_selection (GalA11yETableItem *a11y);
  71 
  72 static AtkObject * eti_ref_at (AtkTable *table, gint row, gint column);
  73 
  74 static void
  75 free_columns (ETableCol **columns)
  76 {
  77 	gint ii;
  78 
  79 	if (!columns)
  80 		return;
  81 
  82 	for (ii = 0; columns[ii]; ii++) {
  83 		g_object_unref (columns[ii]);
  84 	}
  85 
  86 	g_free (columns);
  87 }
  88 
  89 static void
  90 item_finalized (gpointer user_data,
  91                 GObject *gone_item)
  92 {
  93 	GalA11yETableItem *a11y;
  94 	GalA11yETableItemPrivate *priv;
  95 
  96 	a11y = GAL_A11Y_E_TABLE_ITEM (user_data);
  97 	priv = GET_PRIVATE (a11y);
  98 
  99 	priv->item = NULL;
 100 
 101 	atk_state_set_add_state (priv->state_set, ATK_STATE_DEFUNCT);
 102 	atk_object_notify_state_change (ATK_OBJECT (a11y), ATK_STATE_DEFUNCT, TRUE);
 103 
 104 	if (priv->selection)
 105 		gal_a11y_e_table_item_unref_selection (a11y);
 106 
 107 	g_object_unref (a11y);
 108 }
 109 
 110 static AtkStateSet *
 111 eti_ref_state_set (AtkObject *accessible)
 112 {
 113 	GalA11yETableItemPrivate *priv = GET_PRIVATE (accessible);
 114 
 115 	g_object_ref (priv->state_set);
 116 
 117 	return priv->state_set;
 118 }
 119 
 120 inline static gint
 121 view_to_model_row (ETableItem *eti,
 122                    gint row)
 123 {
 124 	if (eti->uses_source_model) {
 125 		ETableSubset *etss = E_TABLE_SUBSET (eti->table_model);
 126 		if (row >= 0 && row < etss->n_map) {
 127 			eti->row_guess = row;
 128 			return etss->map_table[row];
 129 		} else
 130 			return -1;
 131 	} else
 132 		return row;
 133 }
 134 
 135 inline static gint
 136 view_to_model_col (ETableItem *eti,
 137                    gint col)
 138 {
 139 	ETableCol *ecol = e_table_header_get_column (eti->header, col);
 140 	return ecol ? ecol->col_idx : -1;
 141 }
 142 
 143 inline static gint
 144 model_to_view_row (ETableItem *eti,
 145                    gint row)
 146 {
 147 	gint i;
 148 	if (row == -1)
 149 		return -1;
 150 	if (eti->uses_source_model) {
 151 		ETableSubset *etss = E_TABLE_SUBSET (eti->table_model);
 152 		if (eti->row_guess >= 0 && eti->row_guess < etss->n_map) {
 153 			if (etss->map_table[eti->row_guess] == row) {
 154 				return eti->row_guess;
 155 			}
 156 		}
 157 		for (i = 0; i < etss->n_map; i++) {
 158 			if (etss->map_table[i] == row)
 159 				return i;
 160 		}
 161 		return -1;
 162 	} else
 163 		return row;
 164 }
 165 
 166 inline static gint
 167 model_to_view_col (ETableItem *eti,
 168                    gint col)
 169 {
 170 	gint i;
 171 	if (col == -1)
 172 		return -1;
 173 	for (i = 0; i < eti->cols; i++) {
 174 		ETableCol *ecol = e_table_header_get_column (eti->header, i);
 175 		if (ecol->col_idx == col)
 176 			return i;
 177 	}
 178 	return -1;
 179 }
 180 
 181 inline static GObject *
 182 eti_a11y_get_gobject (AtkObject *accessible)
 183 {
 184 	return atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible));
 185 }
 186 
 187 static void
 188 eti_a11y_reset_focus_object (GalA11yETableItem *a11y,
 189                              ETableItem *item,
 190                              gboolean notify)
 191 {
 192 	ESelectionModel * esm;
 193 	gint cursor_row, cursor_col, view_row, view_col;
 194 	AtkObject *cell, *old_cell;
 195 
 196 	esm = item->selection;
 197 	g_return_if_fail (esm);
 198 
 199 	cursor_row = e_selection_model_cursor_row (esm);
 200 	cursor_col = e_selection_model_cursor_col (esm);
 201 
 202 	view_row = model_to_view_row (item, cursor_row);
 203 	view_col = model_to_view_col (item, cursor_col);
 204 
 205 	if (view_row == -1)
 206 		view_row = 0;
 207 	if (view_col == -1)
 208 		view_col = 0;
 209 
 210 	old_cell = (AtkObject *) g_object_get_data (G_OBJECT (a11y), "gail-focus-object");
 211 	if (old_cell && GAL_A11Y_IS_E_CELL (old_cell))
 212 		gal_a11y_e_cell_remove_state (
 213 			GAL_A11Y_E_CELL (old_cell), ATK_STATE_FOCUSED, FALSE);
 214 	if (old_cell)
 215 		g_object_unref (old_cell);
 216 
 217 	cell = eti_ref_at (ATK_TABLE (a11y), view_row, view_col);
 218 
 219 	if (cell != NULL) {
 220 		g_object_set_data (G_OBJECT (a11y), "gail-focus-object", cell);
 221 		gal_a11y_e_cell_add_state (
 222 			GAL_A11Y_E_CELL (cell), ATK_STATE_FOCUSED, FALSE);
 223 	} else
 224 		g_object_set_data (G_OBJECT (a11y), "gail-focus-object", NULL);
 225 
 226 	if (notify && cell)
 227 		atk_focus_tracker_notify (cell);
 228 }
 229 
 230 static void
 231 eti_dispose (GObject *object)
 232 {
 233 	GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (object);
 234 	GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
 235 
 236 	if (priv->columns) {
 237 		free_columns (priv->columns);
 238 		priv->columns = NULL;
 239 	}
 240 
 241 	if (priv->item) {
 242 		g_object_weak_unref (G_OBJECT (priv->item), item_finalized, a11y);
 243 		priv->item = NULL;
 244 	}
 245 
 246 	if (parent_class->dispose)
 247 		parent_class->dispose (object);
 248 }
 249 
 250 /* Static functions */
 251 static gint
 252 eti_get_n_children (AtkObject *accessible)
 253 {
 254 	g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), 0);
 255 	if (!eti_a11y_get_gobject (accessible))
 256 		return 0;
 257 
 258 	return atk_table_get_n_columns (ATK_TABLE (accessible)) *
 259 		(atk_table_get_n_rows (ATK_TABLE (accessible)) + 1);
 260 }
 261 
 262 static AtkObject *
 263 eti_ref_child (AtkObject *accessible,
 264                gint index)
 265 {
 266 	ETableItem *item;
 267 	gint col, row;
 268 
 269 	g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), NULL);
 270 	item = E_TABLE_ITEM (eti_a11y_get_gobject (accessible));
 271 	if (!item)
 272 		return NULL;
 273 
 274 	if (index < item->cols) {
 275 		ETableCol *ecol;
 276 		AtkObject *child;
 277 
 278 		ecol = e_table_header_get_column (item->header, index);
 279 		child = gal_a11y_e_table_column_header_new (ecol, item);
 280 		return child;
 281 	}
 282 	index -= item->cols;
 283 
 284 	col = index % item->cols;
 285 	row = index / item->cols;
 286 
 287 	return eti_ref_at (ATK_TABLE (accessible), row, col);
 288 }
 289 
 290 static void
 291 eti_get_extents (AtkComponent *component,
 292                  gint *x,
 293                  gint *y,
 294                  gint *width,
 295                  gint *height,
 296                  AtkCoordType coord_type)
 297 {
 298 	ETableItem *item;
 299 	AtkObject *parent;
 300 
 301 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component)));
 302 	if (!item)
 303 		return;
 304 
 305 	parent = ATK_OBJECT (component)->accessible_parent;
 306 	if (parent && ATK_IS_COMPONENT (parent))
 307 		atk_component_get_extents (
 308 			ATK_COMPONENT (parent),
 309 			x, y,
 310 			width, height,
 311 			coord_type);
 312 
 313 	if (parent && GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD (parent)) {
 314 		ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (
 315 			atk_gobject_accessible_get_object (
 316 			ATK_GOBJECT_ACCESSIBLE (parent)));
 317 		if (etcta) {
 318 			*width = etcta->width;
 319 			*height = etcta->height;
 320 		}
 321 	}
 322 }
 323 
 324 static AtkObject *
 325 eti_ref_accessible_at_point (AtkComponent *component,
 326                              gint x,
 327                              gint y,
 328                              AtkCoordType coord_type)
 329 {
 330 	gint row = -1;
 331 	gint col = -1;
 332 	gint x_origin, y_origin;
 333 	ETableItem *item;
 334 	GtkWidget *tableOrTree;
 335 
 336 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component)));
 337 	if (!item)
 338 		return NULL;
 339 
 340 	atk_component_get_position (
 341 		component,
 342 		&x_origin,
 343 		&y_origin,
 344 		coord_type);
 345 	x -= x_origin;
 346 	y -= y_origin;
 347 
 348 	tableOrTree = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas));
 349 
 350 	if (E_IS_TREE (tableOrTree))
 351 		e_tree_get_cell_at (E_TREE (tableOrTree), x, y, &row, &col);
 352 	else
 353 		e_table_get_cell_at (E_TABLE (tableOrTree), x, y, &row, &col);
 354 
 355 	if (row != -1 && col != -1) {
 356 		return eti_ref_at (ATK_TABLE (component), row, col);
 357 	} else {
 358 		return NULL;
 359 	}
 360 }
 361 
 362 static void
 363 cell_destroyed (gpointer data)
 364 {
 365 	GalA11yECell * cell;
 366 
 367 	g_return_if_fail (GAL_A11Y_IS_E_CELL (data));
 368 	cell = GAL_A11Y_E_CELL (data);
 369 
 370 	g_return_if_fail (cell->item && G_IS_OBJECT (cell->item));
 371 
 372 	if (cell->item) {
 373 		g_object_unref (cell->item);
 374 		cell->item = NULL;
 375 	}
 376 
 377 }
 378 
 379 /* atk table */
 380 static AtkObject *
 381 eti_ref_at (AtkTable *table,
 382             gint row,
 383             gint column)
 384 {
 385 	ETableItem *item;
 386 	AtkObject * ret;
 387 	GalA11yETableItemPrivate *priv = GET_PRIVATE (table);
 388 
 389 	if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
 390 		return NULL;
 391 
 392 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 393 	if (!item)
 394 		return NULL;
 395 
 396 	if (column >= 0 &&
 397 	    column < item->cols &&
 398 	    row >= 0 &&
 399 	    row < item->rows &&
 400 	    item->cell_views_realized) {
 401 		ECellView *cell_view = item->cell_views[column];
 402 		ETableCol *ecol = e_table_header_get_column (item->header, column);
 403 		ret = gal_a11y_e_cell_registry_get_object (
 404 			NULL,
 405 			item,
 406 			cell_view,
 407 			ATK_OBJECT (table),
 408 			ecol->col_idx,
 409 			column,
 410 			row);
 411 		if (ATK_IS_OBJECT (ret)) {
 412 			g_object_weak_ref (
 413 				G_OBJECT (ret),
 414 				(GWeakNotify) cell_destroyed,
 415 				ret);
 416 			/* if current cell is focused, add FOCUSED state */
 417 			if (e_selection_model_cursor_row (item->selection) ==
 418 				GAL_A11Y_E_CELL (ret)->row &&
 419 				e_selection_model_cursor_col (item->selection) ==
 420 				GAL_A11Y_E_CELL (ret)->model_col)
 421 				gal_a11y_e_cell_add_state (
 422 					GAL_A11Y_E_CELL (ret),
 423 					ATK_STATE_FOCUSED, FALSE);
 424 		} else
 425 			ret = NULL;
 426 
 427 		return ret;
 428 	}
 429 
 430 	return NULL;
 431 }
 432 
 433 static gint
 434 eti_get_index_at (AtkTable *table,
 435                   gint row,
 436                   gint column)
 437 {
 438 	ETableItem *item;
 439 
 440 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 441 	if (!item)
 442 		return -1;
 443 
 444 	return column + (row + 1) * item->cols;
 445 }
 446 
 447 static gint
 448 eti_get_column_at_index (AtkTable *table,
 449                          gint index)
 450 {
 451 	ETableItem *item;
 452 
 453 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 454 	if (!item)
 455 		return -1;
 456 
 457 	return index % item->cols;
 458 }
 459 
 460 static gint
 461 eti_get_row_at_index (AtkTable *table,
 462                       gint index)
 463 {
 464 	ETableItem *item;
 465 
 466 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 467 	if (!item)
 468 		return -1;
 469 
 470 	return index / item->cols - 1;
 471 }
 472 
 473 static gint
 474 eti_get_n_columns (AtkTable *table)
 475 {
 476 	ETableItem *item;
 477 
 478 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 479 	if (!item)
 480 		return -1;
 481 
 482 	return item->cols;
 483 }
 484 
 485 static gint
 486 eti_get_n_rows (AtkTable *table)
 487 {
 488 	ETableItem *item;
 489 
 490 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 491 	if (!item)
 492 		return -1;
 493 
 494 	return item->rows;
 495 }
 496 
 497 static gint
 498 eti_get_column_extent_at (AtkTable *table,
 499                           gint row,
 500                           gint column)
 501 {
 502 	ETableItem *item;
 503 	gint width;
 504 
 505 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 506 	if (!item)
 507 		return -1;
 508 
 509 	e_table_item_get_cell_geometry (
 510 		item,
 511 		&row,
 512 		&column,
 513 		NULL,
 514 		NULL,
 515 		&width,
 516 		NULL);
 517 
 518 	return width;
 519 }
 520 
 521 static gint
 522 eti_get_row_extent_at (AtkTable *table,
 523                        gint row,
 524                        gint column)
 525 {
 526 	ETableItem *item;
 527 	gint height;
 528 
 529 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 530 	if (!item)
 531 		return -1;
 532 
 533 	e_table_item_get_cell_geometry (
 534 		item,
 535 		&row,
 536 		&column,
 537 		NULL,
 538 		NULL,
 539 		NULL,
 540 		&height);
 541 
 542 	return height;
 543 }
 544 
 545 static AtkObject *
 546 eti_get_caption (AtkTable *table)
 547 {
 548 	/* Unimplemented */
 549 	return NULL;
 550 }
 551 
 552 static const gchar *
 553 eti_get_column_description (AtkTable *table,
 554                             gint column)
 555 {
 556 	ETableItem *item;
 557 	ETableCol *ecol;
 558 
 559 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 560 	if (!item)
 561 		return NULL;
 562 
 563 	ecol = e_table_header_get_column (item->header, column);
 564 
 565 	return ecol->text;
 566 }
 567 
 568 static AtkObject *
 569 eti_get_column_header (AtkTable *table,
 570                        gint column)
 571 {
 572 	ETableItem *item;
 573 	ETableCol *ecol;
 574 	AtkObject *atk_obj = NULL;
 575 
 576 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 577 	if (!item)
 578 		return NULL;
 579 
 580 	ecol = e_table_header_get_column (item->header, column);
 581 	if (ecol) {
 582 		atk_obj = gal_a11y_e_table_column_header_new (ecol, item);
 583 	}
 584 
 585 	return atk_obj;
 586 }
 587 
 588 static const gchar *
 589 eti_get_row_description (AtkTable *table,
 590                          gint row)
 591 {
 592 	/* Unimplemented */
 593 	return NULL;
 594 }
 595 
 596 static AtkObject *
 597 eti_get_row_header (AtkTable *table,
 598                     gint row)
 599 {
 600 	/* Unimplemented */
 601 	return NULL;
 602 }
 603 
 604 static AtkObject *
 605 eti_get_summary (AtkTable *table)
 606 {
 607 	/* Unimplemented */
 608 	return NULL;
 609 }
 610 
 611 static gboolean
 612 table_is_row_selected (AtkTable *table,
 613                        gint row)
 614 {
 615 	ETableItem *item;
 616 	GalA11yETableItemPrivate *priv = GET_PRIVATE (table);
 617 
 618 	if (row < 0)
 619 		return FALSE;
 620 
 621 	if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
 622 		return FALSE;
 623 
 624 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 625 	if (!item)
 626 		return FALSE;
 627 
 628 	return e_selection_model_is_row_selected (
 629 		item->selection, view_to_model_row (item, row));
 630 }
 631 
 632 static gboolean
 633 table_is_selected (AtkTable *table,
 634                    gint row,
 635                    gint column)
 636 {
 637 	return table_is_row_selected (table, row);
 638 }
 639 
 640 static gint
 641 table_get_selected_rows (AtkTable *table,
 642                          gint **rows_selected)
 643 {
 644 	ETableItem *item;
 645 	gint n_selected, row, index_selected;
 646 	GalA11yETableItemPrivate *priv = GET_PRIVATE (table);
 647 
 648 	if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
 649 		return 0;
 650 
 651 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 652 	if (!item)
 653 		return 0;
 654 
 655 	n_selected = e_selection_model_selected_count (item->selection);
 656 	if (rows_selected) {
 657 		*rows_selected = (gint *) g_malloc (n_selected * sizeof (gint));
 658 
 659 		index_selected = 0;
 660 		for (row = 0; row < item->rows && index_selected < n_selected; ++row) {
 661 			if (atk_table_is_row_selected (table, row)) {
 662 				(*rows_selected)[index_selected] = row;
 663 				++index_selected;
 664 			}
 665 		}
 666 	}
 667 	return n_selected;
 668 }
 669 
 670 static gboolean
 671 table_add_row_selection (AtkTable *table,
 672                          gint row)
 673 {
 674 	ETableItem *item;
 675 
 676 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 677 	if (!item)
 678 		return FALSE;
 679 
 680 	if (table_is_row_selected (table, row))
 681 		return TRUE;
 682 	e_selection_model_toggle_single_row (
 683 		item->selection,
 684 		view_to_model_row (item, row));
 685 
 686 	return TRUE;
 687 }
 688 
 689 static gboolean
 690 table_remove_row_selection (AtkTable *table,
 691                             gint row)
 692 {
 693 	ETableItem *item;
 694 	GalA11yETableItemPrivate *priv = GET_PRIVATE (table);
 695 
 696 	if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
 697 		return FALSE;
 698 
 699 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
 700 	if (!item)
 701 		return FALSE;
 702 
 703 	if (!atk_table_is_row_selected (table, row))
 704 		return TRUE;
 705 
 706 	e_selection_model_toggle_single_row (
 707 		item->selection, view_to_model_row (item, row));
 708 
 709 	return TRUE;
 710 }
 711 
 712 static void
 713 eti_atk_table_iface_init (AtkTableIface *iface)
 714 {
 715 	iface->ref_at = eti_ref_at;
 716 	iface->get_index_at = eti_get_index_at;
 717 	iface->get_column_at_index = eti_get_column_at_index;
 718 	iface->get_row_at_index = eti_get_row_at_index;
 719 	iface->get_n_columns = eti_get_n_columns;
 720 	iface->get_n_rows = eti_get_n_rows;
 721 	iface->get_column_extent_at = eti_get_column_extent_at;
 722 	iface->get_row_extent_at = eti_get_row_extent_at;
 723 	iface->get_caption = eti_get_caption;
 724 	iface->get_column_description = eti_get_column_description;
 725 	iface->get_column_header = eti_get_column_header;
 726 	iface->get_row_description = eti_get_row_description;
 727 	iface->get_row_header = eti_get_row_header;
 728 	iface->get_summary = eti_get_summary;
 729 
 730 	iface->is_row_selected = table_is_row_selected;
 731 	iface->is_selected = table_is_selected;
 732 	iface->get_selected_rows = table_get_selected_rows;
 733 	iface->add_row_selection = table_add_row_selection;
 734 	iface->remove_row_selection = table_remove_row_selection;
 735 }
 736 
 737 static void
 738 eti_atk_component_iface_init (AtkComponentIface *iface)
 739 {
 740 	component_parent_iface         = g_type_interface_peek_parent (iface);
 741 
 742 	iface->ref_accessible_at_point = eti_ref_accessible_at_point;
 743 	iface->get_extents             = eti_get_extents;
 744 }
 745 
 746 static void
 747 eti_rows_inserted (ETableModel *model,
 748                    gint row,
 749                    gint count,
 750                    AtkObject *table_item)
 751 {
 752 	gint n_cols,n_rows,i,j;
 753 	GalA11yETableItem * item_a11y;
 754 	gint old_nrows;
 755 
 756 	g_return_if_fail (table_item);
 757 	item_a11y = GAL_A11Y_E_TABLE_ITEM (table_item);
 758 
 759 	n_cols = atk_table_get_n_columns (ATK_TABLE (table_item));
 760 	n_rows = atk_table_get_n_rows (ATK_TABLE (table_item));
 761 
 762 	old_nrows = GET_PRIVATE (item_a11y)->rows;
 763 
 764 	g_return_if_fail (n_cols > 0 && n_rows > 0);
 765 	g_return_if_fail (old_nrows == n_rows - count);
 766 
 767 	GET_PRIVATE (table_item)->rows = n_rows;
 768 
 769 	g_signal_emit_by_name (
 770 		table_item, "row-inserted", row,
 771 		count, NULL);
 772 
 773 	for (i = row; i < (row + count); i++) {
 774 		for (j = 0; j < n_cols; j++) {
 775 			g_signal_emit_by_name (
 776 				table_item,
 777 				"children_changed::add",
 778 				(((i + 1) * n_cols) + j), NULL, NULL);
 779 		}
 780 	}
 781 
 782 	g_signal_emit_by_name (table_item, "visible-data-changed");
 783 }
 784 
 785 static void
 786 eti_rows_deleted (ETableModel *model,
 787                   gint row,
 788                   gint count,
 789                   AtkObject *table_item)
 790 {
 791 	gint i,j, n_rows, n_cols, old_nrows;
 792 	ETableItem *item = E_TABLE_ITEM (
 793 		atk_gobject_accessible_get_object (
 794 		ATK_GOBJECT_ACCESSIBLE (table_item)));
 795 
 796 	n_rows = atk_table_get_n_rows (ATK_TABLE (table_item));
 797 	n_cols = atk_table_get_n_columns (ATK_TABLE (table_item));
 798 
 799 	old_nrows = GET_PRIVATE (table_item)->rows;
 800 
 801 	g_return_if_fail (row + count <= old_nrows);
 802 	g_return_if_fail (old_nrows == n_rows + count);
 803 	GET_PRIVATE (table_item)->rows = n_rows;
 804 
 805 	g_signal_emit_by_name (
 806 		table_item, "row-deleted", row,
 807 		count, NULL);
 808 
 809 	for (i = row; i < (row + count); i++) {
 810 		for (j = 0; j < n_cols; j++) {
 811 			g_signal_emit_by_name (
 812 				table_item,
 813 				"children_changed::remove",
 814 				(((i + 1) * n_cols) + j), NULL, NULL);
 815 		}
 816 	}
 817 	g_signal_emit_by_name (table_item, "visible-data-changed");
 818 	eti_a11y_reset_focus_object ((GalA11yETableItem *) table_item, item, TRUE);
 819 }
 820 
 821 static void
 822 eti_tree_model_node_changed_cb (ETreeModel *model,
 823                                 ETreePath node,
 824                                 ETableItem *eti)
 825 {
 826 	AtkObject *atk_obj;
 827 	GalA11yETableItem *a11y;
 828 
 829 	g_return_if_fail (E_IS_TABLE_ITEM (eti));
 830 
 831 	atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti));
 832 	a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj);
 833 
 834 	/* we can't figure out which rows are changed, so just send out a signal ... */
 835 	if  (GET_PRIVATE (a11y)->rows > 0)
 836 		g_signal_emit_by_name (a11y, "visible-data-changed");
 837 }
 838 
 839 enum {
 840         ETI_HEADER_UNCHANGED = 0,
 841         ETI_HEADER_REORDERED,
 842         ETI_HEADER_NEW_ADDED,
 843         ETI_HEADER_REMOVED
 844 };
 845 
 846 /*
 847  * 1. Check what actually happened: column reorder, remove or add
 848  * 2. Update cache
 849  * 3. Emit signals
 850  */
 851 static void
 852 eti_header_structure_changed (ETableHeader *eth,
 853                               AtkObject *a11y)
 854 {
 855 
 856 	gboolean reorder_found = FALSE, added_found = FALSE, removed_found = FALSE;
 857 	GalA11yETableItem * a11y_item;
 858 	ETableCol ** cols, **prev_cols;
 859 	GalA11yETableItemPrivate *priv;
 860 	gint *state = NULL, *prev_state = NULL, *reorder = NULL;
 861 	gint i,j,n_rows,n_cols, prev_n_cols;
 862 
 863 	a11y_item = GAL_A11Y_E_TABLE_ITEM (a11y);
 864 	priv = GET_PRIVATE (a11y_item);
 865 
 866 	/* Assume rows do not changed. */
 867 	n_rows = priv->rows;
 868 
 869 	prev_n_cols = priv->cols;
 870 	prev_cols = priv->columns;
 871 
 872 	cols = e_table_header_get_columns (eth);
 873 	n_cols = eth->col_count;
 874 
 875 	g_return_if_fail (cols && prev_cols && n_cols > 0);
 876 
 877         /* Init to ETI_HEADER_UNCHANGED. */
 878 	state = g_malloc0 (sizeof (gint) * n_cols);
 879 	prev_state = g_malloc0 (sizeof (gint) * prev_n_cols);
 880 	reorder = g_malloc0 (sizeof (gint) * n_cols);
 881 
 882         /* Compare with previously saved column headers. */
 883 	for (i = 0; i < n_cols && cols[i]; i++) {
 884 		for (j = 0; j < prev_n_cols && prev_cols[j]; j++) {
 885 			if (prev_cols[j] == cols[i] && i != j) {
 886 
 887 				reorder_found = TRUE;
 888 				state[i] = ETI_HEADER_REORDERED;
 889 				reorder[i] = j;
 890 
 891 				break;
 892 			} else if (prev_cols[j] == cols[i]) {
 893                                 /* OK, this column is not changed. */
 894 				break;
 895 			}
 896 		}
 897 
 898                 /* cols[i] is new added column. */
 899 		if (j == prev_n_cols) {
 900 			added_found = TRUE;
 901 			state[i] = ETI_HEADER_NEW_ADDED;
 902 		}
 903 	}
 904 
 905         /* Now try to find if there are removed columns. */
 906 	for (i = 0; i < prev_n_cols && prev_cols[i]; i++) {
 907 		for (j = 0; j < n_cols && cols[j]; j++)
 908 			if (prev_cols[j] == cols[i])
 909 				break;
 910 
 911                 /* Removed columns found. */
 912 		if (j == n_cols) {
 913 			removed_found = TRUE;
 914 			prev_state[j] = ETI_HEADER_REMOVED;
 915 		}
 916 	}
 917 
 918 	/* If nothing interesting just return. */
 919 	if (!reorder_found && !added_found && !removed_found)
 920 		return;
 921 
 922 	/* Emit signals */
 923 	if (reorder_found)
 924 		g_signal_emit_by_name (a11y_item, "column_reordered");
 925 
 926 	if (removed_found) {
 927 		for (i = 0; i < prev_n_cols; i++) {
 928 			if (prev_state[i] == ETI_HEADER_REMOVED) {
 929 				g_signal_emit_by_name (
 930 					a11y_item, "column-deleted", i, 1);
 931 				for (j = 0; j < n_rows; j++)
 932 					g_signal_emit_by_name (
 933 						a11y_item,
 934 						"children_changed::remove",
 935 						((j + 1) * prev_n_cols + i),
 936 						NULL, NULL);
 937 			}
 938 		}
 939 	}
 940 
 941 	if (added_found) {
 942 		for (i = 0; i < n_cols; i++) {
 943 			if (state[i] == ETI_HEADER_NEW_ADDED) {
 944 				g_signal_emit_by_name (
 945 					a11y_item, "column-inserted", i, 1);
 946 				for (j = 0; j < n_rows; j++)
 947 					g_signal_emit_by_name (
 948 						a11y_item,
 949 						"children_changed::add",
 950 						((j + 1) * n_cols + i),
 951 						NULL, NULL);
 952 			}
 953 		}
 954 	}
 955 
 956 	priv->cols = n_cols;
 957 
 958 	g_free (state);
 959 	g_free (reorder);
 960 	g_free (prev_state);
 961 
 962 	free_columns (priv->columns);
 963 	priv->columns = cols;
 964 }
 965 
 966 static void
 967 eti_real_initialize (AtkObject *obj,
 968                      gpointer data)
 969 {
 970 	ETableItem * eti;
 971 	ETableModel * model;
 972 
 973 	ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
 974 	eti = E_TABLE_ITEM (data);
 975 
 976 	model = eti->table_model;
 977 
 978 	g_signal_connect (
 979 		model, "model-rows-inserted",
 980 		G_CALLBACK (eti_rows_inserted), obj);
 981 	g_signal_connect (
 982 		model, "model-rows-deleted",
 983 		G_CALLBACK (eti_rows_deleted), obj);
 984 	g_signal_connect (
 985 		eti->header, "structure_change",
 986 		G_CALLBACK (eti_header_structure_changed), obj);
 987 
 988 }
 989 
 990 static void
 991 eti_class_init (GalA11yETableItemClass *class)
 992 {
 993 	AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (class);
 994 	GObjectClass *object_class = G_OBJECT_CLASS (class);
 995 
 996 	quark_accessible_object =
 997 		g_quark_from_static_string ("gtk-accessible-object");
 998 
 999 	parent_class = g_type_class_ref (PARENT_TYPE);
1000 
1001 	object_class->dispose = eti_dispose;
1002 
1003 	atk_object_class->get_n_children = eti_get_n_children;
1004 	atk_object_class->ref_child = eti_ref_child;
1005 	atk_object_class->initialize = eti_real_initialize;
1006 	atk_object_class->ref_state_set = eti_ref_state_set;
1007 }
1008 
1009 static void
1010 eti_init (GalA11yETableItem *a11y)
1011 {
1012 	GalA11yETableItemPrivate *priv;
1013 
1014 	priv = GET_PRIVATE (a11y);
1015 
1016 	priv->selection_change_id = 0;
1017 	priv->cursor_change_id = 0;
1018 	priv->selection = NULL;
1019 }
1020 
1021 /* atk selection */
1022 
1023 static void	atk_selection_interface_init	(AtkSelectionIface *iface);
1024 static gboolean	selection_add_selection		(AtkSelection *selection,
1025 						 gint i);
1026 static gboolean	selection_clear_selection	(AtkSelection *selection);
1027 static AtkObject *
1028 		selection_ref_selection		(AtkSelection *selection,
1029 						 gint i);
1030 static gint	selection_get_selection_count	(AtkSelection *selection);
1031 static gboolean	selection_is_child_selected	(AtkSelection *selection,
1032 						 gint i);
1033 
1034 /* callbacks */
1035 static void eti_a11y_selection_model_removed_cb (ETableItem *eti,
1036 						 ESelectionModel *selection,
1037 						 gpointer data);
1038 static void eti_a11y_selection_model_added_cb (ETableItem *eti,
1039 					       ESelectionModel *selection,
1040 					       gpointer data);
1041 static void eti_a11y_selection_changed_cb (ESelectionModel *selection,
1042 					   GalA11yETableItem *a11y);
1043 static void eti_a11y_cursor_changed_cb (ESelectionModel *selection,
1044 					gint row, gint col,
1045 					GalA11yETableItem *a11y);
1046 
1047 /**
1048  * gal_a11y_e_table_item_get_type:
1049  * @void:
1050  *
1051  * Registers the &GalA11yETableItem class if necessary, and returns the type ID
1052  * associated to it.
1053  *
1054  * Return value: The type ID of the &GalA11yETableItem class.
1055  **/
1056 GType
1057 gal_a11y_e_table_item_get_type (void)
1058 {
1059 	static GType type = 0;
1060 
1061 	if (!type) {
1062 		AtkObjectFactory *factory;
1063 
1064 		GTypeInfo info = {
1065 			sizeof (GalA11yETableItemClass),
1066 			(GBaseInitFunc) NULL,
1067 			(GBaseFinalizeFunc) NULL,
1068 			(GClassInitFunc) eti_class_init,
1069 			(GClassFinalizeFunc) NULL,
1070 			NULL, /* class_data */
1071 			sizeof (GalA11yETableItem),
1072 			0,
1073 			(GInstanceInitFunc) eti_init,
1074 			NULL /* value_table_item */
1075 		};
1076 
1077 		static const GInterfaceInfo atk_component_info = {
1078 			(GInterfaceInitFunc) eti_atk_component_iface_init,
1079 			(GInterfaceFinalizeFunc) NULL,
1080 			NULL
1081 		};
1082 		static const GInterfaceInfo atk_table_info = {
1083 			(GInterfaceInitFunc) eti_atk_table_iface_init,
1084 			(GInterfaceFinalizeFunc) NULL,
1085 			NULL
1086 		};
1087 
1088 		static const GInterfaceInfo atk_selection_info = {
1089 			(GInterfaceInitFunc) atk_selection_interface_init,
1090 			(GInterfaceFinalizeFunc) NULL,
1091 			NULL
1092 		};
1093 
1094 		factory = atk_registry_get_factory (
1095 			atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM);
1096 		parent_type = atk_object_factory_get_accessible_type (factory);
1097 
1098 		type = gal_a11y_type_register_static_with_private (
1099 			PARENT_TYPE, "GalA11yETableItem", &info, 0,
1100 			sizeof (GalA11yETableItemPrivate), &priv_offset);
1101 
1102 		g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
1103 		g_type_add_interface_static (type, ATK_TYPE_TABLE, &atk_table_info);
1104 		g_type_add_interface_static (type, ATK_TYPE_SELECTION, &atk_selection_info);
1105 	}
1106 
1107 	return type;
1108 }
1109 
1110 AtkObject *
1111 gal_a11y_e_table_item_new (ETableItem *item)
1112 {
1113 	GalA11yETableItem *a11y;
1114 	AtkObject *accessible;
1115 	ESelectionModel * esm;
1116 	AtkObject *parent;
1117 	const gchar *name;
1118 
1119 	g_return_val_if_fail (item && item->cols >= 0 && item->rows >= 0, NULL);
1120 	a11y = g_object_new (gal_a11y_e_table_item_get_type (), NULL);
1121 
1122 	atk_object_initialize (ATK_OBJECT (a11y), item);
1123 
1124 	GET_PRIVATE (a11y)->state_set = atk_state_set_new ();
1125 
1126 	atk_state_set_add_state (GET_PRIVATE (a11y)->state_set, ATK_STATE_TRANSIENT);
1127 	atk_state_set_add_state (GET_PRIVATE (a11y)->state_set, ATK_STATE_ENABLED);
1128 	atk_state_set_add_state (GET_PRIVATE (a11y)->state_set, ATK_STATE_SENSITIVE);
1129 	atk_state_set_add_state (GET_PRIVATE (a11y)->state_set, ATK_STATE_SHOWING);
1130 	atk_state_set_add_state (GET_PRIVATE (a11y)->state_set, ATK_STATE_VISIBLE);
1131 
1132 	accessible  = ATK_OBJECT (a11y);
1133 
1134 	GET_PRIVATE (a11y)->item = item;
1135 	/* Initialize cell data. */
1136 	GET_PRIVATE (a11y)->cols = item->cols;
1137 	GET_PRIVATE (a11y)->rows = item->rows;
1138 
1139 	GET_PRIVATE (a11y)->columns = e_table_header_get_columns (item->header);
1140 	if (GET_PRIVATE (a11y)->columns == NULL)
1141 		return NULL;
1142 
1143 	if (item) {
1144 		g_signal_connect (
1145 			item, "selection_model_removed",
1146 			G_CALLBACK (eti_a11y_selection_model_removed_cb), NULL);
1147 		g_signal_connect (
1148 			item, "selection_model_added",
1149 			G_CALLBACK (eti_a11y_selection_model_added_cb), NULL);
1150 		if (item->selection)
1151 			gal_a11y_e_table_item_ref_selection (
1152 				a11y,
1153 				item->selection);
1154 
1155 		/* find the TableItem's parent: table or tree */
1156 		GET_PRIVATE (a11y)->widget = gtk_widget_get_parent (
1157 			GTK_WIDGET (item->parent.canvas));
1158 		parent = gtk_widget_get_accessible (GET_PRIVATE (a11y)->widget);
1159 		name = atk_object_get_name (parent);
1160 		if (name)
1161 			atk_object_set_name (accessible, name);
1162 		atk_object_set_parent (accessible, parent);
1163 
1164 		if (E_IS_TREE (GET_PRIVATE (a11y)->widget)) {
1165 			ETreeModel *model;
1166 			model = e_tree_get_model (E_TREE (GET_PRIVATE (a11y)->widget));
1167 			g_signal_connect (
1168 				model, "node_changed",
1169 				G_CALLBACK (eti_tree_model_node_changed_cb), item);
1170 			accessible->role = ATK_ROLE_TREE_TABLE;
1171 		} else if (E_IS_TABLE (GET_PRIVATE (a11y)->widget)) {
1172 			accessible->role = ATK_ROLE_TABLE;
1173 		}
1174 	}
1175 
1176 	if (item)
1177 		g_object_weak_ref (G_OBJECT (item), item_finalized, g_object_ref (a11y));
1178 
1179 	esm = item->selection;
1180 
1181 	if (esm != NULL) {
1182 		eti_a11y_reset_focus_object (a11y, item, FALSE);
1183 	}
1184 
1185 	return ATK_OBJECT (a11y);
1186 }
1187 
1188 static gboolean
1189 gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y,
1190                                      ESelectionModel *selection)
1191 {
1192 	GalA11yETableItemPrivate *priv;
1193 
1194 	g_return_val_if_fail (a11y && selection, FALSE);
1195 
1196 	priv = GET_PRIVATE (a11y);
1197 	priv->selection_change_id = g_signal_connect (
1198 		selection, "selection_changed",
1199 		G_CALLBACK (eti_a11y_selection_changed_cb), a11y);
1200 	priv->cursor_change_id = g_signal_connect (
1201 		selection, "cursor_changed",
1202 		G_CALLBACK (eti_a11y_cursor_changed_cb), a11y);
1203 
1204 	priv->selection = selection;
1205 	g_object_ref (selection);
1206 
1207 	return TRUE;
1208 }
1209 
1210 static gboolean
1211 gal_a11y_e_table_item_unref_selection (GalA11yETableItem *a11y)
1212 {
1213 	GalA11yETableItemPrivate *priv;
1214 
1215 	g_return_val_if_fail (a11y, FALSE);
1216 
1217 	priv = GET_PRIVATE (a11y);
1218 
1219 	g_return_val_if_fail (priv->selection_change_id != 0, FALSE);
1220 	g_return_val_if_fail (priv->cursor_change_id != 0, FALSE);
1221 
1222 	g_signal_handler_disconnect (
1223 		priv->selection,
1224 		priv->selection_change_id);
1225 	g_signal_handler_disconnect (
1226 		priv->selection,
1227 		priv->cursor_change_id);
1228 	priv->cursor_change_id = 0;
1229 	priv->selection_change_id = 0;
1230 
1231 	g_object_unref (priv->selection);
1232 	priv->selection = NULL;
1233 
1234 	return TRUE;
1235 }
1236 
1237 /* callbacks */
1238 
1239 static void
1240 eti_a11y_selection_model_removed_cb (ETableItem *eti,
1241                                      ESelectionModel *selection,
1242                                      gpointer data)
1243 {
1244 	AtkObject *atk_obj;
1245 	GalA11yETableItem *a11y;
1246 
1247 	g_return_if_fail (E_IS_TABLE_ITEM (eti));
1248 	g_return_if_fail (E_IS_SELECTION_MODEL (selection));
1249 
1250 	atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti));
1251 	a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj);
1252 
1253 	if (selection == GET_PRIVATE (a11y)->selection)
1254 		gal_a11y_e_table_item_unref_selection (a11y);
1255 }
1256 
1257 static void
1258 eti_a11y_selection_model_added_cb (ETableItem *eti,
1259                                    ESelectionModel *selection,
1260                                    gpointer data)
1261 {
1262 	AtkObject *atk_obj;
1263 	GalA11yETableItem *a11y;
1264 
1265 	g_return_if_fail (E_IS_TABLE_ITEM (eti));
1266 	g_return_if_fail (E_IS_SELECTION_MODEL (selection));
1267 
1268 	atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti));
1269 	a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj);
1270 
1271 	if (GET_PRIVATE (a11y)->selection)
1272 		gal_a11y_e_table_item_unref_selection (a11y);
1273 	gal_a11y_e_table_item_ref_selection (a11y, selection);
1274 }
1275 
1276 static void
1277 eti_a11y_selection_changed_cb (ESelectionModel *selection,
1278                                GalA11yETableItem *a11y)
1279 {
1280 	GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
1281 
1282 	if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
1283 		return;
1284 
1285 	g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y));
1286 
1287 	g_signal_emit_by_name (a11y, "selection_changed");
1288 }
1289 
1290 static void
1291 eti_a11y_cursor_changed_cb (ESelectionModel *selection,
1292                             gint row,
1293                             gint col,
1294                             GalA11yETableItem *a11y)
1295 {
1296 	ETableItem *item;
1297 	GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
1298 
1299 	g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y));
1300 
1301 	if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT))
1302 		return;
1303 
1304 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (a11y)));
1305 
1306 	g_return_if_fail (item);
1307 
1308 	if (row == -1 && col == -1)
1309 		return;
1310 	eti_a11y_reset_focus_object (a11y, item, TRUE);
1311 }
1312 
1313 /* atk selection */
1314 
1315 static void atk_selection_interface_init (AtkSelectionIface *iface)
1316 {
1317 	g_return_if_fail (iface != NULL);
1318 	iface->add_selection = selection_add_selection;
1319 	iface->clear_selection = selection_clear_selection;
1320 	iface->ref_selection = selection_ref_selection;
1321 	iface->get_selection_count = selection_get_selection_count;
1322 	iface->is_child_selected = selection_is_child_selected;
1323 }
1324 
1325 static gboolean
1326 selection_add_selection (AtkSelection *selection,
1327                          gint index)
1328 {
1329 	AtkTable *table;
1330 	gint row, col, cursor_row, cursor_col, model_row, model_col;
1331 	ETableItem *item;
1332 
1333 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection)));
1334 	if (!item)
1335 		return FALSE;
1336 
1337 	table = ATK_TABLE (selection);
1338 
1339 	row = atk_table_get_row_at_index (table, index);
1340 	col = atk_table_get_column_at_index (table, index);
1341 
1342 	model_row = view_to_model_row (item, row);
1343 	model_col = view_to_model_col (item, col);
1344 
1345 	cursor_row = e_selection_model_cursor_row (item->selection);
1346 	cursor_col = e_selection_model_cursor_col (item->selection);
1347 
1348 	/* check whether is selected already */
1349 	if (model_row == cursor_row && model_col == cursor_col)
1350 		return TRUE;
1351 
1352 	if (model_row != cursor_row) {
1353 		/* we need to make the item get focus */
1354 		e_canvas_item_grab_focus (GNOME_CANVAS_ITEM (item), TRUE);
1355 
1356 		/* FIXME, currently we only support single row selection */
1357 		atk_selection_clear_selection (selection);
1358 		atk_table_add_row_selection (table, row);
1359 	}
1360 
1361 	e_selection_model_change_cursor (
1362 		item->selection,
1363 		model_row,
1364 		model_col);
1365 	e_selection_model_cursor_changed (
1366 		item->selection,
1367 		model_row,
1368 		model_col);
1369 	e_selection_model_cursor_activated (
1370 		item->selection,
1371 		model_row,
1372 		model_col);
1373 	return TRUE;
1374 }
1375 
1376 static gboolean
1377 selection_clear_selection (AtkSelection *selection)
1378 {
1379 	ETableItem *item;
1380 
1381 	item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection)));
1382 	if (!item)
1383 		return FALSE;
1384 
1385 	e_selection_model_clear (item->selection);
1386 	return TRUE;
1387 }
1388 
1389 static AtkObject *
1390 selection_ref_selection (AtkSelection *selection,
1391                          gint index)
1392 {
1393 	AtkTable *table;
1394 	gint row, col;
1395 
1396 	table = ATK_TABLE (selection);
1397 	row = atk_table_get_row_at_index (table, index);
1398 	col = atk_table_get_column_at_index (table, index);
1399 	if (!atk_table_is_row_selected (table, row))
1400 		return NULL;
1401 
1402 	return eti_ref_at (table, row, col);
1403 }
1404 
1405 static gint
1406 selection_get_selection_count (AtkSelection *selection)
1407 {
1408 	AtkTable *table;
1409 	gint n_selected;
1410 
1411 	table = ATK_TABLE (selection);
1412 	n_selected = atk_table_get_selected_rows (table, NULL);
1413 	if (n_selected > 0)
1414 		n_selected *= atk_table_get_n_columns (table);
1415 	return n_selected;
1416 }
1417 
1418 static gboolean
1419 selection_is_child_selected (AtkSelection *selection,
1420                              gint i)
1421 {
1422 	gint row;
1423 
1424 	row = atk_table_get_row_at_index (ATK_TABLE (selection), i);
1425 	return atk_table_is_row_selected (ATK_TABLE (selection), row);
1426 }
1427 
1428 void
1429 gal_a11y_e_table_item_init (void)
1430 {
1431 	if (atk_get_root ())
1432 		atk_registry_set_factory_type (
1433 			atk_get_default_registry (),
1434 			E_TYPE_TABLE_ITEM,
1435 			gal_a11y_e_table_item_factory_get_type ());
1436 }