aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/table
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2009-05-20 22:50:00 +0800
committerMilan Crha <mcrha@redhat.com>2009-05-20 22:50:00 +0800
commitf4cf9af33ccde3142a3011e8b2dbcfb4cbc9ae81 (patch)
tree1c0228db536f5fa0efc6e0f779bb86df610989d0 /widgets/table
parent3acc45b10c9849aa5385a762b4d139472916dca1 (diff)
downloadgsoc2013-evolution-f4cf9af33ccde3142a3011e8b2dbcfb4cbc9ae81.tar.gz
gsoc2013-evolution-f4cf9af33ccde3142a3011e8b2dbcfb4cbc9ae81.tar.zst
gsoc2013-evolution-f4cf9af33ccde3142a3011e8b2dbcfb4cbc9ae81.zip
Use -no-undefined on Linux too
There still left two things opened, search for KILL-BONOBO to find them. One is in calendar's Makefile.am, one in composer.
Diffstat (limited to 'widgets/table')
-rw-r--r--widgets/table/Makefile.am52
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-popup.c144
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-popup.h62
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-registry.c149
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-registry.h72
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-text.c737
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-text.h64
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-toggle.c191
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-toggle.h68
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-tree.c260
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-tree.h64
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-vbox.c225
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell-vbox.h67
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell.c644
-rw-r--r--widgets/table/a11y/gal-a11y-e-cell.h113
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-click-to-add-factory.c106
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-click-to-add-factory.h50
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-click-to-add.c344
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-click-to-add.h55
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-column-header.c229
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-column-header.h55
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-factory.c99
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-factory.h51
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-item-factory.c105
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-item-factory.h50
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-item.c1327
-rw-r--r--widgets/table/a11y/gal-a11y-e-table-item.h59
-rw-r--r--widgets/table/a11y/gal-a11y-e-table.c308
-rw-r--r--widgets/table/a11y/gal-a11y-e-table.h59
-rw-r--r--widgets/table/a11y/gal-a11y-e-tree-factory.c98
-rw-r--r--widgets/table/a11y/gal-a11y-e-tree-factory.h50
-rw-r--r--widgets/table/a11y/gal-a11y-e-tree.c191
-rw-r--r--widgets/table/a11y/gal-a11y-e-tree.h58
-rw-r--r--widgets/table/e-cell-combo.c2
-rw-r--r--widgets/table/e-cell-date-edit.c1033
-rw-r--r--widgets/table/e-cell-date-edit.h106
-rw-r--r--widgets/table/e-cell-date.c2
-rw-r--r--widgets/table/e-cell-hbox.c4
-rw-r--r--widgets/table/e-cell-percent.c152
-rw-r--r--widgets/table/e-cell-percent.h51
-rw-r--r--widgets/table/e-cell-popup.c4
-rw-r--r--widgets/table/e-cell-text.c6
-rw-r--r--widgets/table/e-cell-toggle.c4
-rw-r--r--widgets/table/e-cell-tree.c4
-rw-r--r--widgets/table/e-cell-vbox.c4
-rw-r--r--widgets/table/e-table-click-to-add.c2
-rw-r--r--widgets/table/e-table-config.c2
-rw-r--r--widgets/table/e-table-group-container.c2
-rw-r--r--widgets/table/e-table-header-utils.c2
-rw-r--r--widgets/table/e-table-item.c4
-rw-r--r--widgets/table/e-table-utils.c2
-rw-r--r--widgets/table/e-table.c4
-rw-r--r--widgets/table/e-tree.c2
53 files changed, 7563 insertions, 35 deletions
diff --git a/widgets/table/Makefile.am b/widgets/table/Makefile.am
index be43b559e4..a53b249ce4 100644
--- a/widgets/table/Makefile.am
+++ b/widgets/table/Makefile.am
@@ -1,9 +1,3 @@
-if OS_WIN32
-WIN32_BOOTSTRAP_LIBS = \
- $(top_builddir)/win32/libemiscwidgets.la \
- $(top_builddir)/win32/libetext.la
-endif
-
glade_DATA = \
e-table-config.glade \
e-table-field-chooser.glade
@@ -24,7 +18,9 @@ libetable_la_SOURCES = \
e-cell-checkbox.c \
e-cell-combo.c \
e-cell-date.c \
+ e-cell-date-edit.c \
e-cell-number.c \
+ e-cell-percent.c \
e-cell-pixbuf.c \
e-cell-popup.c \
e-cell-size.c \
@@ -76,7 +72,23 @@ libetable_la_SOURCES = \
e-tree-selection-model.c \
e-tree-sorted.c \
e-tree-table-adapter.c \
- e-tree.c
+ e-tree.c \
+ a11y/gal-a11y-e-cell.c \
+ a11y/gal-a11y-e-cell-popup.c \
+ a11y/gal-a11y-e-cell-registry.c \
+ a11y/gal-a11y-e-cell-text.c \
+ a11y/gal-a11y-e-cell-toggle.c \
+ a11y/gal-a11y-e-cell-tree.c \
+ a11y/gal-a11y-e-cell-vbox.c \
+ a11y/gal-a11y-e-table.c \
+ a11y/gal-a11y-e-table-click-to-add.c \
+ a11y/gal-a11y-e-table-click-to-add-factory.c \
+ a11y/gal-a11y-e-table-column-header.c \
+ a11y/gal-a11y-e-table-factory.c \
+ a11y/gal-a11y-e-table-item.c \
+ a11y/gal-a11y-e-table-item-factory.c \
+ a11y/gal-a11y-e-tree.c \
+ a11y/gal-a11y-e-tree-factory.c
libetableincludedir = $(privincludedir)/table
@@ -85,7 +97,9 @@ libetableinclude_HEADERS = \
e-cell-checkbox.h \
e-cell-combo.h \
e-cell-date.h \
+ e-cell-date-edit.h \
e-cell-number.h \
+ e-cell-percent.h \
e-cell-pixbuf.h \
e-cell-popup.h \
e-cell-size.h \
@@ -140,16 +154,34 @@ libetableinclude_HEADERS = \
e-tree-selection-model.h \
e-tree-sorted.h \
e-tree-table-adapter.h \
- e-tree.h
+ e-tree.h \
+ a11y/gal-a11y-e-cell.h \
+ a11y/gal-a11y-e-cell-popup.h \
+ a11y/gal-a11y-e-cell-registry.h \
+ a11y/gal-a11y-e-cell-text.h \
+ a11y/gal-a11y-e-cell-toggle.h \
+ a11y/gal-a11y-e-cell-tree.h \
+ a11y/gal-a11y-e-cell-vbox.h \
+ a11y/gal-a11y-e-table.h \
+ a11y/gal-a11y-e-table-click-to-add.h \
+ a11y/gal-a11y-e-table-click-to-add-factory.h \
+ a11y/gal-a11y-e-table-column-header.h \
+ a11y/gal-a11y-e-table-factory.h \
+ a11y/gal-a11y-e-table-item.h \
+ a11y/gal-a11y-e-table-item-factory.h \
+ a11y/gal-a11y-e-tree.h \
+ a11y/gal-a11y-e-tree-factory.h
libetable_la_LDFLAGS = $(NO_UNDEFINED)
libetable_la_LIBADD = \
- $(WIN32_BOOTSTRAP_LIBS) \
- $(top_builddir)/e-util/libeutil.la \
$(top_builddir)/a11y/libevolution-a11y.la \
+ $(top_builddir)/e-util/libeutil.la \
+ $(top_builddir)/widgets/misc/libemiscwidgets.la \
+ $(top_builddir)/widgets/text/libetext.la \
$(E_UTIL_LIBS) \
$(E_WIDGETS_LIBS) \
+ $(MATH_LIB) \
$(GNOME_PLATFORM_LIBS)
icons = \
diff --git a/widgets/table/a11y/gal-a11y-e-cell-popup.c b/widgets/table/a11y/gal-a11y-e-cell-popup.c
new file mode 100644
index 0000000000..1a40b23a21
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-popup.c
@@ -0,0 +1,144 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yang Wu <yang.wu@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "a11y/gal-a11y-util.h"
+#include "table/e-cell-popup.h"
+#include <glib/gi18n.h>
+
+#include "gal-a11y-e-cell-popup.h"
+#include "gal-a11y-e-cell-registry.h"
+
+static AtkObjectClass *parent_class = NULL;
+#define PARENT_TYPE (gal_a11y_e_cell_get_type ())
+
+static void gal_a11y_e_cell_popup_class_init (GalA11yECellPopupClass *klass);
+static void popup_cell_action (GalA11yECell *cell);
+
+/**
+ * gal_a11y_e_cell_popup_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yECellPopup class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yECellPopup class.
+ **/
+GType
+gal_a11y_e_cell_popup_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (GalA11yECellPopupClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gal_a11y_e_cell_popup_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yECellPopup),
+ 0,
+ (GInstanceInitFunc) NULL,
+ NULL /* value_cell_popup */
+ };
+
+ type = g_type_register_static (PARENT_TYPE, "GalA11yECellPopup", &info, 0);
+ gal_a11y_e_cell_type_add_action_interface (type);
+ }
+
+ return type;
+}
+
+static void
+gal_a11y_e_cell_popup_class_init (GalA11yECellPopupClass *klass)
+{
+ parent_class = g_type_class_ref (PARENT_TYPE);
+}
+
+AtkObject *
+gal_a11y_e_cell_popup_new (ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row)
+{
+ AtkObject *a11y;
+ GalA11yECell *cell;
+ ECellPopup *popupcell;
+ ECellView* child_view = NULL;
+
+ popupcell= E_CELL_POPUP(cell_view->ecell);
+
+ if (popupcell && popupcell->popup_cell_view)
+ child_view = popupcell->popup_cell_view->child_view;
+
+ if (child_view && child_view->ecell) {
+ a11y = gal_a11y_e_cell_registry_get_object (NULL,
+ item,
+ child_view,
+ parent,
+ model_col,
+ view_col,
+ row);
+ } else {
+ a11y = g_object_new (GAL_A11Y_TYPE_E_CELL_POPUP, NULL);
+ gal_a11y_e_cell_construct (a11y,
+ item,
+ cell_view,
+ parent,
+ model_col,
+ view_col,
+ row);
+ }
+ 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 */
+ "<Alt>Down", /* action keybinding */
+ popup_cell_action);
+
+ a11y->role = ATK_ROLE_TABLE_CELL;
+ return a11y;
+}
+
+static void
+popup_cell_action (GalA11yECell *cell)
+{
+ gint finished;
+ GdkEvent event;
+
+ event.key.type = GDK_KEY_PRESS;
+ event.key.window = GTK_LAYOUT(GNOME_CANVAS_ITEM(cell->item)->canvas)->bin_window;;
+ event.key.send_event = TRUE;
+ event.key.time = GDK_CURRENT_TIME;
+ event.key.state = GDK_MOD1_MASK;
+ event.key.keyval = GDK_Down;
+
+ g_signal_emit_by_name (cell->item, "event", &event, &finished);
+}
diff --git a/widgets/table/a11y/gal-a11y-e-cell-popup.h b/widgets/table/a11y/gal-a11y-e-cell-popup.h
new file mode 100644
index 0000000000..4f205c10bc
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-popup.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yang Wu <yang.wu@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_CELL_POPUP_H__
+#define __GAL_A11Y_E_CELL_POPUP_H__
+
+#include <glib-object.h>
+#include <table/e-table-item.h>
+#include <table/a11y/gal-a11y-e-cell.h>
+#include <atk/atkgobjectaccessible.h>
+
+#define GAL_A11Y_TYPE_E_CELL_POPUP (gal_a11y_e_cell_popup_get_type ())
+#define GAL_A11Y_E_CELL_POPUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_POPUP, GalA11yECellPopup))
+#define GAL_A11Y_E_CELL_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_POPUP, GalA11yECellPopupClass))
+#define GAL_A11Y_IS_E_CELL_POPUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_POPUP))
+#define GAL_A11Y_IS_E_CELL_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_POPUP))
+
+typedef struct _GalA11yECellPopup GalA11yECellPopup;
+typedef struct _GalA11yECellPopupClass GalA11yECellPopupClass;
+
+/* This struct should actually be larger as this isn't what we derive from.
+ * The GalA11yECellPopupPrivate comes right after the parent class structure.
+ **/
+struct _GalA11yECellPopup {
+ GalA11yECell object;
+};
+
+struct _GalA11yECellPopupClass {
+ GalA11yECellClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_cell_popup_get_type (void);
+AtkObject *gal_a11y_e_cell_popup_new (ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row);
+
+#endif /* ! __GAL_A11Y_E_CELL_POPUP_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-cell-registry.c b/widgets/table/a11y/gal-a11y-e-cell-registry.c
new file mode 100644
index 0000000000..b88fb581fc
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-registry.c
@@ -0,0 +1,149 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include "gal-a11y-e-cell.h"
+#include "gal-a11y-e-cell-registry.h"
+
+static GObjectClass *parent_class;
+static GalA11yECellRegistry *default_registry;
+#define PARENT_TYPE (G_TYPE_OBJECT)
+
+struct _GalA11yECellRegistryPrivate {
+ GHashTable *table;
+};
+
+/* Static functions */
+
+static void
+gal_a11y_e_cell_registry_finalize (GObject *obj)
+{
+ GalA11yECellRegistry *registry = GAL_A11Y_E_CELL_REGISTRY (obj);
+
+ g_hash_table_destroy (registry->priv->table);
+ g_free (registry->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gal_a11y_e_cell_registry_class_init (GalA11yECellRegistryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ object_class->finalize = gal_a11y_e_cell_registry_finalize;
+}
+
+static void
+gal_a11y_e_cell_registry_init (GalA11yECellRegistry *registry)
+{
+ registry->priv = g_new (GalA11yECellRegistryPrivate, 1);
+ registry->priv->table = g_hash_table_new (NULL, NULL);
+}
+
+/**
+ * gal_a11y_e_cell_registry_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yECellRegistry class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yECellRegistry class.
+ **/
+GType
+gal_a11y_e_cell_registry_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (GalA11yECellRegistryClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gal_a11y_e_cell_registry_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yECellRegistry),
+ 0,
+ (GInstanceInitFunc) gal_a11y_e_cell_registry_init,
+ NULL /* value_cell */
+ };
+
+ type = g_type_register_static (PARENT_TYPE, "GalA11yECellRegistry", &info, 0);
+ }
+
+ return type;
+}
+
+static void
+init_default_registry (void)
+{
+ if (default_registry == NULL) {
+ default_registry = g_object_new (gal_a11y_e_cell_registry_get_type(), NULL);
+ }
+}
+
+
+AtkObject *
+gal_a11y_e_cell_registry_get_object (GalA11yECellRegistry *registry,
+ ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row)
+{
+ GalA11yECellRegistryFunc func = NULL;
+ GType type;
+
+ if (registry == NULL) {
+ init_default_registry ();
+ registry = default_registry;
+ }
+
+ type = GTK_OBJECT_TYPE (cell_view->ecell);
+ while (func == NULL && type != 0) {
+ func = g_hash_table_lookup (registry->priv->table, GINT_TO_POINTER (type));
+ type = g_type_parent (type);
+ }
+
+ if (func)
+ return func (item, cell_view, parent, model_col, view_col, row);
+ else
+ return gal_a11y_e_cell_new (item, cell_view, parent, model_col, view_col, row);
+}
+
+void
+gal_a11y_e_cell_registry_add_cell_type (GalA11yECellRegistry *registry,
+ GType type,
+ GalA11yECellRegistryFunc func)
+{
+ if (registry == NULL) {
+ init_default_registry ();
+ registry = default_registry;
+ }
+
+ g_hash_table_insert (registry->priv->table, GINT_TO_POINTER (type), func);
+}
diff --git a/widgets/table/a11y/gal-a11y-e-cell-registry.h b/widgets/table/a11y/gal-a11y-e-cell-registry.h
new file mode 100644
index 0000000000..f231567222
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-registry.h
@@ -0,0 +1,72 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_CELL_REGISTRY_H__
+#define __GAL_A11Y_E_CELL_REGISTRY_H__
+
+#include <glib-object.h>
+#include <atk/atkobject.h>
+#include <table/e-table-item.h>
+#include <table/e-cell.h>
+
+#define GAL_A11Y_TYPE_E_CELL_REGISTRY (gal_a11y_e_cell_registry_get_type ())
+#define GAL_A11Y_E_CELL_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_REGISTRY, GalA11yECellRegistry))
+#define GAL_A11Y_E_CELL_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_REGISTRY, GalA11yECellRegistryClass))
+#define GAL_A11Y_IS_E_CELL_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_REGISTRY))
+#define GAL_A11Y_IS_E_CELL_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_REGISTRY))
+
+typedef struct _GalA11yECellRegistry GalA11yECellRegistry;
+typedef struct _GalA11yECellRegistryClass GalA11yECellRegistryClass;
+typedef struct _GalA11yECellRegistryPrivate GalA11yECellRegistryPrivate;
+
+typedef AtkObject *(*GalA11yECellRegistryFunc) (ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row);
+
+struct _GalA11yECellRegistry {
+ GObject object;
+
+ GalA11yECellRegistryPrivate *priv;
+};
+
+struct _GalA11yECellRegistryClass {
+ GObjectClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_cell_registry_get_type (void);
+AtkObject *gal_a11y_e_cell_registry_get_object (GalA11yECellRegistry *registry,
+ ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row);
+void gal_a11y_e_cell_registry_add_cell_type (GalA11yECellRegistry *registry,
+ GType type,
+ GalA11yECellRegistryFunc func);
+
+#endif /* ! __GAL_A11Y_E_CELL_REGISTRY_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-cell-text.c b/widgets/table/a11y/gal-a11y-e-cell-text.c
new file mode 100644
index 0000000000..e77c0739a9
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-text.c
@@ -0,0 +1,737 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <atk/atk.h>
+
+#include "a11y/gal-a11y-util.h"
+#include "table/e-cell-text.h"
+#include <glib/gi18n.h>
+
+#include "gal-a11y-e-cell-text.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;
+ 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 *
+ect_get_text (AtkText *text,
+ gint start_offset,
+ gint end_offset)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ gchar *full_text;
+ gchar *ret_val;
+
+ 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);
+ else
+ end_offset = g_utf8_offset_to_pointer (full_text, end_offset) - full_text;
+
+ start_offset = g_utf8_offset_to_pointer (full_text, start_offset) - full_text;
+
+ ret_val = g_strndup (full_text + start_offset, end_offset - start_offset);
+
+ g_free (full_text);
+
+ return ret_val;
+}
+
+static gchar *
+ect_get_text_after_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ /* Unimplemented */
+ return NULL;
+}
+
+static gchar *
+ect_get_text_at_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ /* Unimplemented */
+ return NULL;
+}
+
+static gunichar
+ect_get_character_at_offset (AtkText *text,
+ gint offset)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ gunichar ret_val;
+ gchar *at_offset;
+ gchar *full_text;
+
+ if (!ect_check (text))
+ return -1;
+
+ 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);
+ g_free (full_text);
+
+ return ret_val;
+}
+
+
+static gchar*
+ect_get_text_before_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ /* Unimplemented */
+ return NULL;
+}
+
+
+static gint
+ect_get_caret_offset (AtkText *text)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ gint start, end;
+
+ 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_by_view (gaec->cell_view, gaec->model_col, gaec->row);
+ end = g_utf8_pointer_to_offset (full_text, full_text + end);
+ g_free (full_text);
+
+ return end;
+ }
+ else
+ return -1;
+}
+
+static AtkAttributeSet*
+ect_get_run_attributes (AtkText *text,
+ gint offset,
+ gint *start_offset,
+ gint *end_offset)
+{
+ /* Unimplemented */
+ return NULL;
+}
+
+
+static AtkAttributeSet*
+ect_get_default_attributes (AtkText *text)
+{
+ /* Unimplemented */
+ return NULL;
+}
+
+
+static void
+ect_get_character_extents (AtkText *text,
+ gint offset,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coords)
+{
+ /* Unimplemented */
+}
+
+
+static gint
+ect_get_character_count (AtkText *text)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ gint ret_val;
+ gchar *full_text;
+
+ if (!ect_check (text))
+ return -1;
+
+ 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);
+ g_free (full_text);
+ return ret_val;
+}
+
+
+static gint
+ect_get_offset_at_point (AtkText *text,
+ gint x,
+ gint y,
+ AtkCoordType coords)
+{
+ /* Unimplemented */
+ return 0;
+}
+
+
+static gint
+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,
+ &selection_end)
+ && selection_start != selection_end)
+ return 1;
+ return 0;
+}
+
+
+static gchar*
+ect_get_selection (AtkText *text,
+ gint selection_num,
+ gint *start_offset,
+ gint *end_offset)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ gchar *ret_val;
+ gint selection_start, selection_end;
+
+ if (selection_num == 0
+ && e_cell_text_get_selection (gaec->cell_view,
+ gaec->view_col, gaec->row,
+ &selection_start,
+ &selection_end)
+ && selection_start != selection_end) {
+ gint real_start, real_end, len;
+ 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);
+ real_start = MIN (MAX (0, real_start), len);
+ real_end = MIN (MAX (0, real_end), len);
+
+ ret_val = g_strndup (full_text + real_start, real_end - real_start);
+
+ real_start = g_utf8_pointer_to_offset (full_text, full_text + real_start);
+ real_end = g_utf8_pointer_to_offset (full_text, full_text + real_end);
+
+ if (start_offset)
+ *start_offset = real_start;
+ if (end_offset)
+ *end_offset = real_end;
+ g_free (full_text);
+ } else {
+ if (start_offset)
+ *start_offset = 0;
+ if (end_offset)
+ *end_offset = 0;
+ ret_val = NULL;
+ }
+
+ return ret_val;
+}
+
+
+static gboolean
+ect_add_selection (AtkText *text,
+ gint start_offset,
+ gint end_offset)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+
+ if (start_offset != end_offset) {
+ gint real_start, real_end, len;
+ gchar *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 (end_offset == -1)
+ end_offset = len;
+
+ real_start = MIN (start_offset, end_offset);
+ real_end = MAX (start_offset, end_offset);
+
+ real_start = MIN (MAX (0, real_start), len);
+ real_end = MIN (MAX (0, real_end), len);
+
+ 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;
+ g_free (full_text);
+
+ if (e_cell_text_set_selection (gaec->cell_view,
+ gaec->view_col, gaec->row,
+ real_start, real_end)) {
+ g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed");
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+static gboolean
+ect_remove_selection (AtkText *text,
+ gint selection_num)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ gint selection_start, selection_end;
+
+ if (selection_num == 0
+ && e_cell_text_get_selection (gaec->cell_view,
+ gaec->view_col, gaec->row,
+ &selection_start,
+ &selection_end)
+ && selection_start != selection_end
+ && e_cell_text_set_selection (gaec->cell_view,
+ gaec->view_col, gaec->row,
+ selection_end, selection_end)) {
+ g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed");
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+
+static gboolean
+ect_set_selection (AtkText *text,
+ gint selection_num,
+ gint start_offset,
+ gint end_offset)
+{
+ if (selection_num == 0) {
+ atk_text_add_selection (text, start_offset, end_offset);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+
+static gboolean
+ect_set_caret_offset (AtkText *text,
+ gint offset)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ gchar *full_text;
+ gint len;
+
+ 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)
+ offset = len;
+ else
+ offset = MIN (MAX (0, offset), len);
+
+ offset = g_utf8_offset_to_pointer (full_text, offset) - full_text;
+
+ g_free (full_text);
+
+ return e_cell_text_set_selection (gaec->cell_view,
+ gaec->view_col, gaec->row,
+ offset, offset);
+}
+
+static gboolean
+ect_set_run_attributes (AtkEditableText *text,
+ AtkAttributeSet *attrib_set,
+ gint start_offset,
+ gint end_offset)
+{
+ /* Unimplemented */
+ return FALSE;
+}
+
+static void
+ect_set_text_contents (AtkEditableText *text,
+ const gchar *string)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell);
+
+ e_cell_text_set_value (ect, gaec->item->table_model, gaec->model_col, gaec->row, string);
+ e_table_item_enter_edit (gaec->item, gaec->view_col, gaec->row);
+}
+
+static void
+ect_insert_text (AtkEditableText *text,
+ const gchar *string,
+ gint length,
+ gint *position)
+{
+ /* Utf8 unimplemented */
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell);
+
+ 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);
+
+ *position += length;
+
+ g_free (result);
+ g_free (full_text);
+}
+
+static void
+ect_copy_text (AtkEditableText *text,
+ gint start_pos,
+ gint end_pos)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ if (start_pos != end_pos
+ && atk_text_set_selection (ATK_TEXT (text), 0, start_pos, end_pos))
+ e_cell_text_copy_clipboard (gaec->cell_view,
+ gaec->view_col, gaec->row);
+}
+
+static void
+ect_delete_text (AtkEditableText *text,
+ gint start_pos,
+ gint end_pos)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+ if (start_pos != end_pos
+ && atk_text_set_selection (ATK_TEXT (text), 0, start_pos, end_pos))
+ e_cell_text_delete_selection (gaec->cell_view,
+ gaec->view_col, gaec->row);
+}
+
+static void
+ect_cut_text (AtkEditableText *text,
+ gint start_pos,
+ gint end_pos)
+{
+ ect_copy_text (text, start_pos, end_pos);
+ ect_delete_text (text, start_pos, end_pos);
+}
+
+static void
+ect_paste_text (AtkEditableText *text,
+ gint position)
+{
+ GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
+
+ e_table_item_enter_edit (gaec->item, gaec->view_col, gaec->row);
+
+ if (atk_text_set_caret_offset (ATK_TEXT (text), position))
+ e_cell_text_paste_clipboard (gaec->cell_view,
+ gaec->view_col, gaec->row);
+}
+
+static void
+ect_do_action_edit (AtkAction *action)
+{
+ GalA11yECell *a11y = GAL_A11Y_E_CELL (action);
+ 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
+ect_atk_text_iface_init (AtkTextIface *iface)
+{
+ iface->get_text = ect_get_text;
+ iface->get_text_after_offset = ect_get_text_after_offset;
+ iface->get_text_at_offset = ect_get_text_at_offset;
+ iface->get_character_at_offset = ect_get_character_at_offset;
+ iface->get_text_before_offset = ect_get_text_before_offset;
+ iface->get_caret_offset = ect_get_caret_offset;
+ iface->get_run_attributes = ect_get_run_attributes;
+ iface->get_default_attributes = ect_get_default_attributes;
+ iface->get_character_extents = ect_get_character_extents;
+ iface->get_character_count = ect_get_character_count;
+ iface->get_offset_at_point = ect_get_offset_at_point;
+ iface->get_n_selections = ect_get_n_selections;
+ iface->get_selection = ect_get_selection;
+ iface->add_selection = ect_add_selection;
+ iface->remove_selection = ect_remove_selection;
+ iface->set_selection = ect_set_selection;
+ iface->set_caret_offset = ect_set_caret_offset;
+}
+
+static void
+ect_atk_editable_text_iface_init (AtkEditableTextIface *iface)
+{
+ iface->set_run_attributes = ect_set_run_attributes;
+ iface->set_text_contents = ect_set_text_contents;
+ iface->insert_text = ect_insert_text;
+ iface->copy_text = ect_copy_text;
+ iface->cut_text = ect_cut_text;
+ iface->delete_text = ect_delete_text;
+ iface->paste_text = ect_paste_text;
+}
+
+static void
+ect_class_init (GalA11yECellTextClass *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_action_init (GalA11yECellText *a11y)
+{
+ 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);
+}
+
+/**
+ * gal_a11y_e_cell_text_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yECellText class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yECellText class.
+ **/
+GType
+gal_a11y_e_cell_text_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (GalA11yECellTextClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) ect_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yECellText),
+ 0,
+ (GInstanceInitFunc) NULL,
+ NULL /* value_cell_text */
+ };
+
+ static const GInterfaceInfo atk_text_info = {
+ (GInterfaceInitFunc) ect_atk_text_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ static const GInterfaceInfo atk_editable_text_info = {
+ (GInterfaceInitFunc) ect_atk_editable_text_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ type = g_type_register_static (PARENT_TYPE, "GalA11yECellText", &info, 0);
+ g_type_add_interface_static (type, ATK_TYPE_TEXT, &atk_text_info);
+ g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info);
+ gal_a11y_e_cell_type_add_action_interface (type);
+ }
+
+ 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,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row)
+{
+ AtkObject *a11y;
+ GalA11yECell *gaec;
+ GalA11yECellText *gaet;
+ ECellText *ect;
+
+ a11y = g_object_new (gal_a11y_e_cell_text_get_type (), NULL);
+
+ gal_a11y_e_cell_construct (a11y,
+ item,
+ cell_view,
+ parent,
+ 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/widgets/table/a11y/gal-a11y-e-cell-text.h b/widgets/table/a11y/gal-a11y-e-cell-text.h
new file mode 100644
index 0000000000..208bc67c66
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-text.h
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_CELL_TEXT_H__
+#define __GAL_A11Y_E_CELL_TEXT_H__
+
+#include <glib-object.h>
+#include <table/e-table-item.h>
+#include <table/e-cell-text.h>
+#include <table/a11y/gal-a11y-e-cell.h>
+
+#define GAL_A11Y_TYPE_E_CELL_TEXT (gal_a11y_e_cell_text_get_type ())
+#define GAL_A11Y_E_CELL_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_TEXT, GalA11yECellText))
+#define GAL_A11Y_E_CELL_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_TEXT, GalA11yECellTextClass))
+#define GAL_A11Y_IS_E_CELL_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_TEXT))
+#define GAL_A11Y_IS_E_CELL_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_TEXT))
+
+typedef struct _GalA11yECellText GalA11yECellText;
+typedef struct _GalA11yECellTextClass GalA11yECellTextClass;
+typedef struct _GalA11yECellTextPrivate GalA11yECellTextPrivate;
+
+/* This struct should actually be larger as this isn't what we derive from.
+ * The GalA11yECellTextPrivate comes right after the parent class structure.
+ **/
+struct _GalA11yECellText {
+ GalA11yECell object;
+ gint inserted_id;
+ gint deleted_id;
+};
+
+struct _GalA11yECellTextClass {
+ GalA11yECellClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_cell_text_get_type (void);
+AtkObject *gal_a11y_e_cell_text_new (ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row);
+
+#endif /* ! __GAL_A11Y_E_CELL_TEXT_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-cell-toggle.c b/widgets/table/a11y/gal-a11y-e-cell-toggle.c
new file mode 100644
index 0000000000..23114b0373
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-toggle.c
@@ -0,0 +1,191 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <gtk/gtk.h>
+
+#include "table/e-cell-toggle.h"
+#include "table/e-table-model.h"
+#include <glib/gi18n.h>
+
+#include "gal-a11y-e-cell-toggle.h"
+
+#define PARENT_TYPE (gal_a11y_e_cell_get_type ())
+static GObjectClass *parent_class;
+
+static void gal_a11y_e_cell_toggle_class_init (GalA11yECellToggleClass *klass);
+
+static void
+gal_a11y_e_cell_toggle_dispose (GObject *object)
+{
+ GalA11yECellToggle *a11y = GAL_A11Y_E_CELL_TOGGLE (object);
+
+ ETableModel *e_table_model = GAL_A11Y_E_CELL (a11y)->item->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);
+}
+
+GType
+gal_a11y_e_cell_toggle_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ static const GTypeInfo tinfo =
+ {
+ sizeof (GalA11yECellToggleClass),
+ (GBaseInitFunc) NULL, /* base init */
+ (GBaseFinalizeFunc) NULL, /* base finalize */
+ (GClassInitFunc) gal_a11y_e_cell_toggle_class_init, /* class init */
+ (GClassFinalizeFunc) NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (GalA11yECellToggle), /* instance size */
+ 0, /* nb preallocs */
+ NULL, /* instance init */
+ NULL /* value table */
+ };
+
+
+ type = g_type_register_static (GAL_A11Y_TYPE_E_CELL,
+ "GalA11yECellToggle", &tinfo, 0);
+ gal_a11y_e_cell_type_add_action_interface (type);
+
+ }
+ return type;
+}
+
+
+static void
+gal_a11y_e_cell_toggle_class_init (GalA11yECellToggleClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gal_a11y_e_cell_toggle_dispose;
+ parent_class = g_type_class_ref (PARENT_TYPE);
+}
+
+static void
+toggle_cell_action (GalA11yECell *cell)
+{
+ gint finished;
+ GdkEventButton event;
+ gint x, y, width, height;
+ gint row, col;
+
+ row = cell->row;
+ col = cell->view_col;
+
+ e_table_item_get_cell_geometry (cell->item, &row, &col,
+ &x, &y, &width, &height);
+
+ event.x = x + width / 2 + (int)(GNOME_CANVAS_ITEM (cell->item)->x1);
+ event.y = y + height / 2 + (int)(GNOME_CANVAS_ITEM (cell->item)->y1);
+
+ event.type = GDK_BUTTON_PRESS;
+ event.window = GTK_LAYOUT(GNOME_CANVAS_ITEM(cell->item)->canvas)->bin_window;
+ event.button = 1;
+ event.send_event = TRUE;
+ event.time = GDK_CURRENT_TIME;
+ event.axes = NULL;
+
+ g_signal_emit_by_name (cell->item, "event", &event, &finished);
+}
+
+static void
+model_change_cb (ETableModel *etm,
+ gint col,
+ gint row,
+ GalA11yECell *cell)
+{
+ gint value;
+
+ if (col == cell->model_col && row == cell->row) {
+
+ value = GPOINTER_TO_INT (
+ e_table_model_value_at (cell->cell_view->e_table_model,
+ 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
+ gal_a11y_e_cell_remove_state (cell, ATK_STATE_CHECKED, TRUE);
+ }
+}
+
+
+AtkObject*
+gal_a11y_e_cell_toggle_new (ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row)
+{
+ AtkObject *a11y;
+ GalA11yECell *cell;
+ GalA11yECellToggle *toggle_cell;
+ gint value;
+
+ a11y = ATK_OBJECT(g_object_new (GAL_A11Y_TYPE_E_CELL_TOGGLE, NULL));
+
+ g_return_val_if_fail (a11y != NULL, NULL);
+
+ cell = GAL_A11Y_E_CELL(a11y);
+ toggle_cell = GAL_A11Y_E_CELL_TOGGLE(a11y);
+ a11y->role = ATK_ROLE_TABLE_CELL;
+
+ gal_a11y_e_cell_construct (a11y,
+ item,
+ cell_view,
+ parent,
+ model_col,
+ view_col,
+ row);
+
+ gal_a11y_e_cell_add_action (cell,
+ _("toggle"), /* action name*/
+ _("toggle the cell"), /* action description */
+ NULL, /* action keybinding */
+ toggle_cell_action);
+
+ toggle_cell->model_id = g_signal_connect (item->table_model,
+ "model_cell_changed",
+ (GCallback) model_change_cb,
+ a11y);
+
+ value = GPOINTER_TO_INT (
+ e_table_model_value_at (cell->cell_view->e_table_model,
+ cell->model_col, cell->row));
+ if (value)
+ gal_a11y_e_cell_add_state (cell, ATK_STATE_CHECKED, FALSE);
+ else
+ gal_a11y_e_cell_remove_state (cell, ATK_STATE_CHECKED, FALSE);
+
+ return a11y;
+}
diff --git a/widgets/table/a11y/gal-a11y-e-cell-toggle.h b/widgets/table/a11y/gal-a11y-e-cell-toggle.h
new file mode 100644
index 0000000000..56483aae6b
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-toggle.h
@@ -0,0 +1,68 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_CELL_TOGGLE_H__
+#define __GAL_A11Y_E_CELL_TOGGLE_H__
+
+#include <atk/atk.h>
+#include "gal-a11y-e-cell.h"
+#include "gal-a11y-e-cell-toggle.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GAL_A11Y_TYPE_E_CELL_TOGGLE (gal_a11y_e_cell_toggle_get_type ())
+#define GAL_A11Y_E_CELL_TOGGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_TOGGLE, GalA11yECellToggle))
+#define GAL_A11Y_E_CELL_TOGGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_E_CELL_TOGGLE, GalA11yECellToggleClass))
+#define GAL_A11Y_IS_E_CELL_TOGGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_TOGGLE))
+#define GAL_A11Y_IS_E_CELL_TOGGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_TOGGLE))
+#define GAL_A11Y_E_CELL_TOGGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GAL_A11Y_TYPE_E_CELL_TOGGLE, GalA11yECellToggleClass))
+
+typedef struct _GalA11yECellToggle GalA11yECellToggle;
+typedef struct _GalA11yECellToggleClass GalA11yECellToggleClass;
+
+struct _GalA11yECellToggle
+{
+ GalA11yECell parent;
+ gint model_id;
+};
+
+GType gal_a11y_e_cell_toggle_get_type (void);
+
+struct _GalA11yECellToggleClass
+{
+ GalA11yECellClass parent_class;
+};
+
+AtkObject *gal_a11y_e_cell_toggle_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_TOGGLE_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-cell-tree.c b/widgets/table/a11y/gal-a11y-e-cell-tree.c
new file mode 100644
index 0000000000..520a818a37
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-tree.c
@@ -0,0 +1,260 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Tim Wo <tim.wo@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <atk/atk.h>
+
+#include "a11y/gal-a11y-util.h"
+#include "table/e-cell-tree.h"
+#include "table/e-table.h"
+#include "table/e-tree-table-adapter.h"
+#include <glib/gi18n.h>
+
+#include "gal-a11y-e-cell-tree.h"
+#include "gal-a11y-e-cell-registry.h"
+
+#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellTreeClass))
+static AtkObjectClass *a11y_parent_class;
+#define A11Y_PARENT_TYPE (gal_a11y_e_cell_get_type ())
+
+#define d(x)
+
+static void
+ectr_model_row_changed_cb (ETableModel *etm,
+ gint row,
+ GalA11yECell *a11y)
+{
+ ETreePath node;
+ ETreeModel *tree_model;
+ ETreeTableAdapter *tree_table_adapter;
+
+ g_return_if_fail (a11y);
+ if (a11y->row != row)
+ return;
+
+ node = e_table_model_value_at (etm, -1, a11y->row);
+ tree_model = e_table_model_value_at (etm, -2, a11y->row);
+ tree_table_adapter = e_table_model_value_at (etm, -3, a11y->row);
+
+ if (e_tree_model_node_is_expandable (tree_model, node)) {
+ gboolean is_exp = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node);
+ if (is_exp)
+ gal_a11y_e_cell_add_state (a11y, ATK_STATE_EXPANDED, TRUE);
+ else
+ gal_a11y_e_cell_remove_state (a11y, ATK_STATE_EXPANDED, TRUE);
+ }
+}
+
+static void
+kill_view_cb(ECellView *subcell_view,
+ gpointer psubcell_a11ies)
+{
+ GList *node;
+ GList *subcell_a11ies = (GList *) psubcell_a11ies;
+ GalA11yECell *subcell;
+
+ for (node = subcell_a11ies; node != NULL; node = g_list_next (node))
+ {
+ subcell = GAL_A11Y_E_CELL(node->data);
+ if (subcell && subcell->cell_view == subcell_view)
+ {
+ d(fprintf(stderr, "subcell_view %p deleted before the a11y object %p\n", subcell_view, subcell));
+ subcell->cell_view = NULL;
+ }
+ }
+}
+
+static void
+ectr_subcell_weak_ref (GalA11yECellTree *a11y,
+ GalA11yECell *subcell_a11y)
+{
+ ECellView *subcell_view = subcell_a11y ? subcell_a11y->cell_view : NULL;
+ if (subcell_a11y && subcell_view && subcell_view->kill_view_cb_data)
+ subcell_view->kill_view_cb_data = g_list_remove(subcell_view->kill_view_cb_data, subcell_a11y);
+
+ g_signal_handler_disconnect (GAL_A11Y_E_CELL (a11y)->item->table_model,
+ a11y->model_row_changed_id);
+ g_object_unref (a11y);
+}
+
+static void
+ectr_do_action_expand (AtkAction *action)
+{
+ GalA11yECell *a11y;
+ ETableModel *table_model;
+ ETreePath node;
+ ETreeModel *tree_model;
+ ETreeTableAdapter *tree_table_adapter;
+
+ a11y = GAL_A11Y_E_CELL (action);
+ table_model = a11y->item->table_model;
+ node = e_table_model_value_at (table_model, -1, a11y->row);
+ tree_model = e_table_model_value_at (table_model, -2, a11y->row);
+ tree_table_adapter = e_table_model_value_at (table_model, -3, a11y->row);
+
+ if (e_tree_model_node_is_expandable (tree_model, node)) {
+ e_tree_table_adapter_node_set_expanded (tree_table_adapter,
+ node,
+ TRUE);
+ gal_a11y_e_cell_add_state (a11y, ATK_STATE_EXPANDED, TRUE);
+ }
+}
+
+static void
+ectr_do_action_collapse (AtkAction *action)
+{
+ GalA11yECell *a11y;
+ ETableModel *table_model;
+ ETreePath node;
+ ETreeModel *tree_model;
+ ETreeTableAdapter *tree_table_adapter;
+
+ a11y = GAL_A11Y_E_CELL (action);
+ table_model = a11y->item->table_model;
+ node = e_table_model_value_at (table_model, -1, a11y->row);
+ tree_model = e_table_model_value_at (table_model, -2, a11y->row);
+ tree_table_adapter = e_table_model_value_at (table_model, -3, a11y->row);
+
+ if (e_tree_model_node_is_expandable (tree_model, node)) {
+ e_tree_table_adapter_node_set_expanded (tree_table_adapter,
+ node,
+ FALSE);
+ gal_a11y_e_cell_remove_state (a11y, ATK_STATE_EXPANDED, TRUE);
+ }
+}
+
+static void
+ectr_class_init (GalA11yECellTreeClass *klass)
+{
+ a11y_parent_class = g_type_class_ref (A11Y_PARENT_TYPE);
+}
+
+static void
+ectr_init (GalA11yECellTree *a11y)
+{
+}
+
+GType
+gal_a11y_e_cell_tree_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (GalA11yECellTreeClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) ectr_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yECellTree),
+ 0,
+ (GInstanceInitFunc) ectr_init,
+ NULL /* value_cell_text */
+ };
+
+ type = g_type_register_static (A11Y_PARENT_TYPE, "GalA11yECellTree", &info, 0);
+ gal_a11y_e_cell_type_add_action_interface (type);
+ }
+
+ return type;
+}
+
+AtkObject *
+gal_a11y_e_cell_tree_new (ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row)
+{
+ AtkObject *subcell_a11y;
+ GalA11yECellTree *a11y;
+
+ ETreePath node;
+ ETreeModel *tree_model;
+ ETreeTableAdapter *tree_table_adapter;
+
+ ECellView *subcell_view;
+ subcell_view = e_cell_tree_view_get_subcell_view (cell_view);
+
+ if (subcell_view->ecell) {
+ subcell_a11y = gal_a11y_e_cell_registry_get_object (NULL,
+ item,
+ subcell_view,
+ parent,
+ model_col,
+ 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"),
+ 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"),
+ NULL,
+ (ACTION_FUNC)ectr_do_action_collapse);
+
+ /* init AtkStates for the cell's a11y object */
+ node = e_table_model_value_at (item->table_model, -1, row);
+ tree_model = e_table_model_value_at (item->table_model, -2, row);
+ tree_table_adapter = e_table_model_value_at (item->table_model, -3, row);
+ if (e_tree_model_node_is_expandable (tree_model, node)) {
+ gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (subcell_a11y), ATK_STATE_EXPANDABLE, FALSE);
+ if (e_tree_table_adapter_node_is_expanded (tree_table_adapter, node))
+ gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL (subcell_a11y), ATK_STATE_EXPANDED, FALSE);
+ }
+ }
+ else
+ subcell_a11y = NULL;
+
+ /* create a companion a11y object, this object has type GalA11yECellTree
+ and it connects to some signals to determine whether a tree cell is
+ expanded or collapsed */
+ a11y = g_object_new (gal_a11y_e_cell_tree_get_type (), NULL);
+ gal_a11y_e_cell_construct (ATK_OBJECT (a11y),
+ item,
+ cell_view,
+ parent,
+ model_col,
+ view_col,
+ row);
+ a11y->model_row_changed_id =
+ g_signal_connect (item->table_model, "model_row_changed",
+ G_CALLBACK (ectr_model_row_changed_cb),
+ subcell_a11y);
+
+ if (subcell_a11y && subcell_view)
+ {
+ subcell_view->kill_view_cb = kill_view_cb;
+ if (!g_list_find(subcell_view->kill_view_cb_data, subcell_a11y))
+ subcell_view->kill_view_cb_data = g_list_append(subcell_view->kill_view_cb_data, subcell_a11y);
+ }
+
+ g_object_weak_ref (G_OBJECT (subcell_a11y), (GWeakNotify) ectr_subcell_weak_ref, a11y);
+
+ return subcell_a11y;
+}
diff --git a/widgets/table/a11y/gal-a11y-e-cell-tree.h b/widgets/table/a11y/gal-a11y-e-cell-tree.h
new file mode 100644
index 0000000000..f6f6d9dd70
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-tree.h
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Tim Wo <tim.wo@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_CELL_TREE_H__
+#define __GAL_A11Y_E_CELL_TREE_H__
+
+#include <glib-object.h>
+#include <table/e-table-item.h>
+#include <table/e-cell-tree.h>
+#include "gal-a11y-e-cell.h"
+
+#define GAL_A11Y_TYPE_E_CELL_TREE (gal_a11y_e_cell_tree_get_type ())
+#define GAL_A11Y_E_CELL_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_TREE, GalA11yECellTree))
+#define GAL_A11Y_E_CELL_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_TREE, GalA11yECellTreeClass))
+#define GAL_A11Y_IS_E_CELL_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_TREE))
+#define GAL_A11Y_IS_E_CELL_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_TREE))
+
+typedef struct _GalA11yECellTree GalA11yECellTree;
+typedef struct _GalA11yECellTreeClass GalA11yECellTreeClass;
+typedef struct _GalA11yECellTreePrivate GalA11yECellTreePrivate;
+
+/* This struct should actually be larger as this isn't what we derive from.
+ * The GalA11yECellTreePrivate comes right after the parent class structure.
+ **/
+struct _GalA11yECellTree {
+ GalA11yECell object;
+
+ int model_row_changed_id;
+};
+
+struct _GalA11yECellTreeClass {
+ GalA11yECellClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_cell_tree_get_type (void);
+AtkObject *gal_a11y_e_cell_tree_new (ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row);
+
+#endif /* ! __GAL_A11Y_E_CELL_TREE_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-cell-vbox.c b/widgets/table/a11y/gal-a11y-e-cell-vbox.c
new file mode 100644
index 0000000000..08859d07ef
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-vbox.c
@@ -0,0 +1,225 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Eric Zhao <eric.zhao@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2004 Sun Microsystem, Inc.
+ *
+ */
+
+#include <config.h>
+
+#include <atk/atk.h>
+
+#include "table/e-cell-vbox.h"
+
+#include "gal-a11y-e-cell-registry.h"
+#include "gal-a11y-e-cell-vbox.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);
+
+ return GAL_A11Y_E_CELL_VBOX (a11y)->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) {
+ ECellView *subcell_view;
+ gint model_col, row;
+ row = gaec->row;
+ model_col = ecvv->model_cols[i];
+ 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;
+ GalA11yECell *gaec;
+ GalA11yECellVbox *gaev;
+ ECellVboxView *ecvv;
+
+ 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);
+
+ gaec = GAL_A11Y_E_CELL (a11y);
+ gaev = GAL_A11Y_E_CELL_VBOX (a11y);
+ 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/widgets/table/a11y/gal-a11y-e-cell-vbox.h b/widgets/table/a11y/gal-a11y-e-cell-vbox.h
new file mode 100644
index 0000000000..276a60177a
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell-vbox.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Eric Zhao <eric.zhao@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2004 Sun Microsystem, Inc.
+ *
+ */
+
+#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/widgets/table/a11y/gal-a11y-e-cell.c b/widgets/table/a11y/gal-a11y-e-cell.c
new file mode 100644
index 0000000000..6154fc0acd
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell.c
@@ -0,0 +1,644 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "a11y/gal-a11y-util.h"
+#include "table/e-table.h"
+#include "table/e-tree.h"
+#include <glib/gi18n.h>
+
+#include "gal-a11y-e-cell.h"
+#include "gal-a11y-e-cell-vbox.h"
+#include "gal-a11y-e-table-item.h"
+
+#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellClass))
+static GObjectClass *parent_class;
+#define PARENT_TYPE (atk_object_get_type ())
+
+
+#if 0
+static void
+unref_item (gpointer user_data, GObject *obj_loc)
+{
+ GalA11yECell *a11y = GAL_A11Y_E_CELL (user_data);
+ a11y->item = NULL;
+ g_object_unref (a11y);
+}
+
+static void
+unref_cell (gpointer user_data, GObject *obj_loc)
+{
+ GalA11yECell *a11y = GAL_A11Y_E_CELL (user_data);
+ a11y->cell_view = NULL;
+ g_object_unref (a11y);
+}
+#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
+gal_a11y_e_cell_dispose (GObject *object)
+{
+ GalA11yECell *a11y = GAL_A11Y_E_CELL (object);
+
+#if 0
+ if (a11y->item)
+ g_object_unref (G_OBJECT (a11y->item)); /*, unref_item, a11y); */
+ if (a11y->cell_view)
+ g_object_unref (G_OBJECT (a11y->cell_view)); /*, unref_cell, a11y); */
+ if (a11y->parent)
+ g_object_unref (a11y->parent);
+#endif
+
+ 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 *
+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_object_ref(cell->state_set);
+
+ return cell->state_set;
+}
+
+static AtkObject*
+gal_a11y_e_cell_get_parent (AtkObject *accessible)
+{
+ GalA11yECell *a11y = GAL_A11Y_E_CELL (accessible);
+ return a11y->parent;
+}
+
+static gint
+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 + 1) * a11y->item->cols + a11y->view_col;
+}
+
+
+/* Component IFace */
+static void
+gal_a11y_e_cell_get_extents (AtkComponent *component,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coord_type)
+{
+ GalA11yECell *a11y = GAL_A11Y_E_CELL (component);
+ GtkWidget *tableOrTree;
+ int row;
+ int col;
+ int xval;
+ int yval;
+
+ row = a11y->row;
+ col = a11y->view_col;
+
+ 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);
+ if (x && *x != G_MININT)
+ *x += xval;
+ if (y && *y != G_MININT)
+ *y += yval;
+}
+
+static gboolean
+gal_a11y_e_cell_grab_focus (AtkComponent *component)
+{
+ GalA11yECell *a11y;
+ gint index;
+ GtkWidget *toplevel;
+ GalA11yETableItem *a11yTableItem;
+
+ a11y = GAL_A11Y_E_CELL (component);
+
+ /* for e_cell_vbox's children, we just grab the e_cell_vbox */
+ if (GAL_A11Y_IS_E_CELL_VBOX (a11y->parent)) {
+ return atk_component_grab_focus (ATK_COMPONENT (a11y->parent));
+ }
+
+ 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;
+}
+
+/* Table IFace */
+
+static void
+gal_a11y_e_cell_atk_component_iface_init (AtkComponentIface *iface)
+{
+ iface->get_extents = gal_a11y_e_cell_get_extents;
+ iface->grab_focus = gal_a11y_e_cell_grab_focus;
+}
+
+static void
+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 = gal_a11y_e_cell_dispose;
+
+ 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
+gal_a11y_e_cell_init (GalA11yECell *a11y)
+{
+ a11y->item = NULL;
+ a11y->cell_view = NULL;
+ a11y->parent = NULL;
+ a11y->model_col = -1;
+ a11y->view_col = -1;
+ a11y->row = -1;
+
+ 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);
+}
+
+
+static ActionInfo *
+_gal_a11y_e_cell_get_action_info (GalA11yECell *cell,
+ gint index)
+{
+ GList *list_node;
+
+ g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), NULL);
+ if (cell->action_list == NULL)
+ return NULL;
+ list_node = g_list_nth (cell->action_list, index);
+ if (!list_node)
+ return NULL;
+ return (ActionInfo *) (list_node->data);
+}
+
+static void
+_gal_a11y_e_cell_destroy_action_info (gpointer action_info,
+ gpointer user_data)
+{
+ ActionInfo *info = (ActionInfo *)action_info;
+
+ g_return_if_fail (info != NULL);
+ g_free (info->name);
+ g_free (info->description);
+ g_free (info->keybinding);
+ g_free (info);
+}
+
+
+gboolean
+gal_a11y_e_cell_add_action ( GalA11yECell * cell,
+ const gchar *action_name,
+ const gchar *action_description,
+ const gchar *action_keybinding,
+ ACTION_FUNC action_func)
+{
+ ActionInfo *info;
+ g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE);
+ info = g_new (ActionInfo, 1);
+
+ if (action_name != NULL)
+ info->name = g_strdup (action_name);
+ else
+ info->name = NULL;
+
+ if (action_description != NULL)
+ info->description = g_strdup (action_description);
+ else
+ info->description = NULL;
+ if (action_keybinding != NULL)
+ info->keybinding = g_strdup (action_keybinding);
+ else
+ info->keybinding = NULL;
+ info->do_action_func = action_func;
+
+ cell->action_list = g_list_append (cell->action_list, (gpointer) info);
+ return TRUE;
+}
+
+gboolean
+gal_a11y_e_cell_remove_action (GalA11yECell *cell,
+ gint action_index)
+{
+ GList *list_node;
+
+ g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE);
+ list_node = g_list_nth (cell->action_list, action_index);
+ if (!list_node)
+ return FALSE;
+ g_return_val_if_fail (list_node->data != NULL, FALSE);
+ _gal_a11y_e_cell_destroy_action_info (list_node->data, NULL);
+ cell->action_list = g_list_remove_link (cell->action_list, list_node);
+
+ return TRUE;
+}
+
+gboolean
+gal_a11y_e_cell_remove_action_by_name (GalA11yECell *cell,
+ const gchar *action_name)
+{
+ GList *list_node;
+ gboolean action_found= FALSE;
+
+ g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE);
+ for (list_node = cell->action_list; list_node && !action_found;
+ list_node = list_node->next) {
+ if (!g_ascii_strcasecmp (((ActionInfo *)(list_node->data))->name, action_name)) {
+ action_found = TRUE;
+ break;
+ }
+ }
+
+ g_return_val_if_fail (action_found, FALSE);
+ _gal_a11y_e_cell_destroy_action_info (list_node->data, NULL);
+ cell->action_list = g_list_remove_link (cell->action_list, list_node);
+
+ return TRUE;
+}
+
+static gint
+gal_a11y_e_cell_action_get_n_actions (AtkAction *action)
+{
+ GalA11yECell *cell = GAL_A11Y_E_CELL(action);
+ if (cell->action_list != NULL)
+ return g_list_length (cell->action_list);
+ else
+ return 0;
+}
+
+static G_CONST_RETURN gchar *
+gal_a11y_e_cell_action_get_name (AtkAction *action,
+ gint index)
+{
+ GalA11yECell *cell = GAL_A11Y_E_CELL(action);
+ ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
+
+ if (info == NULL)
+ return NULL;
+ return info->name;
+}
+
+static G_CONST_RETURN gchar *
+gal_a11y_e_cell_action_get_description (AtkAction *action,
+ gint index)
+{
+ GalA11yECell *cell = GAL_A11Y_E_CELL(action);
+ ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
+
+ if (info == NULL)
+ return NULL;
+ return info->description;
+}
+
+static gboolean
+gal_a11y_e_cell_action_set_description (AtkAction *action,
+ gint index,
+ const gchar *desc)
+{
+ GalA11yECell *cell = GAL_A11Y_E_CELL(action);
+ ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
+
+ if (info == NULL)
+ return FALSE;
+ g_free (info->description);
+ info->description = g_strdup (desc);
+ return TRUE;
+}
+
+static G_CONST_RETURN gchar *
+gal_a11y_e_cell_action_get_keybinding (AtkAction *action,
+ gint index)
+{
+ GalA11yECell *cell = GAL_A11Y_E_CELL(action);
+ ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
+ if (info == NULL)
+ return NULL;
+
+ return info->keybinding;
+}
+
+static gboolean
+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);
+ g_object_unref (cell);
+
+ return FALSE;
+}
+
+static gboolean
+gal_a11y_e_cell_action_do_action (AtkAction *action,
+ gint index)
+{
+ 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);
+ if (cell->action_idle_handler)
+ return FALSE;
+ cell->action_func = info->do_action_func;
+ g_object_ref (cell);
+ cell->action_idle_handler = g_idle_add (idle_do_action, cell);
+
+ return TRUE;
+}
+
+static void
+gal_a11y_e_cell_atk_action_interface_init (AtkActionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_n_actions = gal_a11y_e_cell_action_get_n_actions;
+ iface->do_action = gal_a11y_e_cell_action_do_action;
+ iface->get_name = gal_a11y_e_cell_action_get_name;
+ iface->get_description = gal_a11y_e_cell_action_get_description;
+ iface->set_description = gal_a11y_e_cell_action_set_description;
+ iface->get_keybinding = gal_a11y_e_cell_action_get_keybinding;
+}
+
+void
+gal_a11y_e_cell_type_add_action_interface (GType type)
+{
+ static const GInterfaceInfo atk_action_info =
+ {
+ (GInterfaceInitFunc) gal_a11y_e_cell_atk_action_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ g_type_add_interface_static (type, ATK_TYPE_ACTION,
+ &atk_action_info);
+}
+
+gboolean
+gal_a11y_e_cell_add_state (GalA11yECell *cell,
+ AtkStateType state_type,
+ gboolean emit_signal)
+{
+ if (!atk_state_set_contains_state (cell->state_set, state_type)) {
+ gboolean rc;
+
+ rc = atk_state_set_add_state (cell->state_set, state_type);
+ /*
+ * The signal should only be generated if the value changed,
+ * not when the cell is set up. So states that are set
+ * initially should pass FALSE as the emit_signal argument.
+ */
+
+ if (emit_signal) {
+ atk_object_notify_state_change (ATK_OBJECT (cell), state_type, TRUE);
+ /* If state_type is ATK_STATE_VISIBLE, additional
+ notification */
+ if (state_type == ATK_STATE_VISIBLE)
+ g_signal_emit_by_name (cell, "visible_data_changed");
+ }
+
+ return rc;
+ }
+ else
+ return FALSE;
+}
+
+gboolean
+gal_a11y_e_cell_remove_state (GalA11yECell *cell,
+ AtkStateType state_type,
+ gboolean emit_signal)
+{
+ if (atk_state_set_contains_state (cell->state_set, state_type)) {
+ gboolean rc;
+
+ rc = atk_state_set_remove_state (cell->state_set, state_type);
+ /*
+ * The signal should only be generated if the value changed,
+ * not when the cell is set up. So states that are set
+ * initially should pass FALSE as the emit_signal argument.
+ */
+
+ if (emit_signal) {
+ atk_object_notify_state_change (ATK_OBJECT (cell), state_type, FALSE);
+ /* If state_type is ATK_STATE_VISIBLE, additional notification */
+ if (state_type == ATK_STATE_VISIBLE)
+ g_signal_emit_by_name (cell, "visible_data_changed");
+ }
+
+ return rc;
+ }
+ else
+ return FALSE;
+}
+
+/**
+ * gal_a11y_e_cell_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yECell class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yECell class.
+ **/
+GType
+gal_a11y_e_cell_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (GalA11yECellClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gal_a11y_e_cell_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yECell),
+ 0,
+ (GInstanceInitFunc) gal_a11y_e_cell_init,
+ NULL /* value_cell */
+ };
+
+ static const GInterfaceInfo atk_component_info = {
+ (GInterfaceInitFunc) gal_a11y_e_cell_atk_component_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ type = g_type_register_static (PARENT_TYPE, "GalA11yECell", &info, 0);
+ g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
+ }
+
+ return type;
+}
+
+AtkObject *
+gal_a11y_e_cell_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_get_type (), NULL);
+
+ gal_a11y_e_cell_construct (a11y,
+ item,
+ cell_view,
+ parent,
+ model_col,
+ view_col,
+ row);
+ return a11y;
+}
+
+void
+gal_a11y_e_cell_construct (AtkObject *object,
+ ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row)
+{
+ GalA11yECell *a11y = GAL_A11Y_E_CELL (object);
+ a11y->item = item;
+ a11y->cell_view = cell_view;
+ a11y->parent = parent;
+ a11y->model_col = model_col;
+ a11y->view_col = view_col;
+ 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 (cell_view)
+ g_object_ref (G_OBJECT (cell_view));
+
+
+#endif
+}
diff --git a/widgets/table/a11y/gal-a11y-e-cell.h b/widgets/table/a11y/gal-a11y-e-cell.h
new file mode 100644
index 0000000000..cdae721112
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-cell.h
@@ -0,0 +1,113 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_CELL_H__
+#define __GAL_A11Y_E_CELL_H__
+
+#include <glib-object.h>
+#include <table/e-table-item.h>
+#include <table/e-cell.h>
+
+#define GAL_A11Y_TYPE_E_CELL (gal_a11y_e_cell_get_type ())
+#define GAL_A11Y_E_CELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL, GalA11yECell))
+#define GAL_A11Y_E_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL, GalA11yECellClass))
+#define GAL_A11Y_IS_E_CELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL))
+#define GAL_A11Y_IS_E_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL))
+
+typedef struct _GalA11yECell GalA11yECell;
+typedef struct _GalA11yECellClass GalA11yECellClass;
+typedef struct _GalA11yECellPrivate GalA11yECellPrivate;
+typedef struct _ActionInfo ActionInfo;
+typedef void (*ACTION_FUNC) (GalA11yECell *cell);
+
+
+/* This struct should actually be larger as this isn't what we derive from.
+ * The GalA11yECellPrivate comes right after the parent class structure.
+ **/
+struct _GalA11yECell {
+ AtkObject object;
+
+ ETableItem *item;
+ ECellView *cell_view;
+ AtkObject *parent;
+ int model_col;
+ int view_col;
+ int row;
+ AtkStateSet *state_set;
+ GList *action_list;
+ gint action_idle_handler;
+ ACTION_FUNC action_func;
+};
+
+struct _GalA11yECellClass {
+ AtkObjectClass parent_class;
+};
+
+struct _ActionInfo {
+ gchar *name;
+ gchar *description;
+ gchar *keybinding;
+ ACTION_FUNC do_action_func;
+};
+
+
+
+/* Standard Glib function */
+GType gal_a11y_e_cell_get_type (void);
+AtkObject *gal_a11y_e_cell_new (ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row);
+void gal_a11y_e_cell_construct (AtkObject *object,
+ ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row);
+
+void gal_a11y_e_cell_type_add_action_interface (GType type);
+
+gboolean gal_a11y_e_cell_add_action (GalA11yECell *cell,
+ const gchar *action_name,
+ const gchar *action_description,
+ const gchar *action_keybinding,
+ ACTION_FUNC action_func);
+
+gboolean gal_a11y_e_cell_remove_action (GalA11yECell *cell,
+ gint action_id);
+
+gboolean gal_a11y_e_cell_remove_action_by_name (GalA11yECell *cell,
+ const gchar *action_name);
+
+gboolean gal_a11y_e_cell_add_state (GalA11yECell *cell,
+ AtkStateType state_type,
+ gboolean emit_signal);
+
+gboolean gal_a11y_e_cell_remove_state (GalA11yECell *cell,
+ AtkStateType state_type,
+ gboolean emit_signal);
+
+
+#endif /* ! __GAL_A11Y_E_CELL_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-table-click-to-add-factory.c b/widgets/table/a11y/gal-a11y-e-table-click-to-add-factory.c
new file mode 100644
index 0000000000..9161b4d834
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-click-to-add-factory.c
@@ -0,0 +1,106 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yuedong Du <yuedong.du@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <atk/atk.h>
+
+#include "table/e-table.h"
+#include "table/e-table-click-to-add.h"
+
+#include "gal-a11y-e-table.h"
+#include "gal-a11y-e-table-click-to-add.h"
+#include "gal-a11y-e-table-click-to-add-factory.h"
+
+#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETableClickToAddFactoryClass))
+static AtkObjectFactoryClass *parent_class;
+#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY)
+
+/* Static functions */
+
+static GType
+gal_a11y_e_table_click_to_add_factory_get_accessible_type (void)
+{
+ return GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD;
+}
+
+static AtkObject*
+gal_a11y_e_table_click_to_add_factory_create_accessible (GObject *obj)
+{
+ AtkObject * atk_object;
+
+ g_return_val_if_fail (E_IS_TABLE_CLICK_TO_ADD(obj), NULL);
+
+ atk_object = gal_a11y_e_table_click_to_add_new (obj);
+
+ return atk_object;
+}
+
+static void
+gal_a11y_e_table_click_to_add_factory_class_init (GalA11yETableClickToAddFactoryClass *klass)
+{
+ AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ factory_class->create_accessible = gal_a11y_e_table_click_to_add_factory_create_accessible;
+ factory_class->get_accessible_type = gal_a11y_e_table_click_to_add_factory_get_accessible_type;
+}
+
+static void
+gal_a11y_e_table_click_to_add_factory_init (GalA11yETableClickToAddFactory *factory)
+{
+}
+
+/**
+ * gal_a11y_e_table_factory_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yETableFactory class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yETableFactory class.
+ **/
+GType
+gal_a11y_e_table_click_to_add_factory_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (GalA11yETableClickToAddFactoryClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gal_a11y_e_table_click_to_add_factory_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yETableClickToAddFactory),
+ 0,
+ (GInstanceInitFunc) gal_a11y_e_table_click_to_add_factory_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (PARENT_TYPE, "GalA11yETableClickToAddFactory", &info, 0);
+ }
+
+ return type;
+}
diff --git a/widgets/table/a11y/gal-a11y-e-table-click-to-add-factory.h b/widgets/table/a11y/gal-a11y-e-table-click-to-add-factory.h
new file mode 100644
index 0000000000..0e4ac11f79
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-click-to-add-factory.h
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yuedong Du <yuedong.du@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY_H__
+#define __GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY_H__
+
+#include <glib-object.h>
+#include <atk/atkobjectfactory.h>
+
+#define GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY (gal_a11y_e_table_item_factory_get_type ())
+#define GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY, GalA11yETableClickToAddFactory))
+#define GAL_A11Y_E_TABLE_CLICK_TO_ADD_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY, GalA11yETableClickToAddFactoryClass))
+#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY))
+#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD_FACTORY))
+
+typedef struct _GalA11yETableClickToAddFactory GalA11yETableClickToAddFactory;
+typedef struct _GalA11yETableClickToAddFactoryClass GalA11yETableClickToAddFactoryClass;
+
+struct _GalA11yETableClickToAddFactory {
+ AtkObject object;
+};
+
+struct _GalA11yETableClickToAddFactoryClass {
+ AtkObjectClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_table_click_to_add_factory_get_type (void);
+
+#endif
diff --git a/widgets/table/a11y/gal-a11y-e-table-click-to-add.c b/widgets/table/a11y/gal-a11y-e-table-click-to-add.c
new file mode 100644
index 0000000000..85c896ccf3
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-click-to-add.c
@@ -0,0 +1,344 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yuedong Du <yuedong.du@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <atk/atk.h>
+
+#include "a11y/gal-a11y-util.h"
+#include "table/e-table-click-to-add.h"
+#include "table/e-table-group.h"
+#include "table/e-table-group-leaf.h"
+#include <glib/gi18n.h>
+
+#include "gal-a11y-e-table-click-to-add.h"
+#include "gal-a11y-e-table-click-to-add-factory.h"
+
+static AtkObjectClass *parent_class;
+static GType parent_type;
+static gint priv_offset;
+#define GET_PRIVATE(object) ((GalA11yETableClickToAddPrivate *) (((char *) object) + priv_offset))
+#define PARENT_TYPE (parent_type)
+
+struct _GalA11yETableClickToAddPrivate {
+ gpointer rect;
+ gpointer row;
+};
+
+
+static gint
+etcta_get_n_actions (AtkAction *action)
+{
+ return 1;
+}
+
+static G_CONST_RETURN gchar*
+etcta_get_description (AtkAction *action,
+ gint i)
+{
+ if (i == 0)
+ return _("click to add");
+
+ return NULL;
+}
+
+static G_CONST_RETURN gchar*
+etcta_action_get_name (AtkAction *action, gint i)
+{
+ if (i == 0)
+ return _("click");
+
+ return NULL;
+}
+
+
+static gboolean
+idle_do_action (gpointer data)
+{
+ GdkEventButton event;
+ ETableClickToAdd * etcta;
+ gint finished;
+
+ g_return_val_if_fail ( data!= NULL, FALSE);
+
+ etcta = E_TABLE_CLICK_TO_ADD (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (data)));
+ g_return_val_if_fail (etcta, FALSE);
+
+ event.x = 0;
+ event.y = 0;
+
+ event.type = GDK_BUTTON_PRESS;
+ event.window = GTK_LAYOUT(GNOME_CANVAS_ITEM(etcta)->canvas)->bin_window;
+ event.button = 1;
+ event.send_event = TRUE;
+ event.time = GDK_CURRENT_TIME;
+ event.axes = NULL;
+
+ g_signal_emit_by_name (etcta, "event", &event, &finished);
+
+ return FALSE;
+}
+
+static gboolean
+etcta_do_action (AtkAction * action, gint i)
+{
+ g_return_val_if_fail (i == 0, FALSE);
+
+ g_idle_add (idle_do_action, action);
+
+ return TRUE;
+}
+
+static void
+atk_action_interface_init (AtkActionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->do_action = etcta_do_action;
+ iface->get_n_actions = etcta_get_n_actions;
+ iface->get_description = etcta_get_description;
+ iface->get_name = etcta_action_get_name;
+}
+
+
+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);
+
+ 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
+etcta_get_n_children (AtkObject *accessible)
+{
+ return 1;
+}
+
+static AtkObject*
+etcta_ref_child (AtkObject *accessible,
+ gint i)
+{
+ AtkObject * atk_obj = NULL;
+ ETableClickToAdd * etcta;
+
+ if ( i != 0 )
+ return NULL;
+
+ etcta = E_TABLE_CLICK_TO_ADD(atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
+
+ g_return_val_if_fail (etcta, NULL);
+
+ if (etcta->rect) {
+ atk_obj = atk_gobject_accessible_for_object (G_OBJECT(etcta->rect));
+ } else if (etcta->row) {
+ atk_obj = atk_gobject_accessible_for_object (G_OBJECT(etcta->row));
+ }
+
+ g_object_ref (atk_obj);
+
+ 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)
+{
+ AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ 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
+etcta_init (GalA11yETableClickToAdd *a11y)
+{
+}
+
+/**
+ * gal_a11y_e_table_click_to_add_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yETableClickToAdd class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yETableClickToAdd class.
+ **/
+GType
+gal_a11y_e_table_click_to_add_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ AtkObjectFactory *factory;
+
+ GTypeInfo info = {
+ sizeof (GalA11yETableClickToAddClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) etcta_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yETableClickToAdd),
+ 0,
+ (GInstanceInitFunc) etcta_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo atk_action_info = {
+ (GInterfaceInitFunc) atk_action_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ factory = atk_registry_get_factory (atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM);
+
+ parent_type = atk_object_factory_get_accessible_type (factory);
+ type = gal_a11y_type_register_static_with_private (PARENT_TYPE,
+ "GalA11yETableClickToAdd", &info, 0,
+ sizeof(GalA11yETableClickToAddPrivate), &priv_offset);
+
+ g_type_add_interface_static (type, ATK_TYPE_ACTION, &atk_action_info);
+
+ }
+
+ return type;
+}
+
+static gboolean
+etcta_event (GnomeCanvasItem *item, GdkEvent *e, gpointer data)
+{
+ ETableClickToAdd *etcta = E_TABLE_CLICK_TO_ADD (item);
+ GalA11yETableClickToAdd *a11y;
+ GalA11yETableClickToAddPrivate *priv;
+
+ g_return_val_if_fail (item, TRUE);
+
+ g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD(data), FALSE);
+ a11y = GAL_A11Y_E_TABLE_CLICK_TO_ADD (data);
+
+ priv = GET_PRIVATE (a11y);
+
+ /* rect replaced by row. */
+ if (etcta->rect == NULL && priv->rect != NULL) {
+ g_signal_emit_by_name (a11y, "children_changed::remove", 0, NULL, NULL);
+
+ }
+ /* row inserted, and/or replaced by a new row. */
+ if (etcta->row != NULL && priv->row == NULL) {
+ g_signal_emit_by_name (a11y, "children_changed::add", 0, NULL, NULL);
+ } else if (etcta->row != NULL && priv->row != NULL && etcta->row != priv->row) {
+ g_signal_emit_by_name (a11y, "children_changed::remove", 0, NULL, NULL);
+ g_signal_emit_by_name (a11y, "children_changed::add", 0, NULL, NULL);
+ }
+
+
+ priv->rect = etcta->rect;
+ priv->row = etcta->row;
+
+ return FALSE;
+}
+
+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)
+{
+ GalA11yETableClickToAdd *a11y;
+ ETableClickToAdd * etcta;
+ GalA11yETableClickToAddPrivate *priv;
+
+ g_return_val_if_fail (widget != NULL, NULL);
+
+ a11y = g_object_new (gal_a11y_e_table_click_to_add_get_type (), NULL);
+ priv = GET_PRIVATE (a11y);
+
+ etcta = E_TABLE_CLICK_TO_ADD(widget);
+
+
+ atk_object_initialize (ATK_OBJECT (a11y), etcta);
+
+ priv->rect = etcta->rect;
+ priv->row = etcta->row;
+
+
+ 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);
+}
+
+void
+gal_a11y_e_table_click_to_add_init (void)
+{
+ if (atk_get_root ())
+ atk_registry_set_factory_type (atk_get_default_registry (),
+ E_TABLE_CLICK_TO_ADD_TYPE,
+ gal_a11y_e_table_click_to_add_factory_get_type ());
+
+}
+
diff --git a/widgets/table/a11y/gal-a11y-e-table-click-to-add.h b/widgets/table/a11y/gal-a11y-e-table-click-to-add.h
new file mode 100644
index 0000000000..ccefc7a9b8
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-click-to-add.h
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_TABLE_CLICK_TO_ADD_H__
+#define __GAL_A11Y_E_TABLE_CLICK_TO_ADD_H__
+
+#include <glib-object.h>
+#include <table/e-table-item.h>
+#include <atk/atkgobjectaccessible.h>
+
+#define GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD (gal_a11y_e_table_click_to_add_get_type ())
+#define GAL_A11Y_E_TABLE_CLICK_TO_ADD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD, GalA11yETableClickToAdd))
+#define GAL_A11Y_E_TABLE_CLICK_TO_ADD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD, GalA11yETableClickToAddClass))
+#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD))
+#define GAL_A11Y_IS_E_TABLE_CLICK_TO_ADD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_CLICK_TO_ADD))
+
+typedef struct _GalA11yETableClickToAdd GalA11yETableClickToAdd;
+typedef struct _GalA11yETableClickToAddClass GalA11yETableClickToAddClass;
+typedef struct _GalA11yETableClickToAddPrivate GalA11yETableClickToAddPrivate;
+
+/* This struct should actually be larger as this isn't what we derive from.
+ * The GalA11yETableClickToAddPrivate comes right after the parent class structure.
+ **/
+struct _GalA11yETableClickToAdd {
+ AtkGObjectAccessible parent;
+};
+
+struct _GalA11yETableClickToAddClass {
+ AtkGObjectAccessibleClass parent_class;
+};
+
+/* Standard Glib function */
+GType gal_a11y_e_table_click_to_add_get_type (void);
+AtkObject *gal_a11y_e_table_click_to_add_new (GObject *widget);
+
+void gal_a11y_e_table_click_to_add_init (void);
+#endif /* ! __GAL_A11Y_E_TABLE_CLICK_TO_ADD_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-table-column-header.c b/widgets/table/a11y/gal-a11y-e-table-column-header.c
new file mode 100644
index 0000000000..a50a286940
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-column-header.c
@@ -0,0 +1,229 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Li Yuan <li.yuan@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include <atk/atkobject.h>
+#include <atk/atkregistry.h>
+#include "table/e-table-header-item.h"
+#include "a11y/gal-a11y-util.h"
+#include "gal-a11y-e-table-column-header.h"
+
+static GObjectClass *parent_class;
+static gint priv_offset;
+
+#define GET_PRIVATE(object) ((GalA11yETableColumnHeaderPrivate *) (((char *) object) + priv_offset))
+#define PARENT_TYPE (atk_gobject_accessible_get_type ())
+
+struct _GalA11yETableColumnHeaderPrivate {
+ ETableItem *item;
+ AtkObject *parent;
+ AtkStateSet *state_set;
+};
+
+static void
+etch_init (GalA11yETableColumnHeader *a11y)
+{
+ GET_PRIVATE (a11y)->item = NULL;
+ GET_PRIVATE (a11y)->parent = NULL;
+ GET_PRIVATE (a11y)->state_set = NULL;
+}
+
+static AtkStateSet *
+gal_a11y_e_table_column_header_ref_state_set (AtkObject *accessible)
+{
+ GalA11yETableColumnHeaderPrivate *priv = GET_PRIVATE (accessible);
+
+ g_return_val_if_fail (priv->state_set, NULL);
+
+ g_object_ref(priv->state_set);
+
+ return priv->state_set;
+}
+
+static void
+gal_a11y_e_table_column_header_real_initialize (AtkObject *obj, gpointer data)
+{
+ ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+}
+
+static void
+gal_a11y_e_table_column_header_dispose (GObject *object)
+{
+ GalA11yETableColumnHeader *a11y = GAL_A11Y_E_TABLE_COLUMN_HEADER (object);
+ GalA11yETableColumnHeaderPrivate *priv = GET_PRIVATE (a11y);
+
+ if (priv->state_set) {
+ g_object_unref (priv->state_set);
+ priv->state_set = NULL;
+ }
+
+ if (parent_class->dispose)
+ parent_class->dispose (object);
+
+}
+
+static void
+etch_class_init (GalA11yETableColumnHeaderClass *klass)
+{
+ AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ object_class->dispose = gal_a11y_e_table_column_header_dispose;
+
+ class->ref_state_set = gal_a11y_e_table_column_header_ref_state_set;
+ class->initialize = gal_a11y_e_table_column_header_real_initialize;
+}
+
+inline static GObject *
+etch_a11y_get_gobject (AtkGObjectAccessible *accessible)
+{
+ return atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible));
+}
+
+static gboolean
+gal_a11y_e_table_column_header_do_action (AtkAction *action,
+ gint i)
+{
+ gboolean return_value = TRUE;
+ GtkWidget *widget;
+ GalA11yETableColumnHeader *a11y;
+ ETableHeaderItem *ethi;
+ ETableItem *item;
+ ETableCol *col;
+
+ switch (i) {
+ case 0:
+ a11y = GAL_A11Y_E_TABLE_COLUMN_HEADER (action);
+ col = E_TABLE_COL (etch_a11y_get_gobject (ATK_GOBJECT_ACCESSIBLE (a11y)));
+ item = GET_PRIVATE (a11y)->item;
+ widget = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas));
+ if (E_IS_TREE (widget)) {
+ ethi = E_TABLE_HEADER_ITEM (e_tree_get_header_item (E_TREE (widget)));
+ }
+ else if (E_IS_TABLE (widget))
+ ethi = E_TABLE_HEADER_ITEM (E_TABLE (widget)->header_item);
+ else
+ break;
+ ethi_change_sort_state (ethi, col);
+ default:
+ return_value = FALSE;
+ break;
+ }
+ return return_value;
+}
+
+static gint
+gal_a11y_e_table_column_header_get_n_actions (AtkAction *action)
+{
+ return 1;
+}
+
+static G_CONST_RETURN gchar*
+gal_a11y_e_table_column_header_action_get_name (AtkAction *action,
+ gint i)
+{
+ G_CONST_RETURN gchar *return_value;
+
+ switch (i) {
+ case 0:
+ return_value = _("sort");
+ break;
+ default:
+ return_value = NULL;
+ break;
+ }
+ return return_value;
+}
+
+static void
+atk_action_interface_init (AtkActionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->do_action = gal_a11y_e_table_column_header_do_action;
+ iface->get_n_actions = gal_a11y_e_table_column_header_get_n_actions;
+ iface->get_name = gal_a11y_e_table_column_header_action_get_name;
+}
+
+GType
+gal_a11y_e_table_column_header_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (GalA11yETableColumnHeaderClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) etch_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ sizeof (GalA11yETableColumnHeader),
+ 0,
+ (GInstanceInitFunc) etch_init,
+ NULL
+ };
+ static const GInterfaceInfo atk_action_info = {
+ (GInterfaceInitFunc) atk_action_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETableColumnHeader", &info, 0,
+ sizeof (GalA11yETableColumnHeaderPrivate), &priv_offset);
+
+ g_type_add_interface_static (type, ATK_TYPE_ACTION, &atk_action_info);
+ }
+
+ return type;
+}
+
+AtkObject *
+gal_a11y_e_table_column_header_new (ETableCol *ecol, ETableItem *item)
+{
+ GalA11yETableColumnHeader *a11y;
+ AtkObject *accessible;
+
+ g_return_val_if_fail (E_IS_TABLE_COL (ecol), NULL);
+
+ a11y = g_object_new (gal_a11y_e_table_column_header_get_type(), NULL);
+ accessible = ATK_OBJECT (a11y);
+ atk_object_initialize (accessible, ecol);
+
+ GET_PRIVATE (a11y)->item = item;
+ GET_PRIVATE (a11y)->state_set = atk_state_set_new ();
+
+ atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_VISIBLE);
+ 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_SENSITIVE);
+ atk_state_set_add_state (GET_PRIVATE(a11y)->state_set, ATK_STATE_ENABLED);
+
+ if (ecol->text)
+ atk_object_set_name (accessible, ecol->text);
+ atk_object_set_role (accessible, ATK_ROLE_TABLE_COLUMN_HEADER);
+
+ return ATK_OBJECT (a11y);
+}
diff --git a/widgets/table/a11y/gal-a11y-e-table-column-header.h b/widgets/table/a11y/gal-a11y-e-table-column-header.h
new file mode 100644
index 0000000000..083f0af3de
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-column-header.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Li Yuan <li.yuan@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+
+#ifndef __GAL_A11Y_E_TABLE_COLUMN_HEADER_H__
+#define __GAL_A11Y_E_TABLE_COLUMN_HEADER_H__
+
+#include <glib-object.h>
+#include <atk/atkgobjectaccessible.h>
+
+#define GAL_A11Y_TYPE_E_TABLE_COLUMN_HEADER (gal_a11y_e_table_column_header_get_type ())
+#define GAL_A11Y_E_TABLE_COLUMN_HEADER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_COLUMN_HEADER, GalA11yETableColumnHeader))
+#define GAL_A11Y_E_TABLE_COLUMN_HEADER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_COLUMN_HEADER, GalA11yETableColumnHeaderClass))
+#define GAL_A11Y_IS_E_TABLE_COLUMN_HEADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_COLUMN_HEADER))
+#define GAL_A11Y_IS_E_TABLE_COLUMN_HEADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_COLUMN_HEADER))
+
+typedef struct _GalA11yETableColumnHeader GalA11yETableColumnHeader;
+typedef struct _GalA11yETableColumnHeaderClass GalA11yETableColumnHeaderClass;
+typedef struct _GalA11yETableColumnHeaderPrivate GalA11yETableColumnHeaderPrivate;
+
+struct _GalA11yETableColumnHeader {
+ AtkGObjectAccessible parent;
+};
+
+struct _GalA11yETableColumnHeaderClass {
+ AtkGObjectAccessibleClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_table_column_header_get_type (void);
+AtkObject *gal_a11y_e_table_column_header_new (ETableCol *etc, ETableItem *item);
+void gal_a11y_e_table_column_header_init (void);
+
+#endif /* ! __GAL_A11Y_E_TABLE_COLUMN_HEADER_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-table-factory.c b/widgets/table/a11y/gal-a11y-e-table-factory.c
new file mode 100644
index 0000000000..37c396aba8
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-factory.c
@@ -0,0 +1,99 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include "gal-a11y-e-table.h"
+#include "gal-a11y-e-table-factory.h"
+
+#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETableFactoryClass))
+static AtkObjectFactoryClass *parent_class;
+#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY)
+
+/* Static functions */
+
+static GType
+gal_a11y_e_table_factory_get_accessible_type (void)
+{
+ return GAL_A11Y_TYPE_E_TABLE;
+}
+
+static AtkObject*
+gal_a11y_e_table_factory_create_accessible (GObject *obj)
+{
+ AtkObject *accessible;
+
+ accessible = gal_a11y_e_table_new (obj);
+
+ return accessible;
+}
+
+static void
+gal_a11y_e_table_factory_class_init (GalA11yETableFactoryClass *klass)
+{
+ AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ factory_class->create_accessible = gal_a11y_e_table_factory_create_accessible;
+ factory_class->get_accessible_type = gal_a11y_e_table_factory_get_accessible_type;
+}
+
+static void
+gal_a11y_e_table_factory_init (GalA11yETableFactory *factory)
+{
+}
+
+/**
+ * gal_a11y_e_table_factory_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yETableFactory class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yETableFactory class.
+ **/
+GType
+gal_a11y_e_table_factory_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (GalA11yETableFactoryClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gal_a11y_e_table_factory_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yETableFactory),
+ 0,
+ (GInstanceInitFunc) gal_a11y_e_table_factory_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (PARENT_TYPE, "GalA11yETableFactory", &info, 0);
+ }
+
+ return type;
+}
diff --git a/widgets/table/a11y/gal-a11y-e-table-factory.h b/widgets/table/a11y/gal-a11y-e-table-factory.h
new file mode 100644
index 0000000000..e3ef52c872
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-factory.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_TABLE_FACTORY_H__
+#define __GAL_A11Y_E_TABLE_FACTORY_H__
+
+#include <glib-object.h>
+#include <atk/atkobjectfactory.h>
+
+#define GAL_A11Y_TYPE_E_TABLE_FACTORY (gal_a11y_e_table_factory_get_type ())
+#define GAL_A11Y_E_TABLE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_FACTORY, GalA11yETableFactory))
+#define GAL_A11Y_E_TABLE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_FACTORY, GalA11yETableFactoryClass))
+#define GAL_A11Y_IS_E_TABLE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_FACTORY))
+#define GAL_A11Y_IS_E_TABLE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_FACTORY))
+
+typedef struct _GalA11yETableFactory GalA11yETableFactory;
+typedef struct _GalA11yETableFactoryClass GalA11yETableFactoryClass;
+
+struct _GalA11yETableFactory {
+ AtkObject object;
+};
+
+struct _GalA11yETableFactoryClass {
+ AtkObjectClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_table_factory_get_type (void);
+
+#endif /* ! __GAL_A11Y_E_TABLE_FACTORY_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-table-item-factory.c b/widgets/table/a11y/gal-a11y-e-table-item-factory.c
new file mode 100644
index 0000000000..43508e4796
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-item-factory.c
@@ -0,0 +1,105 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yuedong Du <yuedong.du@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <atk/atk.h>
+
+#include "table/e-table.h"
+#include "table/e-tree.h"
+
+#include "gal-a11y-e-table.h"
+#include "gal-a11y-e-table-item.h"
+#include "gal-a11y-e-table-item-factory.h"
+
+#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETableItemFactoryClass))
+static AtkObjectFactoryClass *parent_class;
+#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY)
+
+/* Static functions */
+
+static GType
+gal_a11y_e_table_item_factory_get_accessible_type (void)
+{
+ return GAL_A11Y_TYPE_E_TABLE_ITEM;
+}
+
+static AtkObject*
+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 (E_TABLE_ITEM (obj));
+
+ return accessible;
+}
+
+static void
+gal_a11y_e_table_item_factory_class_init (GalA11yETableItemFactoryClass *klass)
+{
+ AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ factory_class->create_accessible = gal_a11y_e_table_item_factory_create_accessible;
+ factory_class->get_accessible_type = gal_a11y_e_table_item_factory_get_accessible_type;
+}
+
+static void
+gal_a11y_e_table_item_factory_init (GalA11yETableItemFactory *factory)
+{
+}
+
+/**
+ * gal_a11y_e_table_factory_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yETableFactory class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yETableFactory class.
+ **/
+GType
+gal_a11y_e_table_item_factory_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (GalA11yETableItemFactoryClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gal_a11y_e_table_item_factory_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yETableItemFactory),
+ 0,
+ (GInstanceInitFunc) gal_a11y_e_table_item_factory_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (PARENT_TYPE, "GalA11yETableItemFactory", &info, 0);
+ }
+
+ return type;
+}
diff --git a/widgets/table/a11y/gal-a11y-e-table-item-factory.h b/widgets/table/a11y/gal-a11y-e-table-item-factory.h
new file mode 100644
index 0000000000..a85c9e894f
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-item-factory.h
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yuedong Du <yuedong.du@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_TABLE_ITEM_FACTORY_H__
+#define __GAL_A11Y_E_TABLE_ITEM_FACTORY_H__
+
+#include <glib-object.h>
+#include <atk/atkobjectfactory.h>
+
+#define GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY (gal_a11y_e_table_item_factory_get_type ())
+#define GAL_A11Y_E_TABLE_ITEM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY, GalA11yETableItemFactory))
+#define GAL_A11Y_E_TABLE_ITEM_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY, GalA11yETableItemFactoryClass))
+#define GAL_A11Y_IS_E_TABLE_ITEM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY))
+#define GAL_A11Y_IS_E_TABLE_ITEM_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM_FACTORY))
+
+typedef struct _GalA11yETableItemFactory GalA11yETableItemFactory;
+typedef struct _GalA11yETableItemFactoryClass GalA11yETableItemFactoryClass;
+
+struct _GalA11yETableItemFactory {
+ AtkObject object;
+};
+
+struct _GalA11yETableItemFactoryClass {
+ AtkObjectClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_table_item_factory_get_type (void);
+
+#endif /* ! __GAL_A11Y_E_TABLE_FACTORY_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-table-item.c b/widgets/table/a11y/gal-a11y-e-table-item.c
new file mode 100644
index 0000000000..16d50df9b0
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-item.c
@@ -0,0 +1,1327 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ * Bolian Yin <bolian.yin@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <atk/atk.h>
+
+#include "a11y/gal-a11y-util.h"
+#include "table/e-table-click-to-add.h"
+#include "table/e-table-subset.h"
+#include "table/e-table.h"
+#include "table/e-tree.h"
+#include "misc/e-canvas.h"
+#include "misc/e-selection-model.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-e-table-column-header.h"
+
+#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETableItemClass))
+static GObjectClass *parent_class;
+static AtkComponentIface *component_parent_iface;
+static GType parent_type;
+static gint priv_offset;
+static GQuark quark_accessible_object = 0;
+#define GET_PRIVATE(object) ((GalA11yETableItemPrivate *) (((char *) object) + priv_offset))
+#define PARENT_TYPE (parent_type)
+
+struct _GalA11yETableItemPrivate {
+ gint cols;
+ gint rows;
+ int selection_change_id;
+ int cursor_change_id;
+ ETableCol ** columns;
+ ESelectionModel *selection;
+ AtkStateSet *state_set;
+ GtkWidget *widget;
+};
+
+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 AtkObject* eti_ref_at (AtkTable *table, gint row, gint column);
+
+static void
+item_destroyed (GtkObject *item, gpointer user_data)
+{
+ GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (user_data);
+ 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;
+}
+
+inline static gint
+view_to_model_row(ETableItem *eti, int row)
+{
+ if (eti->uses_source_model) {
+ ETableSubset *etss = E_TABLE_SUBSET(eti->table_model);
+ if (row >= 0 && row < etss->n_map) {
+ eti->row_guess = row;
+ return etss->map_table[row];
+ } else
+ return -1;
+ } else
+ return row;
+}
+
+inline static gint
+view_to_model_col(ETableItem *eti, int col)
+{
+ ETableCol *ecol = e_table_header_get_column (eti->header, col);
+ return ecol ? ecol->col_idx : -1;
+}
+
+inline static gint
+model_to_view_row(ETableItem *eti, int row)
+{
+ int i;
+ if (row == -1)
+ return -1;
+ if (eti->uses_source_model) {
+ ETableSubset *etss = E_TABLE_SUBSET(eti->table_model);
+ if (eti->row_guess >= 0 && eti->row_guess < etss->n_map) {
+ if (etss->map_table[eti->row_guess] == row) {
+ return eti->row_guess;
+ }
+ }
+ for (i = 0; i < etss->n_map; i++) {
+ if (etss->map_table[i] == row)
+ return i;
+ }
+ return -1;
+ } else
+ return row;
+}
+
+inline static gint
+model_to_view_col(ETableItem *eti, int col)
+{
+ int i;
+ if (col == -1)
+ return -1;
+ for (i = 0; i < eti->cols; i++) {
+ ETableCol *ecol = e_table_header_get_column (eti->header, i);
+ if (ecol->col_idx == col)
+ return i;
+ }
+ return -1;
+}
+
+inline static GObject *
+eti_a11y_get_gobject (AtkObject *accessible)
+{
+ return atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible));
+}
+
+static void
+eti_a11y_reset_focus_object (GalA11yETableItem *a11y, ETableItem *item, gboolean notify)
+{
+ ESelectionModel * esm;
+ int cursor_row, cursor_col, view_row, view_col;
+ AtkObject *cell, *old_cell;
+
+ esm = item->selection;
+ g_return_if_fail (esm);
+
+ 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;
+
+ 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);
+
+ 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);
+ } else
+ g_object_set_data (G_OBJECT (a11y), "gail-focus-object", NULL);
+
+ if (notify && cell)
+ atk_focus_tracker_notify (cell);
+}
+
+static void
+eti_dispose (GObject *object)
+{
+ GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (object);
+ GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
+
+ if (priv->columns) {
+ g_free(priv->columns);
+ priv->columns = NULL;
+ }
+
+ if (parent_class->dispose)
+ parent_class->dispose (object);
+}
+
+/* Static functions */
+static gint
+eti_get_n_children (AtkObject *accessible)
+{
+ g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), 0);
+ if (!eti_a11y_get_gobject (accessible))
+ return 0;
+
+ return atk_table_get_n_columns (ATK_TABLE (accessible)) *
+ (atk_table_get_n_rows (ATK_TABLE (accessible)) + 1);
+}
+
+static AtkObject*
+eti_ref_child (AtkObject *accessible, gint index)
+{
+ ETableItem *item;
+ gint col, row;
+
+ g_return_val_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (accessible), NULL);
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (accessible));
+ if (!item)
+ return NULL;
+
+ if (index < item->cols) {
+ ETableCol *ecol;
+ AtkObject *child;
+
+ ecol = e_table_header_get_column (item->header, index);
+ child = gal_a11y_e_table_column_header_new (ecol, item);
+ return child;
+ }
+ index -= item->cols;
+
+ col = index % item->cols;
+ row = index / item->cols;
+
+ return eti_ref_at (ATK_TABLE (accessible), row, col);
+}
+
+static void
+eti_get_extents (AtkComponent *component,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coord_type)
+{
+ ETableItem *item;
+ AtkObject *parent;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (component)));
+ if (!item)
+ return;
+
+ 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*
+eti_ref_accessible_at_point (AtkComponent *component,
+ gint x,
+ gint y,
+ AtkCoordType coord_type)
+{
+ int row = -1;
+ 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)
+ return NULL;
+
+ atk_component_get_position (component,
+ &x_origin,
+ &y_origin,
+ coord_type);
+ x -= x_origin;
+ y -= y_origin;
+
+ 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 eti_ref_at (ATK_TABLE (component), row, col);
+ } else {
+ return NULL;
+ }
+}
+
+
+static void
+cell_destroyed (gpointer data)
+{
+ GalA11yECell * cell;
+
+ g_return_if_fail (GAL_A11Y_IS_E_CELL (data));
+ cell = GAL_A11Y_E_CELL (data);
+
+ g_return_if_fail (cell->item && G_IS_OBJECT (cell->item));
+
+ if (cell->item) {
+ g_object_unref (cell->item);
+ cell->item = NULL;
+ }
+
+}
+
+/* atk table */
+static AtkObject*
+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)
+ return NULL;
+
+ if (column >= 0 &&
+ column < item->cols &&
+ row >= 0 &&
+ row < item->rows &&
+ item->cell_views_realized) {
+ ECellView *cell_view = item->cell_views[column];
+ ETableCol *ecol = e_table_header_get_column (item->header, column);
+ ret = gal_a11y_e_cell_registry_get_object (NULL,
+ item,
+ cell_view,
+ ATK_OBJECT (table),
+ ecol->col_idx,
+ column,
+ 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;
+ }
+
+ return NULL;
+}
+
+static gint
+eti_get_index_at (AtkTable *table, gint row, gint column)
+{
+ ETableItem *item;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
+ if (!item)
+ return -1;
+
+ return column + (row + 1) * item->cols;
+}
+
+static gint
+eti_get_column_at_index (AtkTable *table, gint index)
+{
+ ETableItem *item;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
+ if (!item)
+ return -1;
+
+ return index % item->cols;
+}
+
+static gint
+eti_get_row_at_index (AtkTable *table, gint index)
+{
+ ETableItem *item;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
+ if (!item)
+ return -1;
+
+ return index / item->cols - 1;
+}
+
+static gint
+eti_get_n_columns (AtkTable *table)
+{
+ ETableItem *item;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
+ if (!item)
+ return -1;
+
+ return item->cols;
+}
+
+static gint
+eti_get_n_rows (AtkTable *table)
+{
+ ETableItem *item;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
+ if (!item)
+ return -1;
+
+ return item->rows;
+}
+
+static gint
+eti_get_column_extent_at (AtkTable *table,
+ gint row,
+ gint column)
+{
+ ETableItem *item;
+ int width;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
+ if (!item)
+ return -1;
+
+ e_table_item_get_cell_geometry (item,
+ &row,
+ &column,
+ NULL,
+ NULL,
+ &width,
+ NULL);
+
+ return width;
+}
+
+static gint
+eti_get_row_extent_at (AtkTable *table,
+ gint row,
+ gint column)
+{
+ ETableItem *item;
+ int height;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
+ if (!item)
+ return -1;
+
+ e_table_item_get_cell_geometry (item,
+ &row,
+ &column,
+ NULL,
+ NULL,
+ NULL,
+ &height);
+
+ return height;
+}
+
+static AtkObject *
+eti_get_caption (AtkTable *table)
+{
+ /* Unimplemented */
+ return NULL;
+}
+
+static G_CONST_RETURN gchar *
+eti_get_column_description (AtkTable *table,
+ gint column)
+{
+ ETableItem *item;
+ ETableCol *ecol;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
+ if (!item)
+ return NULL;
+
+ ecol = e_table_header_get_column (item->header, column);
+
+ return ecol->text;
+}
+
+static AtkObject *
+eti_get_column_header (AtkTable *table, gint column)
+{
+ ETableItem *item;
+ ETableCol *ecol;
+ AtkObject *atk_obj = NULL;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
+ if (!item)
+ return NULL;
+
+ ecol = e_table_header_get_column (item->header, column);
+ if (ecol) {
+ atk_obj = gal_a11y_e_table_column_header_new (ecol, item);
+ }
+
+ return atk_obj;
+}
+
+static G_CONST_RETURN gchar *
+eti_get_row_description (AtkTable *table,
+ gint row)
+{
+ /* Unimplemented */
+ return NULL;
+}
+
+static AtkObject *
+eti_get_row_header (AtkTable *table,
+ gint row)
+{
+ /* Unimplemented */
+ return NULL;
+}
+
+static AtkObject *
+eti_get_summary (AtkTable *table)
+{
+ /* Unimplemented */
+ return NULL;
+}
+
+static gboolean
+table_is_row_selected (AtkTable *table, gint row)
+{
+ ETableItem *item;
+ GalA11yETableItemPrivate *priv = GET_PRIVATE (table);
+
+ if (row < 0)
+ return FALSE;
+
+ 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, view_to_model_row (item, row));
+}
+
+static gboolean
+table_is_selected (AtkTable *table, gint row, gint column)
+{
+ return table_is_row_selected (table, row);
+}
+
+static gint
+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)
+ return 0;
+
+ n_selected = e_selection_model_selected_count (item->selection);
+ if (rows_selected) {
+ *rows_selected = (gint *) g_malloc (n_selected * sizeof (gint));
+
+ index_selected = 0;
+ for (row = 0; row < item->rows && index_selected < n_selected; ++row) {
+ if (atk_table_is_row_selected (table, row)) {
+ (*rows_selected)[index_selected] = row;
+ ++index_selected;
+ }
+ }
+ }
+ return n_selected;
+}
+
+static gboolean
+table_add_row_selection (AtkTable *table, gint row)
+{
+ ETableItem *item;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (table)));
+ if (!item)
+ return FALSE;
+
+ if (table_is_row_selected (table, row))
+ return TRUE;
+ e_selection_model_toggle_single_row (item->selection,
+ view_to_model_row (item, row));
+
+ return TRUE;
+}
+
+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)
+ return FALSE;
+
+ if (!atk_table_is_row_selected (table, row))
+ return TRUE;
+ e_selection_model_toggle_single_row (item->selection, view_to_model_row (item, row));
+ return TRUE;
+}
+
+static void
+eti_atk_table_iface_init (AtkTableIface *iface)
+{
+ iface->ref_at = eti_ref_at;
+ iface->get_index_at = eti_get_index_at;
+ iface->get_column_at_index = eti_get_column_at_index;
+ iface->get_row_at_index = eti_get_row_at_index;
+ iface->get_n_columns = eti_get_n_columns;
+ iface->get_n_rows = eti_get_n_rows;
+ iface->get_column_extent_at = eti_get_column_extent_at;
+ iface->get_row_extent_at = eti_get_row_extent_at;
+ iface->get_caption = eti_get_caption;
+ iface->get_column_description = eti_get_column_description;
+ iface->get_column_header = eti_get_column_header;
+ iface->get_row_description = eti_get_row_description;
+ iface->get_row_header = eti_get_row_header;
+ iface->get_summary = eti_get_summary;
+
+ iface->is_row_selected = table_is_row_selected;
+ iface->is_selected = table_is_selected;
+ iface->get_selected_rows = table_get_selected_rows;
+ iface->add_row_selection = table_add_row_selection;
+ iface->remove_row_selection = table_remove_row_selection;
+}
+
+static void
+eti_atk_component_iface_init (AtkComponentIface *iface)
+{
+ component_parent_iface = g_type_interface_peek_parent (iface);
+
+ iface->ref_accessible_at_point = eti_ref_accessible_at_point;
+ iface->get_extents = eti_get_extents;
+}
+
+static void
+eti_rows_inserted (ETableModel * model, int row, int count,
+ AtkObject * table_item)
+{
+ gint n_cols,n_rows,i,j;
+ GalA11yETableItem * item_a11y;
+ gint old_nrows;
+
+ g_return_if_fail (table_item);
+ item_a11y = GAL_A11Y_E_TABLE_ITEM (table_item);
+
+ n_cols = atk_table_get_n_columns (ATK_TABLE(table_item));
+ n_rows = atk_table_get_n_rows (ATK_TABLE(table_item));
+
+ old_nrows = GET_PRIVATE(item_a11y)->rows;
+
+ g_return_if_fail (n_cols > 0 && n_rows > 0);
+ g_return_if_fail (old_nrows == n_rows - count);
+
+ GET_PRIVATE(table_item)->rows = n_rows;
+
+ g_signal_emit_by_name (table_item, "row-inserted", 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::add",
+ ( ((i + 1)*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;
+ ETableItem *item = E_TABLE_ITEM (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (table_item)));
+
+ n_rows = atk_table_get_n_rows (ATK_TABLE(table_item));
+ n_cols = atk_table_get_n_columns (ATK_TABLE(table_item));
+
+ 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;
+
+ 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 + 1)*n_cols) + j), NULL, NULL);
+ }
+ }
+ g_signal_emit_by_name (table_item, "visible-data-changed");
+ eti_a11y_reset_focus_object ((GalA11yETableItem *)table_item, item, TRUE);
+}
+
+static void
+eti_tree_model_node_changed_cb (ETreeModel *model, ETreePath node, ETableItem *eti)
+{
+ AtkObject *atk_obj;
+ GalA11yETableItem *a11y;
+
+ g_return_if_fail (E_IS_TABLE_ITEM (eti));
+
+ 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 send out a signal ... */
+ if (GET_PRIVATE (a11y)->rows > 0)
+ g_signal_emit_by_name (a11y, "visible-data-changed");
+}
+
+enum {
+ ETI_HEADER_UNCHANGED = 0,
+ ETI_HEADER_REORDERED,
+ ETI_HEADER_NEW_ADDED,
+ ETI_HEADER_REMOVED,
+};
+
+/*
+ * 1. Check what actually happened: column reorder, remove or add
+ * 2. Update cache
+ * 3. Emit signals
+ */
+static void
+eti_header_structure_changed (ETableHeader *eth, AtkObject *a11y)
+{
+
+ gboolean reorder_found=FALSE, added_found=FALSE, removed_found=FALSE;
+ GalA11yETableItem * a11y_item;
+ ETableCol ** cols, **prev_cols;
+ GalA11yETableItemPrivate *priv;
+ gint *state = NULL, *prev_state = NULL, *reorder = NULL;
+ gint i,j,n_rows,n_cols, prev_n_cols;
+
+ a11y_item = GAL_A11Y_E_TABLE_ITEM (a11y);
+ priv = GET_PRIVATE (a11y_item);
+
+ /* Assume rows do not changed. */
+ n_rows = priv->rows;
+
+ prev_n_cols = priv->cols;
+ prev_cols = priv->columns;
+
+ cols = e_table_header_get_columns (eth);
+ n_cols = eth->col_count;
+
+ g_return_if_fail (cols && prev_cols && n_cols > 0);
+
+ /* Init to ETI_HEADER_UNCHANGED. */
+ state = g_malloc0 (sizeof (gint) * n_cols);
+ prev_state = g_malloc0 (sizeof (gint) * prev_n_cols);
+ reorder = g_malloc0 (sizeof (gint) * n_cols);
+
+ /* Compare with previously saved column headers. */
+ for ( i = 0 ; i < n_cols && cols[i]; i ++ ) {
+ for ( j = 0 ; j < prev_n_cols && prev_cols[j]; j ++ ) {
+ if ( prev_cols [j] == cols[i] && i != j ) {
+
+ reorder_found = TRUE;
+ state [i] = ETI_HEADER_REORDERED;
+ reorder [i] = j;
+
+ break;
+ } else if (prev_cols[j] == cols[i]) {
+ /* OK, this column is not changed. */
+ break;
+ }
+ }
+
+ /* cols[i] is new added column. */
+ if ( j == prev_n_cols ) {
+ added_found = TRUE;
+ state[i] = ETI_HEADER_NEW_ADDED;
+ }
+ }
+
+ /* Now try to find if there are removed columns. */
+ for (i = 0 ; i < prev_n_cols && prev_cols[i]; i ++) {
+ for (j = 0 ; j < n_cols && cols[j]; j ++)
+ if ( prev_cols [j] == cols[i] )
+ break;
+
+ /* Removed columns found. */
+ if ( j == n_cols ) {
+ removed_found = TRUE;
+ prev_state[j] = ETI_HEADER_REMOVED;
+ }
+ }
+
+ /* If nothing interesting just return. */
+ if (!reorder_found && !added_found && !removed_found)
+ return;
+
+ /* Emit signals */
+ if (reorder_found)
+ g_signal_emit_by_name (G_OBJECT(a11y_item), "column_reordered");
+
+
+ if (removed_found) {
+ for (i = 0; i < prev_n_cols; i ++ ) {
+ if (prev_state[i] == ETI_HEADER_REMOVED) {
+ g_signal_emit_by_name (G_OBJECT(a11y_item), "column-deleted", i, 1);
+ for (j = 0 ; j < n_rows; j ++)
+ g_signal_emit_by_name (G_OBJECT(a11y_item), "children_changed::remove", ((j+1)*prev_n_cols+i), NULL, NULL);
+ }
+ }
+ }
+
+ if (added_found) {
+ for ( i = 0; i < n_cols; i ++ ) {
+ if (state[i] == ETI_HEADER_NEW_ADDED) {
+ g_signal_emit_by_name (G_OBJECT(a11y_item), "column-inserted", i, 1);
+ for (j = 0 ; j < n_rows; j ++)
+ g_signal_emit_by_name (G_OBJECT(a11y_item), "children_changed::add", ((j+1)*n_cols+i), NULL, NULL);
+ }
+ }
+ }
+
+ priv->cols = n_cols;
+
+ g_free (state);
+ g_free (reorder);
+ g_free (prev_state);
+
+ g_free (priv->columns);
+ priv->columns = cols;
+}
+
+
+static void
+eti_real_initialize (AtkObject *obj,
+ gpointer data)
+{
+ ETableItem * eti;
+ ETableModel * model;
+
+ ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+ eti = E_TABLE_ITEM (data);
+
+ model = eti->table_model;
+
+ g_signal_connect (model, "model-rows-inserted",
+ G_CALLBACK (eti_rows_inserted),
+ obj);
+ g_signal_connect (model, "model-rows-deleted",
+ G_CALLBACK (eti_rows_deleted),
+ obj);
+ g_signal_connect (G_OBJECT (eti->header), "structure_change",
+ G_CALLBACK (eti_header_structure_changed), obj);
+
+}
+
+static void
+eti_class_init (GalA11yETableItemClass *klass)
+{
+ AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ quark_accessible_object = g_quark_from_static_string ("gtk-accessible-object");
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ object_class->dispose = eti_dispose;
+
+ atk_object_class->get_n_children = eti_get_n_children;
+ atk_object_class->ref_child = eti_ref_child;
+ atk_object_class->initialize = eti_real_initialize;
+ atk_object_class->ref_state_set = eti_ref_state_set;
+}
+
+static void
+eti_init (GalA11yETableItem *a11y)
+{
+ GalA11yETableItemPrivate *priv;
+
+ priv = GET_PRIVATE (a11y);
+
+ priv->selection_change_id = 0;
+ priv->cursor_change_id = 0;
+ priv->selection = NULL;
+}
+
+/* atk selection */
+
+static void atk_selection_interface_init (AtkSelectionIface *iface);
+static gboolean selection_add_selection (AtkSelection *selection,
+ gint i);
+static gboolean selection_clear_selection (AtkSelection *selection);
+static AtkObject* selection_ref_selection (AtkSelection *selection,
+ gint i);
+static gint selection_get_selection_count (AtkSelection *selection);
+static gboolean selection_is_child_selected (AtkSelection *selection,
+ gint i);
+
+/* callbacks */
+static void eti_a11y_selection_model_removed_cb (ETableItem *eti,
+ ESelectionModel *selection,
+ gpointer data);
+static void eti_a11y_selection_model_added_cb (ETableItem *eti,
+ ESelectionModel *selection,
+ gpointer data);
+static void eti_a11y_selection_changed_cb (ESelectionModel *selection,
+ GalA11yETableItem *a11y);
+static void eti_a11y_cursor_changed_cb (ESelectionModel *selection,
+ int row, int col,
+ GalA11yETableItem *a11y);
+
+/**
+ * gal_a11y_e_table_item_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yETableItem class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yETableItem class.
+ **/
+GType
+gal_a11y_e_table_item_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ AtkObjectFactory *factory;
+
+ GTypeInfo info = {
+ sizeof (GalA11yETableItemClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) eti_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yETableItem),
+ 0,
+ (GInstanceInitFunc) eti_init,
+ NULL /* value_table_item */
+ };
+
+ static const GInterfaceInfo atk_component_info = {
+ (GInterfaceInitFunc) eti_atk_component_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+ static const GInterfaceInfo atk_table_info = {
+ (GInterfaceInitFunc) eti_atk_table_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ static const GInterfaceInfo atk_selection_info = {
+ (GInterfaceInitFunc) atk_selection_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+
+ factory = atk_registry_get_factory (atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM);
+ parent_type = atk_object_factory_get_accessible_type (factory);
+
+ type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETableItem", &info, 0,
+ sizeof (GalA11yETableItemPrivate), &priv_offset);
+
+ g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
+ g_type_add_interface_static (type, ATK_TYPE_TABLE, &atk_table_info);
+ g_type_add_interface_static (type, ATK_TYPE_SELECTION, &atk_selection_info);
+ }
+
+ return type;
+}
+
+AtkObject *
+gal_a11y_e_table_item_new (ETableItem *item)
+{
+ GalA11yETableItem *a11y;
+ AtkObject *accessible;
+ ESelectionModel * esm;
+ 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)->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);
+
+ /* Initialize cell data. */
+ GET_PRIVATE (a11y)->cols = item->cols;
+ GET_PRIVATE (a11y)->rows = item->rows;
+
+ GET_PRIVATE (a11y)->columns = e_table_header_get_columns (item->header);
+ if ( GET_PRIVATE (a11y)->columns == NULL)
+ return NULL;
+
+ if (item) {
+ g_signal_connect (G_OBJECT(item), "selection_model_removed",
+ G_CALLBACK (eti_a11y_selection_model_removed_cb), NULL);
+ g_signal_connect (G_OBJECT(item), "selection_model_added",
+ G_CALLBACK (eti_a11y_selection_model_added_cb), NULL);
+ if (item->selection)
+ gal_a11y_e_table_item_ref_selection (a11y,
+ item->selection);
+
+ /* 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 (item)
+ g_signal_connect (G_OBJECT (item), "destroy",
+ G_CALLBACK (item_destroyed),
+ a11y);
+ esm = item->selection;
+
+ if (esm != NULL) {
+ eti_a11y_reset_focus_object (a11y, item, FALSE);
+ }
+
+ return ATK_OBJECT (a11y);
+}
+
+static gboolean
+gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y,
+ ESelectionModel *selection)
+{
+ GalA11yETableItemPrivate *priv;
+
+ g_return_val_if_fail (a11y && selection, FALSE);
+
+ priv = GET_PRIVATE (a11y);
+ priv->selection_change_id = g_signal_connect (
+ G_OBJECT(selection), "selection_changed",
+ G_CALLBACK (eti_a11y_selection_changed_cb), a11y);
+ priv->cursor_change_id = g_signal_connect (
+ G_OBJECT(selection), "cursor_changed",
+ G_CALLBACK (eti_a11y_cursor_changed_cb), a11y);
+
+ priv->selection = selection;
+ g_object_ref (selection);
+
+ return TRUE;
+}
+
+static gboolean
+gal_a11y_e_table_item_unref_selection (GalA11yETableItem *a11y)
+{
+ GalA11yETableItemPrivate *priv;
+
+ g_return_val_if_fail (a11y, FALSE);
+
+ priv = GET_PRIVATE (a11y);
+
+ g_return_val_if_fail (priv->selection_change_id != 0, FALSE);
+ g_return_val_if_fail (priv->cursor_change_id != 0, FALSE);
+
+
+ g_signal_handler_disconnect (priv->selection,
+ priv->selection_change_id);
+ g_signal_handler_disconnect (priv->selection,
+ priv->cursor_change_id);
+ priv->cursor_change_id = 0;
+ priv->selection_change_id = 0;
+
+ g_object_unref (priv->selection);
+ priv->selection = NULL;
+
+ return TRUE;
+}
+
+/* callbacks */
+
+static void
+eti_a11y_selection_model_removed_cb (ETableItem *eti, ESelectionModel *selection,
+ gpointer data)
+{
+ AtkObject *atk_obj;
+ GalA11yETableItem *a11y;
+
+ g_return_if_fail (E_IS_TABLE_ITEM (eti));
+ g_return_if_fail (E_IS_SELECTION_MODEL (selection));
+
+ atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti));
+ a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj);
+
+ if (selection == GET_PRIVATE (a11y)->selection)
+ gal_a11y_e_table_item_unref_selection (a11y);
+}
+
+static void
+eti_a11y_selection_model_added_cb (ETableItem *eti, ESelectionModel *selection,
+ gpointer data)
+{
+ AtkObject *atk_obj;
+ GalA11yETableItem *a11y;
+
+ g_return_if_fail (E_IS_TABLE_ITEM (eti));
+ g_return_if_fail (E_IS_SELECTION_MODEL (selection));
+
+ atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti));
+ a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj);
+
+ if (GET_PRIVATE (a11y)->selection)
+ gal_a11y_e_table_item_unref_selection (a11y);
+ gal_a11y_e_table_item_ref_selection (a11y, 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");
+}
+
+static void
+eti_a11y_cursor_changed_cb (ESelectionModel *selection,
+ int row, int col, GalA11yETableItem *a11y)
+{
+ ETableItem *item;
+ GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
+
+ g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y));
+
+ 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;
+ eti_a11y_reset_focus_object (a11y, item, TRUE);
+}
+
+/* atk selection */
+
+static void atk_selection_interface_init (AtkSelectionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+ iface->add_selection = selection_add_selection;
+ iface->clear_selection = selection_clear_selection;
+ iface->ref_selection = selection_ref_selection;
+ iface->get_selection_count = selection_get_selection_count;
+ iface->is_child_selected = selection_is_child_selected;
+}
+
+static gboolean
+selection_add_selection (AtkSelection *selection, gint index)
+{
+ AtkTable *table;
+ gint row, col, cursor_row, cursor_col, model_row, model_col;
+ ETableItem *item;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection)));
+ if (!item)
+ return FALSE;
+
+ table = ATK_TABLE (selection);
+
+ row = atk_table_get_row_at_index (table, index);
+ 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,
+ model_row,
+ model_col);
+ e_selection_model_cursor_changed (item->selection,
+ model_row,
+ model_col);
+ e_selection_model_cursor_activated (item->selection,
+ model_row,
+ model_col);
+ return TRUE;
+}
+
+static gboolean
+selection_clear_selection (AtkSelection *selection)
+{
+ ETableItem *item;
+
+ item = E_TABLE_ITEM (eti_a11y_get_gobject (ATK_OBJECT (selection)));
+ if (!item)
+ return FALSE;
+
+ e_selection_model_clear (item->selection);
+ return TRUE;
+}
+
+static AtkObject *
+selection_ref_selection (AtkSelection *selection, gint index)
+{
+ AtkTable *table;
+ gint row, col;
+
+ table = ATK_TABLE (selection);
+ row = atk_table_get_row_at_index (table, index);
+ col = atk_table_get_column_at_index (table, index);
+ if (!atk_table_is_row_selected (table, row))
+ return NULL;
+
+ return eti_ref_at (table, row, col);
+}
+
+static gint
+selection_get_selection_count (AtkSelection *selection)
+{
+ AtkTable *table;
+ gint n_selected;
+
+ table = ATK_TABLE (selection);
+ n_selected = atk_table_get_selected_rows (table, NULL);
+ if (n_selected > 0)
+ n_selected *= atk_table_get_n_columns (table);
+ return n_selected;
+}
+
+static gboolean
+selection_is_child_selected (AtkSelection *selection, gint i)
+{
+ gint row;
+
+ 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)
+{
+ if (atk_get_root ())
+ atk_registry_set_factory_type (atk_get_default_registry (),
+ E_TABLE_ITEM_TYPE,
+ gal_a11y_e_table_item_factory_get_type ());
+}
+
diff --git a/widgets/table/a11y/gal-a11y-e-table-item.h b/widgets/table/a11y/gal-a11y-e-table-item.h
new file mode 100644
index 0000000000..e89f0824b3
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table-item.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_TABLE_ITEM_H__
+#define __GAL_A11Y_E_TABLE_ITEM_H__
+
+#include <glib-object.h>
+#include <table/e-table-item.h>
+#include <atk/atkgobjectaccessible.h>
+
+#define GAL_A11Y_TYPE_E_TABLE_ITEM (gal_a11y_e_table_item_get_type ())
+#define GAL_A11Y_E_TABLE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM, GalA11yETableItem))
+#define GAL_A11Y_E_TABLE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM, GalA11yETableItemClass))
+#define GAL_A11Y_IS_E_TABLE_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE_ITEM))
+#define GAL_A11Y_IS_E_TABLE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE_ITEM))
+
+typedef struct _GalA11yETableItem GalA11yETableItem;
+typedef struct _GalA11yETableItemClass GalA11yETableItemClass;
+typedef struct _GalA11yETableItemPrivate GalA11yETableItemPrivate;
+
+/* This struct should actually be larger as this isn't what we derive from.
+ * The GalA11yETableItemPrivate comes right after the parent class structure.
+ **/
+struct _GalA11yETableItem {
+ AtkGObjectAccessible parent;
+};
+
+struct _GalA11yETableItemClass {
+ AtkGObjectAccessibleClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_table_item_get_type (void);
+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/widgets/table/a11y/gal-a11y-e-table.c b/widgets/table/a11y/gal-a11y-e-table.c
new file mode 100644
index 0000000000..20261d4eab
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table.c
@@ -0,0 +1,308 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include "a11y/gal-a11y-util.h"
+#include "table/e-table.h"
+#include "table/e-table-click-to-add.h"
+#include "table/e-table-group.h"
+#include "table/e-table-group-container.h"
+#include "table/e-table-group-leaf.h"
+
+#include "gal-a11y-e-table.h"
+#include "gal-a11y-e-table-factory.h"
+#include "gal-a11y-e-table-item.h"
+
+#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETableClass))
+static AtkObjectClass *parent_class;
+static GType parent_type;
+static gint priv_offset;
+#define GET_PRIVATE(object) ((GalA11yETablePrivate *) (((char *) object) + priv_offset))
+#define PARENT_TYPE (parent_type)
+
+struct _GalA11yETablePrivate {
+ AtkObject *child_item;
+};
+
+/* Static functions */
+static ETableItem *
+find_first_table_item (ETableGroup *group)
+{
+ GnomeCanvasGroup *cgroup;
+ GList *l;
+
+ 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 gboolean
+init_child_item (GalA11yETable *a11y)
+{
+ 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*
+et_ref_accessible_at_point (AtkComponent *component,
+ gint x,
+ gint y,
+ AtkCoordType coord_type)
+{
+ GalA11yETable *a11y = GAL_A11Y_E_TABLE (component);
+ if (GET_PRIVATE (a11y)->child_item)
+ g_object_ref (GET_PRIVATE (a11y)->child_item);
+ return GET_PRIVATE (a11y)->child_item;
+}
+
+static gint
+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->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*
+et_ref_child (AtkObject *accessible,
+ gint i)
+{
+ GalA11yETable *a11y = GAL_A11Y_E_TABLE (accessible);
+ ETable * et;
+ gint child_no;
+
+ et = E_TABLE(GTK_ACCESSIBLE (a11y)->widget);
+
+ 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) {
+ ETableClickToAdd * etcta;
+
+ if (et && et->use_click_to_add && et->click_to_add) {
+ etcta = E_TABLE_CLICK_TO_ADD(et->click_to_add);
+ accessible = atk_gobject_accessible_for_object (G_OBJECT(etcta));
+ if (accessible)
+ g_object_ref (accessible);
+ return accessible;
+ }
+ }
+
+ return NULL;
+}
+
+static AtkLayer
+et_get_layer (AtkComponent *component)
+{
+ return ATK_LAYER_WIDGET;
+}
+
+static void
+et_class_init (GalA11yETableClass *klass)
+{
+ AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ atk_object_class->get_n_children = et_get_n_children;
+ atk_object_class->ref_child = et_ref_child;
+}
+
+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
+et_init (GalA11yETable *a11y)
+{
+ GalA11yETablePrivate *priv;
+
+ priv = GET_PRIVATE (a11y);
+
+ priv->child_item = NULL;
+}
+
+/**
+ * gal_a11y_e_table_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yETable class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yETable class.
+ **/
+GType
+gal_a11y_e_table_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ AtkObjectFactory *factory;
+
+ GTypeInfo info = {
+ sizeof (GalA11yETableClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) et_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yETable),
+ 0,
+ (GInstanceInitFunc) et_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo atk_component_info = {
+ (GInterfaceInitFunc) et_atk_component_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ factory = atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET);
+ parent_type = atk_object_factory_get_accessible_type (factory);
+
+ type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETable", &info, 0,
+ sizeof (GalA11yETablePrivate), &priv_offset);
+ g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
+ }
+
+ return type;
+}
+
+AtkObject *
+gal_a11y_e_table_new (GObject *widget)
+{
+ GalA11yETable *a11y;
+ ETable *table;
+
+ table = E_TABLE (widget);
+
+ a11y = g_object_new (gal_a11y_e_table_get_type (), NULL);
+
+ 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);
+}
+
+void
+gal_a11y_e_table_init (void)
+{
+ if (atk_get_root ())
+ atk_registry_set_factory_type (atk_get_default_registry (),
+ E_TABLE_TYPE,
+ gal_a11y_e_table_factory_get_type ());
+
+}
+
diff --git a/widgets/table/a11y/gal-a11y-e-table.h b/widgets/table/a11y/gal-a11y-e-table.h
new file mode 100644
index 0000000000..ab133f5c71
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-table.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_TABLE_H__
+#define __GAL_A11Y_E_TABLE_H__
+
+#include <gtk/gtk.h>
+#include <atk/atkobject.h>
+#include <atk/atkcomponent.h>
+
+#define GAL_A11Y_TYPE_E_TABLE (gal_a11y_e_table_get_type ())
+#define GAL_A11Y_E_TABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TABLE, GalA11yETable))
+#define GAL_A11Y_E_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TABLE, GalA11yETableClass))
+#define GAL_A11Y_IS_E_TABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TABLE))
+#define GAL_A11Y_IS_E_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TABLE))
+
+typedef struct _GalA11yETable GalA11yETable;
+typedef struct _GalA11yETableClass GalA11yETableClass;
+typedef struct _GalA11yETablePrivate GalA11yETablePrivate;
+
+/* This struct should actually be larger as this isn't what we derive from.
+ * The GalA11yETablePrivate comes right after the parent class structure.
+ **/
+struct _GalA11yETable {
+ GtkAccessible object;
+};
+
+struct _GalA11yETableClass {
+ GtkAccessibleClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_table_get_type (void);
+AtkObject *gal_a11y_e_table_new (GObject *table);
+
+void gal_a11y_e_table_init (void);
+
+#endif /* ! __GAL_A11Y_E_TABLE_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-tree-factory.c b/widgets/table/a11y/gal-a11y-e-tree-factory.c
new file mode 100644
index 0000000000..cacb3fe082
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-tree-factory.c
@@ -0,0 +1,98 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yuedong Du <yuedong.du@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include "gal-a11y-e-tree.h"
+#include "gal-a11y-e-tree-factory.h"
+
+#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETreeFactoryClass))
+static AtkObjectFactoryClass *parent_class;
+#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY)
+
+/* Static functions */
+
+static GType
+gal_a11y_e_tree_factory_get_accessible_type (void)
+{
+ return GAL_A11Y_TYPE_E_TREE;
+}
+
+static AtkObject*
+gal_a11y_e_tree_factory_create_accessible (GObject *obj)
+{
+ AtkObject *accessible;
+
+ accessible = gal_a11y_e_tree_new (obj);
+
+ return accessible;
+}
+
+static void
+gal_a11y_e_tree_factory_class_init (GalA11yETreeFactoryClass *klass)
+{
+ AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ factory_class->create_accessible = gal_a11y_e_tree_factory_create_accessible;
+ factory_class->get_accessible_type = gal_a11y_e_tree_factory_get_accessible_type;
+}
+
+static void
+gal_a11y_e_tree_factory_init (GalA11yETreeFactory *factory)
+{
+}
+
+/**
+ * gal_a11y_e_tree_factory_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yETreeFactory class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yETreeFactory class.
+ **/
+GType
+gal_a11y_e_tree_factory_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof (GalA11yETreeFactoryClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gal_a11y_e_tree_factory_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yETreeFactory),
+ 0,
+ (GInstanceInitFunc) gal_a11y_e_tree_factory_init,
+ NULL /* value_tree */
+ };
+
+ type = g_type_register_static (PARENT_TYPE, "GalA11yETreeFactory", &info, 0);
+ }
+
+ return type;
+}
diff --git a/widgets/table/a11y/gal-a11y-e-tree-factory.h b/widgets/table/a11y/gal-a11y-e-tree-factory.h
new file mode 100644
index 0000000000..621d256c48
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-tree-factory.h
@@ -0,0 +1,50 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yuedong Du <yuedong.du@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_TREE_FACTORY_H__
+#define __GAL_A11Y_E_TREE_FACTORY_H__
+
+#include <glib-object.h>
+#include <atk/atkobjectfactory.h>
+
+#define GAL_A11Y_TYPE_E_TREE_FACTORY (gal_a11y_e_table_factory_get_type ())
+#define GAL_A11Y_E_TREE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TREE_FACTORY, GalA11yETreeFactory))
+#define GAL_A11Y_E_TREE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TREE_FACTORY, GalA11yETreeFactoryClass))
+#define GAL_A11Y_IS_E_TREE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TREE_FACTORY))
+#define GAL_A11Y_IS_E_TREE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TREE_FACTORY))
+
+typedef struct _GalA11yETreeFactory GalA11yETreeFactory;
+typedef struct _GalA11yETreeFactoryClass GalA11yETreeFactoryClass;
+
+struct _GalA11yETreeFactory {
+ AtkObject object;
+};
+
+struct _GalA11yETreeFactoryClass {
+ AtkObjectClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_tree_factory_get_type (void);
+
+#endif /* ! __GAL_A11Y_E_TREE_FACTORY_H__ */
diff --git a/widgets/table/a11y/gal-a11y-e-tree.c b/widgets/table/a11y/gal-a11y-e-tree.c
new file mode 100644
index 0000000000..6fde32b8e7
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-tree.c
@@ -0,0 +1,191 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yuedong Du <yuedong.du@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include "a11y/gal-a11y-util.h"
+#include "table/e-table-item.h"
+#include "table/e-tree.h"
+
+#include "gal-a11y-e-table-item.h"
+#include "gal-a11y-e-tree.h"
+#include "gal-a11y-e-tree-factory.h"
+
+#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETreeClass))
+static AtkObjectClass *parent_class;
+static GType parent_type;
+static gint priv_offset;
+#define GET_PRIVATE(object) ((GalA11yETreePrivate *) (((char *) object) + priv_offset))
+#define PARENT_TYPE (parent_type)
+
+struct _GalA11yETreePrivate {
+ AtkObject *child_item;
+};
+
+/* Static functions */
+
+static void
+init_child_item (GalA11yETree *a11y)
+{
+ GalA11yETreePrivate *priv = GET_PRIVATE (a11y);
+ ETree *tree = E_TREE (GTK_ACCESSIBLE (a11y)->widget);
+ ETableItem * eti;
+
+ g_return_if_fail (tree);
+ eti = e_tree_get_item (tree);
+ if (priv->child_item == NULL) {
+ priv->child_item = atk_gobject_accessible_for_object (G_OBJECT (eti));
+ }
+}
+
+static AtkObject*
+et_ref_accessible_at_point (AtkComponent *component,
+ gint x,
+ gint y,
+ AtkCoordType coord_type)
+{
+ GalA11yETree *a11y = GAL_A11Y_E_TREE (component);
+ init_child_item (a11y);
+ return GET_PRIVATE (a11y)->child_item;
+}
+
+static gint
+et_get_n_children (AtkObject *accessible)
+{
+ return 1;
+}
+
+static AtkObject*
+et_ref_child (AtkObject *accessible,
+ gint i)
+{
+ GalA11yETree *a11y = GAL_A11Y_E_TREE (accessible);
+ if (i != 0)
+ return NULL;
+ init_child_item (a11y);
+ g_object_ref (GET_PRIVATE (a11y)->child_item);
+ return GET_PRIVATE (a11y)->child_item;
+}
+
+static AtkLayer
+et_get_layer (AtkComponent *component)
+{
+ return ATK_LAYER_WIDGET;
+}
+
+static void
+et_class_init (GalA11yETreeClass *klass)
+{
+ AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ atk_object_class->get_n_children = et_get_n_children;
+ atk_object_class->ref_child = et_ref_child;
+}
+
+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
+et_init (GalA11yETree *a11y)
+{
+ GalA11yETreePrivate *priv;
+
+ priv = GET_PRIVATE (a11y);
+
+ priv->child_item = NULL;
+}
+
+/**
+ * gal_a11y_e_tree_get_type:
+ * @void:
+ *
+ * Registers the &GalA11yETree class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GalA11yETree class.
+ **/
+GType
+gal_a11y_e_tree_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ AtkObjectFactory *factory;
+
+ GTypeInfo info = {
+ sizeof (GalA11yETreeClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) et_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GalA11yETree),
+ 0,
+ (GInstanceInitFunc) et_init,
+ NULL /* value_tree */
+ };
+
+ static const GInterfaceInfo atk_component_info = {
+ (GInterfaceInitFunc) et_atk_component_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ factory = atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET);
+ parent_type = atk_object_factory_get_accessible_type (factory);
+
+ type = gal_a11y_type_register_static_with_private (PARENT_TYPE, "GalA11yETree", &info, 0,
+ sizeof (GalA11yETreePrivate), &priv_offset);
+ g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
+ }
+
+ return type;
+}
+
+AtkObject *
+gal_a11y_e_tree_new (GObject *widget)
+{
+ GalA11yETree *a11y;
+
+ a11y = g_object_new (gal_a11y_e_tree_get_type (), NULL);
+
+ GTK_ACCESSIBLE (a11y)->widget = GTK_WIDGET (widget);
+
+ return ATK_OBJECT (a11y);
+}
+
+void
+gal_a11y_e_tree_init (void)
+{
+ if (atk_get_root ())
+ atk_registry_set_factory_type (atk_get_default_registry (),
+ E_TREE_TYPE,
+ gal_a11y_e_tree_factory_get_type ());
+
+}
+
diff --git a/widgets/table/a11y/gal-a11y-e-tree.h b/widgets/table/a11y/gal-a11y-e-tree.h
new file mode 100644
index 0000000000..9fe482e1f8
--- /dev/null
+++ b/widgets/table/a11y/gal-a11y-e-tree.h
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yuedong Du <yuedong.du@sun.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_TREE_H__
+#define __GAL_A11Y_E_TREE_H__
+
+#include <gtk/gtk.h>
+#include <atk/atkobject.h>
+#include <atk/atkcomponent.h>
+
+#define GAL_A11Y_TYPE_E_TREE (gal_a11y_e_tree_get_type ())
+#define GAL_A11Y_E_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TREE, GalA11yETree))
+#define GAL_A11Y_E_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TREE, GalA11yETreeClass))
+#define GAL_A11Y_IS_E_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TREE))
+#define GAL_A11Y_IS_E_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TREE))
+
+typedef struct _GalA11yETree GalA11yETree;
+typedef struct _GalA11yETreeClass GalA11yETreeClass;
+typedef struct _GalA11yETreePrivate GalA11yETreePrivate;
+
+/* This struct should actually be larger as this isn't what we derive from.
+ * The GalA11yETablePrivate comes right after the parent class structure.
+ **/
+struct _GalA11yETree {
+ GtkAccessible object;
+};
+
+struct _GalA11yETreeClass {
+ GtkAccessibleClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_tree_get_type (void);
+AtkObject *gal_a11y_e_tree_new (GObject *tree);
+
+void gal_a11y_e_tree_init (void);
+
+#endif /* ! __GAL_A11Y_E_TREE_H__ */
diff --git a/widgets/table/e-cell-combo.c b/widgets/table/e-cell-combo.c
index 84d58200d2..4b75881104 100644
--- a/widgets/table/e-cell-combo.c
+++ b/widgets/table/e-cell-combo.c
@@ -62,7 +62,7 @@
#include <glib/gi18n.h>
#include "e-util/e-util.h"
-#include "misc/e-unicode.h"
+#include "e-util/e-unicode.h"
#include "e-table-item.h"
#include "e-cell-combo.h"
diff --git a/widgets/table/e-cell-date-edit.c b/widgets/table/e-cell-date-edit.c
new file mode 100644
index 0000000000..1cf3838c91
--- /dev/null
+++ b/widgets/table/e-cell-date-edit.c
@@ -0,0 +1,1033 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Damon Chaplin <damon@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/*
+ * ECellDateEdit - a subclass of ECellPopup used to show a date with a popup
+ * window to edit it.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cell-date-edit.h"
+
+#include <string.h>
+#include <time.h>
+#include <glib.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "e-table-item.h"
+#include "e-cell-text.h"
+
+#include <glib/gi18n.h>
+
+#include <libedataserver/e-time-utils.h>
+
+/* This depends on ECalendar which is why I didn't put it in gal. */
+#include <misc/e-calendar.h>
+
+static void e_cell_date_edit_destroy (GtkObject *object);
+static void e_cell_date_edit_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void e_cell_date_edit_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static gint e_cell_date_edit_do_popup (ECellPopup *ecp,
+ GdkEvent *event,
+ int row,
+ int view_col);
+static void e_cell_date_edit_set_popup_values (ECellDateEdit *ecde);
+static void e_cell_date_edit_select_matching_time(ECellDateEdit *ecde,
+ char *time);
+static void e_cell_date_edit_show_popup (ECellDateEdit *ecde,
+ int row,
+ int view_col);
+static void e_cell_date_edit_get_popup_pos (ECellDateEdit *ecde,
+ int row,
+ int view_col,
+ gint *x,
+ gint *y,
+ gint *height,
+ gint *width);
+
+static void e_cell_date_edit_rebuild_time_list (ECellDateEdit *ecde);
+
+static int e_cell_date_edit_key_press (GtkWidget *popup_window,
+ GdkEventKey *event,
+ ECellDateEdit *ecde);
+static int e_cell_date_edit_button_press (GtkWidget *popup_window,
+ GdkEventButton *event,
+ ECellDateEdit *ecde);
+static void e_cell_date_edit_on_ok_clicked (GtkWidget *button,
+ ECellDateEdit *ecde);
+static void e_cell_date_edit_show_time_invalid_warning (ECellDateEdit *ecde);
+static void e_cell_date_edit_on_now_clicked (GtkWidget *button,
+ ECellDateEdit *ecde);
+static void e_cell_date_edit_on_none_clicked (GtkWidget *button,
+ ECellDateEdit *ecde);
+static void e_cell_date_edit_on_today_clicked (GtkWidget *button,
+ ECellDateEdit *ecde);
+static void e_cell_date_edit_update_cell (ECellDateEdit *ecde,
+ char *text);
+static void e_cell_date_edit_on_time_selected (GtkTreeSelection *selection, ECellDateEdit *ecde);
+static void e_cell_date_edit_hide_popup (ECellDateEdit *ecde);
+
+
+/* Our arguments. */
+enum {
+ PROP_0,
+ PROP_SHOW_TIME,
+ PROP_SHOW_NOW_BUTTON,
+ PROP_SHOW_TODAY_BUTTON,
+ PROP_ALLOW_NO_DATE_SET,
+ PROP_USE_24_HOUR_FORMAT,
+ PROP_LOWER_HOUR,
+ PROP_UPPER_HOUR
+};
+
+G_DEFINE_TYPE (ECellDateEdit, e_cell_date_edit, E_CELL_POPUP_TYPE)
+
+
+static void
+e_cell_date_edit_class_init (ECellDateEditClass *class)
+{
+ GObjectClass *object_class;
+ GtkObjectClass *gtk_object_class;
+ ECellPopupClass *ecpc;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = e_cell_date_edit_get_property;
+ object_class->set_property = e_cell_date_edit_set_property;
+
+ gtk_object_class = GTK_OBJECT_CLASS (class);
+ gtk_object_class->destroy = e_cell_date_edit_destroy;
+
+ ecpc = E_CELL_POPUP_CLASS (class);
+ ecpc->popup = e_cell_date_edit_do_popup;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_TIME,
+ g_param_spec_boolean (
+ "show_time",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_NOW_BUTTON,
+ g_param_spec_boolean (
+ "show_now_button",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_TODAY_BUTTON,
+ g_param_spec_boolean (
+ "show_today_button",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ALLOW_NO_DATE_SET,
+ g_param_spec_boolean (
+ "allow_no_date_set",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_USE_24_HOUR_FORMAT,
+ g_param_spec_boolean (
+ "use_24_hour_format",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_LOWER_HOUR,
+ g_param_spec_int (
+ "lower_hour",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_UPPER_HOUR,
+ g_param_spec_int (
+ "upper_hour",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 24,
+ G_PARAM_READWRITE));
+}
+
+
+static void
+e_cell_date_edit_init (ECellDateEdit *ecde)
+{
+ GtkWidget *frame, *vbox, *hbox, *vbox2;
+ GtkWidget *scrolled_window, *bbox, *tree_view;
+ GtkWidget *now_button, *today_button, *none_button, *ok_button;
+ GtkListStore *store;
+
+ ecde->lower_hour = 0;
+ ecde->upper_hour = 24;
+ ecde->use_24_hour_format = TRUE;
+ ecde->need_time_list_rebuild = TRUE;
+ ecde->freeze_count = 0;
+ ecde->time_callback = NULL;
+ ecde->time_callback_data = NULL;
+ ecde->time_callback_destroy = NULL;
+
+ /* We create one popup window for the ECell, since there will only
+ ever be one popup in use at a time. */
+ ecde->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
+
+ gtk_window_set_type_hint (GTK_WINDOW (ecde->popup_window),
+ GDK_WINDOW_TYPE_HINT_COMBO);
+ gtk_window_set_resizable (GTK_WINDOW (ecde->popup_window), TRUE);
+
+ frame = gtk_frame_new (NULL);
+ gtk_container_add (GTK_CONTAINER (ecde->popup_window), frame);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
+ gtk_widget_show (frame);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (frame), vbox);
+ gtk_widget_show (vbox);
+
+ hbox = gtk_hbox_new (FALSE, 4);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ ecde->calendar = e_calendar_new ();
+ gnome_canvas_item_set (GNOME_CANVAS_ITEM (E_CALENDAR (ecde->calendar)->calitem),
+ "move_selection_when_moving", FALSE,
+ NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), ecde->calendar, TRUE, TRUE, 0);
+ gtk_widget_show (ecde->calendar);
+
+ vbox2 = gtk_vbox_new (FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0);
+ gtk_widget_show (vbox2);
+
+ ecde->time_entry = gtk_entry_new ();
+ gtk_widget_set_size_request (ecde->time_entry, 50, -1);
+ gtk_box_pack_start (GTK_BOX (vbox2), ecde->time_entry,
+ FALSE, FALSE, 0);
+ gtk_widget_show (ecde->time_entry);
+
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_box_pack_start (GTK_BOX (vbox2), scrolled_window, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_ALWAYS);
+ gtk_widget_show (scrolled_window);
+
+ store = gtk_list_store_new (1, G_TYPE_STRING);
+ tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+ gtk_tree_view_append_column (
+ GTK_TREE_VIEW (tree_view),
+ gtk_tree_view_column_new_with_attributes ("Text", gtk_cell_renderer_text_new (), "text", 0, NULL));
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
+
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), tree_view);
+ gtk_container_set_focus_vadjustment (GTK_CONTAINER (tree_view),
+ gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_window)));
+ gtk_container_set_focus_hadjustment (GTK_CONTAINER (tree_view),
+ gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (scrolled_window)));
+ gtk_widget_show (tree_view);
+ ecde->time_tree_view = tree_view;
+ g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), "changed",
+ G_CALLBACK (e_cell_date_edit_on_time_selected),
+ ecde);
+
+ bbox = gtk_hbutton_box_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (bbox), 4);
+ gtk_box_set_spacing (GTK_BOX (bbox), 2);
+ gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
+ gtk_widget_show (bbox);
+
+ now_button = gtk_button_new_with_label (_("Now"));
+ gtk_container_add (GTK_CONTAINER (bbox), now_button);
+ gtk_widget_show (now_button);
+ g_signal_connect((now_button), "clicked",
+ G_CALLBACK (e_cell_date_edit_on_now_clicked),
+ ecde);
+ ecde->now_button = now_button;
+
+ today_button = gtk_button_new_with_label (_("Today"));
+ gtk_container_add (GTK_CONTAINER (bbox), today_button);
+ gtk_widget_show (today_button);
+ g_signal_connect((today_button), "clicked",
+ G_CALLBACK (e_cell_date_edit_on_today_clicked),
+ ecde);
+ ecde->today_button = today_button;
+
+ none_button = gtk_button_new_with_label (_("None"));
+ gtk_container_add (GTK_CONTAINER (bbox), none_button);
+ gtk_widget_show (none_button);
+ g_signal_connect((none_button), "clicked",
+ G_CALLBACK (e_cell_date_edit_on_none_clicked),
+ ecde);
+ ecde->none_button = none_button;
+
+ ok_button = gtk_button_new_with_label (_("OK"));
+ gtk_container_add (GTK_CONTAINER (bbox), ok_button);
+ gtk_widget_show (ok_button);
+ g_signal_connect((ok_button), "clicked",
+ G_CALLBACK (e_cell_date_edit_on_ok_clicked),
+ ecde);
+
+
+ g_signal_connect((ecde->popup_window),
+ "key_press_event",
+ G_CALLBACK (e_cell_date_edit_key_press),
+ ecde);
+ g_signal_connect((ecde->popup_window),
+ "button_press_event",
+ G_CALLBACK (e_cell_date_edit_button_press),
+ ecde);
+}
+
+
+/**
+ * e_cell_date_edit_new:
+ *
+ * Creates a new ECellDateEdit renderer.
+ *
+ * Returns: an ECellDateEdit object.
+ */
+ECell *
+e_cell_date_edit_new (void)
+{
+ return g_object_new (e_cell_date_edit_get_type (), NULL);
+}
+
+
+/*
+ * GtkObject::destroy method
+ */
+static void
+e_cell_date_edit_destroy (GtkObject *object)
+{
+ ECellDateEdit *ecde = E_CELL_DATE_EDIT (object);
+
+ e_cell_date_edit_set_get_time_callback (ecde, NULL, NULL, NULL);
+
+ gtk_widget_destroy (ecde->popup_window);
+ ecde->popup_window = NULL;
+
+ GTK_OBJECT_CLASS (e_cell_date_edit_parent_class)->destroy (object);
+}
+
+
+static void
+e_cell_date_edit_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ECellDateEdit *ecde;
+
+ ecde = E_CELL_DATE_EDIT (object);
+
+ switch (property_id) {
+ case PROP_SHOW_TIME:
+ g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->time_entry));
+ return;
+ case PROP_SHOW_NOW_BUTTON:
+ g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->now_button));
+ return;
+ case PROP_SHOW_TODAY_BUTTON:
+ g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->today_button));
+ return;
+ case PROP_ALLOW_NO_DATE_SET:
+ g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->none_button));
+ return;
+ case PROP_USE_24_HOUR_FORMAT:
+ g_value_set_boolean (value, ecde->use_24_hour_format);
+ return;
+ case PROP_LOWER_HOUR:
+ g_value_set_int (value, ecde->lower_hour);
+ return;
+ case PROP_UPPER_HOUR:
+ g_value_set_int (value, ecde->upper_hour);
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+
+static void
+e_cell_date_edit_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ECellDateEdit *ecde;
+ gint ivalue;
+ gboolean bvalue;
+
+ ecde = E_CELL_DATE_EDIT (object);
+
+ switch (property_id) {
+ case PROP_SHOW_TIME:
+ if (g_value_get_boolean (value)) {
+ gtk_widget_show (ecde->time_entry);
+ gtk_widget_show (ecde->time_tree_view);
+ } else {
+ gtk_widget_hide (ecde->time_entry);
+ gtk_widget_hide (ecde->time_tree_view);
+ }
+ return;
+ case PROP_SHOW_NOW_BUTTON:
+ if (g_value_get_boolean (value)) {
+ gtk_widget_show (ecde->now_button);
+ } else {
+ gtk_widget_hide (ecde->now_button);
+ }
+ return;
+ case PROP_SHOW_TODAY_BUTTON:
+ if (g_value_get_boolean (value)) {
+ gtk_widget_show (ecde->today_button);
+ } else {
+ gtk_widget_hide (ecde->today_button);
+ }
+ return;
+ case PROP_ALLOW_NO_DATE_SET:
+ if (g_value_get_boolean (value)) {
+ gtk_widget_show (ecde->none_button);
+ } else {
+ /* FIXME: What if we have no date set now. */
+ gtk_widget_hide (ecde->none_button);
+ }
+ return;
+ case PROP_USE_24_HOUR_FORMAT:
+ bvalue = g_value_get_boolean (value);
+ if (ecde->use_24_hour_format != bvalue) {
+ ecde->use_24_hour_format = bvalue;
+ ecde->need_time_list_rebuild = TRUE;
+ }
+ return;
+ case PROP_LOWER_HOUR:
+ ivalue = g_value_get_int (value);
+ ivalue = CLAMP (ivalue, 0, 24);
+ if (ecde->lower_hour != ivalue) {
+ ecde->lower_hour = ivalue;
+ ecde->need_time_list_rebuild = TRUE;
+ }
+ return;
+ case PROP_UPPER_HOUR:
+ ivalue = g_value_get_int (value);
+ ivalue = CLAMP (ivalue, 0, 24);
+ if (ecde->upper_hour != ivalue) {
+ ecde->upper_hour = ivalue;
+ ecde->need_time_list_rebuild = TRUE;
+ }
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+
+static gint
+e_cell_date_edit_do_popup (ECellPopup *ecp,
+ GdkEvent *event,
+ int row,
+ int view_col)
+{
+ ECellDateEdit *ecde = E_CELL_DATE_EDIT (ecp);
+
+ e_cell_date_edit_show_popup (ecde, row, view_col);
+ e_cell_date_edit_set_popup_values (ecde);
+
+ gtk_grab_add (ecde->popup_window);
+
+ /* Set the focus to the first widget. */
+ gtk_widget_grab_focus (ecde->time_entry);
+ gdk_window_focus (ecde->popup_window->window, GDK_CURRENT_TIME);
+
+ return TRUE;
+}
+
+
+static void
+e_cell_date_edit_set_popup_values (ECellDateEdit *ecde)
+{
+ ECellPopup *ecp = E_CELL_POPUP (ecde);
+ ECellText *ecell_text = E_CELL_TEXT (ecp->child);
+ ECellView *ecv = (ECellView*) ecp->popup_cell_view;
+ ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
+ ETableCol *ecol;
+ char *cell_text;
+ ETimeParseStatus status;
+ struct tm date_tm;
+ GDate date;
+ ECalendarItem *calitem;
+ char buffer[64];
+ gboolean is_date = TRUE;
+
+ ecol = e_table_header_get_column (eti->header, ecp->popup_view_col);
+ cell_text = e_cell_text_get_text (ecell_text, ecv->e_table_model,
+ ecol->col_idx, ecp->popup_row);
+
+ /* Try to parse just a date first. If the value is only a date, we
+ use a DATE value. */
+ status = e_time_parse_date (cell_text, &date_tm);
+ if (status == E_TIME_PARSE_INVALID) {
+ is_date = FALSE;
+ status = e_time_parse_date_and_time (cell_text, &date_tm);
+ }
+
+ /* If there is no date and time set, or the date is invalid, we clear
+ the selections, else we select the appropriate date & time. */
+ calitem = E_CALENDAR_ITEM (E_CALENDAR (ecde->calendar)->calitem);
+ if (status == E_TIME_PARSE_NONE || status == E_TIME_PARSE_INVALID) {
+ gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), "");
+ e_calendar_item_set_selection (calitem, NULL, NULL);
+ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (ecde->time_tree_view)));
+ } else {
+ if (is_date) {
+ buffer[0] = '\0';
+ } else {
+ e_time_format_time (&date_tm, ecde->use_24_hour_format,
+ FALSE, buffer, sizeof (buffer));
+ }
+ gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), buffer);
+
+ g_date_clear (&date, 1);
+ g_date_set_dmy (&date, date_tm.tm_mday, date_tm.tm_mon + 1,
+ date_tm.tm_year + 1900);
+ e_calendar_item_set_selection (calitem, &date, &date);
+
+ if (is_date) {
+ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (ecde->time_tree_view)));
+ } else {
+ e_cell_date_edit_select_matching_time (ecde, buffer);
+ }
+ }
+
+ e_cell_text_free_text (ecell_text, cell_text);
+}
+
+
+static void
+e_cell_date_edit_select_matching_time (ECellDateEdit *ecde,
+ char *time)
+{
+ gboolean found = FALSE;
+ gboolean valid;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (ecde->time_tree_view));
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ecde->time_tree_view));
+
+ for (valid = gtk_tree_model_get_iter_first (model, &iter);
+ valid && !found;
+ valid = gtk_tree_model_iter_next (model, &iter)) {
+ char *str = NULL;
+
+ gtk_tree_model_get (model, &iter, 0, &str, -1);
+
+ if (g_str_equal (str, time)) {
+ GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
+
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (ecde->time_tree_view), path, NULL, FALSE);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (ecde->time_tree_view), path, NULL, FALSE, 0.0, 0.0);
+ gtk_tree_path_free (path);
+
+ found = TRUE;
+ }
+
+ g_free (str);
+ }
+
+ if (!found) {
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (ecde->time_tree_view), 0, 0);
+ }
+}
+
+
+static void
+e_cell_date_edit_show_popup (ECellDateEdit *ecde,
+ int row,
+ int view_col)
+{
+ gint x, y, width, height;
+
+ if (ecde->need_time_list_rebuild)
+ e_cell_date_edit_rebuild_time_list (ecde);
+
+ /* This code is practically copied from GtkCombo. */
+
+ e_cell_date_edit_get_popup_pos (ecde, row, view_col, &x, &y, &height, &width);
+
+ gtk_window_move (GTK_WINDOW (ecde->popup_window), x, y);
+ gtk_widget_set_size_request (ecde->popup_window, width, height);
+ gtk_widget_realize (ecde->popup_window);
+ gdk_window_resize (ecde->popup_window->window, width, height);
+ gtk_widget_show (ecde->popup_window);
+
+ e_cell_popup_set_shown (E_CELL_POPUP (ecde), TRUE);
+}
+
+
+/* Calculates the size and position of the popup window (like GtkCombo). */
+static void
+e_cell_date_edit_get_popup_pos (ECellDateEdit *ecde,
+ int row,
+ int view_col,
+ gint *x,
+ gint *y,
+ gint *height,
+ gint *width)
+{
+ ECellPopup *ecp = E_CELL_POPUP (ecde);
+ ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
+ GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (eti)->canvas);
+ GtkRequisition popup_requisition;
+ gint avail_height, screen_width, column_width, row_height;
+ double x1, y1, wx, wy;
+
+ gdk_window_get_origin (canvas->window, x, y);
+
+ x1 = e_table_header_col_diff (eti->header, 0, view_col + 1);
+ y1 = e_table_item_row_diff (eti, 0, row + 1);
+ column_width = e_table_header_col_diff (eti->header, view_col,
+ view_col + 1);
+ row_height = e_table_item_row_diff (eti, row,
+ row + 1);
+ gnome_canvas_item_i2w (GNOME_CANVAS_ITEM (eti), &x1, &y1);
+
+ gnome_canvas_world_to_window (GNOME_CANVAS (canvas),
+ x1,
+ y1,
+ &wx,
+ &wy);
+
+ x1 = wx;
+ y1 = wy;
+
+ *x += x1;
+ /* The ETable positions don't include the grid lines, I think, so we
+ add 1. */
+ *y += y1 + 1
+ - (int)((GnomeCanvas *)canvas)->layout.vadjustment->value
+ + ((GnomeCanvas *)canvas)->zoom_yofs;
+
+ avail_height = gdk_screen_height () - *y;
+
+ /* We'll use the entire screen width if needed, but we save space for
+ the vertical scrollbar in case we need to show that. */
+ screen_width = gdk_screen_width ();
+
+ gtk_widget_size_request (ecde->popup_window, &popup_requisition);
+
+ /* Calculate the desired width. */
+ *width = popup_requisition.width;
+
+ /* Use at least the same width as the column. */
+ if (*width < column_width)
+ *width = column_width;
+
+ /* Check if it fits in the available height. */
+ if (popup_requisition.height > avail_height) {
+ /* It doesn't fit, so we see if we have the minimum space
+ needed. */
+ if (*y - row_height > avail_height) {
+ /* We don't, so we show the popup above the cell
+ instead of below it. */
+ avail_height = *y - row_height;
+ *y -= (popup_requisition.height + row_height);
+ if (*y < 0)
+ *y = 0;
+ }
+ }
+
+ /* We try to line it up with the right edge of the column, but we don't
+ want it to go off the edges of the screen. */
+ if (*x > screen_width)
+ *x = screen_width;
+ *x -= *width;
+ if (*x < 0)
+ *x = 0;
+
+ *height = popup_requisition.height;
+}
+
+
+/* This handles key press events in the popup window. If the Escape key is
+ pressed we hide the popup, and do not change the cell contents. */
+static int
+e_cell_date_edit_key_press (GtkWidget *popup_window,
+ GdkEventKey *event,
+ ECellDateEdit *ecde)
+{
+ /* If the Escape key is pressed we hide the popup. */
+ if (event->keyval != GDK_Escape)
+ return FALSE;
+
+ e_cell_date_edit_hide_popup (ecde);
+
+ return TRUE;
+}
+
+
+/* This handles button press events in the popup window. If the button is
+ pressed outside the popup, we hide it and do not change the cell contents.
+*/
+static int
+e_cell_date_edit_button_press (GtkWidget *popup_window,
+ GdkEventButton *event,
+ ECellDateEdit *ecde)
+{
+ GtkWidget *event_widget;
+
+ event_widget = gtk_get_event_widget ((GdkEvent*) event);
+ if (gtk_widget_get_toplevel (event_widget) != popup_window) {
+ e_cell_date_edit_hide_popup (ecde);
+ }
+
+ return TRUE;
+}
+
+
+/* Clears the time list and rebuilds it using the lower_hour, upper_hour
+ and use_24_hour_format settings. */
+static void
+e_cell_date_edit_rebuild_time_list (ECellDateEdit *ecde)
+{
+ GtkListStore *store;
+ char buffer[40];
+ struct tm tmp_tm;
+ gint hour, min;
+
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (ecde->time_tree_view)));
+ gtk_list_store_clear (store);
+
+ /* Fill the struct tm with some sane values. */
+ tmp_tm.tm_year = 2000;
+ tmp_tm.tm_mon = 0;
+ tmp_tm.tm_mday = 1;
+ tmp_tm.tm_sec = 0;
+ tmp_tm.tm_isdst = 0;
+
+ for (hour = ecde->lower_hour; hour <= ecde->upper_hour; hour++) {
+ /* We don't want to display midnight at the end, since that is
+ really in the next day. */
+ if (hour == 24)
+ break;
+
+ /* We want to finish on upper_hour, with min == 0. */
+ for (min = 0;
+ min == 0 || (min < 60 && hour != ecde->upper_hour);
+ min += 30) {
+ GtkTreeIter iter;
+
+ tmp_tm.tm_hour = hour;
+ tmp_tm.tm_min = min;
+ e_time_format_time (&tmp_tm, ecde->use_24_hour_format,
+ FALSE, buffer, sizeof (buffer));
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, buffer, -1);
+ }
+ }
+
+ ecde->need_time_list_rebuild = FALSE;
+}
+
+
+static void
+e_cell_date_edit_on_ok_clicked (GtkWidget *button,
+ ECellDateEdit *ecde)
+{
+ ECalendarItem *calitem;
+ GDate start_date, end_date;
+ gboolean day_selected;
+ struct tm date_tm;
+ char buffer[64];
+ const char *text;
+ ETimeParseStatus status;
+ gboolean is_date = FALSE;
+
+ calitem = E_CALENDAR_ITEM (E_CALENDAR (ecde->calendar)->calitem);
+ day_selected = e_calendar_item_get_selection (calitem, &start_date,
+ &end_date);
+
+ text = gtk_entry_get_text (GTK_ENTRY (ecde->time_entry));
+ status = e_time_parse_time (text, &date_tm);
+ if (status == E_TIME_PARSE_INVALID) {
+ e_cell_date_edit_show_time_invalid_warning (ecde);
+ return;
+ } else if (status == E_TIME_PARSE_NONE) {
+ is_date = TRUE;
+ }
+
+ if (day_selected) {
+ date_tm.tm_year = g_date_get_year (&start_date) - 1900;
+ date_tm.tm_mon = g_date_get_month (&start_date) - 1;
+ date_tm.tm_mday = g_date_get_day (&start_date);
+ /* We need to call this to set the weekday. */
+ mktime (&date_tm);
+ e_time_format_date_and_time (&date_tm,
+ ecde->use_24_hour_format,
+ !is_date, FALSE,
+ buffer, sizeof (buffer));
+ } else {
+ buffer[0] = '\0';
+ }
+
+ e_cell_date_edit_update_cell (ecde, buffer);
+ e_cell_date_edit_hide_popup (ecde);
+}
+
+
+static void
+e_cell_date_edit_show_time_invalid_warning (ECellDateEdit *ecde)
+{
+ GtkWidget *dialog;
+ struct tm date_tm;
+ char buffer[64];
+
+ /* Create a useful error message showing the correct format. */
+ date_tm.tm_year = 100;
+ date_tm.tm_mon = 0;
+ date_tm.tm_mday = 1;
+ date_tm.tm_hour = 1;
+ date_tm.tm_min = 30;
+ date_tm.tm_sec = 0;
+ date_tm.tm_isdst = -1;
+ e_time_format_time (&date_tm, ecde->use_24_hour_format, FALSE,
+ buffer, sizeof (buffer));
+
+ /* FIXME: Fix transient settings - I'm not sure it works with popup
+ windows. Maybe we need to use a normal window without decorations.*/
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (ecde->popup_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ _("The time must be in the format: %s"),
+ buffer);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+
+static void
+e_cell_date_edit_on_now_clicked (GtkWidget *button,
+ ECellDateEdit *ecde)
+{
+ struct tm tmp_tm;
+ time_t t;
+ char buffer[64];
+
+ if (ecde->time_callback) {
+ tmp_tm = (*ecde->time_callback) (ecde, ecde->time_callback_data);
+ } else {
+ t = time (NULL);
+ tmp_tm = *localtime (&t);
+ }
+ e_time_format_date_and_time (&tmp_tm,
+ ecde->use_24_hour_format,
+ TRUE, FALSE,
+ buffer, sizeof (buffer));
+
+ e_cell_date_edit_update_cell (ecde, buffer);
+ e_cell_date_edit_hide_popup (ecde);
+}
+
+
+static void
+e_cell_date_edit_on_none_clicked (GtkWidget *button,
+ ECellDateEdit *ecde)
+{
+ e_cell_date_edit_update_cell (ecde, "");
+ e_cell_date_edit_hide_popup (ecde);
+}
+
+
+static void
+e_cell_date_edit_on_today_clicked (GtkWidget *button,
+ ECellDateEdit *ecde)
+{
+ struct tm tmp_tm;
+ time_t t;
+ char buffer[64];
+
+ if (ecde->time_callback) {
+ tmp_tm = (*ecde->time_callback) (ecde, ecde->time_callback_data);
+ } else {
+ t = time (NULL);
+ tmp_tm = *localtime (&t);
+ }
+
+ tmp_tm.tm_hour = 0;
+ tmp_tm.tm_min = 0;
+ tmp_tm.tm_sec = 0;
+ e_time_format_date_and_time (&tmp_tm,
+ ecde->use_24_hour_format,
+ FALSE, FALSE,
+ buffer, sizeof (buffer));
+
+ e_cell_date_edit_update_cell (ecde, buffer);
+ e_cell_date_edit_hide_popup (ecde);
+}
+
+
+static void
+e_cell_date_edit_update_cell (ECellDateEdit *ecde,
+ char *text)
+{
+ ECellPopup *ecp = E_CELL_POPUP (ecde);
+ ECellText *ecell_text = E_CELL_TEXT (ecp->child);
+ ECellView *ecv = (ECellView*) ecp->popup_cell_view;
+ ETableItem *eti = E_TABLE_ITEM (ecv->e_table_item_view);
+ ETableCol *ecol;
+ gchar *old_text;
+
+ /* Compare the new text with the existing cell contents. */
+ ecol = e_table_header_get_column (eti->header, ecp->popup_view_col);
+
+ old_text = e_cell_text_get_text (ecell_text, ecv->e_table_model,
+ ecol->col_idx, ecp->popup_row);
+
+ /* If they are different, update the cell contents. */
+ if (strcmp (old_text, text)) {
+ e_cell_text_set_value (ecell_text, ecv->e_table_model,
+ ecol->col_idx, ecp->popup_row, text);
+ e_cell_leave_edit (ecv, ecp->popup_view_col, ecol->col_idx, ecp->popup_row, NULL);
+ }
+
+ e_cell_text_free_text (ecell_text, old_text);
+}
+
+
+static void
+e_cell_date_edit_on_time_selected (GtkTreeSelection *selection, ECellDateEdit *ecde)
+{
+ gchar *list_item_text = NULL;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, 0, &list_item_text, -1);
+
+ g_return_if_fail (list_item_text != NULL);
+
+ gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), list_item_text);
+
+ g_free (list_item_text);
+}
+
+
+static void
+e_cell_date_edit_hide_popup (ECellDateEdit *ecde)
+{
+ gtk_grab_remove (ecde->popup_window);
+ gtk_widget_hide (ecde->popup_window);
+ e_cell_popup_set_shown (E_CELL_POPUP (ecde), FALSE);
+}
+
+
+/* These freeze and thaw the rebuilding of the time list. They are useful when
+ setting several properties which result in rebuilds of the list, e.g. the
+ lower_hour, upper_hour and use_24_hour_format properties. */
+void
+e_cell_date_edit_freeze (ECellDateEdit *ecde)
+{
+ g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
+
+ ecde->freeze_count++;
+}
+
+
+void
+e_cell_date_edit_thaw (ECellDateEdit *ecde)
+{
+ g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
+
+ if (ecde->freeze_count > 0) {
+ ecde->freeze_count--;
+
+ if (ecde->freeze_count == 0)
+ e_cell_date_edit_rebuild_time_list (ecde);
+ }
+}
+
+
+/* Sets a callback to use to get the current time. This is useful if the
+ application needs to use its own timezone data rather than rely on the
+ Unix timezone. */
+void
+e_cell_date_edit_set_get_time_callback (ECellDateEdit *ecde,
+ ECellDateEditGetTimeCallback cb,
+ gpointer data,
+ GDestroyNotify destroy)
+{
+ g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
+
+ if (ecde->time_callback_data && ecde->time_callback_destroy)
+ (*ecde->time_callback_destroy) (ecde->time_callback_data);
+
+ ecde->time_callback = cb;
+ ecde->time_callback_data = data;
+ ecde->time_callback_destroy = destroy;
+}
diff --git a/widgets/table/e-cell-date-edit.h b/widgets/table/e-cell-date-edit.h
new file mode 100644
index 0000000000..30dee535e8
--- /dev/null
+++ b/widgets/table/e-cell-date-edit.h
@@ -0,0 +1,106 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Damon Chaplin <damon@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/*
+ * ECellDateEdit - a subclass of ECellPopup used to show a date with a popup
+ * window to edit it.
+ */
+
+#ifndef _E_CELL_DATE_EDIT_H_
+#define _E_CELL_DATE_EDIT_H_
+
+#include <time.h>
+#include <table/e-cell-popup.h>
+
+#define E_CELL_DATE_EDIT_TYPE (e_cell_date_edit_get_type ())
+#define E_CELL_DATE_EDIT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_DATE_EDIT_TYPE, ECellDateEdit))
+#define E_CELL_DATE_EDIT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), E_CELL_DATE_EDIT_TYPE, ECellDateEditClass))
+#define E_IS_CELL_DATE_EDIT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_DATE_EDIT_TYPE))
+#define E_IS_CELL_DATE_EDIT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_DATE_EDIT_TYPE))
+
+
+typedef struct _ECellDateEdit ECellDateEdit;
+typedef struct _ECellDateEditClass ECellDateEditClass;
+
+/* The type of the callback function optionally used to get the current time.
+ */
+typedef struct tm (*ECellDateEditGetTimeCallback) (ECellDateEdit *ecde,
+ gpointer data);
+
+struct _ECellDateEdit {
+ ECellPopup parent;
+
+ GtkWidget *popup_window;
+ GtkWidget *calendar;
+ GtkWidget *time_entry;
+ GtkWidget *time_tree_view;
+
+ GtkWidget *now_button;
+ GtkWidget *today_button;
+ GtkWidget *none_button;
+
+ /* This is the range of hours we show in the time list. */
+ gint lower_hour;
+ gint upper_hour;
+
+ /* TRUE if we use 24-hour format for the time list and entry. */
+ gboolean use_24_hour_format;
+
+ /* This is TRUE if we need to rebuild the list of times. */
+ gboolean need_time_list_rebuild;
+
+ /* The freeze count for rebuilding the time list. We only rebuild when
+ this is 0. */
+ gint freeze_count;
+
+ ECellDateEditGetTimeCallback time_callback;
+ gpointer time_callback_data;
+ GDestroyNotify time_callback_destroy;
+};
+
+struct _ECellDateEditClass {
+ ECellPopupClass parent_class;
+};
+
+
+GType e_cell_date_edit_get_type (void);
+ECell *e_cell_date_edit_new (void);
+
+
+/* These freeze and thaw the rebuilding of the time list. They are useful when
+ setting several properties which result in rebuilds of the list, e.g. the
+ lower_hour, upper_hour and use_24_hour_format properties. */
+void e_cell_date_edit_freeze (ECellDateEdit *ecde);
+void e_cell_date_edit_thaw (ECellDateEdit *ecde);
+
+
+/* Sets a callback to use to get the current time. This is useful if the
+ application needs to use its own timezone data rather than rely on the
+ Unix timezone. */
+void e_cell_date_edit_set_get_time_callback(ECellDateEdit *ecde,
+ ECellDateEditGetTimeCallback cb,
+ gpointer data,
+ GDestroyNotify destroy);
+
+
+#endif /* _E_CELL_DATE_EDIT_H_ */
diff --git a/widgets/table/e-cell-date.c b/widgets/table/e-cell-date.c
index ac0274f183..9199d5715b 100644
--- a/widgets/table/e-cell-date.c
+++ b/widgets/table/e-cell-date.c
@@ -29,7 +29,7 @@
#include <glib/gi18n.h>
#include "e-util/e-util.h"
-#include "misc/e-unicode.h"
+#include "e-util/e-unicode.h"
#include "e-cell-date.h"
diff --git a/widgets/table/e-cell-hbox.c b/widgets/table/e-cell-hbox.c
index b9a8544f57..6c0bded852 100644
--- a/widgets/table/e-cell-hbox.c
+++ b/widgets/table/e-cell-hbox.c
@@ -32,8 +32,8 @@
#include <gtk/gtk.h>
-/* #include "a11y/e-table/gal-a11y-e-cell-registry.h" */
-/* #include "a11y/e-table/gal-a11y-e-cell-vbox.h" */
+/* #include "a11y/gal-a11y-e-cell-registry.h" */
+/* #include "a11y/gal-a11y-e-cell-vbox.h" */
#include "e-util/e-util.h"
#include "e-cell-hbox.h"
diff --git a/widgets/table/e-cell-percent.c b/widgets/table/e-cell-percent.c
new file mode 100644
index 0000000000..94e33489e5
--- /dev/null
+++ b/widgets/table/e-cell-percent.c
@@ -0,0 +1,152 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Damon Chaplin <damon@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/*
+ * ECellPercent - a subclass of ECellText used to show an integer percentage
+ * in an ETable.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <glib/gi18n.h>
+
+#include "e-cell-percent.h"
+
+G_DEFINE_TYPE (ECellPercent, e_cell_percent, E_CELL_TEXT_TYPE)
+
+
+static char *
+ecp_get_text (ECellText *cell, ETableModel *model, int col, int row)
+{
+ int percent;
+ static char buffer[8];
+
+ percent = GPOINTER_TO_INT (e_table_model_value_at (model, col, row));
+
+ /* A -ve value means the property is not set. */
+ if (percent < 0) {
+ buffer[0] = '\0';
+ } else {
+ g_snprintf (buffer, sizeof (buffer), "%i%%", percent);
+ }
+
+ return buffer;
+}
+
+static void
+ecp_free_text(ECellText *cell, char *text)
+{
+ /* Do Nothing. */
+}
+
+/* FIXME: We need to set the "transient_for" property for the dialog. */
+static void
+show_percent_warning (void)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (
+ NULL, 0,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "%s", _("The percent value must be between 0 and 100, inclusive"));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static void
+ecp_set_value (ECellText *cell, ETableModel *model, int col, int row,
+ const char *text)
+{
+ int matched, percent;
+ gboolean empty = TRUE;
+ const char *p;
+
+ if (text) {
+ p = text;
+ while (*p) {
+ if (!isspace ((unsigned char) *p)) {
+ empty = FALSE;
+ break;
+ }
+ p++;
+ }
+ }
+
+ if (empty) {
+ percent = -1;
+ } else {
+ matched = sscanf (text, "%i", &percent);
+
+ if (matched != 1 || percent < 0 || percent > 100) {
+ show_percent_warning ();
+ return;
+ }
+ }
+
+ e_table_model_set_value_at (model, col, row,
+ GINT_TO_POINTER (percent));
+}
+
+static void
+e_cell_percent_class_init (ECellPercentClass *ecpc)
+{
+ ECellTextClass *ectc = (ECellTextClass *) ecpc;
+
+ ectc->get_text = ecp_get_text;
+ ectc->free_text = ecp_free_text;
+ ectc->set_value = ecp_set_value;
+}
+
+static void
+e_cell_percent_init (ECellPercent *ecp)
+{
+}
+
+/**
+ * e_cell_percent_new:
+ * @fontname: font to be used to render on the screen
+ * @justify: Justification of the string in the cell.
+ *
+ * Creates a new ECell renderer that can be used to render an integer
+ * percentage that comes from the model. The value returned from the model is
+ * interpreted as being an int.
+ *
+ * See ECellText for other features.
+ *
+ * Returns: an ECell object that can be used to render numbers.
+ */
+ECell *
+e_cell_percent_new (const char *fontname, GtkJustification justify)
+{
+ ECellPercent *ecn = g_object_new (E_CELL_PERCENT_TYPE, NULL);
+
+ e_cell_text_construct (E_CELL_TEXT(ecn), fontname, justify);
+
+ return (ECell *) ecn;
+}
diff --git a/widgets/table/e-cell-percent.h b/widgets/table/e-cell-percent.h
new file mode 100644
index 0000000000..46a7ddc3e3
--- /dev/null
+++ b/widgets/table/e-cell-percent.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Damon Chaplin <damon@ximian.com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/*
+ * ECellPercent - a subclass of ECellText used to show an integer percentage
+ * in an ETable.
+ */
+
+#ifndef _E_CELL_PERCENT_H_
+#define _E_CELL_PERCENT_H_
+
+#include <table/e-cell-text.h>
+
+#define E_CELL_PERCENT_TYPE (e_cell_percent_get_type ())
+#define E_CELL_PERCENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_CELL_PERCENT_TYPE, ECellPercent))
+#define E_CELL_PERCENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), E_CELL_PERCENT_TYPE, ECellPercentClass))
+#define E_IS_CELL_NUMBER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_CELL_PERCENT_TYPE))
+#define E_IS_CELL_NUMBER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_CELL_PERCENT_TYPE))
+
+typedef struct {
+ ECellText base;
+} ECellPercent;
+
+typedef struct {
+ ECellTextClass parent_class;
+} ECellPercentClass;
+
+GType e_cell_percent_get_type (void);
+ECell *e_cell_percent_new (const char *fontname, GtkJustification justify);
+
+#endif /* _E_CELL_PERCENT_H_ */
diff --git a/widgets/table/e-cell-popup.c b/widgets/table/e-cell-popup.c
index 92e03d79a1..e7203c5550 100644
--- a/widgets/table/e-cell-popup.c
+++ b/widgets/table/e-cell-popup.c
@@ -33,8 +33,8 @@
#include <gdk/gdkkeysyms.h>
-#include "a11y/e-table/gal-a11y-e-cell-popup.h"
-#include "a11y/e-table/gal-a11y-e-cell-registry.h"
+#include "a11y/gal-a11y-e-cell-popup.h"
+#include "a11y/gal-a11y-e-cell-registry.h"
#include "e-util/e-util.h"
#include "e-cell-popup.h"
diff --git a/widgets/table/e-cell-text.c b/widgets/table/e-cell-text.c
index e50d3d7ae7..55ec753c2a 100644
--- a/widgets/table/e-cell-text.c
+++ b/widgets/table/e-cell-text.c
@@ -45,15 +45,15 @@
#include <libgnomecanvas/gnome-canvas.h>
#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include "a11y/e-table/gal-a11y-e-cell-registry.h"
-#include "a11y/e-table/gal-a11y-e-cell-text.h"
+#include "a11y/gal-a11y-e-cell-registry.h"
+#include "a11y/gal-a11y-e-cell-text.h"
#include "text/e-text.h"
#include <glib/gi18n.h>
#include "e-util/e-text-event-processor.h"
#include "e-util/e-text-event-processor-emacs-like.h"
#include "e-util/e-util.h"
#include "misc/e-canvas.h"
-#include "misc/e-unicode.h"
+#include "e-util/e-unicode.h"
#include "e-cell-text.h"
#include "e-table-item.h"
diff --git a/widgets/table/e-cell-toggle.c b/widgets/table/e-cell-toggle.c
index 4fc6aca107..38562f58a8 100644
--- a/widgets/table/e-cell-toggle.c
+++ b/widgets/table/e-cell-toggle.c
@@ -28,8 +28,8 @@
#include <gtk/gtk.h>
#include <libgnomecanvas/gnome-canvas.h>
-#include "a11y/e-table/gal-a11y-e-cell-toggle.h"
-#include "a11y/e-table/gal-a11y-e-cell-registry.h"
+#include "a11y/gal-a11y-e-cell-toggle.h"
+#include "a11y/gal-a11y-e-cell-registry.h"
#include "e-util/e-util.h"
#include "misc/e-hsv-utils.h"
diff --git a/widgets/table/e-cell-tree.c b/widgets/table/e-cell-tree.c
index eb7e428fb9..e9cb30bb23 100644
--- a/widgets/table/e-cell-tree.c
+++ b/widgets/table/e-cell-tree.c
@@ -38,8 +38,8 @@
#include <gtk/gtk.h>
#include <libgnomecanvas/gnome-canvas.h>
-#include "a11y/e-table/gal-a11y-e-cell-registry.h"
-#include "a11y/e-table/gal-a11y-e-cell-tree.h"
+#include "a11y/gal-a11y-e-cell-registry.h"
+#include "a11y/gal-a11y-e-cell-tree.h"
#include "e-util/e-util.h"
#include "e-cell-tree.h"
diff --git a/widgets/table/e-cell-vbox.c b/widgets/table/e-cell-vbox.c
index af398ae872..46da90eea4 100644
--- a/widgets/table/e-cell-vbox.c
+++ b/widgets/table/e-cell-vbox.c
@@ -29,8 +29,8 @@
#include <gtk/gtk.h>
-#include "a11y/e-table/gal-a11y-e-cell-registry.h"
-#include "a11y/e-table/gal-a11y-e-cell-vbox.h"
+#include "a11y/gal-a11y-e-cell-registry.h"
+#include "a11y/gal-a11y-e-cell-vbox.h"
#include "e-util/e-util.h"
#include "e-cell-vbox.h"
diff --git a/widgets/table/e-table-click-to-add.c b/widgets/table/e-table-click-to-add.c
index 4871b055eb..dedf8e1c53 100644
--- a/widgets/table/e-table-click-to-add.c
+++ b/widgets/table/e-table-click-to-add.c
@@ -29,7 +29,7 @@
#include <libgnomecanvas/gnome-canvas-util.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
-#include "a11y/e-table/gal-a11y-e-table-click-to-add.h"
+#include "a11y/gal-a11y-e-table-click-to-add.h"
#include "text/e-text.h"
#include <glib/gi18n.h>
#include "e-util/e-util.h"
diff --git a/widgets/table/e-table-config.c b/widgets/table/e-table-config.c
index 5becaa30f2..5f93c32a72 100644
--- a/widgets/table/e-table-config.c
+++ b/widgets/table/e-table-config.c
@@ -38,7 +38,7 @@
#include <glib/gi18n.h>
#include "e-util/e-util-private.h"
#include "e-util/e-util.h"
-#include "misc/e-unicode.h"
+#include "e-util/e-unicode.h"
#include "e-table-config.h"
#include "e-table-memory-store.h"
diff --git a/widgets/table/e-table-group-container.c b/widgets/table/e-table-group-container.c
index c342c6ca7e..f6758025ab 100644
--- a/widgets/table/e-table-group-container.c
+++ b/widgets/table/e-table-group-container.c
@@ -31,7 +31,7 @@
#include "e-util/e-util.h"
#include "misc/e-canvas-utils.h"
#include "misc/e-canvas.h"
-#include "misc/e-unicode.h"
+#include "e-util/e-unicode.h"
#include "e-table-defines.h"
#include "e-table-group-container.h"
diff --git a/widgets/table/e-table-header-utils.c b/widgets/table/e-table-header-utils.c
index afcc0720e1..80b5be42ce 100644
--- a/widgets/table/e-table-header-utils.c
+++ b/widgets/table/e-table-header-utils.c
@@ -29,7 +29,7 @@
#include <gtk/gtk.h>
-#include "misc/e-unicode.h"
+#include "e-util/e-unicode.h"
#include "e-table-defines.h"
#include "e-table-header-utils.h"
diff --git a/widgets/table/e-table-item.c b/widgets/table/e-table-item.c
index 58d6c65f03..394679e6ef 100644
--- a/widgets/table/e-table-item.c
+++ b/widgets/table/e-table-item.c
@@ -36,8 +36,8 @@
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
-#include "a11y/e-table/gal-a11y-e-table-item-factory.h"
-#include "a11y/e-table/gal-a11y-e-table-item.h"
+#include "a11y/gal-a11y-e-table-item-factory.h"
+#include "a11y/gal-a11y-e-table-item.h"
#include <glib/gi18n.h>
#include "e-util/e-util.h"
#include "misc/e-canvas.h"
diff --git a/widgets/table/e-table-utils.c b/widgets/table/e-table-utils.c
index d01d94ae28..96b6004c41 100644
--- a/widgets/table/e-table-utils.c
+++ b/widgets/table/e-table-utils.c
@@ -27,7 +27,7 @@
#include <string.h>
#include "e-util/e-util.h"
-#include "misc/e-unicode.h"
+#include "e-util/e-unicode.h"
#include "e-table-utils.h"
#include "e-table-header-utils.h"
diff --git a/widgets/table/e-table.c b/widgets/table/e-table.c
index 69a300d950..754607c376 100644
--- a/widgets/table/e-table.c
+++ b/widgets/table/e-table.c
@@ -36,13 +36,13 @@
#include <libgnomecanvas/gnome-canvas.h>
#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include "a11y/e-table/gal-a11y-e-table.h"
+#include "a11y/gal-a11y-e-table.h"
#include <glib/gi18n.h>
#include "e-util/e-util.h"
#include "misc/e-canvas.h"
#include "misc/e-canvas-background.h"
#include "misc/e-canvas-vbox.h"
-#include "misc/e-unicode.h"
+#include "e-util/e-unicode.h"
#include "e-table.h"
#include "e-table-click-to-add.h"
diff --git a/widgets/table/e-tree.c b/widgets/table/e-tree.c
index 0963229c94..08399609a0 100644
--- a/widgets/table/e-tree.c
+++ b/widgets/table/e-tree.c
@@ -30,7 +30,7 @@
#include <gtk/gtk.h>
#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
-#include "a11y/e-table/gal-a11y-e-tree.h"
+#include "a11y/gal-a11y-e-tree.h"
#include <glib/gi18n.h>
#include "e-util/e-util.h"
#include "misc/e-canvas.h"