diff options
Diffstat (limited to 'a11y/e-table')
-rw-r--r-- | a11y/e-table/gal-a11y-e-cell-popup.c | 5 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-cell-text.c | 223 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-cell-text.h | 2 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-cell-toggle.c | 17 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-cell-tree.c | 9 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-cell-vbox.c | 214 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-cell-vbox.h | 64 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-cell.c | 158 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-table-click-to-add.c | 52 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-table-item-factory.c | 2 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-table-item.c | 527 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-table-item.h | 6 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-table.c | 151 | ||||
-rw-r--r-- | a11y/e-table/gal-a11y-e-tree.c | 12 |
14 files changed, 990 insertions, 452 deletions
diff --git a/a11y/e-table/gal-a11y-e-cell-popup.c b/a11y/e-table/gal-a11y-e-cell-popup.c index a3de45afb3..15cae2effb 100644 --- a/a11y/e-table/gal-a11y-e-cell-popup.c +++ b/a11y/e-table/gal-a11y-e-cell-popup.c @@ -31,6 +31,7 @@ #include <atk/atkobject.h> #include <gdk/gdkkeysyms.h> #include <gtk/gtkwidget.h> +#include <glib/gi18n.h> static AtkObjectClass *parent_class = NULL; #define PARENT_TYPE (gal_a11y_e_cell_get_type ()) @@ -118,8 +119,8 @@ gal_a11y_e_cell_popup_new (ETableItem *item, g_return_val_if_fail (a11y != NULL, NULL); cell = GAL_A11Y_E_CELL(a11y); gal_a11y_e_cell_add_action (cell, - "popup", /* action name*/ - "popup a child", /* action description */ + _("popup"), /* action name*/ + _("popup a child"), /* action description */ "<Alt>Down", /* action keybinding */ popup_cell_action); diff --git a/a11y/e-table/gal-a11y-e-cell-text.c b/a11y/e-table/gal-a11y-e-cell-text.c index d94a3640a3..89c1b3a813 100644 --- a/a11y/e-table/gal-a11y-e-cell-text.c +++ b/a11y/e-table/gal-a11y-e-cell-text.c @@ -15,18 +15,84 @@ #include <atk/atktext.h> #include <atk/atkeditabletext.h> #include <atk/atkaction.h> +#include <atk/atkstateset.h> +#include <glib/gi18n.h> #define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellTextClass)) static AtkObjectClass *parent_class; #define PARENT_TYPE (gal_a11y_e_cell_get_type ()) /* Static functions */ +static void +ect_dispose (GObject *object) +{ + GObjectClass *g_class; + GalA11yECell *gaec = GAL_A11Y_E_CELL (object); + GalA11yECellText *gaet = GAL_A11Y_E_CELL_TEXT (object); + + if (gaet->inserted_id != 0) { + ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); + + if (ect) { + g_signal_handler_disconnect (ect, gaet->inserted_id); + g_signal_handler_disconnect (ect, gaet->deleted_id); + } + + gaet->inserted_id = 0; + gaet->deleted_id = 0; + } + + g_class = (GObjectClass *)parent_class; + if (g_class->dispose) + g_class->dispose (object); + +} + +static gboolean +ect_check (gpointer a11y) +{ + GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y); + ETableItem *item = gaec->item; + + g_return_val_if_fail ((gaec->item != NULL), FALSE); + g_return_val_if_fail ((gaec->cell_view != NULL), FALSE); + g_return_val_if_fail ((gaec->cell_view->ecell != NULL), FALSE); + + if (atk_state_set_contains_state (gaec->state_set, ATK_STATE_DEFUNCT)) + return FALSE; + + if (gaec->row < 0 || gaec->row >= item->rows + || gaec->view_col <0 || gaec->view_col >= item->cols + || gaec->model_col <0 || gaec->model_col >= e_table_model_column_count (item->table_model)) + return FALSE; + + if (!E_IS_CELL_TEXT (gaec->cell_view->ecell)) + return FALSE; + + return TRUE; +} + static G_CONST_RETURN gchar* ect_get_name (AtkObject * a11y) { - GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y); - ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); - return e_cell_text_get_text (ect, gaec->item->table_model, gaec->model_col, gaec->row); + GalA11yECell *gaec; + char *name; + + if (!ect_check (a11y)) + return NULL; + + gaec = GAL_A11Y_E_CELL (a11y); + name = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); + if (name != NULL) { + ATK_OBJECT_CLASS (parent_class)->set_name (a11y, name); + g_free (name); + } + + if (a11y->name != NULL && strcmp (a11y->name, "")) { + return a11y->name; + } else { + return parent_class->get_name (a11y); + } } static gchar * @@ -35,9 +101,13 @@ ect_get_text (AtkText *text, gint end_offset) { GalA11yECell *gaec = GAL_A11Y_E_CELL (text); - ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); + gchar *full_text; gchar *ret_val; - gchar *full_text = e_cell_text_get_text (ect, gaec->item->table_model, gaec->model_col, gaec->row); + + if (!ect_check (text)) + return NULL; + + full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); if (end_offset == -1) end_offset = strlen (full_text); @@ -48,7 +118,7 @@ ect_get_text (AtkText *text, ret_val = g_strndup (full_text + start_offset, end_offset - start_offset); - e_cell_text_free_text (ect, full_text); + g_free (full_text); return ret_val; } @@ -80,13 +150,16 @@ ect_get_character_at_offset (AtkText *text, gint offset) { GalA11yECell *gaec = GAL_A11Y_E_CELL (text); - ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); gunichar ret_val; gchar *at_offset; - gchar *full_text = e_cell_text_get_text (ect, gaec->item->table_model, gaec->model_col, gaec->row); + + if (!ect_check (text)) + return -1; + + gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); at_offset = g_utf8_offset_to_pointer (full_text, offset); ret_val = g_utf8_get_char_validated (at_offset, -1); - e_cell_text_free_text (ect, full_text); + g_free (full_text); return ret_val; } @@ -108,18 +181,17 @@ static gint ect_get_caret_offset (AtkText *text) { GalA11yECell *gaec = GAL_A11Y_E_CELL (text); - ECellText *ect = NULL; gint start, end; - g_return_val_if_fail (gaec && gaec->cell_view && gaec->cell_view->ecell && E_IS_CELL_TEXT (gaec->cell_view->ecell), -1); - ect = E_CELL_TEXT (gaec->cell_view->ecell); + if (!ect_check (text)) + return -1; if (e_cell_text_get_selection (gaec->cell_view, gaec->view_col, gaec->row, &start, &end)) { - gchar *full_text = e_cell_text_get_text (ect, gaec->item->table_model, gaec->model_col, gaec->row); + gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); end = g_utf8_pointer_to_offset (full_text, full_text + end); - e_cell_text_free_text (ect, full_text); + g_free (full_text); return end; } @@ -163,13 +235,15 @@ static gint ect_get_character_count (AtkText *text) { GalA11yECell *gaec = GAL_A11Y_E_CELL (text); - ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); gint ret_val; - gchar *full_text = e_cell_text_get_text (ect, gaec->item->table_model, gaec->model_col, gaec->row); + if (!ect_check (text)) + return -1; + + gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); ret_val = g_utf8_strlen (full_text, -1); - e_cell_text_free_text (ect, full_text); + g_free (full_text); return ret_val; } @@ -190,6 +264,10 @@ ect_get_n_selections (AtkText *text) { GalA11yECell *gaec = GAL_A11Y_E_CELL (text); gint selection_start, selection_end; + + if (!ect_check (text)) + return 0; + if (e_cell_text_get_selection (gaec->cell_view, gaec->view_col, gaec->row, &selection_start, @@ -207,7 +285,6 @@ ect_get_selection (AtkText *text, gint *end_offset) { GalA11yECell *gaec = GAL_A11Y_E_CELL (text); - ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); gchar *ret_val; gint selection_start, selection_end; @@ -218,7 +295,7 @@ ect_get_selection (AtkText *text, &selection_end) && selection_start != selection_end) { gint real_start, real_end, len; - gchar *full_text = e_cell_text_get_text (ect, gaec->item->table_model, gaec->model_col, gaec->row); + gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); len = strlen (full_text); real_start = MIN (selection_start, selection_end); real_end = MAX (selection_start, selection_end); @@ -234,7 +311,7 @@ ect_get_selection (AtkText *text, *start_offset = real_start; if (end_offset) *end_offset = real_end; - e_cell_text_free_text (ect, full_text); + g_free (full_text); } else { if (start_offset) *start_offset = 0; @@ -253,12 +330,11 @@ ect_add_selection (AtkText *text, gint end_offset) { GalA11yECell *gaec = GAL_A11Y_E_CELL (text); - ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); if (start_offset != end_offset) { gint real_start, real_end, len; gchar *full_text = - e_cell_text_get_text (ect, gaec->item->table_model, gaec->model_col, gaec->row); + e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); len = g_utf8_strlen (full_text, -1); if (end_offset == -1) @@ -272,7 +348,7 @@ ect_add_selection (AtkText *text, real_start = g_utf8_offset_to_pointer (full_text, real_start) - full_text; real_end = g_utf8_offset_to_pointer (full_text, real_end) - full_text; - e_cell_text_free_text (ect, full_text); + g_free (full_text); if (e_cell_text_set_selection (gaec->cell_view, gaec->view_col, gaec->row, @@ -330,11 +406,10 @@ ect_set_caret_offset (AtkText *text, gint offset) { GalA11yECell *gaec = GAL_A11Y_E_CELL (text); - ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); gchar *full_text; gint len; - full_text = e_cell_text_get_text (ect, gaec->item->table_model, gaec->model_col, gaec->row); + full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); len = g_utf8_strlen (full_text, -1); if (offset == -1) @@ -344,7 +419,7 @@ ect_set_caret_offset (AtkText *text, offset = g_utf8_offset_to_pointer (full_text, offset) - full_text; - e_cell_text_free_text (ect, full_text); + g_free (full_text); return e_cell_text_set_selection (gaec->cell_view, gaec->view_col, gaec->row, @@ -382,7 +457,7 @@ ect_insert_text (AtkEditableText *text, GalA11yECell *gaec = GAL_A11Y_E_CELL (text); ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); - gchar *full_text = e_cell_text_get_text (ect, gaec->item->table_model, gaec->model_col, gaec->row); + gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row); gchar *result = g_strdup_printf ("%.*s%.*s%s", *position, full_text, length, string, full_text + *position); e_cell_text_set_value (ect, gaec->item->table_model, gaec->model_col, gaec->row, result); @@ -390,7 +465,7 @@ ect_insert_text (AtkEditableText *text, *position += length; g_free (result); - e_cell_text_free_text (ect, full_text); + g_free (full_text); } static void @@ -443,7 +518,43 @@ static void ect_do_action_edit (AtkAction *action) { GalA11yECell *a11y = GAL_A11Y_E_CELL (action); - e_table_item_enter_edit (a11y->item, a11y->view_col, a11y->row); + ETableModel *e_table_model = a11y->item->table_model; + + if (e_table_model_is_cell_editable(e_table_model, a11y->model_col, a11y->row)) { + e_table_item_enter_edit (a11y->item, a11y->view_col, a11y->row); + } +} + +/* text signal handlers */ +static void +ect_text_inserted_cb (ECellText *text, ECellView *cell_view, int pos, int len, int row, int model_col, gpointer data) +{ + GalA11yECellText *gaet; + GalA11yECell *gaec; + + if (!ect_check (data)) + return; + gaet = GAL_A11Y_E_CELL_TEXT (data); + gaec = GAL_A11Y_E_CELL (data); + + if (cell_view == gaec->cell_view && row == gaec->row && model_col == gaec->model_col) { + g_signal_emit_by_name (gaet, "text_changed::insert", pos, len); + + } +} + +static void +ect_text_deleted_cb (ECellText *text, ECellView *cell_view, int pos, int len, int row, int model_col, gpointer data) +{ + GalA11yECellText *gaet; + GalA11yECell *gaec; + if (!ect_check (data)) + return; + gaet = GAL_A11Y_E_CELL_TEXT (data); + gaec = GAL_A11Y_E_CELL (data); + if (cell_view == gaec->cell_view && row == gaec->row && model_col == gaec->model_col) { + g_signal_emit_by_name (gaet, "text_changed::delete", pos, len); + } } static void @@ -483,19 +594,25 @@ ect_atk_editable_text_iface_init (AtkEditableTextIface *iface) static void ect_class_init (GalA11yECellTextClass *klass) { - AtkObjectClass *a11y = ATK_OBJECT_CLASS (klass); + AtkObjectClass *a11y = ATK_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + parent_class = g_type_class_ref (PARENT_TYPE); a11y->get_name = ect_get_name; + object_class->dispose = ect_dispose; } static void -ect_init (GalA11yECellText *a11y) +ect_action_init (GalA11yECellText *a11y) { - gal_a11y_e_cell_add_action (GAL_A11Y_E_CELL (a11y), - "edit", - "begin editing this cell", + GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y); + ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell); + if (ect->editable && e_table_model_is_cell_editable (gaec->cell_view->e_table_model, gaec->model_col, gaec->row)) + gal_a11y_e_cell_add_action (gaec, + _("edit"), + _("begin editing this cell"), NULL, - (ACTION_FUNC)ect_do_action_edit); + (ACTION_FUNC) ect_do_action_edit); } /** @@ -522,7 +639,7 @@ gal_a11y_e_cell_text_get_type (void) NULL, /* class_data */ sizeof (GalA11yECellText), 0, - (GInstanceInitFunc) ect_init, + (GInstanceInitFunc) NULL, NULL /* value_cell_text */ }; @@ -547,6 +664,14 @@ gal_a11y_e_cell_text_get_type (void) return type; } +static void +cell_text_destroyed (gpointer data) +{ + g_return_if_fail (GAL_A11Y_IS_E_CELL_TEXT (data)); + + g_object_unref (data); +} + AtkObject * gal_a11y_e_cell_text_new (ETableItem *item, ECellView *cell_view, @@ -556,6 +681,9 @@ gal_a11y_e_cell_text_new (ETableItem *item, int row) { AtkObject *a11y; + GalA11yECell *gaec; + GalA11yECellText *gaet; + ECellText *ect; a11y = g_object_new (gal_a11y_e_cell_text_get_type (), NULL); @@ -566,5 +694,28 @@ gal_a11y_e_cell_text_new (ETableItem *item, model_col, view_col, row); + gaet = GAL_A11Y_E_CELL_TEXT (a11y); + + /* will be unrefed in cell_text_destroyed */ + g_object_ref (a11y); + + gaet->inserted_id = g_signal_connect (E_CELL_TEXT (((ECellView *)cell_view)->ecell), + "text_inserted", G_CALLBACK (ect_text_inserted_cb), a11y); + gaet->deleted_id = g_signal_connect (E_CELL_TEXT (((ECellView *)cell_view)->ecell), + "text_deleted", G_CALLBACK (ect_text_deleted_cb), a11y); + + g_object_weak_ref (G_OBJECT (((ECellView *)cell_view)->ecell), + (GWeakNotify) cell_text_destroyed, + a11y); + + ect_action_init (gaet); + + ect = E_CELL_TEXT (cell_view->ecell); + gaec = GAL_A11Y_E_CELL (a11y); + if (ect->editable && e_table_model_is_cell_editable (gaec->cell_view->e_table_model, gaec->model_col, gaec->row)) + gal_a11y_e_cell_add_state (gaec, ATK_STATE_EDITABLE, FALSE); + else + gal_a11y_e_cell_remove_state (gaec, ATK_STATE_EDITABLE, FALSE); + return a11y; } diff --git a/a11y/e-table/gal-a11y-e-cell-text.h b/a11y/e-table/gal-a11y-e-cell-text.h index 3d9a4447be..50056476c3 100644 --- a/a11y/e-table/gal-a11y-e-cell-text.h +++ b/a11y/e-table/gal-a11y-e-cell-text.h @@ -29,6 +29,8 @@ typedef struct _GalA11yECellTextPrivate GalA11yECellTextPrivate; **/ struct _GalA11yECellText { GalA11yECell object; + gint inserted_id; + gint deleted_id; }; struct _GalA11yECellTextClass { diff --git a/a11y/e-table/gal-a11y-e-cell-toggle.c b/a11y/e-table/gal-a11y-e-cell-toggle.c index 0d01028cc9..21f4955d1d 100644 --- a/a11y/e-table/gal-a11y-e-cell-toggle.c +++ b/a11y/e-table/gal-a11y-e-cell-toggle.c @@ -2,6 +2,8 @@ #include "gal-a11y-e-cell-toggle.h" #include <gal/e-table/e-cell-toggle.h> #include <gal/e-table/e-table-model.h> +#include <atk/atkcomponent.h> +#include <glib/gi18n.h> #define PARENT_TYPE (gal_a11y_e_cell_get_type ()) static GObjectClass *parent_class; @@ -15,8 +17,10 @@ gal_a11y_e_cell_toggle_dispose (GObject *object) ETableModel *e_table_model = GAL_A11Y_E_CELL (a11y)->item->table_model; - if (e_table_model) + if (e_table_model && a11y->model_id > 0) { g_signal_handler_disconnect (e_table_model, a11y->model_id); + a11y->model_id = 0; + } if (parent_class->dispose) parent_class->dispose (object); @@ -91,8 +95,8 @@ toggle_cell_action (GalA11yECell *cell) static void model_change_cb (ETableModel *etm, - gint row, gint col, + gint row, GalA11yECell *cell) { gint value; @@ -101,7 +105,10 @@ model_change_cb (ETableModel *etm, value = GPOINTER_TO_INT ( e_table_model_value_at (cell->cell_view->e_table_model, - cell->model_col, cell->row)); + cell->model_col, cell->row)); + /* Cheat gnopernicus, or it will ignore the state change signal */ + atk_focus_tracker_notify (ATK_OBJECT (cell)); + if (value) gal_a11y_e_cell_add_state (cell, ATK_STATE_CHECKED, TRUE); else @@ -140,8 +147,8 @@ gal_a11y_e_cell_toggle_new (ETableItem *item, row); gal_a11y_e_cell_add_action (cell, - "toggle", /* action name*/ - "toggle the cell", /* action description */ + _("toggle"), /* action name*/ + _("toggle the cell"), /* action description */ NULL, /* action keybinding */ toggle_cell_action); diff --git a/a11y/e-table/gal-a11y-e-cell-tree.c b/a11y/e-table/gal-a11y-e-cell-tree.c index ae833d9150..126bbcfbe5 100644 --- a/a11y/e-table/gal-a11y-e-cell-tree.c +++ b/a11y/e-table/gal-a11y-e-cell-tree.c @@ -14,6 +14,7 @@ #include "gal/e-table/e-cell-tree.h" #include "gal/e-table/e-table.h" #include "gal/e-table/e-tree-table-adapter.h" +#include <glib/gi18n.h> #define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellTreeClass)) static AtkObjectClass *a11y_parent_class; @@ -164,14 +165,14 @@ gal_a11y_e_cell_tree_new (ETableItem *item, view_col, row); gal_a11y_e_cell_add_action (GAL_A11Y_E_CELL (subcell_a11y), - "expand", - "expands the row in the ETree containing this cell", + _("expand"), + _("expands the row in the ETree containing this cell"), NULL, (ACTION_FUNC)ectr_do_action_expand); gal_a11y_e_cell_add_action (GAL_A11Y_E_CELL (subcell_a11y), - "collapse", - "collapses the row in the ETree containing this cell", + _("collapse"), + _("collapses the row in the ETree containing this cell"), NULL, (ACTION_FUNC)ectr_do_action_collapse); diff --git a/a11y/e-table/gal-a11y-e-cell-vbox.c b/a11y/e-table/gal-a11y-e-cell-vbox.c new file mode 100644 index 0000000000..4f2c156da8 --- /dev/null +++ b/a11y/e-table/gal-a11y-e-cell-vbox.c @@ -0,0 +1,214 @@ +/* Evolution Accessibility: gal-a11y-e-cell-vbox.c + * + * Copyright (C) 2004 Sun Microsystem, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Eric Zhao <eric.zhao@sun.com> Sun Microsystem Inc., 2004 + * + */ +#include "gal-a11y-e-cell-vbox.h" +#include "gal-a11y-e-cell-registry.h" +#include <gal/e-table/e-cell-vbox.h> +#include <atk/atkcomponent.h> + +static GObjectClass *parent_class; +static AtkComponentIface *component_parent_iface; +#define PARENT_TYPE (gal_a11y_e_cell_get_type ()) + +static gint +ecv_get_n_children (AtkObject *a11y) +{ + g_return_val_if_fail (GAL_A11Y_IS_E_CELL_VBOX (a11y), 0); + GalA11yECellVbox *gaev = GAL_A11Y_E_CELL_VBOX (a11y); + return (gaev->a11y_subcell_count); +} + +static void +subcell_destroyed (gpointer data) +{ + GalA11yECell *cell; + AtkObject *parent; + GalA11yECellVbox *gaev; + + g_return_if_fail (GAL_A11Y_IS_E_CELL (data)); + cell = GAL_A11Y_E_CELL (data); + + parent = atk_object_get_parent (ATK_OBJECT (cell)); + g_return_if_fail (GAL_A11Y_IS_E_CELL_VBOX (parent)); + gaev = GAL_A11Y_E_CELL_VBOX (parent); + + if (cell->view_col < gaev->a11y_subcell_count) + gaev->a11y_subcells[cell->view_col] = NULL; +} + +static AtkObject* +ecv_ref_child (AtkObject *a11y, gint i) +{ + GalA11yECellVbox *gaev = GAL_A11Y_E_CELL_VBOX (a11y); + GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y); + ECellVboxView *ecvv = (ECellVboxView *) (gaec->cell_view); + AtkObject *ret; + if (i < gaev->a11y_subcell_count) { + if (gaev->a11y_subcells[i] == NULL) { + gint model_col, row; + row = gaec->row; + model_col = ecvv->model_cols[i]; + ECellView *subcell_view = ecvv->subcell_views[i]; + ret = gal_a11y_e_cell_registry_get_object (NULL, + gaec->item, + subcell_view, + a11y, + model_col, + gaec->view_col, /* FIXME should the view column use a fake one or the same as its parent? */ + row); + gaev->a11y_subcells[i] = ret; + g_object_ref (ret); + g_object_weak_ref (G_OBJECT (ret), + (GWeakNotify) subcell_destroyed, + ret); + } else { + ret = (AtkObject *) gaev->a11y_subcells[i]; + if (ATK_IS_OBJECT (ret)) + g_object_ref (ret); + else + ret = NULL; + } + } else { + ret = NULL; + } + + return ret; +} + +static void +ecv_dispose (GObject *object) +{ + GalA11yECellVbox *gaev = GAL_A11Y_E_CELL_VBOX (object); + if (gaev->a11y_subcells) + g_free (gaev->a11y_subcells); + + if (parent_class->dispose) + parent_class->dispose (object); +} + +/* AtkComponet interface */ +static AtkObject* +ecv_ref_accessible_at_point (AtkComponent *component, + gint x, + gint y, + AtkCoordType coord_type) +{ + gint x0, y0, width, height; + int subcell_height, i; + + GalA11yECell *gaec = GAL_A11Y_E_CELL (component); + ECellVboxView *ecvv = (ECellVboxView *) (gaec->cell_view); + + atk_component_get_extents (component, &x0, &y0, &width, &height, coord_type); + x -= x0; + y -= y0; + if (x < 0 || x > width || y < 0 || y > height) + return NULL; + + for (i = 0; i < ecvv->subcell_view_count; i++) { + subcell_height = e_cell_height (ecvv->subcell_views[i], ecvv->model_cols[i], gaec->view_col, gaec->row); + if ( 0 <= y && y <= subcell_height) { + return ecv_ref_child ((AtkObject *)component, i); + } else + y -= subcell_height; + } + + return NULL; +} + +static void +ecv_class_init (GalA11yECellVboxClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + AtkObjectClass *a11y_class = ATK_OBJECT_CLASS (klass); + parent_class = g_type_class_ref (PARENT_TYPE); + + object_class->dispose = ecv_dispose; + + a11y_class->get_n_children = ecv_get_n_children; + a11y_class->ref_child = ecv_ref_child; +} + +static void +ecv_init (GalA11yECellVbox *a11y) +{ +} + +static void +ecv_atk_component_iface_init (AtkComponentIface *iface) +{ + component_parent_iface = g_type_interface_peek_parent (iface); + + iface->ref_accessible_at_point = ecv_ref_accessible_at_point; +} + +GType +gal_a11y_e_cell_vbox_get_type (void) +{ + static GType type = 0; + if (!type) { + GTypeInfo info = { + sizeof (GalA11yECellVboxClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ecv_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yECellVbox), + 0, + (GInstanceInitFunc) ecv_init, + NULL /* value_cell */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) ecv_atk_component_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yECellVbox", &info, 0); + gal_a11y_e_cell_type_add_action_interface (type); + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info); + } + + return type; +} + +AtkObject *gal_a11y_e_cell_vbox_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + int model_col, + int view_col, + int row) +{ + AtkObject *a11y; + + a11y = g_object_new (gal_a11y_e_cell_vbox_get_type (), NULL); + + gal_a11y_e_cell_construct (a11y, item, cell_view, parent, model_col, view_col, row); + + GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y); + GalA11yECellVbox *gaev = GAL_A11Y_E_CELL_VBOX (a11y); + ECellVboxView *ecvv = (ECellVboxView *) (gaec->cell_view); + gaev->a11y_subcell_count = ecvv->subcell_view_count; + gaev->a11y_subcells = g_malloc0 (sizeof(AtkObject *)*gaev->a11y_subcell_count); + return a11y; +} diff --git a/a11y/e-table/gal-a11y-e-cell-vbox.h b/a11y/e-table/gal-a11y-e-cell-vbox.h new file mode 100644 index 0000000000..ea0c9d8dc9 --- /dev/null +++ b/a11y/e-table/gal-a11y-e-cell-vbox.h @@ -0,0 +1,64 @@ +/* Evolution Accessibility: gal-a11y-e-cell-vbox.h + * + * Copyright (C) 2004 Sun Microsystem, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Eric Zhao <eric.zhao@sun.com> Sun Microsystem Inc., 2004 + * + */ +#ifndef __GAL_A11Y_E_CELL_VBOX_H__ +#define __GAL_A11Y_E_CELL_VBOX_H__ + +#include "gal-a11y-e-cell.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GAL_A11Y_TYPE_E_CELL_VBOX (gal_a11y_e_cell_vbox_get_type ()) +#define GAL_A11Y_E_CELL_VBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_VBOX, GalA11yECellVbox)) +#define GAL_A11Y_E_CELL_VBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_E_CELL_VBOX, GalA11yECellVboxClass)) +#define GAL_A11Y_IS_E_CELL_VBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_VBOX)) +#define GAL_A11Y_IS_E_CELL_VBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_VBOX)) +#define GAL_A11Y_E_CELL_VBOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GAL_A11Y_TYPE_E_CELL_VBOX, GalA11yECellVboxClass)) + +typedef struct _GalA11yECellVbox GalA11yECellVbox; +typedef struct _GalA11yECellVboxClass GalA11yECellVboxClass; + +struct _GalA11yECellVbox +{ + GalA11yECell object; + int a11y_subcell_count; + gpointer *a11y_subcells; +}; + +struct _GalA11yECellVboxClass +{ + GalA11yECellClass parent_class; +}; + +GType gal_a11y_e_cell_vbox_get_type (void); +AtkObject *gal_a11y_e_cell_vbox_new (ETableItem *item, + ECellView *cell_view, + AtkObject *parent, + int model_col, + int view_col, + int row); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __GAL_A11Y_E_CELL_VBOX_H__ */ diff --git a/a11y/e-table/gal-a11y-e-cell.c b/a11y/e-table/gal-a11y-e-cell.c index 9df3568e6c..f22b8f6b44 100644 --- a/a11y/e-table/gal-a11y-e-cell.c +++ b/a11y/e-table/gal-a11y-e-cell.c @@ -7,7 +7,10 @@ */ #include <config.h> +#include <string.h> #include "gal/e-table/e-table.h" +#include "gal/e-table/e-tree.h" +#include "gal-a11y-e-table-item.h" #include "gal-a11y-e-cell.h" #include "gal-a11y-util.h" #include <atk/atkobject.h> @@ -15,6 +18,7 @@ #include <atk/atkaction.h> #include <atk/atkstateset.h> #include <gtk/gtkwindow.h> +#include <glib/gi18n.h> #define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellClass)) static GObjectClass *parent_class; @@ -39,8 +43,28 @@ unref_cell (gpointer user_data, GObject *obj_loc) } #endif +static gboolean +is_valid (AtkObject *cell) +{ + GalA11yECell *a11y = GAL_A11Y_E_CELL (cell); + GalA11yETableItem *a11yItem = GAL_A11Y_E_TABLE_ITEM (a11y->parent); + AtkStateSet *item_ss; + gboolean ret = TRUE; + + item_ss = atk_object_ref_state_set (ATK_OBJECT (a11yItem)); + if (atk_state_set_contains_state (item_ss, ATK_STATE_DEFUNCT)) + ret = FALSE; + + g_object_unref (item_ss); + + if (ret && atk_state_set_contains_state (a11y->state_set, ATK_STATE_DEFUNCT)) + ret = FALSE; + + return ret; +} + static void -eti_dispose (GObject *object) +gal_a11y_e_cell_dispose (GObject *object) { GalA11yECell *a11y = GAL_A11Y_E_CELL (object); @@ -53,43 +77,69 @@ eti_dispose (GObject *object) g_object_unref (a11y->parent); #endif - if (a11y->state_set) + if (a11y->state_set) { g_object_unref (a11y->state_set); + a11y->state_set = NULL; + } if (parent_class->dispose) parent_class->dispose (object); + } /* Static functions */ +static G_CONST_RETURN gchar* +gal_a11y_e_cell_get_name (AtkObject * a11y) +{ + GalA11yECell *cell = GAL_A11Y_E_CELL (a11y); + ETableCol *ecol; + + if (a11y->name != NULL && strcmp (a11y->name, "")) + return a11y->name; + + if (cell->item != NULL) { + ecol = e_table_header_get_column (cell->item->header, cell->view_col); + if (ecol != NULL) + return ecol->text; + } + + return _("Table Cell"); +} + static AtkStateSet * -eti_ref_state_set (AtkObject *accessible) +gal_a11y_e_cell_ref_state_set (AtkObject *accessible) { GalA11yECell *cell = GAL_A11Y_E_CELL (accessible); - g_return_val_if_fail (cell->state_set, NULL); + g_return_val_if_fail (cell->state_set, NULL); + g_object_ref(cell->state_set); + return cell->state_set; } static AtkObject* -eti_get_parent (AtkObject *accessible) +gal_a11y_e_cell_get_parent (AtkObject *accessible) { GalA11yECell *a11y = GAL_A11Y_E_CELL (accessible); return a11y->parent; } static gint -eti_get_index_in_parent (AtkObject *accessible) +gal_a11y_e_cell_get_index_in_parent (AtkObject *accessible) { GalA11yECell *a11y = GAL_A11Y_E_CELL (accessible); + if (!is_valid (accessible)) + return -1; + return a11y->row * a11y->item->cols + a11y->view_col; } /* Component IFace */ static void -eti_get_extents (AtkComponent *component, +gal_a11y_e_cell_get_extents (AtkComponent *component, gint *x, gint *y, gint *width, @@ -97,6 +147,7 @@ eti_get_extents (AtkComponent *component, AtkCoordType coord_type) { GalA11yECell *a11y = GAL_A11Y_E_CELL (component); + GtkWidget *tableOrTree; int row; int col; int xval; @@ -105,14 +156,16 @@ eti_get_extents (AtkComponent *component, row = a11y->row; col = a11y->view_col; - - e_table_item_get_cell_geometry (a11y->item, - &row, - &col, - &xval, - &yval, - width, - height); + tableOrTree = gtk_widget_get_parent (GTK_WIDGET (a11y->item->parent.canvas)); + if (E_IS_TREE (tableOrTree)) { + e_tree_get_cell_geometry (E_TREE (tableOrTree), + row, col, &xval, &yval, + width, height); + } else { + e_table_get_cell_geometry (E_TABLE (tableOrTree), + row, col, &xval, &yval, + width, height); + } atk_component_get_position (ATK_COMPONENT (a11y->parent), x, y, coord_type); @@ -123,22 +176,23 @@ eti_get_extents (AtkComponent *component, } static gboolean -eti_grab_focus (AtkComponent *component) +gal_a11y_e_cell_grab_focus (AtkComponent *component) { GalA11yECell *a11y; - gint view_row; - GtkWidget *e_table, *toplevel; + gint index; + GtkWidget *toplevel; + GalA11yETableItem *a11yTableItem; a11y = GAL_A11Y_E_CELL (component); - e_table = gtk_widget_get_parent (GTK_WIDGET (GNOME_CANVAS_ITEM (a11y->item)->canvas)); - view_row = e_table_view_to_model_row (E_TABLE (e_table), a11y->row); - - e_selection_model_select_single_row (a11y->item->selection, view_row); - e_selection_model_change_cursor (a11y->item->selection, view_row, a11y->view_col); - - gtk_widget_grab_focus (e_table); - toplevel = gtk_widget_get_toplevel (e_table); - if (GTK_WIDGET_TOPLEVEL (toplevel)) + a11yTableItem = GAL_A11Y_E_TABLE_ITEM (a11y->parent); + index = atk_object_get_index_in_parent (ATK_OBJECT (a11y)); + + atk_selection_clear_selection (ATK_SELECTION (a11yTableItem)); + atk_selection_add_selection (ATK_SELECTION (a11yTableItem), index); + + gtk_widget_grab_focus (GTK_WIDGET (GNOME_CANVAS_ITEM (a11y->item)->canvas)); + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (GNOME_CANVAS_ITEM (a11y->item)->canvas)); + if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel)) gtk_window_present (GTK_WINDOW (toplevel)); return TRUE; @@ -147,29 +201,30 @@ eti_grab_focus (AtkComponent *component) /* Table IFace */ static void -eti_atk_component_iface_init (AtkComponentIface *iface) +gal_a11y_e_cell_atk_component_iface_init (AtkComponentIface *iface) { - iface->get_extents = eti_get_extents; - iface->grab_focus = eti_grab_focus; + iface->get_extents = gal_a11y_e_cell_get_extents; + iface->grab_focus = gal_a11y_e_cell_grab_focus; } static void -eti_class_init (GalA11yECellClass *klass) +gal_a11y_e_cell_class_init (GalA11yECellClass *klass) { AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_ref (PARENT_TYPE); - object_class->dispose = eti_dispose; + object_class->dispose = gal_a11y_e_cell_dispose; - atk_object_class->get_parent = eti_get_parent; - atk_object_class->get_index_in_parent = eti_get_index_in_parent; - atk_object_class->ref_state_set = eti_ref_state_set; + atk_object_class->get_parent = gal_a11y_e_cell_get_parent; + atk_object_class->get_index_in_parent = gal_a11y_e_cell_get_index_in_parent; + atk_object_class->ref_state_set = gal_a11y_e_cell_ref_state_set; + atk_object_class->get_name = gal_a11y_e_cell_get_name; } static void -eti_init (GalA11yECell *a11y) +gal_a11y_e_cell_init (GalA11yECell *a11y) { a11y->item = NULL; a11y->cell_view = NULL; @@ -181,6 +236,11 @@ eti_init (GalA11yECell *a11y) a11y->state_set = atk_state_set_new (); atk_state_set_add_state (a11y->state_set, ATK_STATE_TRANSIENT); atk_state_set_add_state (a11y->state_set, ATK_STATE_ENABLED); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SELECTABLE); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SHOWING); + atk_state_set_add_state (a11y->state_set, ATK_STATE_FOCUSABLE); + atk_state_set_add_state (a11y->state_set, ATK_STATE_VISIBLE); } @@ -350,6 +410,10 @@ idle_do_action (gpointer data) GalA11yECell *cell; cell = GAL_A11Y_E_CELL (data); + + if (!is_valid (ATK_OBJECT (cell))) + return FALSE; + cell->action_idle_handler = 0; cell->action_func (cell); @@ -363,6 +427,9 @@ gal_a11y_e_cell_action_do_action (AtkAction *action, GalA11yECell *cell = GAL_A11Y_E_CELL(action); ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index); + if (!is_valid (ATK_OBJECT (action))) + return FALSE; + if (info == NULL) return FALSE; g_return_val_if_fail (info->do_action_func, FALSE); @@ -477,17 +544,17 @@ gal_a11y_e_cell_get_type (void) sizeof (GalA11yECellClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, - (GClassInitFunc) eti_class_init, + (GClassInitFunc) gal_a11y_e_cell_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (GalA11yECell), 0, - (GInstanceInitFunc) eti_init, + (GInstanceInitFunc) gal_a11y_e_cell_init, NULL /* value_cell */ }; static const GInterfaceInfo atk_component_info = { - (GInterfaceInitFunc) eti_atk_component_iface_init, + (GInterfaceInitFunc) gal_a11y_e_cell_atk_component_iface_init, (GInterfaceFinalizeFunc) NULL, NULL }; @@ -539,17 +606,16 @@ gal_a11y_e_cell_construct (AtkObject *object, a11y->row = row; ATK_OBJECT (a11y) ->role = ATK_ROLE_TABLE_CELL; + if (item) + g_object_ref (G_OBJECT (item)); + #if 0 if (parent) g_object_ref (parent); - if (item) - g_object_ref (G_OBJECT (item)); /*, - unref_item, - a11y);*/ if (cell_view) - g_object_ref (G_OBJECT (cell_view)); /*, - unref_cell, - a11y);*/ + g_object_ref (G_OBJECT (cell_view)); + + #endif } diff --git a/a11y/e-table/gal-a11y-e-table-click-to-add.c b/a11y/e-table/gal-a11y-e-table-click-to-add.c index 13214a7ddd..c7c84d9deb 100644 --- a/a11y/e-table/gal-a11y-e-table-click-to-add.c +++ b/a11y/e-table/gal-a11y-e-table-click-to-add.c @@ -13,6 +13,7 @@ #include <gal/e-table/e-table-click-to-add.h> #include <atk/atkcomponent.h> #include <atk/atkaction.h> +#include <glib/gi18n.h> static AtkObjectClass *parent_class; static GType parent_type; @@ -37,7 +38,7 @@ etcta_get_description (AtkAction *action, gint i) { if (i == 0) - return "click to add"; + return _("click to add"); return NULL; } @@ -46,7 +47,7 @@ static G_CONST_RETURN gchar* etcta_action_get_name (AtkAction *action, gint i) { if (i == 0) - return "click"; + return _("click"); return NULL; } @@ -104,9 +105,15 @@ atk_action_interface_init (AtkActionIface *iface) static G_CONST_RETURN gchar * etcta_get_name (AtkObject *obj) { + ETableClickToAdd * etcta; + g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD (obj), NULL); - return "click to add"; + etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(obj))); + if (etcta && etcta->message != NULL) + return etcta->message; + + return _("click to add"); } static gint @@ -140,6 +147,20 @@ etcta_ref_child (AtkObject *accessible, return atk_obj; } +static AtkStateSet * +etcta_ref_state_set (AtkObject *accessible) +{ + AtkStateSet * state_set = NULL; + + state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible); + if (state_set != NULL) { + atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state (state_set, ATK_STATE_SHOWING); + } + + return state_set; +} + static void etcta_class_init (GalA11yETableClickToAddClass *klass) { @@ -150,6 +171,7 @@ etcta_class_init (GalA11yETableClickToAddClass *klass) atk_object_class->get_name = etcta_get_name; atk_object_class->get_n_children = etcta_get_n_children; atk_object_class->ref_child = etcta_ref_child; + atk_object_class->ref_state_set = etcta_ref_state_set; } static void @@ -241,6 +263,27 @@ etcta_event (GnomeCanvasItem *item, GdkEvent *e, gpointer data) return TRUE; } +static void +etcta_selection_cursor_changed (ESelectionModel *esm, gint row, gint col, + GalA11yETableClickToAdd *a11y) +{ + ETableClickToAdd *etcta; + AtkObject *row_a11y; + + etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(a11y))); + + if (etcta == NULL || etcta->row == NULL) + return; + + row_a11y = atk_gobject_accessible_for_object (G_OBJECT(etcta->row)); + if (row_a11y) { + AtkObject *cell_a11y = g_object_get_data (G_OBJECT(row_a11y), "gail-focus-object"); + if (cell_a11y) { + atk_focus_tracker_notify (cell_a11y); + } + } +} + AtkObject * gal_a11y_e_table_click_to_add_new (GObject *widget) { @@ -265,5 +308,8 @@ gal_a11y_e_table_click_to_add_new (GObject *widget) g_signal_connect_after (G_OBJECT(widget), "event", G_CALLBACK (etcta_event), a11y); + g_signal_connect (etcta->selection, "cursor_changed", + G_CALLBACK (etcta_selection_cursor_changed), a11y); + return ATK_OBJECT (a11y); } diff --git a/a11y/e-table/gal-a11y-e-table-item-factory.c b/a11y/e-table/gal-a11y-e-table-item-factory.c index 12cb978fde..3c8e60a4bb 100644 --- a/a11y/e-table/gal-a11y-e-table-item-factory.c +++ b/a11y/e-table/gal-a11y-e-table-item-factory.c @@ -31,7 +31,7 @@ gal_a11y_e_table_item_factory_create_accessible (GObject *obj) AtkObject *accessible; g_return_val_if_fail (E_IS_TABLE_ITEM(obj), NULL); - accessible = gal_a11y_e_table_item_new(NULL, E_TABLE_ITEM (obj), 0); + accessible = gal_a11y_e_table_item_new (E_TABLE_ITEM (obj)); return accessible; } diff --git a/a11y/e-table/gal-a11y-e-table-item.c b/a11y/e-table/gal-a11y-e-table-item.c index 627735ba04..2cf407c772 100644 --- a/a11y/e-table/gal-a11y-e-table-item.c +++ b/a11y/e-table/gal-a11y-e-table-item.c @@ -10,11 +10,16 @@ #include <config.h> #include <string.h> #include "gal-a11y-e-table-item.h" +#include "gal-a11y-e-table-item-factory.h" +#include "gal-a11y-e-table-click-to-add.h" #include "gal-a11y-e-cell-registry.h" #include "gal-a11y-e-cell.h" #include "gal-a11y-util.h" #include <gal/e-table/e-table-subset.h> +#include <gal/widgets/e-selection-model.h> +#include <gal/widgets/e-canvas.h> #include <gal/e-table/e-table.h> +#include <gal/e-table/e-table-click-to-add.h> #include <gal/e-table/e-tree.h> #include <atk/atkobject.h> @@ -34,15 +39,13 @@ static GQuark quark_accessible_object = 0; #define PARENT_TYPE (parent_type) struct _GalA11yETableItemPrivate { - AtkObject *parent; - gint index_in_parent; gint cols; gint rows; - gpointer *cell_data; int selection_change_id; int cursor_change_id; ETableCol ** columns; ESelectionModel *selection; + AtkStateSet *state_set; GtkWidget *widget; }; @@ -50,17 +53,31 @@ static gboolean gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y, ESelectionModel *selection); static gboolean gal_a11y_e_table_item_unref_selection (GalA11yETableItem *a11y); -static gpointer *eti_reinit_data (AtkTable *table, ETableItem *item); +static AtkObject* eti_ref_at (AtkTable *table, gint row, gint column); -#if 0 static void -unref_accessible (gpointer user_data, GObject *obj_loc) +item_destroyed (GtkObject *item, gpointer user_data) { GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (user_data); - GET_PRIVATE (a11y)->item = NULL; - g_object_unref (a11y); + GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); + + atk_state_set_add_state (priv->state_set, ATK_STATE_DEFUNCT); + atk_object_notify_state_change (ATK_OBJECT (a11y), ATK_STATE_DEFUNCT, TRUE); + + if (priv->selection) + gal_a11y_e_table_item_unref_selection (a11y); + +} + +static AtkStateSet * +eti_ref_state_set (AtkObject *accessible) +{ + GalA11yETableItemPrivate *priv = GET_PRIVATE (accessible); + + g_object_ref(priv->state_set); + + return priv->state_set; } -#endif inline static gint view_to_model_row(ETableItem *eti, int row) @@ -131,13 +148,6 @@ eti_dispose (GObject *object) GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (object); GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); - priv->parent = NULL; - - if ( priv->cell_data != NULL ) { - g_free(priv->cell_data); - priv->cell_data = NULL; - } - if (priv->columns) { g_free(priv->columns); priv->columns = NULL; @@ -145,25 +155,9 @@ eti_dispose (GObject *object) if (parent_class->dispose) parent_class->dispose (object); - if (priv->selection) - gal_a11y_e_table_item_unref_selection (a11y); } /* Static functions */ -static AtkObject * -eti_get_parent (AtkObject *accessible) -{ - GalA11yETableItem *a11y; - - g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), NULL); - if (!eti_a11y_get_gobject (accessible)) - /* defunct */ - return NULL; - - a11y = GAL_A11Y_E_TABLE_ITEM (accessible); - return GET_PRIVATE (a11y)->parent; -} - static gint eti_get_n_children (AtkObject *accessible) { @@ -186,34 +180,12 @@ eti_ref_child (AtkObject *accessible, gint index) if (!item) return NULL; - if (index < item->cols) { - AtkObject *child; - - /* A column header is required */ - child = atk_table_get_column_header (ATK_TABLE (accessible), index); - if (child) - g_object_ref (child); - return child; - } + /* don't support column header now */ - index -= item->cols; col = index % item->cols; row = index / item->cols; - return atk_table_ref_at (ATK_TABLE (accessible), row, col); -} - -static gint -eti_get_index_in_parent (AtkObject *accessible) -{ - GalA11yETableItem *a11y; - - g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), -1); - if (!eti_a11y_get_gobject (accessible)) - return -1; - - a11y = GAL_A11Y_E_TABLE_ITEM (accessible); - return GET_PRIVATE (a11y)->index_in_parent; + return eti_ref_at (ATK_TABLE (accessible), row, col); } static void @@ -225,33 +197,25 @@ eti_get_extents (AtkComponent *component, AtkCoordType coord_type) { ETableItem *item; - double real_width; - double real_height; - int fake_width; - int fake_height; + AtkObject *parent; item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component))); if (!item) return; - if (component_parent_iface && - component_parent_iface->get_extents) - component_parent_iface->get_extents (component, - x, - y, - &fake_width, - &fake_height, - coord_type); - - gtk_object_get (GTK_OBJECT (item), - "width", &real_width, - "height", &real_height, - NULL); - - if (width) - *width = real_width; - if (height) - *height = real_height; + parent = ATK_OBJECT (component)->accessible_parent; + if (parent && ATK_IS_COMPONENT (parent)) + atk_component_get_extents (ATK_COMPONENT (parent), x, y, + width, height, + coord_type); + + if (parent && GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD (parent)) { + ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (parent))); + if (etcta) { + *width = etcta->width; + *height = etcta->height; + } + } } static AtkObject* @@ -264,6 +228,7 @@ eti_ref_accessible_at_point (AtkComponent *component, int col = -1; int x_origin, y_origin; ETableItem *item; + GtkWidget *tableOrTree; item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component))); if (!item) @@ -276,11 +241,15 @@ eti_ref_accessible_at_point (AtkComponent *component, x -= x_origin; y -= y_origin; - e_table_item_compute_location (item, &x, &y, - &row, &col); + tableOrTree = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas)); + + if (E_IS_TREE(tableOrTree)) + e_tree_get_cell_at (E_TREE (tableOrTree), x, y, &row, &col); + else + e_table_get_cell_at (E_TABLE (tableOrTree), x, y, &row, &col); if (row != -1 && col != -1) { - return atk_table_ref_at (ATK_TABLE (component), row, col); + return eti_ref_at (ATK_TABLE (component), row, col); } else { return NULL; } @@ -290,23 +259,18 @@ eti_ref_accessible_at_point (AtkComponent *component, static void cell_destroyed (gpointer data) { - gint index; - GalA11yETableItem * item; GalA11yECell * cell; g_return_if_fail (GAL_A11Y_IS_E_CELL (data)); cell = GAL_A11Y_E_CELL (data); - - item = GAL_A11Y_E_TABLE_ITEM (atk_gobject_accessible_for_object (G_OBJECT (GAL_A11Y_E_CELL(data)->item))); - g_return_if_fail (item && GAL_A11Y_IS_E_TABLE_ITEM (item)); + g_return_if_fail (cell->item && G_IS_OBJECT (cell->item)); - g_return_if_fail (cell->row < GET_PRIVATE(item)->rows && cell->view_col < GET_PRIVATE(item)->cols); + if (cell->item) { + g_object_unref (cell->item); + cell->item = NULL; + } - index = cell->row * cell->item->cols + cell->view_col; - - if (GET_PRIVATE (item)->cell_data && GET_PRIVATE (item)->cell_data [index] == data) - GET_PRIVATE (item)->cell_data [index] = NULL; } /* atk table */ @@ -315,6 +279,11 @@ eti_ref_at (AtkTable *table, gint row, gint column) { ETableItem *item; AtkObject* ret; + GalA11yETableItemPrivate *priv = GET_PRIVATE (table); + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return NULL; + item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); if (!item) @@ -327,38 +296,23 @@ eti_ref_at (AtkTable *table, gint row, gint column) item->cell_views_realized) { ECellView *cell_view = item->cell_views[column]; ETableCol *ecol = e_table_header_get_column (item->header, column); - gpointer * cell_data; - - cell_data = eti_reinit_data (table, item); - if (cell_data == NULL) - return NULL; - - if (cell_data[row*item->cols + column] == NULL) { - ret = gal_a11y_e_cell_registry_get_object (NULL, + ret = gal_a11y_e_cell_registry_get_object (NULL, item, cell_view, ATK_OBJECT (table), ecol->col_idx, column, - row); - cell_data[row*item->cols + column] = ret; - if (ATK_IS_OBJECT (ret)) { - gal_a11y_e_cell_add_state(ret, ATK_STATE_SHOWING, FALSE); - gal_a11y_e_cell_add_state(ret, ATK_STATE_VISIBLE, FALSE); - g_object_weak_ref (G_OBJECT (ret), - (GWeakNotify) cell_destroyed, - ret); - } else - ret = NULL; - } else { - ret = (AtkObject *) cell_data[row*item->cols + column]; - if (ATK_IS_OBJECT (ret)) { - g_object_ref (ret); - } else { - ret = NULL; - } - } - + row); + if (ATK_IS_OBJECT (ret)) { + g_object_weak_ref (G_OBJECT (ret), + (GWeakNotify) cell_destroyed, + ret); + /* if current cell is focused, add FOCUSED state */ + if (e_selection_model_cursor_row (item->selection) == GAL_A11Y_E_CELL (ret)->row && + e_selection_model_cursor_col (item->selection) == GAL_A11Y_E_CELL (ret)->model_col) + gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (ret), ATK_STATE_FOCUSED, FALSE); + } else + ret = NULL; return ret; } @@ -501,16 +455,21 @@ eti_get_column_header (AtkTable *table, gint column) ETableItem *item; ETableCol *ecol; AtkObject *atk_obj = NULL; - ECell *ecell; item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); if (!item) return NULL; ecol = e_table_header_get_column (item->header, column); - ecell = ecol->ecell; - if (ecell) - atk_obj = atk_gobject_accessible_for_object (G_OBJECT (ecell)); + if (ecol) { + atk_obj = atk_gobject_accessible_for_object (G_OBJECT (ecol)); + if (atk_obj) { + if (ecol->text) + atk_object_set_name (atk_obj, ecol->text); + atk_object_set_role (atk_obj, ATK_ROLE_TABLE_COLUMN_HEADER); + } + } + return atk_obj; } @@ -541,12 +500,16 @@ static gboolean table_is_row_selected (AtkTable *table, gint row) { ETableItem *item; + GalA11yETableItemPrivate *priv = GET_PRIVATE (table); + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return FALSE; item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); if (!item) return FALSE; - return e_selection_model_is_row_selected(item->selection, row); + return e_selection_model_is_row_selected(item->selection, view_to_model_row (item, row)); } static gboolean @@ -560,6 +523,10 @@ table_get_selected_rows (AtkTable *table, gint **rows_selected) { ETableItem *item; gint n_selected, row, index_selected; + GalA11yETableItemPrivate *priv = GET_PRIVATE (table); + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return 0; item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); if (!item) @@ -601,6 +568,10 @@ static gboolean table_remove_row_selection (AtkTable *table, gint row) { ETableItem *item; + GalA11yETableItemPrivate *priv = GET_PRIVATE (table); + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return FALSE; item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table))); if (!item) @@ -608,7 +579,7 @@ table_remove_row_selection (AtkTable *table, gint row) if (!atk_table_is_row_selected (table, row)) return TRUE; - e_selection_model_toggle_single_row (item->selection, row); + e_selection_model_toggle_single_row (item->selection, view_to_model_row (item, row)); return TRUE; } @@ -651,7 +622,6 @@ eti_rows_inserted (ETableModel * model, int row, int count, AtkObject * table_item) { gint n_cols,n_rows,i,j; - gpointer *cell_data; GalA11yETableItem * item_a11y; gint old_nrows; @@ -666,34 +636,8 @@ eti_rows_inserted (ETableModel * model, int row, int count, g_return_if_fail (n_cols > 0 && n_rows > 0); g_return_if_fail (old_nrows == n_rows - count); - cell_data = GET_PRIVATE(table_item)->cell_data; - GET_PRIVATE(table_item)->cell_data = g_realloc (cell_data, (n_rows*n_cols) * sizeof(gpointer)); - cell_data = GET_PRIVATE(table_item)->cell_data; - GET_PRIVATE(table_item)->rows = n_rows; - /* If rows are insert in the middle of a table. */ - if (row + count < n_rows ) { - memmove(&cell_data[(row+count)*n_cols], &cell_data[row*n_cols], - (old_nrows-row)*n_cols*sizeof(gpointer)); - - /* Update cell's index. */ - for (i = row + count; i < n_rows; i ++) { - for (j = 0; j < n_cols; j ++) - if (cell_data[i*n_cols + j] != NULL) { - AtkObject * a11y; - - a11y = ATK_OBJECT(cell_data[i*n_cols + j]); - GAL_A11Y_E_CELL(a11y)->row = i; - } - } - } - - /* Clear cache for the new added rows. */ - for (i = row ; i < row+count; i ++) - for (j = 0 ; j < n_cols; j ++) - cell_data [i*n_cols + j] = NULL; - g_signal_emit_by_name (table_item, "row-inserted", row, count, NULL); @@ -708,132 +652,21 @@ eti_rows_inserted (ETableModel * model, int row, int count, g_signal_emit_by_name (table_item, "visible-data-changed"); } -/* - * reinit the eti's private data - * make sure it is synchronized with the gal-e-table-item - */ -static gpointer * -eti_reinit_data (AtkTable *table, ETableItem *item) -{ - gpointer * cell_data; - - int oldsize, newsize; - cell_data = GET_PRIVATE (table)->cell_data; - if (GET_PRIVATE (table)->rows != item->rows - || GET_PRIVATE (table)->cols != item->cols ) { /* reinit cell_data */ - oldsize = GET_PRIVATE (table)->cols * GET_PRIVATE (table)->rows; - newsize = item->cols*item->rows; - GET_PRIVATE (table)->cols = item->cols; - GET_PRIVATE (table)->rows = item->rows; - - cell_data = g_realloc(cell_data, newsize*sizeof(gpointer)); - if (newsize > oldsize) - memset(&cell_data[oldsize], 0, (newsize-oldsize)*sizeof(gpointer)); - - GET_PRIVATE (table)->cell_data = cell_data; - } - return cell_data; -} - -/* - * clear all the AtkObjects stored in the cell_data - * doesn't free the cell_data or resize it. - */ -static void -eti_clear_rows (ETableModel * model, AtkObject * table_item, int row, int count) -{ - gint i,j, n_rows, n_cols; - gpointer *cell_data; - - g_return_if_fail (model && table_item); - - cell_data = GET_PRIVATE (table_item)->cell_data; - g_return_if_fail (cell_data); - - n_rows = GET_PRIVATE (table_item)->rows; - n_cols = GET_PRIVATE (table_item)->cols; - - g_return_if_fail( row >= 0 && count > 0 && row+count <= n_rows); - - /* DEFUNCT the deleted cells. */ - for (i = row; i < row+count; i ++) { - for (j = 0; j < n_cols; j ++) { - if (cell_data[i*n_cols + j] != NULL) { - AtkObject * a11y; - - a11y = ATK_OBJECT(cell_data[i*n_cols + j]); - gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL(a11y), ATK_STATE_DEFUNCT, TRUE); - cell_data[i*n_cols + j] = NULL; - } - } - } - - g_signal_emit_by_name (table_item, "row-deleted", row, - count, NULL); - - for (i = row; i < row+count; i ++) { - for (j = 0; j < n_cols; j ++) { - g_signal_emit_by_name (table_item, - "children_changed::remove", - ( (i*n_cols) + j), NULL, NULL); - } - } - g_signal_emit_by_name (table_item, "visible-data-changed"); -} - static void eti_rows_deleted (ETableModel * model, int row, int count, AtkObject * table_item) { gint i,j, n_rows, n_cols, old_nrows; - gpointer *cell_data; n_rows = atk_table_get_n_rows (ATK_TABLE(table_item)); n_cols = atk_table_get_n_columns (ATK_TABLE(table_item)); - cell_data = GET_PRIVATE(table_item)->cell_data; old_nrows = GET_PRIVATE(table_item)->rows; g_return_if_fail ( row+count <= old_nrows); g_return_if_fail (old_nrows == n_rows + count); GET_PRIVATE(table_item)->rows = n_rows; - /* DEFUNCT the deleted cells. */ - for (i = row; i < row+count; i ++) { - for (j = 0; j < n_cols; j ++) { - if (cell_data[i*n_cols + j] != NULL) { - AtkObject * a11y; - - a11y = ATK_OBJECT(cell_data[i*n_cols + j]); - gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL(a11y), ATK_STATE_DEFUNCT, TRUE); - cell_data[i*n_cols + j] = NULL; - } - } - } - - /* If more rows left, update the a11y object. */ - if (old_nrows > row + count) { - - /* Remove the defunct cells in cache. */ - memmove (&cell_data[row*n_cols], &cell_data[(row+count)*n_cols], - ( old_nrows-row-count)*n_cols*sizeof(gpointer)); - - GET_PRIVATE(table_item)->cell_data = g_realloc (cell_data, n_rows*n_cols*sizeof(gpointer)); - cell_data = GET_PRIVATE(table_item)->cell_data; - - /* Update index of cells below the deleted rows. */ - for (i = row; i < n_rows; i ++) { - for (j = 0; j < n_cols; j ++) { - if (cell_data[i*n_cols + j] != NULL) { - AtkObject * a11y; - - a11y = ATK_OBJECT(cell_data[i*n_cols + j]); - GAL_A11Y_E_CELL(a11y)->row = i; - } - } - } - } - g_signal_emit_by_name (table_item, "row-deleted", row, count, NULL); @@ -858,9 +691,9 @@ eti_tree_model_node_changed_cb (ETreeModel *model, ETreePath node, ETableItem *e atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti)); a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj); - /* we can't figure out which rows are changed, so just clear all of them ... */ + /* we can't figure out which rows are changed, so just send out a signal ... */ if (GET_PRIVATE (a11y)->rows > 0) - eti_clear_rows (eti->table_model, atk_obj, 0, GET_PRIVATE (a11y)->rows); + g_signal_emit_by_name (a11y, "visible-data-changed"); } enum { @@ -885,14 +718,10 @@ eti_header_structure_changed (ETableHeader *eth, AtkObject *a11y) 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; @@ -949,26 +778,6 @@ eti_header_structure_changed (ETableHeader *eth, AtkObject *a11y) 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"); @@ -1040,11 +849,10 @@ eti_class_init (GalA11yETableItemClass *klass) object_class->dispose = eti_dispose; - atk_object_class->get_parent = eti_get_parent; atk_object_class->get_n_children = eti_get_n_children; atk_object_class->ref_child = eti_ref_child; - atk_object_class->get_index_in_parent = eti_get_index_in_parent; atk_object_class->initialize = eti_real_initialize; + atk_object_class->ref_state_set = eti_ref_state_set; } static void @@ -1054,8 +862,6 @@ eti_init (GalA11yETableItem *a11y) priv = GET_PRIVATE (a11y); - priv->parent = NULL; - priv->index_in_parent = -1; priv->selection_change_id = 0; priv->cursor_change_id = 0; priv->selection = NULL; @@ -1149,37 +955,36 @@ gal_a11y_e_table_item_get_type (void) } AtkObject * -gal_a11y_e_table_item_new (AtkObject *parent, - ETableItem *item, - int index_in_parent) +gal_a11y_e_table_item_new (ETableItem *item) { GalA11yETableItem *a11y; AtkObject *accessible; int n; + ESelectionModel * esm; + AtkObject * cell; + AtkObject *parent; + const char *name; g_return_val_if_fail (item && item->cols >= 0 && item->rows >= 0, NULL); a11y = g_object_new (gal_a11y_e_table_item_get_type (), NULL); atk_object_initialize (ATK_OBJECT (a11y), item); - GET_PRIVATE (a11y)->parent = parent; - GET_PRIVATE (a11y)->index_in_parent = index_in_parent; + GET_PRIVATE (a11y)->state_set = atk_state_set_new (); + + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_TRANSIENT); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_ENABLED); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_SHOWING); + atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_VISIBLE); + accessible = ATK_OBJECT(a11y); - accessible->role = ATK_ROLE_TREE_TABLE; /* Initialize cell data. */ n = item->cols * item->rows; GET_PRIVATE (a11y)->cols = item->cols; GET_PRIVATE (a11y)->rows = item->rows; - if (n > 0) { - GET_PRIVATE (a11y)->cell_data = g_malloc0(n*sizeof(gpointer)); - /* memory error. */ - if ( GET_PRIVATE (a11y)->cell_data == NULL) - return NULL; - } else - GET_PRIVATE (a11y)->cell_data = NULL; - GET_PRIVATE (a11y)->columns = e_table_header_get_columns (item->header); if ( GET_PRIVATE (a11y)->columns == NULL) @@ -1196,22 +1001,49 @@ gal_a11y_e_table_item_new (AtkObject *parent, /* find the TableItem's parent: table or tree */ GET_PRIVATE (a11y)->widget = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas)); + parent = gtk_widget_get_accessible (GET_PRIVATE (a11y)->widget); + name = atk_object_get_name (parent); + if (name) + atk_object_set_name (accessible, name); + atk_object_set_parent (accessible, parent); + if (E_IS_TREE (GET_PRIVATE (a11y)->widget)) { ETreeModel *model; model = e_tree_get_model (E_TREE (GET_PRIVATE (a11y)->widget)); g_signal_connect (G_OBJECT(model), "node_changed", G_CALLBACK (eti_tree_model_node_changed_cb), item); + accessible->role = ATK_ROLE_TREE_TABLE; + } else if (E_IS_TABLE (GET_PRIVATE (a11y)->widget)) { + accessible->role = ATK_ROLE_TABLE; } } - if (parent) - g_object_ref (parent); -#if 0 if (item) - g_object_weak_ref (G_OBJECT (item), - unref_accessible, + g_signal_connect (G_OBJECT (item), "destroy", + G_CALLBACK (item_destroyed), a11y); -#endif + esm = item->selection; + + if (esm != NULL) { + int cursor_row, cursor_col, view_row, view_col; + + cursor_row = e_selection_model_cursor_row(esm); + cursor_col = e_selection_model_cursor_col(esm); + + view_row = model_to_view_row (item, cursor_row); + view_col = model_to_view_col (item, cursor_col); + + if (view_row == -1) + view_row = 0; + if (view_col == -1) + view_col = 0; + + cell = eti_ref_at (ATK_TABLE (a11y), view_row, view_col); + if (cell != NULL) { + g_object_set_data (G_OBJECT(a11y), "gail-focus-object", cell); + gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (cell), ATK_STATE_FOCUSED, FALSE); + } + } return ATK_OBJECT (a11y); } @@ -1304,6 +1136,11 @@ eti_a11y_selection_model_added_cb (ETableItem *eti, ESelectionModel *selection, static void eti_a11y_selection_changed_cb (ESelectionModel *selection, GalA11yETableItem *a11y) { + GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); + + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return; + g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y)); g_signal_emit_by_name (a11y, "selection_changed"); @@ -1316,27 +1153,39 @@ eti_a11y_cursor_changed_cb (ESelectionModel *selection, AtkObject * cell; int view_row, view_col; ETableItem *item; + GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y); g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y)); - g_signal_emit_by_name (a11y, "selection_changed"); + if (atk_state_set_contains_state (priv->state_set, ATK_STATE_DEFUNCT)) + return; item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (a11y))); g_return_if_fail (item); + if (row == -1 && col == -1) + return; + view_row = model_to_view_row (item, row); view_col = model_to_view_col (item, col); - cell = atk_table_ref_at (ATK_TABLE (a11y), view_row, view_col); + if (view_col == -1) + view_col = 0; + cell = eti_ref_at (ATK_TABLE (a11y), view_row, view_col); if (cell != NULL) { - gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (cell), ATK_STATE_FOCUSED, FALSE); + AtkObject *old_cell = (AtkObject *)g_object_get_data (G_OBJECT(a11y), "gail-focus-object"); + if (old_cell && GAL_A11Y_IS_E_CELL (old_cell)) + gal_a11y_e_cell_remove_state (GAL_A11Y_E_CELL (old_cell), ATK_STATE_FOCUSED, FALSE); + if (old_cell) + g_object_unref (old_cell); + + g_object_set_data (G_OBJECT(a11y), "gail-focus-object", cell); if (ATK_IS_OBJECT (cell)) g_signal_emit_by_name (a11y, "active-descendant-changed", cell); - atk_focus_tracker_notify (cell); } } @@ -1357,7 +1206,7 @@ static gboolean selection_add_selection (AtkSelection *selection, gint index) { AtkTable *table; - gint row, col; + gint row, col, cursor_row, cursor_col, model_row, model_col; ETableItem *item; item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection))); @@ -1367,18 +1216,36 @@ selection_add_selection (AtkSelection *selection, gint index) table = ATK_TABLE (selection); row = atk_table_get_row_at_index (table, index); - atk_table_add_row_selection (table, row); - col = atk_table_get_column_at_index (table, index); + + model_row = view_to_model_row (item, row); + model_col = view_to_model_col (item, col); + + cursor_row = e_selection_model_cursor_row (item->selection); + cursor_col = e_selection_model_cursor_col (item->selection); + + /* check whether is selected already */ + if (model_row == cursor_row && model_col == cursor_col) + return TRUE; + + if (model_row != cursor_row) { + /* we need to make the item get focus */ + e_canvas_item_grab_focus (GNOME_CANVAS_ITEM (item), TRUE); + + /* FIXME, currently we only support single row selection */ + atk_selection_clear_selection (selection); + atk_table_add_row_selection (table, row); + } + e_selection_model_change_cursor (item->selection, - view_to_model_row (item, row), - view_to_model_col (item, col)); + model_row, + model_col); e_selection_model_cursor_changed (item->selection, - view_to_model_row (item, row), - view_to_model_col (item, col)); + model_row, + model_col); e_selection_model_cursor_activated (item->selection, - view_to_model_row (item, row), - view_to_model_col (item, col)); + model_row, + model_col); return TRUE; } @@ -1407,7 +1274,7 @@ selection_ref_selection (AtkSelection *selection, gint index) if (!atk_table_is_row_selected (table, row)) return NULL; - return atk_table_ref_at (table, row, col); + return eti_ref_at (table, row, col); } static gint @@ -1431,3 +1298,11 @@ selection_is_child_selected (AtkSelection *selection, gint i) row = atk_table_get_row_at_index (ATK_TABLE (selection), i); return atk_table_is_row_selected (ATK_TABLE (selection), row); } + +void +gal_a11y_e_table_item_init (void) +{ + atk_registry_set_factory_type (atk_get_default_registry (), + E_TABLE_ITEM_TYPE, + gal_a11y_e_table_item_factory_get_type ()); +} diff --git a/a11y/e-table/gal-a11y-e-table-item.h b/a11y/e-table/gal-a11y-e-table-item.h index f3a447131d..0317132804 100644 --- a/a11y/e-table/gal-a11y-e-table-item.h +++ b/a11y/e-table/gal-a11y-e-table-item.h @@ -37,8 +37,8 @@ struct _GalA11yETableItemClass { /* Standard Glib function */ GType gal_a11y_e_table_item_get_type (void); -AtkObject *gal_a11y_e_table_item_new (AtkObject *parent, - ETableItem *item, - int index_in_parent); +AtkObject *gal_a11y_e_table_item_new (ETableItem *item); + +void gal_a11y_e_table_item_init (void); #endif /* ! __GAL_A11Y_E_TABLE_ITEM_H__ */ diff --git a/a11y/e-table/gal-a11y-e-table.c b/a11y/e-table/gal-a11y-e-table.c index 8f4f246e70..16fef97c9d 100644 --- a/a11y/e-table/gal-a11y-e-table.c +++ b/a11y/e-table/gal-a11y-e-table.c @@ -12,6 +12,7 @@ #include "gal-a11y-util.h" #include <gal/e-table/e-table.h> #include <gal/e-table/e-table-group.h> +#include <gal/e-table/e-table-group-container.h> #include <gal/e-table/e-table-group-leaf.h> #include <gal/e-table/e-table-click-to-add.h> @@ -27,16 +28,80 @@ struct _GalA11yETablePrivate { }; /* Static functions */ +static ETableItem * +find_first_table_item (ETableGroup *group) +{ + GnomeCanvasGroup *cgroup; + GList *l; -static void + cgroup = GNOME_CANVAS_GROUP (group); + + for (l = cgroup->item_list; l; l = l->next) { + GnomeCanvasItem *i; + + i = GNOME_CANVAS_ITEM (l->data); + + if (E_IS_TABLE_GROUP (i)) + return find_first_table_item (E_TABLE_GROUP (i)); + else if (E_IS_TABLE_ITEM (i)) { + return E_TABLE_ITEM (i); + } + } + + return NULL; +} + +static AtkObject* +eti_get_accessible (ETableItem *eti, AtkObject *parent) +{ + AtkObject *a11y = NULL; + + g_return_val_if_fail (eti, NULL); + + a11y = atk_gobject_accessible_for_object (G_OBJECT (eti)); + g_return_val_if_fail (a11y, NULL); + + return a11y; +} + +static ETableItem * +find_table_item (ETable *table) +{ + if (e_table_model_row_count(table->model) < 1) + return NULL; + else { + if (table->group) + return find_first_table_item (table->group); + } + + return NULL; +} + +static gboolean init_child_item (GalA11yETable *a11y) { - GalA11yETablePrivate *priv = GET_PRIVATE (a11y); - ETable *table = E_TABLE (GTK_ACCESSIBLE (a11y)->widget); - if (priv->child_item == NULL) { - priv->child_item = atk_gobject_accessible_for_object (G_OBJECT(E_TABLE_GROUP_LEAF (table->group)->item)); - priv->child_item->role = ATK_ROLE_TABLE; + ETable *table; + + if (!a11y || !GTK_IS_ACCESSIBLE (a11y)) + return FALSE; + + table = E_TABLE (GTK_ACCESSIBLE (a11y)->widget); + if (table && GTK_WIDGET_MAPPED (GTK_WIDGET (table)) && table->group && E_IS_TABLE_GROUP_CONTAINER(table->group)) { + ETableGroupContainer *etgc = (ETableGroupContainer *)table->group; + GList *list; + + for (list = etgc->children; list; list = g_list_next (list)) { + ETableGroupContainerChildNode *child_node = list->data; + ETableGroup *child = child_node->child; + ETableItem *eti = find_first_table_item (child); + + eti_get_accessible (eti, ATK_OBJECT (a11y)); + } } + g_object_unref (a11y); + g_object_unref (table); + + return FALSE; } static AtkObject* @@ -46,7 +111,8 @@ et_ref_accessible_at_point (AtkComponent *component, AtkCoordType coord_type) { GalA11yETable *a11y = GAL_A11Y_E_TABLE (component); - init_child_item (a11y); + if (GET_PRIVATE (a11y)->child_item) + g_object_ref (GET_PRIVATE (a11y)->child_item); return GET_PRIVATE (a11y)->child_item; } @@ -55,13 +121,23 @@ et_get_n_children (AtkObject *accessible) { GalA11yETable *a11y = GAL_A11Y_E_TABLE (accessible); ETable * et; + int n = 0; et = E_TABLE(GTK_ACCESSIBLE (a11y)->widget); - if (et && et->use_click_to_add) { - return 2; - } - return 1; + if (et->group) { + if (E_IS_TABLE_GROUP_LEAF (et->group)) + n = 1; + else if (E_IS_TABLE_GROUP_CONTAINER (et->group)) { + ETableGroupContainer *etgc = (ETableGroupContainer *)et->group; + n = g_list_length (etgc->children); + } + } + + if (et && et->use_click_to_add && et->click_to_add) { + n++; + } + return n; } static AtkObject* @@ -70,24 +146,40 @@ et_ref_child (AtkObject *accessible, { GalA11yETable *a11y = GAL_A11Y_E_TABLE (accessible); ETable * et; + gint child_no; et = E_TABLE(GTK_ACCESSIBLE (a11y)->widget); - if (i == 0) { - init_child_item (a11y); - g_object_ref (GET_PRIVATE (a11y)->child_item); - return GET_PRIVATE (a11y)->child_item; - } else if (i == 1) { + child_no = et_get_n_children (accessible); + if (i == 0 || i < child_no - 1) { + if (E_IS_TABLE_GROUP_LEAF (et->group)) { + ETableItem *eti = find_first_table_item (et->group); + AtkObject *aeti = eti_get_accessible (eti, accessible); + if (aeti) + g_object_ref (aeti); + return aeti; + + } else if (E_IS_TABLE_GROUP_CONTAINER (et->group)) { + ETableGroupContainer *etgc = (ETableGroupContainer *) et->group; + ETableGroupContainerChildNode *child_node = g_list_nth_data (etgc->children, i); + if (child_node) { + ETableGroup *child = child_node->child; + ETableItem * eti = find_first_table_item (child); + AtkObject *aeti = eti_get_accessible (eti, accessible); + if (aeti) + g_object_ref (aeti); + return aeti; + } + } + } else if (i == child_no -1) { AtkObject * accessible; ETableClickToAdd * etcta; if (et && et->use_click_to_add && et->click_to_add) { etcta = E_TABLE_CLICK_TO_ADD(et->click_to_add); - if (etcta->rect) { - accessible = atk_gobject_accessible_for_object (G_OBJECT(etcta)); - } else { - accessible = atk_gobject_accessible_for_object (G_OBJECT(etcta->row)); - } + accessible = atk_gobject_accessible_for_object (G_OBJECT(etcta)); + if (accessible) + g_object_ref (accessible); return accessible; } } @@ -95,6 +187,12 @@ et_ref_child (AtkObject *accessible, return NULL; } +static AtkLayer +et_get_layer (AtkComponent *component) +{ + return ATK_LAYER_WIDGET; +} + static void et_class_init (GalA11yETableClass *klass) { @@ -110,6 +208,7 @@ static void et_atk_component_iface_init (AtkComponentIface *iface) { iface->ref_accessible_at_point = et_ref_accessible_at_point; + iface->get_layer = et_get_layer; } static void @@ -181,5 +280,15 @@ gal_a11y_e_table_new (GObject *widget) GTK_ACCESSIBLE (a11y)->widget = GTK_WIDGET (widget); + /* we need to init all the children for multiple table items */ + if (table && GTK_WIDGET_MAPPED (GTK_WIDGET (table)) && table->group && E_IS_TABLE_GROUP_CONTAINER (table->group)) { + /* Ref it here so that it is still valid in the idle function */ + /* It will be unrefed in the idle function */ + g_object_ref (a11y); + g_object_ref (widget); + + g_idle_add ((GSourceFunc)init_child_item, a11y); + } + return ATK_OBJECT (a11y); } diff --git a/a11y/e-table/gal-a11y-e-tree.c b/a11y/e-table/gal-a11y-e-tree.c index 9bb49496d4..9f371729ae 100644 --- a/a11y/e-table/gal-a11y-e-tree.c +++ b/a11y/e-table/gal-a11y-e-tree.c @@ -35,11 +35,6 @@ init_child_item (GalA11yETree *a11y) eti = e_tree_get_item (tree); if (priv->child_item == NULL) { priv->child_item = atk_gobject_accessible_for_object (G_OBJECT (eti)); - if (!priv->child_item) - priv->child_item = gal_a11y_e_table_item_new (ATK_OBJECT (a11y),eti, 0); - - g_return_if_fail (priv->child_item); - priv->child_item->role = ATK_ROLE_TREE_TABLE; } } @@ -72,6 +67,12 @@ et_ref_child (AtkObject *accessible, return GET_PRIVATE (a11y)->child_item; } +static AtkLayer +et_get_layer (AtkComponent *component) +{ + return ATK_LAYER_WIDGET; +} + static void et_class_init (GalA11yETreeClass *klass) { @@ -87,6 +88,7 @@ static void et_atk_component_iface_init (AtkComponentIface *iface) { iface->ref_accessible_at_point = et_ref_accessible_at_point; + iface->get_layer = et_get_layer; } static void |