From f4cf9af33ccde3142a3011e8b2dbcfb4cbc9ae81 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Wed, 20 May 2009 16:50:00 +0200 Subject: 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. --- widgets/Makefile.am | 4 +- widgets/menus/gal-view-collection.c | 2 +- widgets/menus/gal-view-instance.c | 2 +- widgets/menus/gal-view-new-dialog.c | 2 +- widgets/misc/Makefile.am | 43 +- widgets/misc/a11y/ea-calendar-cell.c | 387 ++++ widgets/misc/a11y/ea-calendar-cell.h | 90 + widgets/misc/a11y/ea-calendar-item.c | 1314 +++++++++++++ widgets/misc/a11y/ea-calendar-item.h | 72 + widgets/misc/a11y/ea-widgets.c | 32 + widgets/misc/a11y/ea-widgets.h | 32 + widgets/misc/e-calendar-item.c | 2 +- widgets/misc/e-cell-date-edit.c | 1033 ---------- widgets/misc/e-cell-date-edit.h | 106 - widgets/misc/e-cell-percent.c | 152 -- widgets/misc/e-cell-percent.h | 51 - widgets/misc/e-reflow-model.c | 350 ---- widgets/misc/e-reflow-model.h | 112 -- widgets/misc/e-reflow.c | 1534 --------------- widgets/misc/e-reflow.h | 146 -- widgets/misc/e-search-bar.c | 2 +- widgets/misc/e-unicode.c | 2052 -------------------- widgets/misc/e-unicode.h | 113 -- widgets/table/Makefile.am | 52 +- widgets/table/a11y/gal-a11y-e-cell-popup.c | 144 ++ widgets/table/a11y/gal-a11y-e-cell-popup.h | 62 + widgets/table/a11y/gal-a11y-e-cell-registry.c | 149 ++ widgets/table/a11y/gal-a11y-e-cell-registry.h | 72 + widgets/table/a11y/gal-a11y-e-cell-text.c | 737 +++++++ widgets/table/a11y/gal-a11y-e-cell-text.h | 64 + widgets/table/a11y/gal-a11y-e-cell-toggle.c | 191 ++ widgets/table/a11y/gal-a11y-e-cell-toggle.h | 68 + widgets/table/a11y/gal-a11y-e-cell-tree.c | 260 +++ widgets/table/a11y/gal-a11y-e-cell-tree.h | 64 + widgets/table/a11y/gal-a11y-e-cell-vbox.c | 225 +++ widgets/table/a11y/gal-a11y-e-cell-vbox.h | 67 + widgets/table/a11y/gal-a11y-e-cell.c | 644 ++++++ widgets/table/a11y/gal-a11y-e-cell.h | 113 ++ .../a11y/gal-a11y-e-table-click-to-add-factory.c | 106 + .../a11y/gal-a11y-e-table-click-to-add-factory.h | 50 + widgets/table/a11y/gal-a11y-e-table-click-to-add.c | 344 ++++ widgets/table/a11y/gal-a11y-e-table-click-to-add.h | 55 + .../table/a11y/gal-a11y-e-table-column-header.c | 229 +++ .../table/a11y/gal-a11y-e-table-column-header.h | 55 + widgets/table/a11y/gal-a11y-e-table-factory.c | 99 + widgets/table/a11y/gal-a11y-e-table-factory.h | 51 + widgets/table/a11y/gal-a11y-e-table-item-factory.c | 105 + widgets/table/a11y/gal-a11y-e-table-item-factory.h | 50 + widgets/table/a11y/gal-a11y-e-table-item.c | 1327 +++++++++++++ widgets/table/a11y/gal-a11y-e-table-item.h | 59 + widgets/table/a11y/gal-a11y-e-table.c | 308 +++ widgets/table/a11y/gal-a11y-e-table.h | 59 + widgets/table/a11y/gal-a11y-e-tree-factory.c | 98 + widgets/table/a11y/gal-a11y-e-tree-factory.h | 50 + widgets/table/a11y/gal-a11y-e-tree.c | 191 ++ widgets/table/a11y/gal-a11y-e-tree.h | 58 + widgets/table/e-cell-combo.c | 2 +- widgets/table/e-cell-date-edit.c | 1033 ++++++++++ widgets/table/e-cell-date-edit.h | 106 + widgets/table/e-cell-date.c | 2 +- widgets/table/e-cell-hbox.c | 4 +- widgets/table/e-cell-percent.c | 152 ++ widgets/table/e-cell-percent.h | 51 + widgets/table/e-cell-popup.c | 4 +- widgets/table/e-cell-text.c | 6 +- widgets/table/e-cell-toggle.c | 4 +- widgets/table/e-cell-tree.c | 4 +- widgets/table/e-cell-vbox.c | 4 +- widgets/table/e-table-click-to-add.c | 2 +- widgets/table/e-table-config.c | 2 +- widgets/table/e-table-group-container.c | 2 +- widgets/table/e-table-header-utils.c | 2 +- widgets/table/e-table-item.c | 4 +- widgets/table/e-table-utils.c | 2 +- widgets/table/e-table.c | 4 +- widgets/table/e-tree.c | 2 +- widgets/text/Makefile.am | 21 +- widgets/text/a11y/gal-a11y-e-text-factory.c | 101 + widgets/text/a11y/gal-a11y-e-text-factory.h | 50 + widgets/text/a11y/gal-a11y-e-text.c | 1134 +++++++++++ widgets/text/a11y/gal-a11y-e-text.h | 57 + widgets/text/e-reflow-model.c | 350 ++++ widgets/text/e-reflow-model.h | 112 ++ widgets/text/e-reflow.c | 1534 +++++++++++++++ widgets/text/e-reflow.h | 146 ++ widgets/text/e-text.c | 4 +- 86 files changed, 13010 insertions(+), 5730 deletions(-) create mode 100644 widgets/misc/a11y/ea-calendar-cell.c create mode 100644 widgets/misc/a11y/ea-calendar-cell.h create mode 100644 widgets/misc/a11y/ea-calendar-item.c create mode 100644 widgets/misc/a11y/ea-calendar-item.h create mode 100644 widgets/misc/a11y/ea-widgets.c create mode 100644 widgets/misc/a11y/ea-widgets.h delete mode 100644 widgets/misc/e-cell-date-edit.c delete mode 100644 widgets/misc/e-cell-date-edit.h delete mode 100644 widgets/misc/e-cell-percent.c delete mode 100644 widgets/misc/e-cell-percent.h delete mode 100644 widgets/misc/e-reflow-model.c delete mode 100644 widgets/misc/e-reflow-model.h delete mode 100644 widgets/misc/e-reflow.c delete mode 100644 widgets/misc/e-reflow.h delete mode 100644 widgets/misc/e-unicode.c delete mode 100644 widgets/misc/e-unicode.h create mode 100644 widgets/table/a11y/gal-a11y-e-cell-popup.c create mode 100644 widgets/table/a11y/gal-a11y-e-cell-popup.h create mode 100644 widgets/table/a11y/gal-a11y-e-cell-registry.c create mode 100644 widgets/table/a11y/gal-a11y-e-cell-registry.h create mode 100644 widgets/table/a11y/gal-a11y-e-cell-text.c create mode 100644 widgets/table/a11y/gal-a11y-e-cell-text.h create mode 100644 widgets/table/a11y/gal-a11y-e-cell-toggle.c create mode 100644 widgets/table/a11y/gal-a11y-e-cell-toggle.h create mode 100644 widgets/table/a11y/gal-a11y-e-cell-tree.c create mode 100644 widgets/table/a11y/gal-a11y-e-cell-tree.h create mode 100644 widgets/table/a11y/gal-a11y-e-cell-vbox.c create mode 100644 widgets/table/a11y/gal-a11y-e-cell-vbox.h create mode 100644 widgets/table/a11y/gal-a11y-e-cell.c create mode 100644 widgets/table/a11y/gal-a11y-e-cell.h create mode 100644 widgets/table/a11y/gal-a11y-e-table-click-to-add-factory.c create mode 100644 widgets/table/a11y/gal-a11y-e-table-click-to-add-factory.h create mode 100644 widgets/table/a11y/gal-a11y-e-table-click-to-add.c create mode 100644 widgets/table/a11y/gal-a11y-e-table-click-to-add.h create mode 100644 widgets/table/a11y/gal-a11y-e-table-column-header.c create mode 100644 widgets/table/a11y/gal-a11y-e-table-column-header.h create mode 100644 widgets/table/a11y/gal-a11y-e-table-factory.c create mode 100644 widgets/table/a11y/gal-a11y-e-table-factory.h create mode 100644 widgets/table/a11y/gal-a11y-e-table-item-factory.c create mode 100644 widgets/table/a11y/gal-a11y-e-table-item-factory.h create mode 100644 widgets/table/a11y/gal-a11y-e-table-item.c create mode 100644 widgets/table/a11y/gal-a11y-e-table-item.h create mode 100644 widgets/table/a11y/gal-a11y-e-table.c create mode 100644 widgets/table/a11y/gal-a11y-e-table.h create mode 100644 widgets/table/a11y/gal-a11y-e-tree-factory.c create mode 100644 widgets/table/a11y/gal-a11y-e-tree-factory.h create mode 100644 widgets/table/a11y/gal-a11y-e-tree.c create mode 100644 widgets/table/a11y/gal-a11y-e-tree.h create mode 100644 widgets/table/e-cell-date-edit.c create mode 100644 widgets/table/e-cell-date-edit.h create mode 100644 widgets/table/e-cell-percent.c create mode 100644 widgets/table/e-cell-percent.h create mode 100644 widgets/text/a11y/gal-a11y-e-text-factory.c create mode 100644 widgets/text/a11y/gal-a11y-e-text-factory.h create mode 100644 widgets/text/a11y/gal-a11y-e-text.c create mode 100644 widgets/text/a11y/gal-a11y-e-text.h create mode 100644 widgets/text/e-reflow-model.c create mode 100644 widgets/text/e-reflow-model.h create mode 100644 widgets/text/e-reflow.c create mode 100644 widgets/text/e-reflow.h (limited to 'widgets') diff --git a/widgets/Makefile.am b/widgets/Makefile.am index 347c0f7c66..99305b844e 100644 --- a/widgets/Makefile.am +++ b/widgets/Makefile.am @@ -1,9 +1,9 @@ SUBDIRS = \ - table \ - text \ misc \ + text \ e-timezone-dialog \ + table \ menus EXTRA_DIST = \ diff --git a/widgets/menus/gal-view-collection.c b/widgets/menus/gal-view-collection.c index 890ee3ea7f..9541f0fb9c 100644 --- a/widgets/menus/gal-view-collection.c +++ b/widgets/menus/gal-view-collection.c @@ -33,7 +33,7 @@ #include #include "e-util/e-util.h" #include "e-util/e-xml-utils.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "gal-view-collection.h" diff --git a/widgets/menus/gal-view-instance.c b/widgets/menus/gal-view-instance.c index 19ec402fa3..40a9e5262a 100644 --- a/widgets/menus/gal-view-instance.c +++ b/widgets/menus/gal-view-instance.c @@ -38,7 +38,7 @@ #include #include "e-util/e-util.h" #include "e-util/e-xml-utils.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "gal-define-views-dialog.h" #include "gal-view-instance.h" diff --git a/widgets/menus/gal-view-new-dialog.c b/widgets/menus/gal-view-new-dialog.c index 061c04b71a..8716764c49 100644 --- a/widgets/menus/gal-view-new-dialog.c +++ b/widgets/menus/gal-view-new-dialog.c @@ -27,7 +27,7 @@ #include #include "e-util/e-util.h" #include "e-util/e-util-private.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include "gal-define-views-model.h" #include "gal-view-new-dialog.h" diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am index 212d67557b..bd2c9f9f36 100644 --- a/widgets/misc/Makefile.am +++ b/widgets/misc/Makefile.am @@ -1,10 +1,5 @@ -if OS_WIN32 -WIN32_BOOTSTRAP_LIBS = $(top_builddir)/win32/libfilter.la -endif - INCLUDES = \ -I$(top_srcdir) \ - -I$(top_srcdir)/a11y/widgets \ -I$(top_srcdir)/filter \ -I$(top_srcdir)/widgets \ -DEVOLUTION_IMAGES=\""$(imagesdir)"\" \ @@ -50,13 +45,10 @@ widgetsinclude_HEADERS = \ e-attachment-view.h \ e-calendar.h \ e-calendar-item.h \ - e-camel-activity.h \ e-canvas.h \ e-canvas-background.h \ e-canvas-utils.h \ e-canvas-vbox.h \ - e-cell-date-edit.h \ - e-cell-percent.h \ e-cell-renderer-combo.h \ e-charset-picker.h \ e-colors.h \ @@ -75,8 +67,6 @@ widgetsinclude_HEADERS = \ e-popup-menu.h \ e-preferences-window.h \ e-printable.h \ - e-reflow.h \ - e-reflow-model.h \ e-search-bar.h \ e-selection-model.h \ e-selection-model-array.h \ @@ -91,8 +81,10 @@ widgetsinclude_HEADERS = \ e-spinner.c \ e-spinner.h \ e-timeout-activity.h \ - e-unicode.h \ - e-url-entry.h + e-url-entry.h \ + a11y/ea-calendar-cell.h \ + a11y/ea-calendar-item.h \ + a11y/ea-widgets.h libemiscwidgets_la_SOURCES = \ $(widgetsinclude_HEADERS) \ @@ -115,13 +107,10 @@ libemiscwidgets_la_SOURCES = \ e-attachment-view.c \ e-calendar.c \ e-calendar-item.c \ - e-camel-activity.c \ e-canvas.c \ e-canvas-background.c \ e-canvas-utils.c \ e-canvas-vbox.c \ - e-cell-date-edit.c \ - e-cell-percent.c \ e-cell-renderer-combo.c \ e-charset-picker.c \ e-colors.c \ @@ -140,8 +129,6 @@ libemiscwidgets_la_SOURCES = \ e-popup-menu.c \ e-preferences-window.c \ e-printable.c \ - e-reflow-model.c \ - e-reflow.c \ e-search-bar.c \ e-selection-model.c \ e-selection-model-array.c \ @@ -154,20 +141,20 @@ libemiscwidgets_la_SOURCES = \ e-signature-script-dialog.c \ e-signature-tree-view.c \ e-timeout-activity.c \ - e-unicode.c \ - e-url-entry.c + e-url-entry.c \ + a11y/ea-calendar-cell.c \ + a11y/ea-calendar-item.c \ + a11y/ea-widgets.c libemiscwidgets_la_LDFLAGS = $(NO_UNDEFINED) -libemiscwidgets_la_LIBADD = \ - $(top_builddir)/e-util/libeutil.la \ - $(top_builddir)/filter/libfilter.la \ - $(top_builddir)/widgets/table/libetable.la \ - $(top_builddir)/widgets/text/libetext.la \ - $(top_builddir)/a11y/widgets/libevolution-widgets-a11y.la \ - $(top_builddir)/a11y/libevolution-a11y.la \ - $(EVOLUTION_MAIL_LIBS) \ - $(GNOME_PLATFORM_LIBS) \ +libemiscwidgets_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/filter/libfilter.la \ + $(top_builddir)/a11y/libevolution-a11y.la \ + $(EVOLUTION_MAIL_LIBS) \ + $(GNOME_PLATFORM_LIBS) \ + $(MATH_LIB) \ $(ICONV_LIBS) noinst_PROGRAMS = \ diff --git a/widgets/misc/a11y/ea-calendar-cell.c b/widgets/misc/a11y/ea-calendar-cell.c new file mode 100644 index 0000000000..8173d6d25f --- /dev/null +++ b/widgets/misc/a11y/ea-calendar-cell.c @@ -0,0 +1,387 @@ +/* + * + * 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 + * + * + * Authors: + * Bolian Yin + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include +#include +#include "ea-calendar-cell.h" +#include "ea-calendar-item.h" +#include "a11y/ea-factory.h" + +/* ECalendarCell */ + +static void e_calendar_cell_class_init (ECalendarCellClass *class); + +EA_FACTORY_GOBJECT (EA_TYPE_CALENDAR_CELL, ea_calendar_cell, ea_calendar_cell_new) + +GType +e_calendar_cell_get_type (void) +{ + static GType type = 0; + + if (!type) { + static GTypeInfo tinfo = { + sizeof (ECalendarCellClass), + (GBaseInitFunc) NULL, /* base init */ + (GBaseFinalizeFunc) NULL, /* base finalize */ + (GClassInitFunc) e_calendar_cell_class_init, /* class init */ + (GClassFinalizeFunc) NULL, /* class finalize */ + NULL, /* class data */ + sizeof (ECalendarCell), /* instance size */ + 0, /* nb preallocs */ + (GInstanceInitFunc) NULL, /* instance init */ + NULL /* value table */ + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "ECalendarCell", &tinfo, 0); + } + + return type; +} + +static void +e_calendar_cell_class_init (ECalendarCellClass *class) +{ + EA_SET_FACTORY (e_calendar_cell_get_type (), ea_calendar_cell); +} + +ECalendarCell * +e_calendar_cell_new (ECalendarItem *calitem, gint row, gint column) +{ + GObject *object; + ECalendarCell *cell; + + g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), NULL); + + object = g_object_new (E_TYPE_CALENDAR_CELL, NULL); + cell = E_CALENDAR_CELL (object); + cell->calitem = calitem; + cell->row = row; + cell->column = column; + +#ifdef ACC_DEBUG + g_print ("EvoAcc: e_calendar_cell created %p\n", (void *)cell); +#endif + + return cell; +} + +/* EaCalendarCell */ + +static void ea_calendar_cell_class_init (EaCalendarCellClass *klass); +static void ea_calendar_cell_init (EaCalendarCell *a11y); + +static G_CONST_RETURN gchar* ea_calendar_cell_get_name (AtkObject *accessible); +static G_CONST_RETURN gchar* ea_calendar_cell_get_description (AtkObject *accessible); +static AtkObject * ea_calendar_cell_get_parent (AtkObject *accessible); +static gint ea_calendar_cell_get_index_in_parent (AtkObject *accessible); +static AtkStateSet *ea_calendar_cell_ref_state_set (AtkObject *accessible); + +/* component interface */ +static void atk_component_interface_init (AtkComponentIface *iface); +static void component_interface_get_extents (AtkComponent *component, + gint *x, gint *y, + gint *width, gint *height, + AtkCoordType coord_type); +static gboolean component_interface_grab_focus (AtkComponent *component); + +static gpointer parent_class = NULL; + +#ifdef ACC_DEBUG +static gint n_ea_calendar_cell_created = 0, n_ea_calendar_cell_destroyed = 0; +static void ea_calendar_cell_finalize (GObject *object); +#endif + +GType +ea_calendar_cell_get_type (void) +{ + static GType type = 0; + + if (!type) { + static GTypeInfo tinfo = { + sizeof (EaCalendarCellClass), + (GBaseInitFunc) NULL, /* base init */ + (GBaseFinalizeFunc) NULL, /* base finalize */ + (GClassInitFunc) ea_calendar_cell_class_init, /* class init */ + (GClassFinalizeFunc) NULL, /* class finalize */ + NULL, /* class data */ + sizeof (EaCalendarCell), /* instance size */ + 0, /* nb preallocs */ + (GInstanceInitFunc) ea_calendar_cell_init, /* instance init */ + NULL /* value table */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) atk_component_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + type = g_type_register_static (ATK_TYPE_GOBJECT_ACCESSIBLE, + "EaCalendarCell", &tinfo, 0); + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, + &atk_component_info); + } + + return type; +} + +static void +ea_calendar_cell_class_init (EaCalendarCellClass *klass) +{ + AtkObjectClass *class = ATK_OBJECT_CLASS (klass); + +#ifdef ACC_DEBUG + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = ea_calendar_cell_finalize; +#endif + + parent_class = g_type_class_peek_parent (klass); + + class->get_name = ea_calendar_cell_get_name; + class->get_description = ea_calendar_cell_get_description; + + class->get_parent = ea_calendar_cell_get_parent; + class->get_index_in_parent = ea_calendar_cell_get_index_in_parent; + class->ref_state_set = ea_calendar_cell_ref_state_set; +} + +static void +ea_calendar_cell_init (EaCalendarCell *a11y) +{ + a11y->state_set = atk_state_set_new (); + atk_state_set_add_state (a11y->state_set, ATK_STATE_TRANSIENT); + atk_state_set_add_state (a11y->state_set, ATK_STATE_ENABLED); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SELECTABLE); + atk_state_set_add_state (a11y->state_set, ATK_STATE_SHOWING); + atk_state_set_add_state (a11y->state_set, ATK_STATE_FOCUSABLE); +} + +AtkObject* +ea_calendar_cell_new (GObject *obj) +{ + gpointer object; + AtkObject *atk_object; + + g_return_val_if_fail (E_IS_CALENDAR_CELL (obj), NULL); + object = g_object_new (EA_TYPE_CALENDAR_CELL, NULL); + atk_object = ATK_OBJECT (object); + atk_object_initialize (atk_object, obj); + atk_object->role = ATK_ROLE_TABLE_CELL; + +#ifdef ACC_DEBUG + ++n_ea_calendar_cell_created; + g_print ("ACC_DEBUG: n_ea_calendar_cell_created = %d\n", + n_ea_calendar_cell_created); +#endif + return atk_object; +} + +#ifdef ACC_DEBUG +static void ea_calendar_cell_finalize (GObject *object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); + + ++n_ea_calendar_cell_destroyed; + g_print ("ACC_DEBUG: n_ea_calendar_cell_destroyed = %d\n", + n_ea_calendar_cell_destroyed); +} +#endif + +static G_CONST_RETURN gchar* +ea_calendar_cell_get_name (AtkObject *accessible) +{ + GObject *g_obj; + + g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), NULL); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)); + if (!g_obj) + /* defunct object*/ + return NULL; + + if (!accessible->name) { + AtkObject *atk_obj; + EaCalendarItem *ea_calitem; + ECalendarCell *cell; + gint day_index; + gint year, month, day; + gchar buffer[128]; + + cell = E_CALENDAR_CELL (g_obj); + atk_obj = ea_calendar_cell_get_parent (accessible); + ea_calitem = EA_CALENDAR_ITEM (atk_obj); + day_index = atk_table_get_index_at (ATK_TABLE (ea_calitem), + cell->row, cell->column); + e_calendar_item_get_date_for_offset (cell->calitem, day_index, + &year, &month, &day); + + g_snprintf (buffer, 128, "%d-%d-%d", year, month + 1, day); + ATK_OBJECT_CLASS (parent_class)->set_name (accessible, buffer); + } + return accessible->name; +} + +static G_CONST_RETURN gchar* +ea_calendar_cell_get_description (AtkObject *accessible) +{ + return ea_calendar_cell_get_name (accessible); +} + +static AtkObject * +ea_calendar_cell_get_parent (AtkObject *accessible) +{ + GObject *g_obj; + ECalendarCell *cell; + ECalendarItem *calitem; + + g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), NULL); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)); + if (!g_obj) + /* defunct object*/ + return NULL; + + cell = E_CALENDAR_CELL (g_obj); + calitem = cell->calitem; + return atk_gobject_accessible_for_object (G_OBJECT (calitem)); +} + +static gint +ea_calendar_cell_get_index_in_parent (AtkObject *accessible) +{ + GObject *g_obj; + ECalendarCell *cell; + AtkObject *parent; + + g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), -1); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)); + if (!g_obj) + return -1; + cell = E_CALENDAR_CELL (g_obj); + parent = atk_object_get_parent (accessible); + return atk_table_get_index_at (ATK_TABLE (parent), + cell->row, cell->column); +} + +static AtkStateSet * +ea_calendar_cell_ref_state_set (AtkObject *accessible) +{ + EaCalendarCell *atk_cell = EA_CALENDAR_CELL (accessible); + + g_return_val_if_fail (atk_cell->state_set, NULL); + + g_object_ref(atk_cell->state_set); + + return atk_cell->state_set; + +} + +/* Atk Component Interface */ + +static void +atk_component_interface_init (AtkComponentIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->get_extents = component_interface_get_extents; + iface->grab_focus = component_interface_grab_focus; +} + +static void +component_interface_get_extents (AtkComponent *component, + gint *x, gint *y, gint *width, gint *height, + AtkCoordType coord_type) +{ + GObject *g_obj; + AtkObject *atk_obj, *atk_canvas; + ECalendarCell *cell; + ECalendarItem *calitem; + EaCalendarItem *ea_calitem; + gint day_index; + gint year, month, day; + gint canvas_x, canvas_y, canvas_width, canvas_height; + + *x = *y = *width = *height = 0; + + g_return_if_fail (EA_IS_CALENDAR_CELL (component)); + + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(component)); + if (!g_obj) + /* defunct object*/ + return; + + cell = E_CALENDAR_CELL (g_obj); + calitem = cell->calitem; + atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem)); + ea_calitem = EA_CALENDAR_ITEM (atk_obj); + day_index = atk_table_get_index_at (ATK_TABLE (ea_calitem), + cell->row, cell->column); + e_calendar_item_get_date_for_offset (calitem, day_index, + &year, &month, &day); + + if (!e_calendar_item_get_day_extents (calitem, + year, month, day, + x, y, width, height)) + return; + atk_canvas = atk_object_get_parent (ATK_OBJECT (ea_calitem)); + atk_component_get_extents (ATK_COMPONENT (atk_canvas), + &canvas_x, &canvas_y, + &canvas_width, &canvas_height, + coord_type); + *x += canvas_x; + *y += canvas_y; +} + +static gboolean +component_interface_grab_focus (AtkComponent *component) +{ + GObject *g_obj; + GtkWidget *toplevel; + AtkObject *ea_calitem; + ECalendarItem *calitem; + EaCalendarCell *a11y; + gint index; + + a11y = EA_CALENDAR_CELL (component); + ea_calitem = ea_calendar_cell_get_parent (ATK_OBJECT (a11y)); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(ea_calitem)); + calitem = E_CALENDAR_ITEM (g_obj); + + index = atk_object_get_index_in_parent (ATK_OBJECT (a11y)); + + atk_selection_clear_selection (ATK_SELECTION (ea_calitem)); + atk_selection_add_selection (ATK_SELECTION (ea_calitem), index); + + gtk_widget_grab_focus (GTK_WIDGET (GNOME_CANVAS_ITEM (calitem)->canvas)); + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (GNOME_CANVAS_ITEM (calitem)->canvas)); + if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel)) + gtk_window_present (GTK_WINDOW (toplevel)); + + return TRUE; + +} diff --git a/widgets/misc/a11y/ea-calendar-cell.h b/widgets/misc/a11y/ea-calendar-cell.h new file mode 100644 index 0000000000..a07b7e8bbc --- /dev/null +++ b/widgets/misc/a11y/ea-calendar-cell.h @@ -0,0 +1,90 @@ +/* + * 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 + * + * + * Authors: + * Bolian Yin + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __EA_CALENDAR_CELL_H__ +#define __EA_CALENDAR_CELL_H__ + +#include +#include "misc/e-calendar-item.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define E_TYPE_CALENDAR_CELL (e_calendar_cell_get_type ()) +#define E_CALENDAR_CELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CALENDAR_CELL, ECalendarCell)) +#define E_CALENDAR_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CALENDAR_CELL, ECalendarCellClass)) +#define E_IS_CALENDAR_CELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CALENDAR_CELL)) +#define E_IS_CALENDAR_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CALENDAR_CELL)) +#define E_CALENDAR_CELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CALENDAR_CELL, ECalendarCellClass)) + +typedef struct _ECalendarCell ECalendarCell; +typedef struct _ECalendarCellClass ECalendarCellClass; + +struct _ECalendarCell +{ + GObject parent; + ECalendarItem *calitem; + gint row; + gint column; +}; + +GType e_calendar_cell_get_type (void); + +struct _ECalendarCellClass +{ + GObjectClass parent_class; +}; + +ECalendarCell * e_calendar_cell_new (ECalendarItem *calitem, + gint row, gint column); + +#define EA_TYPE_CALENDAR_CELL (ea_calendar_cell_get_type ()) +#define EA_CALENDAR_CELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EA_TYPE_CALENDAR_CELL, EaCalendarCell)) +#define EA_CALENDAR_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EA_TYPE_CALENDAR_CELL, EaCalendarCellClass)) +#define EA_IS_CALENDAR_CELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EA_TYPE_CALENDAR_CELL)) +#define EA_IS_CALENDAR_CELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EA_TYPE_CALENDAR_CELL)) +#define EA_CALENDAR_CELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EA_TYPE_CALENDAR_CELL, EaCalendarCellClass)) + +typedef struct _EaCalendarCell EaCalendarCell; +typedef struct _EaCalendarCellClass EaCalendarCellClass; + +struct _EaCalendarCell +{ + AtkGObjectAccessible parent; + AtkStateSet *state_set; +}; + +GType ea_calendar_cell_get_type (void); + +struct _EaCalendarCellClass +{ + AtkGObjectAccessibleClass parent_class; +}; + +AtkObject* ea_calendar_cell_new (GObject *gobj); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EA_CALENDAR_CELL_H__ */ diff --git a/widgets/misc/a11y/ea-calendar-item.c b/widgets/misc/a11y/ea-calendar-item.c new file mode 100644 index 0000000000..66f40a92a0 --- /dev/null +++ b/widgets/misc/a11y/ea-calendar-item.c @@ -0,0 +1,1314 @@ +/* + * 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 + * + * + * Authors: + * Bolian Yin + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ea-calendar-item.h" +#include "ea-calendar-cell.h" +#include "a11y/ea-cell-table.h" + +#define EA_CALENDAR_COLUMN_NUM E_CALENDAR_COLS_PER_MONTH + +/* EaCalendarItem */ +static void ea_calendar_item_class_init (EaCalendarItemClass *klass); +static void ea_calendar_item_finalize (GObject *object); + +static G_CONST_RETURN gchar* ea_calendar_item_get_name (AtkObject *accessible); +static G_CONST_RETURN gchar* ea_calendar_item_get_description (AtkObject *accessible); +static gint ea_calendar_item_get_n_children (AtkObject *accessible); +static AtkObject *ea_calendar_item_ref_child (AtkObject *accessible, gint index); +static AtkStateSet* ea_calendar_item_ref_state_set (AtkObject *accessible); + +/* atk table interface */ +static void atk_table_interface_init (AtkTableIface *iface); +static gint table_interface_get_index_at (AtkTable *table, + gint row, + gint column); +static gint table_interface_get_column_at_index (AtkTable *table, + gint index); +static gint table_interface_get_row_at_index (AtkTable *table, + gint index); +static AtkObject* table_interface_ref_at (AtkTable *table, + gint row, + gint column); +static gint table_interface_get_n_rows (AtkTable *table); +static gint table_interface_get_n_columns (AtkTable *table); +static gint table_interface_get_column_extent_at (AtkTable *table, + gint row, + gint column); +static gint table_interface_get_row_extent_at (AtkTable *table, + gint row, + gint column); + +static gboolean table_interface_is_row_selected (AtkTable *table, + gint row); +static gboolean table_interface_is_column_selected (AtkTable *table, + gint row); +static gboolean table_interface_is_selected (AtkTable *table, + gint row, + gint column); +static gint table_interface_get_selected_rows (AtkTable *table, + gint **rows_selected); +static gint table_interface_get_selected_columns (AtkTable *table, + gint **columns_selected); +static gboolean table_interface_add_row_selection (AtkTable *table, gint row); +static gboolean table_interface_remove_row_selection (AtkTable *table, + gint row); +static gboolean table_interface_add_column_selection (AtkTable *table, + gint column); +static gboolean table_interface_remove_column_selection (AtkTable *table, + gint column); +static AtkObject* table_interface_get_row_header (AtkTable *table, gint row); +static AtkObject* table_interface_get_column_header (AtkTable *table, + gint in_col); +static AtkObject* table_interface_get_caption (AtkTable *table); + +static G_CONST_RETURN gchar* +table_interface_get_column_description (AtkTable *table, gint in_col); + +static G_CONST_RETURN gchar* +table_interface_get_row_description (AtkTable *table, gint row); + +static AtkObject* table_interface_get_summary (AtkTable *table); + +/* atk selection interface */ +static void atk_selection_interface_init (AtkSelectionIface *iface); +static gboolean selection_interface_add_selection (AtkSelection *selection, + gint i); +static gboolean selection_interface_clear_selection (AtkSelection *selection); +static AtkObject* selection_interface_ref_selection (AtkSelection *selection, + gint i); +static gint selection_interface_get_selection_count (AtkSelection *selection); +static gboolean selection_interface_is_child_selected (AtkSelection *selection, + gint i); + +/* callbacks */ +static void selection_preview_change_cb (ECalendarItem *calitem); +static void date_range_changed_cb (ECalendarItem *calitem); + +/* helpers */ +static EaCellTable *ea_calendar_item_get_cell_data (EaCalendarItem *ea_calitem); +static void ea_calendar_item_destory_cell_data (EaCalendarItem *ea_calitem); +static gboolean ea_calendar_item_get_column_label (EaCalendarItem *ea_calitem, + gint column, + gchar *buffer, + gint buffer_size); +static gboolean ea_calendar_item_get_row_label (EaCalendarItem *ea_calitem, + gint row, + gchar *buffer, + gint buffer_size); +static gboolean e_calendar_item_get_offset_for_date (ECalendarItem *calitem, + gint year, gint month, gint day, + gint *offset); +static void ea_calendar_set_focus_object (EaCalendarItem *ea_calitem, + AtkObject *item_cell); + +#ifdef ACC_DEBUG +static gint n_ea_calendar_item_created = 0; +static gint n_ea_calendar_item_destroyed = 0; +#endif + +static gpointer parent_class = NULL; + +GType +ea_calendar_item_get_type (void) +{ + static GType type = 0; + AtkObjectFactory *factory; + GTypeQuery query; + GType derived_atk_type; + + if (!type) { + static GTypeInfo tinfo = { + sizeof (EaCalendarItemClass), + (GBaseInitFunc) NULL, /* base init */ + (GBaseFinalizeFunc) NULL, /* base finalize */ + (GClassInitFunc) ea_calendar_item_class_init, /* class init */ + (GClassFinalizeFunc) NULL, /* class finalize */ + NULL, /* class data */ + sizeof (EaCalendarItem), /* instance size */ + 0, /* nb preallocs */ + (GInstanceInitFunc) NULL, /* instance init */ + NULL /* value table */ + }; + + static const GInterfaceInfo atk_table_info = { + (GInterfaceInitFunc) atk_table_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + static const GInterfaceInfo atk_selection_info = { + (GInterfaceInitFunc) atk_selection_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + /* + * Figure out the size of the class and instance + * we are run-time deriving from (GailCanvasItem, in this case) + */ + + factory = atk_registry_get_factory (atk_get_default_registry (), + GNOME_TYPE_CANVAS_ITEM); + derived_atk_type = atk_object_factory_get_accessible_type (factory); + g_type_query (derived_atk_type, &query); + + tinfo.class_size = query.class_size; + tinfo.instance_size = query.instance_size; + + type = g_type_register_static (derived_atk_type, + "EaCalendarItem", &tinfo, 0); + 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; +} + +static void +ea_calendar_item_class_init (EaCalendarItemClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + AtkObjectClass *class = ATK_OBJECT_CLASS (klass); + + gobject_class->finalize = ea_calendar_item_finalize; + parent_class = g_type_class_peek_parent (klass); + + class->get_name = ea_calendar_item_get_name; + class->get_description = ea_calendar_item_get_description; + class->ref_state_set = ea_calendar_item_ref_state_set; + + class->get_n_children = ea_calendar_item_get_n_children; + class->ref_child = ea_calendar_item_ref_child; +} + +AtkObject* +ea_calendar_item_new (GObject *obj) +{ + gpointer object; + AtkObject *atk_object; + AtkObject *item_cell; + + g_return_val_if_fail (E_IS_CALENDAR_ITEM (obj), NULL); + object = g_object_new (EA_TYPE_CALENDAR_ITEM, NULL); + atk_object = ATK_OBJECT (object); + atk_object_initialize (atk_object, obj); + atk_object->role = ATK_ROLE_CALENDAR; + + item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_object), + 0); + if (item_cell) + ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_object), item_cell); + +#ifdef ACC_DEBUG + ++n_ea_calendar_item_created; + g_print ("ACC_DEBUG: n_ea_calendar_item_created = %d\n", + n_ea_calendar_item_created); +#endif + /* connect signal handlers */ + g_signal_connect (obj, "selection_preview_changed", + G_CALLBACK (selection_preview_change_cb), + atk_object); + g_signal_connect (obj, "date_range_changed", + G_CALLBACK (date_range_changed_cb), + atk_object); + + return atk_object; +} + +static void +ea_calendar_item_finalize (GObject *object) +{ + EaCalendarItem *ea_calitem; + + g_return_if_fail (EA_IS_CALENDAR_ITEM (object)); + + ea_calitem = EA_CALENDAR_ITEM (object); + + /* Free the allocated cell data */ + ea_calendar_item_destory_cell_data (ea_calitem); + + G_OBJECT_CLASS (parent_class)->finalize (object); +#ifdef ACC_DEBUG + ++n_ea_calendar_item_destroyed; + printf ("ACC_DEBUG: n_ea_calendar_item_destroyed = %d\n", + n_ea_calendar_item_destroyed); +#endif +} + +static G_CONST_RETURN gchar* +ea_calendar_item_get_name (AtkObject *accessible) +{ + GObject *g_obj; + ECalendarItem *calitem; + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + gchar *name_str = NULL; + gchar buffer_start[128] = ""; + gchar buffer_end[128] = ""; + struct tm day_start = { 0 }; + struct tm day_end = { 0 }; + + g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), NULL); + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)); + if (!g_obj) + return NULL; + g_return_val_if_fail (E_IS_CALENDAR_ITEM (g_obj), NULL); + + calitem = E_CALENDAR_ITEM (g_obj); + if (e_calendar_item_get_date_range (calitem, + &start_year, &start_month, &start_day, + &end_year, &end_month, &end_day)) { + + day_start.tm_year = start_year - 1900; + day_start.tm_mon = start_month; + day_start.tm_mday = start_day; + day_start.tm_isdst = -1; + e_utf8_strftime (buffer_start, sizeof (buffer_start), _("%d %B %Y"), &day_start); + + day_end.tm_year = end_year - 1900; + day_end.tm_mon = end_month; + day_end.tm_mday = end_day; + day_end.tm_isdst = -1; + e_utf8_strftime (buffer_end, sizeof (buffer_end), _("%d %B %Y"), &day_end); + + name_str = g_strdup_printf (_("Calendar: from %s to %s"), buffer_start, buffer_end); + } + +#if 0 + if (e_calendar_item_get_selection (calitem, &select_start, &select_end)) { + GDate select_start, select_end; + gint year1, year2, month1, month2, day1, day2; + + year1 = g_date_get_year (&select_start); + month1 = g_date_get_month (&select_start); + day1 = g_date_get_day (&select_start); + + year2 = g_date_get_year (&select_end); + month2 = g_date_get_month (&select_end); + day2 = g_date_get_day (&select_end); + + sprintf (new_name + strlen (new_name), + " : current selection: from %d-%d-%d to %d-%d-%d.", + year1, month1, day1, + year2, month2, day2); + } +#endif + + ATK_OBJECT_CLASS (parent_class)->set_name (accessible, name_str); + g_free (name_str); + + return accessible->name; +} + +static G_CONST_RETURN gchar* +ea_calendar_item_get_description (AtkObject *accessible) +{ + if (accessible->description) + return accessible->description; + + return _("evolution calendar item"); +} + +static AtkStateSet* +ea_calendar_item_ref_state_set (AtkObject *accessible) +{ + AtkStateSet *state_set; + GObject *g_obj; + + state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible); + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)); + if (!g_obj) + return state_set; + + atk_state_set_add_state (state_set, ATK_STATE_ENABLED); + atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE); + + return state_set; +} + +static gint +ea_calendar_item_get_n_children (AtkObject *accessible) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + gint n_children = 0; + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + GDate *start_date, *end_date; + + g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), -1); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + calitem = E_CALENDAR_ITEM (g_obj); + if (!e_calendar_item_get_date_range (calitem, &start_year, + &start_month, &start_day, + &end_year, &end_month, + &end_day)) + return 0; + + start_date = g_date_new_dmy (start_day, start_month + 1, start_year); + end_date = g_date_new_dmy (end_day, end_month + 1, end_year); + + n_children = g_date_days_between (start_date, end_date) + 1; + g_free (start_date); + g_free (end_date); + return n_children; +} + +static AtkObject * +ea_calendar_item_ref_child (AtkObject *accessible, gint index) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + gint n_children; + ECalendarCell *cell; + EaCellTable *cell_data; + EaCalendarItem *ea_calitem; + + g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), NULL); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return NULL; + + calitem = E_CALENDAR_ITEM (g_obj); + + n_children = ea_calendar_item_get_n_children (accessible); + if (index < 0 || index >= n_children) + return NULL; + + ea_calitem = EA_CALENDAR_ITEM (accessible); + cell_data = ea_calendar_item_get_cell_data (ea_calitem); + if (!cell_data) + return NULL; + + cell = ea_cell_table_get_cell_at_index (cell_data, index); + if (!cell) { + cell = e_calendar_cell_new (calitem, + index / EA_CALENDAR_COLUMN_NUM, + index % EA_CALENDAR_COLUMN_NUM); + ea_cell_table_set_cell_at_index (cell_data, index, cell); + g_object_unref (cell); + } + +#ifdef ACC_DEBUG + g_print ("AccDebug: ea_calendar_item children[%d]=%p\n", index, + (gpointer)cell); +#endif + return g_object_ref (atk_gobject_accessible_for_object (G_OBJECT(cell))); +} + +/* atk table interface */ + +static void +atk_table_interface_init (AtkTableIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->ref_at = table_interface_ref_at; + + iface->get_n_rows = table_interface_get_n_rows; + iface->get_n_columns = table_interface_get_n_columns; + iface->get_index_at = table_interface_get_index_at; + iface->get_column_at_index = table_interface_get_column_at_index; + iface->get_row_at_index = table_interface_get_row_at_index; + iface->get_column_extent_at = table_interface_get_column_extent_at; + iface->get_row_extent_at = table_interface_get_row_extent_at; + + iface->is_selected = table_interface_is_selected; + iface->get_selected_rows = table_interface_get_selected_rows; + iface->get_selected_columns = table_interface_get_selected_columns; + iface->is_row_selected = table_interface_is_row_selected; + iface->is_column_selected = table_interface_is_column_selected; + iface->add_row_selection = table_interface_add_row_selection; + iface->remove_row_selection = table_interface_remove_row_selection; + iface->add_column_selection = table_interface_add_column_selection; + iface->remove_column_selection = table_interface_remove_column_selection; + + iface->get_row_header = table_interface_get_row_header; + iface->get_column_header = table_interface_get_column_header; + iface->get_caption = table_interface_get_caption; + iface->get_summary = table_interface_get_summary; + iface->get_row_description = table_interface_get_row_description; + iface->get_column_description = table_interface_get_column_description; +} + +static AtkObject* +table_interface_ref_at (AtkTable *table, + gint row, + gint column) +{ + gint index; + + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + index = EA_CALENDAR_COLUMN_NUM * row + column; + return ea_calendar_item_ref_child (ATK_OBJECT (ea_calitem), index); +} + +static gint +table_interface_get_n_rows (AtkTable *table) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + gint n_children; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem)); + return (n_children - 1) / EA_CALENDAR_COLUMN_NUM + 1; +} + +static gint +table_interface_get_n_columns (AtkTable *table) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + return EA_CALENDAR_COLUMN_NUM; +} + +static gint +table_interface_get_index_at (AtkTable *table, + gint row, + gint column) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + return row * EA_CALENDAR_COLUMN_NUM + column; +} + +static gint +table_interface_get_column_at_index (AtkTable *table, + gint index) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + gint n_children; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem)); + if (index >= 0 && index < n_children) + return index % EA_CALENDAR_COLUMN_NUM; + return -1; +} + +static gint +table_interface_get_row_at_index (AtkTable *table, + gint index) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + gint n_children; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return -1; + + n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem)); + if (index >= 0 && index < n_children) + return index / EA_CALENDAR_COLUMN_NUM; + return -1; +} + +static gint +table_interface_get_column_extent_at (AtkTable *table, + gint row, + gint column) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + calitem = E_CALENDAR_ITEM (g_obj); + return calitem->cell_width; +} + +static gint +table_interface_get_row_extent_at (AtkTable *table, + gint row, gint column) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + calitem = E_CALENDAR_ITEM (g_obj); + return calitem->cell_height; +} + +/* any day in the row is selected, the row is selected */ +static gboolean +table_interface_is_row_selected (AtkTable *table, + gint row) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + gint n_rows; + ECalendarItem *calitem; + gint row_index_start, row_index_end; + gint sel_index_start, sel_index_end; + + GDate start_date, end_date; + + g_return_val_if_fail (EA_IS_CALENDAR_ITEM (table), FALSE); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (table); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + n_rows = table_interface_get_n_rows (table); + if (row < 0 || row >= n_rows) + return FALSE; + + row_index_start = row * EA_CALENDAR_COLUMN_NUM; + row_index_end = row_index_start + EA_CALENDAR_COLUMN_NUM - 1; + + calitem = E_CALENDAR_ITEM (g_obj); + if (!e_calendar_item_get_selection (calitem, &start_date, &end_date)) + return FALSE; + + e_calendar_item_get_offset_for_date (calitem, + g_date_get_year (&start_date), + g_date_get_month (&start_date), + g_date_get_day (&start_date), + &sel_index_start); + e_calendar_item_get_offset_for_date (calitem, + g_date_get_year (&end_date), + g_date_get_month (&end_date), + g_date_get_day (&end_date), + &sel_index_end); + + if ((sel_index_start < row_index_start && + sel_index_end >= row_index_start) || + (sel_index_start >= row_index_start && + sel_index_start <= row_index_end)) + return TRUE; + return FALSE; +} + +static gboolean +table_interface_is_selected (AtkTable *table, + gint row, + gint column) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + gint n_rows, n_columns; + ECalendarItem *calitem; + gint index; + gint sel_index_start, sel_index_end; + + GDate start_date, end_date; + + g_return_val_if_fail (EA_IS_CALENDAR_ITEM (table), FALSE); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (table); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + n_rows = table_interface_get_n_rows (table); + if (row < 0 || row >= n_rows) + return FALSE; + n_columns = table_interface_get_n_columns (table); + if (column < 0 || column >= n_columns) + return FALSE; + + index = table_interface_get_index_at (table, row, column); + + calitem = E_CALENDAR_ITEM (g_obj); + if (!e_calendar_item_get_selection (calitem, &start_date, &end_date)) + return FALSE; + + e_calendar_item_get_offset_for_date (calitem, + g_date_get_year (&start_date), + g_date_get_month (&start_date), + g_date_get_day (&start_date), + &sel_index_start); + e_calendar_item_get_offset_for_date (calitem, + g_date_get_year (&end_date), + g_date_get_month (&end_date), + g_date_get_day (&end_date), &sel_index_end); + + if (sel_index_start <= index && sel_index_end >= index) + return TRUE; + return FALSE; +} + +static gboolean +table_interface_is_column_selected (AtkTable *table, + gint column) +{ + return FALSE; +} + +static gint +table_interface_get_selected_rows (AtkTable *table, + gint **rows_selected) +{ + *rows_selected = NULL; + return -1; +} + +static gint +table_interface_get_selected_columns (AtkTable *table, + gint **columns_selected) +{ + *columns_selected = NULL; + return -1; +} + +static gboolean +table_interface_add_row_selection (AtkTable *table, + gint row) +{ + return FALSE; +} + +static gboolean +table_interface_remove_row_selection (AtkTable *table, + gint row) +{ + return FALSE; +} + +static gboolean +table_interface_add_column_selection (AtkTable *table, + gint column) +{ + return FALSE; +} + +static gboolean +table_interface_remove_column_selection (AtkTable *table, + gint column) +{ + /* FIXME: NOT IMPLEMENTED */ + return FALSE; +} + +static AtkObject* +table_interface_get_row_header (AtkTable *table, + gint row) +{ + /* FIXME: NOT IMPLEMENTED */ + return NULL; +} + +static AtkObject* +table_interface_get_column_header (AtkTable *table, + gint in_col) +{ + /* FIXME: NOT IMPLEMENTED */ + return NULL; +} + +static AtkObject* +table_interface_get_caption (AtkTable *table) +{ + /* FIXME: NOT IMPLEMENTED */ + return NULL; +} + +static G_CONST_RETURN gchar* +table_interface_get_column_description (AtkTable *table, gint in_col) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + const gchar *description = NULL; + EaCellTable *cell_data; + gint n_columns; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return NULL; + + n_columns = table_interface_get_n_columns (table); + if (in_col < 0 || in_col >= n_columns) + return NULL; + cell_data = ea_calendar_item_get_cell_data (ea_calitem); + if (!cell_data) + return NULL; + + description = ea_cell_table_get_column_label (cell_data, in_col); + if (!description) { + gchar buffer[128] = "column description"; + ea_calendar_item_get_column_label (ea_calitem, in_col, + buffer, sizeof (buffer)); + ea_cell_table_set_column_label (cell_data, in_col, buffer); + description = ea_cell_table_get_column_label (cell_data, + in_col); + } + return description; +} + +static G_CONST_RETURN gchar* +table_interface_get_row_description (AtkTable *table, gint row) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table); + const gchar *description = NULL; + EaCellTable *cell_data; + gint n_rows; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return NULL; + + n_rows = table_interface_get_n_rows (table); + if (row < 0 || row >= n_rows) + return NULL; + cell_data = ea_calendar_item_get_cell_data (ea_calitem); + if (!cell_data) + return NULL; + + description = ea_cell_table_get_row_label (cell_data, row); + if (!description) { + gchar buffer[128] = "row description"; + ea_calendar_item_get_row_label (ea_calitem, row, + buffer, sizeof (buffer)); + ea_cell_table_set_row_label (cell_data, row, buffer); + description = ea_cell_table_get_row_label (cell_data, + row); + } + return description; +} + +static AtkObject* +table_interface_get_summary (AtkTable *table) +{ + /* FIXME: NOT IMPLEMENTED */ + return NULL; +} + +/* atkselection interface */ + +static void +atk_selection_interface_init (AtkSelectionIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->add_selection = selection_interface_add_selection; + iface->clear_selection = selection_interface_clear_selection; + iface->ref_selection = selection_interface_ref_selection; + iface->get_selection_count = selection_interface_get_selection_count; + iface->is_child_selected = selection_interface_is_child_selected; +} + +static gboolean +selection_interface_add_selection (AtkSelection *selection, gint index) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection); + gint year, month, day; + GDate start_date, end_date; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + calitem = E_CALENDAR_ITEM (g_obj); + if (!e_calendar_item_get_date_for_offset (calitem, index, + &year, &month, &day)) + return FALSE; + + /* FIXME: not support mulit-selection */ + g_date_set_dmy (&start_date, day, month + 1, year); + end_date = start_date; + e_calendar_item_set_selection (calitem, &start_date, &end_date); + return TRUE; +} + +static gboolean +selection_interface_clear_selection (AtkSelection *selection) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + calitem = E_CALENDAR_ITEM (g_obj); + e_calendar_item_set_selection (calitem, NULL, NULL); + + return TRUE; +} + +static AtkObject* +selection_interface_ref_selection (AtkSelection *selection, gint i) +{ + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection); + gint count, sel_offset; + GDate start_date, end_date; + + count = selection_interface_get_selection_count (selection); + if (i < 0 || i >= count) + return NULL; + + g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (ea_calitem)); + + calitem = E_CALENDAR_ITEM (g_obj); + if (!e_calendar_item_get_selection (calitem, &start_date, &end_date)) + return NULL; + if (!e_calendar_item_get_offset_for_date (calitem, + g_date_get_year (&start_date), + g_date_get_month (&start_date) - 1, + g_date_get_day (&start_date), + &sel_offset)) + return NULL; + + return ea_calendar_item_ref_child (ATK_OBJECT (selection), sel_offset + i); +} + +static gint +selection_interface_get_selection_count (AtkSelection *selection) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection); + GDate start_date, end_date; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return 0; + + calitem = E_CALENDAR_ITEM (g_obj); + if (e_calendar_item_get_selection (calitem, &start_date, &end_date)) + return g_date_days_between (&start_date, &end_date) + 1; + else + return 0; +} + +static gboolean +selection_interface_is_child_selected (AtkSelection *selection, gint index) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection); + gint row, column, n_children; + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + n_children = atk_object_get_n_accessible_children (ATK_OBJECT (selection)); + if (index < 0 || index >= n_children) + return FALSE; + + row = index / EA_CALENDAR_COLUMN_NUM; + column = index % EA_CALENDAR_COLUMN_NUM; + + return table_interface_is_selected (ATK_TABLE (selection), row, column); +} + +/* callbacks */ + +static void +selection_preview_change_cb (ECalendarItem *calitem) +{ + AtkObject *atk_obj; + AtkObject *item_cell; + + g_return_if_fail (E_IS_CALENDAR_ITEM (calitem)); + atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem)); + ea_calendar_item_destory_cell_data (EA_CALENDAR_ITEM (atk_obj)); + + /* only deal with the first selected child, for now */ + item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_obj), + 0); + + if (item_cell) + ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_obj), item_cell); + + g_signal_emit_by_name (atk_obj, + "active-descendant-changed", + item_cell); + g_signal_emit_by_name (atk_obj, "selection_changed"); +} + +static void +date_range_changed_cb (ECalendarItem *calitem) +{ + AtkObject *atk_obj; + AtkObject *item_cell; + + g_return_if_fail (E_IS_CALENDAR_ITEM (calitem)); + atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem)); + ea_calendar_item_destory_cell_data (EA_CALENDAR_ITEM (atk_obj)); + + item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_obj), + 0); + if (item_cell) + ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_obj), item_cell); + + g_signal_emit_by_name (atk_obj, "model_changed"); +} + +/* helpers */ + +static EaCellTable * +ea_calendar_item_get_cell_data (EaCalendarItem *ea_calitem) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + EaCellTable *cell_data; + + g_return_val_if_fail (ea_calitem, NULL); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return NULL; + + cell_data = g_object_get_data (G_OBJECT(ea_calitem), + "ea-calendar-cell-table"); + + if (!cell_data) { + gint n_cells = ea_calendar_item_get_n_children (ATK_OBJECT(ea_calitem)); + cell_data = ea_cell_table_create (n_cells/EA_CALENDAR_COLUMN_NUM, + EA_CALENDAR_COLUMN_NUM, + FALSE); + g_object_set_data (G_OBJECT(ea_calitem), + "ea-calendar-cell-table", cell_data); + } + return cell_data; +} + +static void +ea_calendar_item_destory_cell_data (EaCalendarItem *ea_calitem) +{ + EaCellTable *cell_data; + + g_return_if_fail (ea_calitem); + + cell_data = g_object_get_data (G_OBJECT(ea_calitem), + "ea-calendar-cell-table"); + if (cell_data) { + g_object_set_data (G_OBJECT(ea_calitem), + "ea-calendar-cell-table", NULL); + ea_cell_table_destroy (cell_data); + } +} + +static gboolean +ea_calendar_item_get_row_label (EaCalendarItem *ea_calitem, gint row, + gchar *buffer, gint buffer_size) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + gint index, week_num; + gint year, month, day; + + g_return_val_if_fail (ea_calitem, FALSE); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + calitem = E_CALENDAR_ITEM (g_obj); + + index = atk_table_get_index_at (ATK_TABLE (ea_calitem), row, 0); + if (!e_calendar_item_get_date_for_offset (calitem, index, + &year, &month, &day)) + return FALSE; + + week_num = e_calendar_item_get_week_number (calitem, + day, month, year); + + g_snprintf (buffer, buffer_size, "week number : %d", week_num); + return TRUE; +} + +static gboolean +ea_calendar_item_get_column_label (EaCalendarItem *ea_calitem, gint column, + gchar *buffer, gint buffer_size) +{ + AtkGObjectAccessible *atk_gobj; + GObject *g_obj; + ECalendarItem *calitem; + const gchar *abbr_name; + + g_return_val_if_fail (ea_calitem, FALSE); + + atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem); + g_obj = atk_gobject_accessible_get_object (atk_gobj); + if (!g_obj) + return FALSE; + + /* Columns are 0 = Monday ... 6 = Sunday */ + calitem = E_CALENDAR_ITEM (g_obj); + abbr_name = e_get_weekday_name (column + 1, TRUE); + g_strlcpy (buffer, abbr_name, buffer_size); + + return TRUE; +} + +/* the coordinate the e-calendar canvas coord */ +gboolean +e_calendar_item_get_day_extents (ECalendarItem *calitem, + gint year, gint month, gint date, + gint *x, gint *y, + gint *width, gint *height) +{ + GnomeCanvasItem *item; + GtkWidget *widget; + GtkStyle *style; + PangoFontDescription *font_desc; + PangoContext *pango_context; + PangoFontMetrics *font_metrics; + gint char_height, xthickness, ythickness, text_y; + gint new_year, new_month, num_months, months_offset; + gint month_x, month_y, month_cell_x, month_cell_y; + gint month_row, month_col; + gint day_row, day_col; + gint days_from_week_start; + + g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE); + + item = GNOME_CANVAS_ITEM (calitem); + widget = GTK_WIDGET (item->canvas); + style = widget->style; + + /* Set up Pango prerequisites */ + font_desc = calitem->font_desc; + if (!font_desc) + font_desc = style->font_desc; + pango_context = gtk_widget_get_pango_context (widget); + font_metrics = pango_context_get_metrics (pango_context, font_desc, + pango_context_get_language (pango_context)); + + char_height = + PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)) + + PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics)); + + xthickness = style->xthickness; + ythickness = style->ythickness; + + new_year = year; + new_month = month; + e_calendar_item_normalize_date (calitem, &new_year, &new_month); + num_months = calitem->rows * calitem->cols; + months_offset = (new_year - calitem->year) * 12 + + new_month - calitem->month; + + if (months_offset > num_months || months_offset < 0) + return FALSE; + + month_row = months_offset / calitem->cols; + month_col = months_offset % calitem->cols; + + month_x = item->x1 + xthickness + calitem->x_offset + + month_col * calitem->month_width; + month_y = item->y1 + ythickness + month_row * calitem->month_height; + + month_cell_x = month_x + E_CALENDAR_ITEM_XPAD_BEFORE_WEEK_NUMBERS + + calitem->month_lpad + E_CALENDAR_ITEM_XPAD_BEFORE_CELLS; + text_y = month_y + ythickness * 2 + + E_CALENDAR_ITEM_YPAD_ABOVE_MONTH_NAME + + char_height + E_CALENDAR_ITEM_YPAD_BELOW_MONTH_NAME + + E_CALENDAR_ITEM_YPAD_ABOVE_DAY_LETTERS + calitem->month_tpad; + + month_cell_y = text_y + char_height + + E_CALENDAR_ITEM_YPAD_BELOW_DAY_LETTERS + 1 + + E_CALENDAR_ITEM_YPAD_ABOVE_CELLS; + + days_from_week_start = + e_calendar_item_get_n_days_from_week_start (calitem, new_year, + new_month); + day_row = (date + days_from_week_start - 1) / EA_CALENDAR_COLUMN_NUM; + day_col = (date + days_from_week_start - 1) % EA_CALENDAR_COLUMN_NUM; + + *x = month_cell_x + day_col * calitem->cell_width; + *y = month_cell_y + day_row * calitem->cell_height; + *width = calitem->cell_width; + *height = calitem->cell_height; + + return TRUE; +} + +/* month is from 0 to 11 */ +gboolean +e_calendar_item_get_date_for_offset (ECalendarItem *calitem, gint day_offset, + gint *year, gint *month, gint *day) +{ + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + GDate *start_date; + + g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE); + + if (!e_calendar_item_get_date_range (calitem, &start_year, + &start_month, &start_day, + &end_year, &end_month, + &end_day)) + return FALSE; + + start_date = g_date_new_dmy (start_day, start_month + 1, start_year); + + g_date_add_days (start_date, day_offset); + + *year = g_date_get_year (start_date); + *month = g_date_get_month (start_date) - 1; + *day = g_date_get_day (start_date); + + return TRUE; +} + +/* the arg month is from 0 to 11 */ +static gboolean +e_calendar_item_get_offset_for_date (ECalendarItem *calitem, + gint year, gint month, gint day, + gint *offset) +{ + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + GDate *start_date, *end_date; + + *offset = 0; + g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE); + + if (!e_calendar_item_get_date_range (calitem, &start_year, + &start_month, &start_day, + &end_year, &end_month, + &end_day)) + return FALSE; + + start_date = g_date_new_dmy (start_day, start_month + 1, start_year); + end_date = g_date_new_dmy (day, month + 1, year); + + *offset = g_date_days_between (start_date, end_date); + g_free (start_date); + g_free (end_date); + + return TRUE; +} + +gint +e_calendar_item_get_n_days_from_week_start (ECalendarItem *calitem, + gint year, gint month) +{ + struct tm tmp_tm; + gint start_weekday, days_from_week_start; + + memset (&tmp_tm, 0, sizeof (tmp_tm)); + tmp_tm.tm_year = year - 1900; + tmp_tm.tm_mon = month; + tmp_tm.tm_mday = 1; + tmp_tm.tm_isdst = -1; + mktime (&tmp_tm); + start_weekday = (tmp_tm.tm_wday + 6) % 7; /* 0 to 6 */ + days_from_week_start = (start_weekday + 7 - calitem->week_start_day) + % 7; + return days_from_week_start; +} + +static void +ea_calendar_set_focus_object (EaCalendarItem *ea_calitem, AtkObject *item_cell) +{ + AtkStateSet *state_set, *old_state_set; + AtkObject *old_cell; + + old_cell = (AtkObject *)g_object_get_data (G_OBJECT(ea_calitem), "gail-focus-object"); + if (old_cell && EA_IS_CALENDAR_CELL (old_cell)) { + old_state_set = atk_object_ref_state_set (old_cell); + atk_state_set_remove_state (old_state_set, ATK_STATE_FOCUSED); + g_object_unref (old_state_set); + } + if (old_cell) + g_object_unref (old_cell); + + state_set = atk_object_ref_state_set (item_cell); + atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); + g_object_set_data (G_OBJECT(ea_calitem), "gail-focus-object", item_cell); + g_object_unref (state_set); +} diff --git a/widgets/misc/a11y/ea-calendar-item.h b/widgets/misc/a11y/ea-calendar-item.h new file mode 100644 index 0000000000..87b825b479 --- /dev/null +++ b/widgets/misc/a11y/ea-calendar-item.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 + * + * + * Authors: + * Bolian Yin + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __EA_CALENDAR_ITEM_H__ +#define __EA_CALENDAR_ITEM_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define EA_TYPE_CALENDAR_ITEM (ea_calendar_item_get_type ()) +#define EA_CALENDAR_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EA_TYPE_CALENDAR_ITEM, EaCalendarItem)) +#define EA_CALENDAR_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EA_TYPE_CALENDAR_ITEM, EaCalendarItemClass)) +#define EA_IS_CALENDAR_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EA_TYPE_CALENDAR_ITEM)) +#define EA_IS_CALENDAR_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EA_TYPE_CALENDAR_ITEM)) +#define EA_CALENDAR_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EA_TYPE_CALENDAR_ITEM, EaCalendarItemClass)) + +typedef struct _EaCalendarItem EaCalendarItem; +typedef struct _EaCalendarItemClass EaCalendarItemClass; + +struct _EaCalendarItem +{ + AtkGObjectAccessible parent; +}; + +GType ea_calendar_item_get_type (void); + +struct _EaCalendarItemClass +{ + AtkGObjectAccessibleClass parent_class; +}; + +AtkObject *ea_calendar_item_new (GObject *obj); +gboolean e_calendar_item_get_day_extents (ECalendarItem *calitem, + gint year, gint month, gint date, + gint *x, gint *y, + gint *width, gint *height); +gboolean e_calendar_item_get_date_for_offset (ECalendarItem *calitem, + gint day_offset, + gint *year, gint *month, + gint *day); +gint e_calendar_item_get_n_days_from_week_start (ECalendarItem *calitem, + gint year, gint month); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __EA_CALENDAR_ITEM_H__ */ diff --git a/widgets/misc/a11y/ea-widgets.c b/widgets/misc/a11y/ea-widgets.c new file mode 100644 index 0000000000..239299da0b --- /dev/null +++ b/widgets/misc/a11y/ea-widgets.c @@ -0,0 +1,32 @@ +/* + * 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 + * + * + * Authors: + * Bolian Yin + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "a11y/ea-factory.h" +#include "ea-calendar-item.h" +#include "ea-widgets.h" + +EA_FACTORY_GOBJECT (EA_TYPE_CALENDAR_ITEM, ea_calendar_item, ea_calendar_item_new) + +void e_calendar_item_a11y_init (void) +{ + EA_SET_FACTORY (e_calendar_item_get_type (), ea_calendar_item); +} diff --git a/widgets/misc/a11y/ea-widgets.h b/widgets/misc/a11y/ea-widgets.h new file mode 100644 index 0000000000..d19c908293 --- /dev/null +++ b/widgets/misc/a11y/ea-widgets.h @@ -0,0 +1,32 @@ +/* + * + * 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 + * + * + * Authors: + * Bolian Yin + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/* Evolution Accessibility +*/ + +#ifndef _EA_WIDGETS_H__ +#define _EA_WIDGETS_H__ + +void e_calendar_item_a11y_init (void); + +#endif /* _EA_WIDGETS_H__ */ diff --git a/widgets/misc/e-calendar-item.c b/widgets/misc/e-calendar-item.c index 32e74dd535..d5f5efd462 100644 --- a/widgets/misc/e-calendar-item.c +++ b/widgets/misc/e-calendar-item.c @@ -26,7 +26,7 @@ #endif #include "e-calendar-item.h" -#include "ea-widgets.h" +#include "a11y/ea-widgets.h" #include #include diff --git a/widgets/misc/e-cell-date-edit.c b/widgets/misc/e-cell-date-edit.c deleted file mode 100644 index 97947980d9..0000000000 --- a/widgets/misc/e-cell-date-edit.c +++ /dev/null @@ -1,1033 +0,0 @@ -/* - * 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 - * - * - * Authors: - * Damon Chaplin - * - * 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 -#endif - -#include "e-cell-date-edit.h" - -#include -#include -#include - -#include -#include - -#include -#include
- -#include - -#include - -/* This depends on ECalendar which is why I didn't put it in gal. */ -#include "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/misc/e-cell-date-edit.h b/widgets/misc/e-cell-date-edit.h deleted file mode 100644 index 30dee535e8..0000000000 --- a/widgets/misc/e-cell-date-edit.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * - * 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 - * - * - * Authors: - * Damon Chaplin - * - * 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 -#include
- -#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/misc/e-cell-percent.c b/widgets/misc/e-cell-percent.c deleted file mode 100644 index 94e33489e5..0000000000 --- a/widgets/misc/e-cell-percent.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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 - * - * - * Authors: - * Damon Chaplin - * - * 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 -#endif - -#include - -#include -#include -#include -#include - -#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/misc/e-cell-percent.h b/widgets/misc/e-cell-percent.h deleted file mode 100644 index 46a7ddc3e3..0000000000 --- a/widgets/misc/e-cell-percent.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * 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 - * - * - * Authors: - * Damon Chaplin - * - * 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
- -#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/misc/e-reflow-model.c b/widgets/misc/e-reflow-model.c deleted file mode 100644 index eae3d43324..0000000000 --- a/widgets/misc/e-reflow-model.c +++ /dev/null @@ -1,350 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * - * 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 - * - * - * Authors: - * Chris Lahey - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ -#include - -#include "e-util/e-util.h" - -#include "e-reflow-model.h" - -G_DEFINE_TYPE (EReflowModel, e_reflow_model, G_TYPE_OBJECT) - -#define d(x) - -d(static gint depth = 0;) - - -enum { - MODEL_CHANGED, - COMPARISON_CHANGED, - MODEL_ITEMS_INSERTED, - MODEL_ITEM_CHANGED, - MODEL_ITEM_REMOVED, - LAST_SIGNAL -}; - -static guint e_reflow_model_signals [LAST_SIGNAL] = { 0, }; - -/** - * e_reflow_model_set_width: - * @e_reflow_model: The e-reflow-model to operate on - * @width: The new value for the width of each item. - */ -void -e_reflow_model_set_width (EReflowModel *e_reflow_model, int width) -{ - g_return_if_fail (e_reflow_model != NULL); - g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); - - E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->set_width (e_reflow_model, width); -} - -/** - * e_reflow_model_count: - * @e_reflow_model: The e-reflow-model to operate on - * - * Returns: the number of items in the reflow model. - */ -int -e_reflow_model_count (EReflowModel *e_reflow_model) -{ - g_return_val_if_fail (e_reflow_model != NULL, 0); - g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), 0); - - return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->count (e_reflow_model); -} - -/** - * e_reflow_model_height: - * @e_reflow_model: The e-reflow-model to operate on - * @n: The item number to get the height of. - * @parent: The parent GnomeCanvasItem. - * - * Returns: the height of the nth item. - */ -int -e_reflow_model_height (EReflowModel *e_reflow_model, int n, GnomeCanvasGroup *parent) -{ - g_return_val_if_fail (e_reflow_model != NULL, 0); - g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), 0); - - return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->height (e_reflow_model, n, parent); -} - -/** - * e_reflow_model_incarnate: - * @e_reflow_model: The e-reflow-model to operate on - * @n: The item to create. - * @parent: The parent GnomeCanvasItem to create a child of. - * - * Create a GnomeCanvasItem to represent the nth piece of data. - * - * Returns: the new GnomeCanvasItem. - */ -GnomeCanvasItem * -e_reflow_model_incarnate (EReflowModel *e_reflow_model, int n, GnomeCanvasGroup *parent) -{ - g_return_val_if_fail (e_reflow_model != NULL, NULL); - g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), NULL); - - return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->incarnate (e_reflow_model, n, parent); -} - -/** - * e_reflow_model_compare: - * @e_reflow_model: The e-reflow-model to operate on - * @n1: The first item to compare - * @n2: The second item to compare - * - * Compares item n1 and item n2 to see which should come first. - * - * Returns: strcmp like semantics for the comparison value. - */ -int -e_reflow_model_compare (EReflowModel *e_reflow_model, int n1, int n2) -{ -#if 0 - g_return_val_if_fail (e_reflow_model != NULL, 0); - g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), 0); -#endif - - return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->compare (e_reflow_model, n1, n2); -} - -/** - * e_reflow_model_reincarnate: - * @e_reflow_model: The e-reflow-model to operate on - * @n: The item to create. - * @item: The item to reuse. - * - * Update item to represent the nth piece of data. - */ -void -e_reflow_model_reincarnate (EReflowModel *e_reflow_model, int n, GnomeCanvasItem *item) -{ - g_return_if_fail (e_reflow_model != NULL); - g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); - - E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->reincarnate (e_reflow_model, n, item); -} - -static void -e_reflow_model_class_init (EReflowModelClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - e_reflow_model_signals [MODEL_CHANGED] = - g_signal_new ("model_changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EReflowModelClass, model_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - e_reflow_model_signals [COMPARISON_CHANGED] = - g_signal_new ("comparison_changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EReflowModelClass, comparison_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - e_reflow_model_signals [MODEL_ITEMS_INSERTED] = - g_signal_new ("model_items_inserted", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EReflowModelClass, model_items_inserted), - NULL, NULL, - e_marshal_NONE__INT_INT, - G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); - - e_reflow_model_signals [MODEL_ITEM_CHANGED] = - g_signal_new ("model_item_changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EReflowModelClass, model_item_changed), - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - - e_reflow_model_signals [MODEL_ITEM_REMOVED] = - g_signal_new ("model_item_removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EReflowModelClass, model_item_removed), - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - - klass->set_width = NULL; - klass->count = NULL; - klass->height = NULL; - klass->incarnate = NULL; - klass->reincarnate = NULL; - - klass->model_changed = NULL; - klass->comparison_changed = NULL; - klass->model_items_inserted = NULL; - klass->model_item_removed = NULL; - klass->model_item_changed = NULL; -} - -static void -e_reflow_model_init (EReflowModel *e_reflow_model) -{ -} - -#if d(!)0 -static void -print_tabs (void) -{ - int i; - for (i = 0; i < depth; i++) - g_print("\t"); -} -#endif - -/** - * e_reflow_model_changed: - * @e_reflow_model: the reflow model to notify of the change - * - * Use this function to notify any views of this reflow model that - * the contents of the reflow model have changed. This will emit - * the signal "model_changed" on the @e_reflow_model object. - * - * It is preferable to use the e_reflow_model_item_changed() signal to - * notify of smaller changes than to invalidate the entire model, as - * the views might have ways of caching the information they render - * from the model. - */ -void -e_reflow_model_changed (EReflowModel *e_reflow_model) -{ - g_return_if_fail (e_reflow_model != NULL); - g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); - - d(print_tabs()); - d(g_print("Emitting model_changed on model 0x%p.\n", e_reflow_model)); - d(depth++); - g_signal_emit (e_reflow_model, - e_reflow_model_signals [MODEL_CHANGED], 0); - d(depth--); -} - -/** - * e_reflow_model_comparison_changed: - * @e_reflow_model: the reflow model to notify of the change - * - * Use this function to notify any views of this reflow model that the - * sorting has changed. The actual contents of the items hasn't, so - * there's no need to re-query the model for the heights of the - * individual items. - */ -void -e_reflow_model_comparison_changed (EReflowModel *e_reflow_model) -{ - g_return_if_fail (e_reflow_model != NULL); - g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); - - d(print_tabs()); - d(g_print("Emitting comparison_changed on model 0x%p.\n", e_reflow_model)); - d(depth++); - g_signal_emit (e_reflow_model, - e_reflow_model_signals [COMPARISON_CHANGED], 0); - d(depth--); -} - -/** - * e_reflow_model_items_inserted: - * @e_reflow_model: The model changed. - * @position: The position the items were insert in. - * @count: The number of items inserted. - * - * Use this function to notify any views of the reflow model that a number of items have been inserted. - **/ -void -e_reflow_model_items_inserted (EReflowModel *e_reflow_model, int position, int count) -{ - g_return_if_fail (e_reflow_model != NULL); - g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); - - d(print_tabs()); - d(g_print("Emitting items_inserted on model 0x%p, position=%d, count=%d.\n", e_reflow_model, position, count)); - d(depth++); - g_signal_emit (e_reflow_model, - e_reflow_model_signals [MODEL_ITEMS_INSERTED], 0, - position, count); - d(depth--); -} - -/** - * e_reflow_model_item_removed: - * @e_reflow_model: The model changed. - * @n: The position from which the items were removed. - * - * Use this function to notify any views of the reflow model that an - * item has been removed. - **/ -void -e_reflow_model_item_removed (EReflowModel *e_reflow_model, - int n) -{ - g_return_if_fail (e_reflow_model != NULL); - g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); - - d(print_tabs()); - d(g_print("Emitting item_removed on model 0x%p, n=%d.\n", e_reflow_model, n)); - d(depth++); - g_signal_emit (e_reflow_model, - e_reflow_model_signals [MODEL_ITEM_REMOVED], 0, - n); - d(depth--); -} - - -/** - * e_reflow_model_item_changed: - * @e_reflow_model: the reflow model to notify of the change - * @item: the item that was changed in the model. - * - * Use this function to notify any views of the reflow model that the - * contents of item @item have changed in model such that the height - * has changed or the item needs to be reincarnated. This function - * will emit the "model_item_changed" signal on the @e_reflow_model - * object - */ -void -e_reflow_model_item_changed (EReflowModel *e_reflow_model, int n) -{ - g_return_if_fail (e_reflow_model != NULL); - g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); - - d(print_tabs()); - d(g_print("Emitting item_changed on model 0x%p, n=%d.\n", e_reflow_model, n)); - d(depth++); - g_signal_emit (e_reflow_model, - e_reflow_model_signals [MODEL_ITEM_CHANGED], 0, - n); - d(depth--); -} diff --git a/widgets/misc/e-reflow-model.h b/widgets/misc/e-reflow-model.h deleted file mode 100644 index 7482e5079f..0000000000 --- a/widgets/misc/e-reflow-model.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * - * 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 - * - * - * Authors: - * Chris Lahey - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _E_REFLOW_MODEL_H_ -#define _E_REFLOW_MODEL_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define E_REFLOW_MODEL_TYPE (e_reflow_model_get_type ()) -#define E_REFLOW_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_REFLOW_MODEL_TYPE, EReflowModel)) -#define E_REFLOW_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_REFLOW_MODEL_TYPE, EReflowModelClass)) -#define E_IS_REFLOW_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_REFLOW_MODEL_TYPE)) -#define E_IS_REFLOW_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_REFLOW_MODEL_TYPE)) -#define E_REFLOW_MODEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_REFLOW_MODEL_TYPE, EReflowModelClass)) - -typedef struct { - GObject base; -} EReflowModel; - -typedef struct { - GObjectClass parent_class; - - /* - * Virtual methods - */ - void (*set_width) (EReflowModel *etm, int width); - - int (*count) (EReflowModel *etm); - int (*height) (EReflowModel *etm, int n, GnomeCanvasGroup *parent); - GnomeCanvasItem *(*incarnate) (EReflowModel *etm, int n, GnomeCanvasGroup *parent); - int (*compare) (EReflowModel *etm, int n1, int n2); - void (*reincarnate) (EReflowModel *etm, int n, GnomeCanvasItem *item); - - /* - * Signals - */ - - /* - * These all come after the change has been made. - * Major structural changes: model_changed - * Changes to the sorting of elements: comparison_changed - * Changes only in an item: item_changed - */ - void (*model_changed) (EReflowModel *etm); - void (*comparison_changed) (EReflowModel *etm); - void (*model_items_inserted) (EReflowModel *etm, int position, int count); - void (*model_item_removed) (EReflowModel *etm, int position); - void (*model_item_changed) (EReflowModel *etm, int n); -} EReflowModelClass; - -GType e_reflow_model_get_type (void); - -/**/ -void e_reflow_model_set_width (EReflowModel *e_reflow_model, - int width); -int e_reflow_model_count (EReflowModel *e_reflow_model); -int e_reflow_model_height (EReflowModel *e_reflow_model, - int n, - GnomeCanvasGroup *parent); -GnomeCanvasItem *e_reflow_model_incarnate (EReflowModel *e_reflow_model, - int n, - GnomeCanvasGroup *parent); -int e_reflow_model_compare (EReflowModel *e_reflow_model, - int n1, - int n2); -void e_reflow_model_reincarnate (EReflowModel *e_reflow_model, - int n, - GnomeCanvasItem *item); - -/* - * Routines for emitting signals on the e_reflow - */ -void e_reflow_model_changed (EReflowModel *e_reflow_model); -void e_reflow_model_comparison_changed (EReflowModel *e_reflow_model); -void e_reflow_model_items_inserted (EReflowModel *e_reflow_model, - int position, - int count); -void e_reflow_model_item_removed (EReflowModel *e_reflow_model, - int n); -void e_reflow_model_item_changed (EReflowModel *e_reflow_model, - int n); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* _E_REFLOW_MODEL_H_ */ diff --git a/widgets/misc/e-reflow.c b/widgets/misc/e-reflow.c deleted file mode 100644 index f51a502a83..0000000000 --- a/widgets/misc/e-reflow.c +++ /dev/null @@ -1,1534 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * 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 - * - * - * Authors: - * Chris Lahey - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - */ -#include - -#include -#include - -#include -#include - -#include "text/e-text.h" -#include -#include "e-util/e-util.h" -#include "misc/e-unicode.h" - -#include "e-canvas.h" -#include "e-canvas-utils.h" -#include "e-reflow.h" -#include "e-selection-model-simple.h" - -static gboolean e_reflow_event (GnomeCanvasItem *item, GdkEvent *event); -static void e_reflow_realize (GnomeCanvasItem *item); -static void e_reflow_unrealize (GnomeCanvasItem *item); -static void e_reflow_draw (GnomeCanvasItem *item, GdkDrawable *drawable, - int x, int y, int width, int height); -static void e_reflow_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags); -static double e_reflow_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item); -static void e_reflow_reflow (GnomeCanvasItem *item, int flags); -static void set_empty(EReflow *reflow); - -static void e_reflow_resize_children (GnomeCanvasItem *item); - -#define E_REFLOW_DIVIDER_WIDTH 2 -#define E_REFLOW_BORDER_WIDTH 7 -#define E_REFLOW_FULL_GUTTER (E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH * 2) - -G_DEFINE_TYPE (EReflow, e_reflow, GNOME_TYPE_CANVAS_GROUP) - -/* The arguments we take */ -enum { - PROP_0, - PROP_MINIMUM_WIDTH, - PROP_WIDTH, - PROP_HEIGHT, - PROP_EMPTY_MESSAGE, - PROP_MODEL, - PROP_COLUMN_WIDTH -}; - -enum { - SELECTION_EVENT, - COLUMN_WIDTH_CHANGED, - LAST_SIGNAL -}; - -static guint signals [LAST_SIGNAL] = {0, }; - -static gint -er_compare (int i1, int i2, gpointer user_data) -{ - EReflow *reflow = user_data; - return e_reflow_model_compare (reflow->model, i1, i2); -} - -static gint -e_reflow_pick_line (EReflow *reflow, double x) -{ - x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; - x /= reflow->column_width + E_REFLOW_FULL_GUTTER; - return x; -} - -static int -er_find_item (EReflow *reflow, GnomeCanvasItem *item) -{ - int i; - for (i = 0; i < reflow->count; i++) { - if (reflow->items[i] == item) - return i; - } - return -1; -} - -static void -e_reflow_resize_children (GnomeCanvasItem *item) -{ - EReflow *reflow; - int i; - int count; - - reflow = E_REFLOW (item); - - count = reflow->count; - for (i = 0; i < count; i++) { - if (reflow->items[i]) - gnome_canvas_item_set(reflow->items[i], - "width", (double) reflow->column_width, - NULL); - } -} - -static inline void -e_reflow_update_selection_row (EReflow *reflow, int row) -{ - if (reflow->items[row]) { - g_object_set(reflow->items[row], - "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), row), - NULL); - } else if (e_selection_model_is_row_selected (E_SELECTION_MODEL (reflow->selection), row)) { - reflow->items[row] = e_reflow_model_incarnate (reflow->model, row, GNOME_CANVAS_GROUP (reflow)); - g_object_set (reflow->items[row], - "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), row), - "width", (double) reflow->column_width, - NULL); - } -} - -static void -e_reflow_update_selection (EReflow *reflow) -{ - int i; - int count; - - count = reflow->count; - for (i = 0; i < count; i++) { - e_reflow_update_selection_row (reflow, i); - } -} - -static void -selection_changed (ESelectionModel *selection, EReflow *reflow) -{ - e_reflow_update_selection (reflow); -} - -static void -selection_row_changed (ESelectionModel *selection, int row, EReflow *reflow) -{ - e_reflow_update_selection_row (reflow, row); -} - -static gboolean -do_adjustment (gpointer user_data) -{ - int row; - GtkAdjustment *adj ; - gfloat value, min_value, max_value; - EReflow *reflow = user_data; - - row = reflow->cursor_row; - if (row == -1) - return FALSE; - - adj = gtk_layout_get_hadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (reflow)->canvas)); - value = adj->value; - - if ((!reflow->items) || (!reflow->items[row])) - return TRUE; - min_value = reflow->items[row]->x2 - adj->page_size; - max_value = reflow->items[row]->x1; - - if (value < min_value) - value = min_value; - - if (value > max_value) - value = max_value; - - if (value != adj->value) { - adj->value = value; - gtk_adjustment_value_changed (adj); - } - - reflow->do_adjustment_idle_id = 0; - - return FALSE; -} - -static void -cursor_changed (ESelectionModel *selection, int row, int col, EReflow *reflow) -{ - int count = reflow->count; - int old_cursor = reflow->cursor_row; - - if (old_cursor < count && old_cursor >= 0) { - if (reflow->items[old_cursor]) { - g_object_set (reflow->items[old_cursor], - "has_cursor", FALSE, - NULL); - } - } - - reflow->cursor_row = row; - - if (row < count && row >= 0) { - if (reflow->items[row]) { - g_object_set (reflow->items[row], - "has_cursor", TRUE, - NULL); - } else { - reflow->items[row] = e_reflow_model_incarnate (reflow->model, row, GNOME_CANVAS_GROUP (reflow)); - g_object_set (reflow->items[row], - "has_cursor", TRUE, - "width", (double) reflow->column_width, - NULL); - } - } - - if (reflow->do_adjustment_idle_id == 0) - reflow->do_adjustment_idle_id = g_idle_add (do_adjustment, reflow); - -} - - -static void -incarnate (EReflow *reflow) -{ - int column_width; - int first_column; - int last_column; - int first_cell; - int last_cell; - int i; - GtkAdjustment *adjustment = gtk_layout_get_hadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (reflow)->canvas)); - - column_width = reflow->column_width; - - first_column = adjustment->value - 1 + E_REFLOW_BORDER_WIDTH; - first_column /= column_width + E_REFLOW_FULL_GUTTER; - - last_column = adjustment->value + adjustment->page_size + 1 - E_REFLOW_BORDER_WIDTH - E_REFLOW_DIVIDER_WIDTH; - last_column /= column_width + E_REFLOW_FULL_GUTTER; - last_column ++; - - if (first_column >= 0 && first_column < reflow->column_count) - first_cell = reflow->columns[first_column]; - else - first_cell = 0; - - if (last_column >= 0 && last_column < reflow->column_count) - last_cell = reflow->columns[last_column]; - else - last_cell = reflow->count; - - for (i = first_cell; i < last_cell; i++) { - int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i); - if (reflow->items[unsorted] == NULL) { - if (reflow->model) { - reflow->items[unsorted] = e_reflow_model_incarnate (reflow->model, unsorted, GNOME_CANVAS_GROUP (reflow)); - g_object_set (reflow->items[unsorted], - "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), unsorted), - "width", (double) reflow->column_width, - NULL); - } - } - } - reflow->incarnate_idle_id = 0; -} - -static gboolean -invoke_incarnate (gpointer user_data) -{ - EReflow *reflow = user_data; - incarnate (reflow); - return FALSE; -} - -static void -queue_incarnate (EReflow *reflow) -{ - if (reflow->incarnate_idle_id == 0) - reflow->incarnate_idle_id = - g_idle_add_full (25, invoke_incarnate, reflow, NULL); -} - -static void -reflow_columns (EReflow *reflow) -{ - GSList *list; - int count; - int start; - int i; - int column_count, column_start; - double running_height; - - if (reflow->reflow_from_column <= 1) { - start = 0; - column_count = 1; - column_start = 0; - } - else { - /* we start one column before the earliest new entry, - so we can handle the case where the new entry is - inserted at the start of the column */ - column_start = reflow->reflow_from_column - 1; - start = reflow->columns[column_start]; - column_count = column_start + 1; - } - - list = NULL; - - running_height = E_REFLOW_BORDER_WIDTH; - - count = reflow->count - start; - for (i = start; i < count; i++) { - int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i); - if (i != 0 && running_height + reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH > reflow->height) { - list = g_slist_prepend (list, GINT_TO_POINTER(i)); - column_count ++; - running_height = E_REFLOW_BORDER_WIDTH * 2 + reflow->heights[unsorted]; - } else - running_height += reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH; - } - - reflow->column_count = column_count; - reflow->columns = g_renew (int, reflow->columns, column_count); - column_count --; - - for (; column_count > column_start; column_count--) { - GSList *to_free; - reflow->columns[column_count] = GPOINTER_TO_INT(list->data); - to_free = list; - list = list->next; - g_slist_free_1 (to_free); - } - reflow->columns[column_start] = start; - - queue_incarnate (reflow); - - reflow->need_reflow_columns = FALSE; - reflow->reflow_from_column = -1; -} - -static void -item_changed (EReflowModel *model, int i, EReflow *reflow) -{ - if (i < 0 || i >= reflow->count) - return; - - reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow)); - if (reflow->items[i] != NULL) - e_reflow_model_reincarnate (model, i, reflow->items[i]); - e_sorter_array_clean (reflow->sorter); - reflow->reflow_from_column = -1; - reflow->need_reflow_columns = TRUE; - e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow)); -} - -static void -item_removed (EReflowModel *model, int i, EReflow *reflow) -{ - int c; - int sorted; - - if (i < 0 || i >= reflow->count) - return; - - sorted = e_sorter_model_to_sorted (E_SORTER (reflow->sorter), i); - for (c = reflow->column_count - 1; c >= 0; c--) { - int start_of_column = reflow->columns[c]; - - if (start_of_column <= sorted) { - if (reflow->reflow_from_column == -1 - || reflow->reflow_from_column > c) { - reflow->reflow_from_column = c; - } - break; - } - } - - if (reflow->items[i]) - gtk_object_destroy (GTK_OBJECT (reflow->items[i])); - - memmove (reflow->heights + i, reflow->heights + i + 1, (reflow->count - i - 1) * sizeof (int)); - memmove (reflow->items + i, reflow->items + i + 1, (reflow->count - i - 1) * sizeof (GnomeCanvasItem *)); - - reflow->count --; - - reflow->heights [reflow->count] = 0; - reflow->items [reflow->count] = NULL; - - reflow->need_reflow_columns = TRUE; - set_empty (reflow); - e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow)); - - e_sorter_array_set_count (reflow->sorter, reflow->count); - - e_selection_model_simple_delete_rows (E_SELECTION_MODEL_SIMPLE (reflow->selection), i, 1); -} - -static void -items_inserted (EReflowModel *model, int position, int count, EReflow *reflow) -{ - int i, oldcount; - - if (position < 0 || position > reflow->count) - return; - - oldcount = reflow->count; - - reflow->count += count; - - if (reflow->count > reflow->allocated_count) { - while (reflow->count > reflow->allocated_count) - reflow->allocated_count += 256; - reflow->heights = g_renew (int, reflow->heights, reflow->allocated_count); - reflow->items = g_renew (GnomeCanvasItem *, reflow->items, reflow->allocated_count); - } - memmove (reflow->heights + position + count, reflow->heights + position, (reflow->count - position - count) * sizeof (int)); - memmove (reflow->items + position + count, reflow->items + position, (reflow->count - position - count) * sizeof (GnomeCanvasItem *)); - for (i = position; i < position + count; i++) { - reflow->items[i] = NULL; - reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow)); - } - - e_selection_model_simple_set_row_count (E_SELECTION_MODEL_SIMPLE (reflow->selection), reflow->count); - if (position == oldcount) - e_sorter_array_append (reflow->sorter, count); - else - e_sorter_array_set_count (reflow->sorter, reflow->count); - - for (i = position; i < position + count; i ++) { - int sorted = e_sorter_model_to_sorted (E_SORTER (reflow->sorter), i); - int c; - - for (c = reflow->column_count - 1; c >= 0; c--) { - int start_of_column = reflow->columns[c]; - - if (start_of_column <= sorted) { - if (reflow->reflow_from_column == -1 - || reflow->reflow_from_column > c) { - reflow->reflow_from_column = c; - } - break; - } - } - } - - reflow->need_reflow_columns = TRUE; - set_empty (reflow); - e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow)); -} - -static void -model_changed (EReflowModel *model, EReflow *reflow) -{ - int i; - int count; - int oldcount; - - count = reflow->count; - oldcount = count; - - for (i = 0; i < count; i++) { - if (reflow->items[i]) - gtk_object_destroy (GTK_OBJECT (reflow->items[i])); - } - g_free (reflow->items); - g_free (reflow->heights); - reflow->count = e_reflow_model_count (model); - reflow->allocated_count = reflow->count; - reflow->items = g_new (GnomeCanvasItem *, reflow->count); - reflow->heights = g_new (int, reflow->count); - - count = reflow->count; - for (i = 0; i < count; i++) { - reflow->items[i] = NULL; - reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow)); - } - - e_selection_model_simple_set_row_count (E_SELECTION_MODEL_SIMPLE (reflow->selection), count); - e_sorter_array_set_count (reflow->sorter, reflow->count); - - reflow->need_reflow_columns = TRUE; - if (oldcount > reflow->count) - reflow_columns (reflow); - set_empty (reflow); - e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow)); -} - -static void -comparison_changed (EReflowModel *model, EReflow *reflow) -{ - e_sorter_array_clean (reflow->sorter); - reflow->reflow_from_column = -1; - reflow->need_reflow_columns = TRUE; - e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow)); -} - -static void -set_empty(EReflow *reflow) -{ - if (reflow->count == 0) { - if (reflow->empty_text) { - if (reflow->empty_message) { - gnome_canvas_item_set(reflow->empty_text, - "width", reflow->minimum_width, - "text", reflow->empty_message, - NULL); - e_canvas_item_move_absolute(reflow->empty_text, - reflow->minimum_width / 2, - 0); - } else { - gtk_object_destroy(GTK_OBJECT(reflow->empty_text)); - reflow->empty_text = NULL; - } - } else { - if (reflow->empty_message) { - reflow->empty_text = - gnome_canvas_item_new(GNOME_CANVAS_GROUP(reflow), - e_text_get_type(), - "anchor", GTK_ANCHOR_N, - "width", reflow->minimum_width, - "clip", TRUE, - "use_ellipsis", TRUE, - "justification", GTK_JUSTIFY_CENTER, - "text", reflow->empty_message, - "draw_background", FALSE, - NULL); - e_canvas_item_move_absolute(reflow->empty_text, - reflow->minimum_width / 2, - 0); - } - } - } else { - if (reflow->empty_text) { - gtk_object_destroy(GTK_OBJECT(reflow->empty_text)); - reflow->empty_text = NULL; - } - } -} - -static void -disconnect_model (EReflow *reflow) -{ - if (reflow->model == NULL) - return; - - g_signal_handler_disconnect (reflow->model, - reflow->model_changed_id); - g_signal_handler_disconnect (reflow->model, - reflow->comparison_changed_id); - g_signal_handler_disconnect (reflow->model, - reflow->model_items_inserted_id); - g_signal_handler_disconnect (reflow->model, - reflow->model_item_removed_id); - g_signal_handler_disconnect (reflow->model, - reflow->model_item_changed_id); - g_object_unref (reflow->model); - - reflow->model_changed_id = 0; - reflow->comparison_changed_id = 0; - reflow->model_items_inserted_id = 0; - reflow->model_item_removed_id = 0; - reflow->model_item_changed_id = 0; - reflow->model = NULL; -} - -static void -disconnect_selection (EReflow *reflow) -{ - if (reflow->selection == NULL) - return; - - g_signal_handler_disconnect (reflow->selection, - reflow->selection_changed_id); - g_signal_handler_disconnect (reflow->selection, - reflow->selection_row_changed_id); - g_signal_handler_disconnect (reflow->selection, - reflow->cursor_changed_id); - g_object_unref (reflow->selection); - - reflow->selection_changed_id = 0; - reflow->selection_row_changed_id = 0; - reflow->cursor_changed_id = 0; - reflow->selection = NULL; -} - -static void -connect_model (EReflow *reflow, EReflowModel *model) -{ - if (reflow->model != NULL) - disconnect_model (reflow); - - if (model == NULL) - return; - - reflow->model = model; - g_object_ref (reflow->model); - reflow->model_changed_id = - g_signal_connect (reflow->model, "model_changed", - G_CALLBACK (model_changed), reflow); - reflow->comparison_changed_id = - g_signal_connect (reflow->model, "comparison_changed", - G_CALLBACK (comparison_changed), reflow); - reflow->model_items_inserted_id = - g_signal_connect (reflow->model, "model_items_inserted", - G_CALLBACK (items_inserted), reflow); - reflow->model_item_removed_id = - g_signal_connect (reflow->model, "model_item_removed", - G_CALLBACK (item_removed), reflow); - reflow->model_item_changed_id = - g_signal_connect (reflow->model, "model_item_changed", - G_CALLBACK (item_changed), reflow); - model_changed (model, reflow); -} - -static void -adjustment_changed (GtkAdjustment *adjustment, EReflow *reflow) -{ - queue_incarnate (reflow); -} - -static void -disconnect_adjustment (EReflow *reflow) -{ - if (reflow->adjustment == NULL) - return; - - g_signal_handler_disconnect (reflow->adjustment, - reflow->adjustment_changed_id); - g_signal_handler_disconnect (reflow->adjustment, - reflow->adjustment_value_changed_id); - - g_object_unref (reflow->adjustment); - - reflow->adjustment_changed_id = 0; - reflow->adjustment_value_changed_id = 0; - reflow->adjustment = NULL; -} - -static void -connect_adjustment (EReflow *reflow, GtkAdjustment *adjustment) -{ - if (reflow->adjustment != NULL) - disconnect_adjustment (reflow); - - if (adjustment == NULL) - return; - - reflow->adjustment = adjustment; - reflow->adjustment_changed_id = - g_signal_connect (adjustment, "changed", - G_CALLBACK (adjustment_changed), reflow); - reflow->adjustment_value_changed_id = - g_signal_connect (adjustment, "value_changed", - G_CALLBACK (adjustment_changed), reflow); - g_object_ref (adjustment); -} - -#if 0 -static void -set_scroll_adjustments (GtkLayout *layout, GtkAdjustment *hadj, GtkAdjustment *vadj, EReflow *reflow) -{ - connect_adjustment (reflow, hadj); -} - -static void -connect_set_adjustment (EReflow *reflow) -{ - reflow->set_scroll_adjustments_id = - g_signal_connect (GNOME_CANVAS_ITEM (reflow)->canvas, - "set_scroll_adjustments", - G_CALLBACK (set_scroll_adjustments), reflow); -} -#endif - -static void -disconnect_set_adjustment (EReflow *reflow) -{ - if (reflow->set_scroll_adjustments_id != 0) { - g_signal_handler_disconnect (GNOME_CANVAS_ITEM (reflow)->canvas, - reflow->set_scroll_adjustments_id); - reflow->set_scroll_adjustments_id = 0; - } -} - -static void -column_width_changed (EReflow *reflow) -{ - g_signal_emit (reflow, signals[COLUMN_WIDTH_CHANGED], 0, reflow->column_width); -} - - - - -/* Virtual functions */ -static void -e_reflow_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - GnomeCanvasItem *item; - EReflow *reflow; - - item = GNOME_CANVAS_ITEM (object); - reflow = E_REFLOW (object); - - switch (prop_id){ - case PROP_HEIGHT: - reflow->height = g_value_get_double (value); - reflow->need_reflow_columns = TRUE; - e_canvas_item_request_reflow(item); - break; - case PROP_MINIMUM_WIDTH: - reflow->minimum_width = g_value_get_double (value); - if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS(object)) - set_empty(reflow); - e_canvas_item_request_reflow(item); - break; - case PROP_EMPTY_MESSAGE: - g_free(reflow->empty_message); - reflow->empty_message = g_strdup(g_value_get_string (value)); - if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS(object)) - set_empty(reflow); - break; - case PROP_MODEL: - connect_model (reflow, (EReflowModel *) g_value_get_object (value)); - break; - case PROP_COLUMN_WIDTH: - if (reflow->column_width != g_value_get_double (value)) { - GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); - double old_width = reflow->column_width; - - reflow->column_width = g_value_get_double (value); - adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2; - adjustment->page_increment = adjustment->page_size - adjustment->step_increment; - gtk_adjustment_changed(adjustment); - e_reflow_resize_children(item); - e_canvas_item_request_reflow(item); - - reflow->need_column_resize = TRUE; - gnome_canvas_item_request_update(item); - - if (old_width != reflow->column_width) - column_width_changed (reflow); - } - break; - } -} - -static void -e_reflow_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - EReflow *reflow; - - reflow = E_REFLOW (object); - - switch (prop_id) { - case PROP_MINIMUM_WIDTH: - g_value_set_double (value, reflow->minimum_width); - break; - case PROP_WIDTH: - g_value_set_double (value, reflow->width); - break; - case PROP_HEIGHT: - g_value_set_double (value, reflow->height); - break; - case PROP_EMPTY_MESSAGE: - g_value_set_string (value, reflow->empty_message); - break; - case PROP_MODEL: - g_value_set_object (value, reflow->model); - break; - case PROP_COLUMN_WIDTH: - g_value_set_double (value, reflow->column_width); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -e_reflow_dispose (GObject *object) -{ - EReflow *reflow = E_REFLOW(object); - - g_free (reflow->items); - g_free (reflow->heights); - g_free (reflow->columns); - - reflow->items = NULL; - reflow->heights = NULL; - reflow->columns = NULL; - reflow->count = 0; - reflow->allocated_count = 0; - - if (reflow->incarnate_idle_id) - g_source_remove (reflow->incarnate_idle_id); - reflow->incarnate_idle_id = 0; - - if (reflow->do_adjustment_idle_id) - g_source_remove (reflow->do_adjustment_idle_id); - reflow->do_adjustment_idle_id = 0; - - disconnect_model (reflow); - disconnect_selection (reflow); - - g_free(reflow->empty_message); - reflow->empty_message = NULL; - - if (reflow->sorter) { - g_object_unref (reflow->sorter); - reflow->sorter = NULL; - } - - G_OBJECT_CLASS(e_reflow_parent_class)->dispose (object); -} - -static void -e_reflow_realize (GnomeCanvasItem *item) -{ - EReflow *reflow; - GtkAdjustment *adjustment; - int count; - int i; - - reflow = E_REFLOW (item); - - if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->realize) - (* GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->realize) (item); - - reflow->arrow_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); - reflow->default_cursor = gdk_cursor_new (GDK_LEFT_PTR); - - count = reflow->count; - for(i = 0; i < count; i++) { - if (reflow->items[i]) - gnome_canvas_item_set(reflow->items[i], - "width", reflow->column_width, - NULL); - } - - set_empty(reflow); - - reflow->need_reflow_columns = TRUE; - e_canvas_item_request_reflow(item); - - adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); - -#if 0 - connect_set_adjustment (reflow); -#endif - connect_adjustment (reflow, adjustment); - - adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2; - adjustment->page_increment = adjustment->page_size - adjustment->step_increment; - gtk_adjustment_changed(adjustment); - - if (!item->canvas->aa) { - } -} - -static void -e_reflow_unrealize (GnomeCanvasItem *item) -{ - EReflow *reflow; - - reflow = E_REFLOW (item); - - if (!item->canvas->aa) { - } - - gdk_cursor_unref (reflow->arrow_cursor); - gdk_cursor_unref (reflow->default_cursor); - reflow->arrow_cursor = NULL; - reflow->default_cursor = NULL; - - g_free (reflow->columns); - reflow->columns = NULL; - - disconnect_set_adjustment (reflow); - disconnect_adjustment (reflow); - - if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->unrealize) - (* GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->unrealize) (item); -} - -static gboolean -e_reflow_event (GnomeCanvasItem *item, GdkEvent *event) -{ - EReflow *reflow; - int return_val = FALSE; - - reflow = E_REFLOW (item); - - switch( event->type ) - { - case GDK_KEY_PRESS: - return_val = e_selection_model_key_press(reflow->selection, (GdkEventKey *) event); - break; -#if 0 - if (event->key.keyval == GDK_Tab || - event->key.keyval == GDK_KP_Tab || - event->key.keyval == GDK_ISO_Left_Tab) { - int i; - int count; - count = reflow->count; - for (i = 0; i < count; i++) { - int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i); - GnomeCanvasItem *item = reflow->items[unsorted]; - EFocus has_focus; - if (item) { - g_object_get(item, - "has_focus", &has_focus, - NULL); - if (has_focus) { - if (event->key.state & GDK_SHIFT_MASK) { - if (i == 0) - return FALSE; - i--; - } else { - if (i == count - 1) - return FALSE; - i++; - } - - unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i); - if (reflow->items[unsorted] == NULL) { - reflow->items[unsorted] = e_reflow_model_incarnate (reflow->model, unsorted, GNOME_CANVAS_GROUP (reflow)); - } - - item = reflow->items[unsorted]; - gnome_canvas_item_set(item, - "has_focus", (event->key.state & GDK_SHIFT_MASK) ? E_FOCUS_END : E_FOCUS_START, - NULL); - return TRUE; - } - } - } - } -#endif - case GDK_BUTTON_PRESS: - switch(event->button.button) - { - case 1: - { - GdkEventButton *button = (GdkEventButton *) event; - double n_x; - n_x = button->x; - n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; - n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER)); - - if ( button->y >= E_REFLOW_BORDER_WIDTH && button->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) { - /* don't allow to drag the first line*/ - if (e_reflow_pick_line(reflow, button->x) == 0) - return TRUE; - reflow->which_column_dragged = e_reflow_pick_line(reflow, button->x); - reflow->start_x = reflow->which_column_dragged * (reflow->column_width + E_REFLOW_FULL_GUTTER) - E_REFLOW_DIVIDER_WIDTH / 2; - reflow->temp_column_width = reflow->column_width; - reflow->column_drag = TRUE; - - gnome_canvas_item_grab (item, - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK, - reflow->arrow_cursor, - button->time); - - reflow->previous_temp_column_width = -1; - reflow->need_column_resize = TRUE; - gnome_canvas_item_request_update(item); - return TRUE; - } - } - break; - case 4: - { - GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); - gdouble new_value = adjustment->value; - new_value -= adjustment->step_increment; - gtk_adjustment_set_value(adjustment, new_value); - } - break; - case 5: - { - GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); - gdouble new_value = adjustment->value; - new_value += adjustment->step_increment; - if ( new_value > adjustment->upper - adjustment->page_size ) - new_value = adjustment->upper - adjustment->page_size; - gtk_adjustment_set_value(adjustment, new_value); - } - break; - } - break; - case GDK_BUTTON_RELEASE: - if (reflow->column_drag) { - gdouble old_width = reflow->column_width; - GdkEventButton *button = (GdkEventButton *) event; - GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); - reflow->temp_column_width = reflow->column_width + - (button->x - reflow->start_x)/(reflow->which_column_dragged - e_reflow_pick_line(reflow, adjustment->value)); - if ( reflow->temp_column_width < 50 ) - reflow->temp_column_width = 50; - reflow->column_drag = FALSE; - if ( old_width != reflow->temp_column_width ) { - gtk_adjustment_set_value(adjustment, adjustment->value + e_reflow_pick_line(reflow, adjustment->value) * (reflow->temp_column_width - reflow->column_width)); - reflow->column_width = reflow->temp_column_width; - adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2; - adjustment->page_increment = adjustment->page_size - adjustment->step_increment; - gtk_adjustment_changed(adjustment); - e_reflow_resize_children(item); - e_canvas_item_request_reflow(item); - gnome_canvas_request_redraw(item->canvas, 0, 0, reflow->width, reflow->height); - column_width_changed (reflow); - } - reflow->need_column_resize = TRUE; - gnome_canvas_item_request_update(item); - gnome_canvas_item_ungrab (item, button->time); - return TRUE; - } - break; - case GDK_MOTION_NOTIFY: - if (reflow->column_drag) { - double old_width = reflow->temp_column_width; - GdkEventMotion *motion = (GdkEventMotion *) event; - GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); - reflow->temp_column_width = reflow->column_width + - (motion->x - reflow->start_x)/(reflow->which_column_dragged - e_reflow_pick_line(reflow, adjustment->value)); - if (reflow->temp_column_width < 50) - reflow->temp_column_width = 50; - if (old_width != reflow->temp_column_width) { - reflow->need_column_resize = TRUE; - gnome_canvas_item_request_update(item); - } - return TRUE; - } else { - GdkEventMotion *motion = (GdkEventMotion *) event; - double n_x; - - n_x = motion->x; - n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; - n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER)); - - if ( motion->y >= E_REFLOW_BORDER_WIDTH && motion->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) { - if ( reflow->default_cursor_shown ) { - gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->arrow_cursor); - reflow->default_cursor_shown = FALSE; - } - } else - if ( ! reflow->default_cursor_shown ) { - gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->default_cursor); - reflow->default_cursor_shown = TRUE; - } - - } - break; - case GDK_ENTER_NOTIFY: - if (!reflow->column_drag) { - GdkEventCrossing *crossing = (GdkEventCrossing *) event; - double n_x; - n_x = crossing->x; - n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; - n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER)); - - if ( crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) { - if ( reflow->default_cursor_shown ) { - gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->arrow_cursor); - reflow->default_cursor_shown = FALSE; - } - } - } - break; - case GDK_LEAVE_NOTIFY: - if (!reflow->column_drag) { - GdkEventCrossing *crossing = (GdkEventCrossing *) event; - double n_x; - n_x = crossing->x; - n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; - n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER)); - if ( !( crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) ) { - if ( ! reflow->default_cursor_shown ) { - gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->default_cursor); - reflow->default_cursor_shown = TRUE; - } - } - } - break; - default: - break; - } - if (return_val) - return return_val; - else if (GNOME_CANVAS_ITEM_CLASS( e_reflow_parent_class )->event) - return (* GNOME_CANVAS_ITEM_CLASS( e_reflow_parent_class )->event) (item, event); - else - return FALSE; -} - -static void e_reflow_draw (GnomeCanvasItem *item, GdkDrawable *drawable, - int x, int y, int width, int height) -{ - int x_rect, y_rect, width_rect, height_rect; - gdouble running_width; - EReflow *reflow = E_REFLOW(item); - int i; - double column_width; - - if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->draw) - GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->draw (item, drawable, x, y, width, height); - column_width = reflow->column_width; - running_width = E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; - x_rect = running_width; - y_rect = E_REFLOW_BORDER_WIDTH; - width_rect = E_REFLOW_DIVIDER_WIDTH; - height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2); - - /* Compute first column to draw. */ - i = x; - i /= column_width + E_REFLOW_FULL_GUTTER; - running_width += i * (column_width + E_REFLOW_FULL_GUTTER); - - for ( ; i < reflow->column_count; i++) { - if ( running_width > x + width ) - break; - x_rect = running_width; - gtk_paint_flat_box(GTK_WIDGET(item->canvas)->style, - drawable, - GTK_STATE_ACTIVE, - GTK_SHADOW_NONE, - NULL, - GTK_WIDGET(item->canvas), - "reflow", - x_rect - x, - y_rect - y, - width_rect, - height_rect); - running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; - } - if (reflow->column_drag) { - int start_line = e_reflow_pick_line(reflow, - gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas))->value); - i = x - start_line * (column_width + E_REFLOW_FULL_GUTTER); - running_width = start_line * (column_width + E_REFLOW_FULL_GUTTER); - column_width = reflow->temp_column_width; - running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER); - i += start_line * (column_width + E_REFLOW_FULL_GUTTER); - running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; - x_rect = running_width; - y_rect = E_REFLOW_BORDER_WIDTH; - width_rect = E_REFLOW_DIVIDER_WIDTH; - height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2); - - /* Compute first column to draw. */ - i /= column_width + E_REFLOW_FULL_GUTTER; - running_width += i * (column_width + E_REFLOW_FULL_GUTTER); - - for ( ; i < reflow->column_count; i++) { - if ( running_width > x + width ) - break; - x_rect = running_width; - gdk_draw_rectangle(drawable, - GTK_WIDGET(item->canvas)->style->fg_gc[GTK_STATE_NORMAL], - TRUE, - x_rect - x, - y_rect - y, - width_rect - 1, - height_rect - 1); - running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; - } - } -} - -static void -e_reflow_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags) -{ - EReflow *reflow; - double x0, x1, y0, y1; - - reflow = E_REFLOW (item); - - if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->update) - GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->update (item, affine, clip_path, flags); - - x0 = item->x1; - y0 = item->y1; - x1 = item->x2; - y1 = item->y2; - if ( x1 < x0 + reflow->width ) - x1 = x0 + reflow->width; - if ( y1 < y0 + reflow->height ) - y1 = y0 + reflow->height; - item->x2 = x1; - item->y2 = y1; - - if (reflow->need_height_update) { - x0 = item->x1; - y0 = item->y1; - x1 = item->x2; - y1 = item->y2; - if ( x0 > 0 ) - x0 = 0; - if ( y0 > 0 ) - y0 = 0; - if ( x1 < E_REFLOW(item)->width ) - x1 = E_REFLOW(item)->width; - if ( x1 < E_REFLOW(item)->height ) - x1 = E_REFLOW(item)->height; - - gnome_canvas_request_redraw(item->canvas, x0, y0, x1, y1); - reflow->need_height_update = FALSE; - } else if (reflow->need_column_resize) { - int x_rect, y_rect, width_rect, height_rect; - int start_line = e_reflow_pick_line(reflow, - gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas))->value); - gdouble running_width; - int i; - double column_width; - - if ( reflow->previous_temp_column_width != -1 ) { - running_width = start_line * (reflow->column_width + E_REFLOW_FULL_GUTTER); - column_width = reflow->previous_temp_column_width; - running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER); - running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; - y_rect = E_REFLOW_BORDER_WIDTH; - width_rect = E_REFLOW_DIVIDER_WIDTH; - height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2); - - for ( i = 0; i < reflow->column_count; i++) { - x_rect = running_width; - gnome_canvas_request_redraw(item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect); - running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; - } - } - - if ( reflow->temp_column_width != -1 ) { - running_width = start_line * (reflow->column_width + E_REFLOW_FULL_GUTTER); - column_width = reflow->temp_column_width; - running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER); - running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; - y_rect = E_REFLOW_BORDER_WIDTH; - width_rect = E_REFLOW_DIVIDER_WIDTH; - height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2); - - for ( i = 0; i < reflow->column_count; i++) { - x_rect = running_width; - gnome_canvas_request_redraw(item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect); - running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; - } - } - - reflow->previous_temp_column_width = reflow->temp_column_width; - reflow->need_column_resize = FALSE; - } -} - -static double -e_reflow_point (GnomeCanvasItem *item, - double x, double y, int cx, int cy, - GnomeCanvasItem **actual_item) -{ - double distance = 1; - - *actual_item = NULL; - - if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->point) - distance = GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->point (item, x, y, cx, cy, actual_item); - if ((int) (distance * item->canvas->pixels_per_unit + 0.5) <= item->canvas->close_enough && *actual_item) - return distance; - - *actual_item = item; - return 0; -#if 0 - if (y >= E_REFLOW_BORDER_WIDTH && y <= reflow->height - E_REFLOW_BORDER_WIDTH) { - float n_x; - n_x = x; - n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; - n_x = fmod(n_x, (reflow->column_width + E_REFLOW_FULL_GUTTER)); - if (n_x < E_REFLOW_FULL_GUTTER) { - *actual_item = item; - return 0; - } - } - return distance; -#endif -} - -static void -e_reflow_reflow( GnomeCanvasItem *item, int flags ) -{ - EReflow *reflow = E_REFLOW(item); - gdouble old_width; - gdouble running_width; - gdouble running_height; - int next_column; - int i; - - if (! (GTK_OBJECT_FLAGS (reflow) & GNOME_CANVAS_ITEM_REALIZED)) - return; - - if (reflow->need_reflow_columns) { - reflow_columns (reflow); - } - - old_width = reflow->width; - - running_width = E_REFLOW_BORDER_WIDTH; - running_height = E_REFLOW_BORDER_WIDTH; - - next_column = 1; - - for (i = 0; i < reflow->count; i++) { - int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i); - if (next_column < reflow->column_count && i == reflow->columns[next_column]) { - running_height = E_REFLOW_BORDER_WIDTH; - running_width += reflow->column_width + E_REFLOW_FULL_GUTTER; - next_column ++; - } - - if (unsorted >= 0 && reflow->items[unsorted]) { - e_canvas_item_move_absolute(GNOME_CANVAS_ITEM(reflow->items[unsorted]), - (double) running_width, - (double) running_height); - running_height += reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH; - } - } - reflow->width = running_width + reflow->column_width + E_REFLOW_BORDER_WIDTH; - if ( reflow->width < reflow->minimum_width ) - reflow->width = reflow->minimum_width; - if (old_width != reflow->width) - e_canvas_item_request_parent_reflow(item); -} - -static int -e_reflow_selection_event_real (EReflow *reflow, GnomeCanvasItem *item, GdkEvent *event) -{ - int row; - int return_val = TRUE; - switch (event->type) { - case GDK_BUTTON_PRESS: - switch (event->button.button) { - case 1: /* Fall through. */ - case 2: - row = er_find_item (reflow, item); - if (event->button.button == 1) { - reflow->maybe_did_something = - e_selection_model_maybe_do_something(reflow->selection, row, 0, event->button.state); - reflow->maybe_in_drag = TRUE; - } else { - e_selection_model_do_something(reflow->selection, row, 0, event->button.state); - } - break; - case 3: - row = er_find_item (reflow, item); - e_selection_model_right_click_down(reflow->selection, row, 0, 0); - break; - default: - return_val = FALSE; - break; - } - break; - case GDK_BUTTON_RELEASE: - if (event->button.button == 1) { - if (reflow->maybe_in_drag) { - reflow->maybe_in_drag = FALSE; - if (!reflow->maybe_did_something) { - row = er_find_item (reflow, item); - e_selection_model_do_something(reflow->selection, row, 0, event->button.state); - } - } - } - break; - case GDK_KEY_PRESS: - return_val = e_selection_model_key_press(reflow->selection, (GdkEventKey *) event); - break; - default: - return_val = FALSE; - break; - } - - return return_val; -} - -static void -e_reflow_class_init (EReflowClass *klass) -{ - GObjectClass *object_class; - GnomeCanvasItemClass *item_class; - - object_class = (GObjectClass*) klass; - item_class = (GnomeCanvasItemClass *) klass; - - object_class->set_property = e_reflow_set_property; - object_class->get_property = e_reflow_get_property; - object_class->dispose = e_reflow_dispose; - - /* GnomeCanvasItem method overrides */ - item_class->event = e_reflow_event; - item_class->realize = e_reflow_realize; - item_class->unrealize = e_reflow_unrealize; - item_class->draw = e_reflow_draw; - item_class->update = e_reflow_update; - item_class->point = e_reflow_point; - - klass->selection_event = e_reflow_selection_event_real; - klass->column_width_changed = NULL; - - g_object_class_install_property (object_class, PROP_MINIMUM_WIDTH, - g_param_spec_double ("minimum_width", - _( "Minimum width" ), - _( "Minimum Width" ), - 0.0, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_WIDTH, - g_param_spec_double ("width", - _( "Width" ), - _( "Width" ), - 0.0, G_MAXDOUBLE, 0.0, - G_PARAM_READABLE)); - - - g_object_class_install_property (object_class, PROP_HEIGHT, - g_param_spec_double ("height", - _( "Height" ), - _( "Height" ), - 0.0, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_EMPTY_MESSAGE, - g_param_spec_string ("empty_message", - _( "Empty message" ), - _( "Empty message" ), - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_MODEL, - g_param_spec_object ("model", - _( "Reflow model" ), - _( "Reflow model" ), - E_REFLOW_MODEL_TYPE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_COLUMN_WIDTH, - g_param_spec_double ("column_width", - _( "Column width" ), - _( "Column width" ), - 0.0, G_MAXDOUBLE, 150.0, - G_PARAM_READWRITE)); - - signals [SELECTION_EVENT] = - g_signal_new ("selection_event", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EReflowClass, selection_event), - NULL, NULL, - e_marshal_INT__OBJECT_BOXED, - G_TYPE_INT, 2, G_TYPE_OBJECT, - GDK_TYPE_EVENT); - - signals [COLUMN_WIDTH_CHANGED] = - g_signal_new ("column_width_changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EReflowClass, column_width_changed), - NULL, NULL, - g_cclosure_marshal_VOID__DOUBLE, - G_TYPE_NONE, 1, G_TYPE_DOUBLE); -} - -static void -e_reflow_init (EReflow *reflow) -{ - reflow->model = NULL; - reflow->items = NULL; - reflow->heights = NULL; - reflow->count = 0; - - reflow->columns = NULL; - reflow->column_count = 0; - - reflow->empty_text = NULL; - reflow->empty_message = NULL; - - reflow->minimum_width = 10; - reflow->width = 10; - reflow->height = 10; - - reflow->column_width = 150; - - reflow->column_drag = FALSE; - - reflow->need_height_update = FALSE; - reflow->need_column_resize = FALSE; - reflow->need_reflow_columns = FALSE; - - reflow->maybe_did_something = FALSE; - reflow->maybe_in_drag = FALSE; - - reflow->default_cursor_shown = TRUE; - reflow->arrow_cursor = NULL; - reflow->default_cursor = NULL; - - reflow->cursor_row = -1; - - reflow->incarnate_idle_id = 0; - reflow->do_adjustment_idle_id = 0; - reflow->set_scroll_adjustments_id = 0; - - reflow->selection = E_SELECTION_MODEL (e_selection_model_simple_new()); - reflow->sorter = e_sorter_array_new (er_compare, reflow); - - g_object_set (reflow->selection, - "sorter", reflow->sorter, - NULL); - - reflow->selection_changed_id = - g_signal_connect(reflow->selection, "selection_changed", - G_CALLBACK (selection_changed), reflow); - reflow->selection_row_changed_id = - g_signal_connect(reflow->selection, "selection_row_changed", - G_CALLBACK (selection_row_changed), reflow); - reflow->cursor_changed_id = - g_signal_connect(reflow->selection, "cursor_changed", - G_CALLBACK (cursor_changed), reflow); - - e_canvas_item_set_reflow_callback(GNOME_CANVAS_ITEM(reflow), e_reflow_reflow); -} diff --git a/widgets/misc/e-reflow.h b/widgets/misc/e-reflow.h deleted file mode 100644 index 6d67369209..0000000000 --- a/widgets/misc/e-reflow.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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 - * - * - * Authors: - * Chris Lahey - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef __E_REFLOW_H__ -#define __E_REFLOW_H__ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -/* EReflow - A canvas item container. - * - * The following arguments are available: - * - * name type read/write description - * -------------------------------------------------------------------------------- - * minimum_width double RW minimum width of the reflow. width >= minimum_width - * width double R width of the reflow - * height double RW height of the reflow - */ - -#define E_REFLOW_TYPE (e_reflow_get_type ()) -#define E_REFLOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_REFLOW_TYPE, EReflow)) -#define E_REFLOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_REFLOW_TYPE, EReflowClass)) -#define E_IS_REFLOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_REFLOW_TYPE)) -#define E_IS_REFLOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_REFLOW_TYPE)) - - -typedef struct EReflowPriv EReflowPriv; - -typedef struct _EReflow EReflow; -typedef struct _EReflowClass EReflowClass; - -struct _EReflow -{ - GnomeCanvasGroup parent; - - /* item specific fields */ - EReflowModel *model; - guint model_changed_id; - guint comparison_changed_id; - guint model_items_inserted_id; - guint model_item_removed_id; - guint model_item_changed_id; - - ESelectionModel *selection; - guint selection_changed_id; - guint selection_row_changed_id; - guint cursor_changed_id; - ESorterArray *sorter; - - GtkAdjustment *adjustment; - guint adjustment_changed_id; - guint adjustment_value_changed_id; - guint set_scroll_adjustments_id; - - int *heights; - GnomeCanvasItem **items; - int count; - int allocated_count; - - int *columns; - gint column_count; /* Number of columnns */ - - GnomeCanvasItem *empty_text; - gchar *empty_message; - - double minimum_width; - double width; - double height; - - double column_width; - - int incarnate_idle_id; - int do_adjustment_idle_id; - - /* These are all for when the column is being dragged. */ - gdouble start_x; - gint which_column_dragged; - double temp_column_width; - double previous_temp_column_width; - - int cursor_row; - - int reflow_from_column; - - guint column_drag : 1; - - guint need_height_update : 1; - guint need_column_resize : 1; - guint need_reflow_columns : 1; - - guint default_cursor_shown : 1; - - guint maybe_did_something : 1; - guint maybe_in_drag : 1; - GdkCursor *arrow_cursor; - GdkCursor *default_cursor; -}; - -struct _EReflowClass -{ - GnomeCanvasGroupClass parent_class; - - int (*selection_event) (EReflow *reflow, GnomeCanvasItem *item, GdkEvent *event); - void (*column_width_changed) (EReflow *reflow, double width); -}; - -/* - * To be added to a reflow, an item must have the argument "width" as - * a Read/Write argument and "height" as a Read Only argument. It - * should also do an ECanvas parent reflow request if its size - * changes. - */ -GType e_reflow_get_type (void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __E_REFLOW_H__ */ diff --git a/widgets/misc/e-search-bar.c b/widgets/misc/e-search-bar.c index 050f840fa8..a588b73b0c 100644 --- a/widgets/misc/e-search-bar.c +++ b/widgets/misc/e-search-bar.c @@ -31,11 +31,11 @@ #include #include #include +#include #include #include #include -#include #define E_SEARCH_BAR_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ diff --git a/widgets/misc/e-unicode.c b/widgets/misc/e-unicode.c deleted file mode 100644 index 9d660b6600..0000000000 --- a/widgets/misc/e-unicode.c +++ /dev/null @@ -1,2052 +0,0 @@ -/* - * e-unicode.c - utf-8 support functions for gal - * - * 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 - * - * - * Authors: - * Lauris Kaplinski - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -/* - * TODO: Break simple ligatures in e_utf8_strstrcasedecomp - */ - -#include - -#include -#include -#include -#include -#include -#ifdef HAVE_ALLOCA_H -#include -#endif - -#include -#include -#include - -#include - -#include -#include "e-unicode.h" - -#define d(x) - -#define FONT_TESTING -#define MAX_DECOMP 8 - -static gint e_canonical_decomposition (gunichar ch, gunichar * buf); -static gunichar e_stripped_char (gunichar ch); - -/* FIXME: this has not been ported fully yet - non ASCII people beware. */ - -/* - * This my favourite - * - * strstr doing case insensitive, decomposing search - * - * Lauris - */ - -const gchar * -e_utf8_strstrcasedecomp (const gchar *haystack, const gchar *needle) -{ - gunichar *nuni; - gunichar unival; - gint nlen; - const gchar *o, *p; - - if (haystack == NULL) return NULL; - if (needle == NULL) return NULL; - if (strlen (needle) == 0) return haystack; - if (strlen (haystack) == 0) return NULL; - - nuni = alloca (sizeof (gunichar) * strlen (needle)); - - nlen = 0; - for (p = e_unicode_get_utf8 (needle, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { - gint sc; - sc = e_stripped_char (unival); - if (sc) { - nuni[nlen++] = sc; - } - } - /* NULL means there was illegal utf-8 sequence */ - if (!p) return NULL; - /* If everything is correct, we have decomposed, lowercase, stripped needle */ - if (nlen < 1) return haystack; - - o = haystack; - for (p = e_unicode_get_utf8 (o, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { - gint sc; - sc = e_stripped_char (unival); - if (sc) { - /* We have valid stripped char */ - if (sc == nuni[0]) { - const gchar *q = p; - gint npos = 1; - while (npos < nlen) { - q = e_unicode_get_utf8 (q, &unival); - if (!q || !unival) return NULL; - sc = e_stripped_char (unival); - if ((!sc) || (sc != nuni[npos])) break; - npos++; - } - if (npos == nlen) { - return o; - } - } - } - o = p; - } - - return NULL; -} - -const gchar * -e_utf8_strstrcase (const gchar *haystack, const gchar *needle) -{ - gunichar *nuni; - gunichar unival; - gint nlen; - const gchar *o, *p; - - if (haystack == NULL) return NULL; - if (needle == NULL) return NULL; - if (strlen (needle) == 0) return haystack; - if (strlen (haystack) == 0) return NULL; - - nuni = alloca (sizeof (gunichar) * strlen (needle)); - - nlen = 0; - for (p = e_unicode_get_utf8 (needle, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { - nuni[nlen++] = g_unichar_tolower (unival); - } - /* NULL means there was illegal utf-8 sequence */ - if (!p) return NULL; - - o = haystack; - for (p = e_unicode_get_utf8 (o, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { - gint sc; - sc = g_unichar_tolower (unival); - /* We have valid stripped char */ - if (sc == nuni[0]) { - const gchar *q = p; - gint npos = 1; - while (npos < nlen) { - q = e_unicode_get_utf8 (q, &unival); - if (!q || !unival) return NULL; - sc = g_unichar_tolower (unival); - if (sc != nuni[npos]) break; - npos++; - } - if (npos == nlen) { - return o; - } - } - o = p; - } - - return NULL; -} - -#if 0 -const gchar * -e_utf8_strstrcase (const gchar *haystack, const gchar *needle) -{ - gchar *p; - gunichar *huni, *nuni; - gunichar unival; - gint hlen, nlen, hp, np; - - if (haystack == NULL) return NULL; - if (needle == NULL) return NULL; - if (strlen (needle) == 0) return haystack; - - huni = alloca (sizeof (gunichar) * strlen (haystack)); - - for (hlen = 0, p = e_unicode_get_utf8 (haystack, &unival); p && unival; hlen++, p = e_unicode_get_utf8 (p, &unival)) { - huni[hlen] = g_unichar_tolower (unival); - } - - if (!p) return NULL; - if (hlen == 0) return NULL; - - nuni = alloca (sizeof (gunichar) * strlen (needle)); - - for (nlen = 0, p = e_unicode_get_utf8 (needle, &unival); p && unival; nlen++, p = e_unicode_get_utf8 (p, &unival)) { - nuni[nlen] = g_unichar_tolower (unival); - } - - if (!p) return NULL; - if (nlen == 0) return NULL; - - if (hlen < nlen) return NULL; - - for (hp = 0; hp <= hlen - nlen; hp++) { - for (np = 0; np < nlen; np++) { - if (huni[hp + np] != nuni[np]) break; - } - if (np == nlen) return haystack + unicode_offset_to_index (haystack, hp); - } - - return NULL; -} -#endif - -gchar * -e_utf8_from_gtk_event_key (GtkWidget *widget, guint keyval, const gchar *string) -{ - gint unival; - gchar *utf; - gint unilen; - - if (keyval == GDK_VoidSymbol) { - utf = e_utf8_from_locale_string (string); - } else { - unival = gdk_keyval_to_unicode (keyval); - - if (unival < ' ') return NULL; - - utf = g_new (gchar, 7); - - unilen = e_unichar_to_utf8 (unival, utf); - - utf[unilen] = '\0'; - } - - return utf; -} - -gchar * -e_utf8_from_iconv_string_sized (iconv_t ic, const gchar *string, gint bytes) -{ - char *new, *ob; - const char *ib; - size_t ibl, obl; - - if (!string) return NULL; - - if (ic == (iconv_t) -1) { - gint i; - /* iso-8859-1 */ - ib = (char *) string; - new = ob = (char *)g_new (unsigned char, bytes * 2 + 1); - for (i = 0; i < (bytes); i ++) { - ob += e_unichar_to_utf8 (ib[i], ob); - } - *ob = '\0'; - return new; - } - - ib = string; - ibl = bytes; - new = ob = g_new (gchar, ibl * 6 + 1); - obl = ibl * 6; - - while (ibl > 0) { - camel_iconv (ic, &ib, &ibl, &ob, &obl); - if (ibl > 0) { - gint len; - if ((*ib & 0x80) == 0x00) len = 1; - else if ((*ib &0xe0) == 0xc0) len = 2; - else if ((*ib &0xf0) == 0xe0) len = 3; - else if ((*ib &0xf8) == 0xf0) len = 4; - else { - g_warning ("Invalid UTF-8 sequence"); - break; - } - ib += len; - ibl = bytes - (ib - string); - if (ibl > bytes) ibl = 0; - *ob++ = '_'; - obl--; - } - } - - *ob = '\0'; - - return new; -} - -gchar * -e_utf8_from_iconv_string (iconv_t ic, const gchar *string) -{ - if (!string) return NULL; - return e_utf8_from_iconv_string_sized (ic, string, strlen (string)); -} - -gchar * -e_utf8_to_iconv_string_sized (iconv_t ic, const gchar *string, gint bytes) -{ - char *new, *ob; - const char *ib; - size_t ibl, obl; - - if (!string) return NULL; - - if (ic == (iconv_t) -1) { - gint len; - const gchar *u; - gunichar uc; - - new = (char *)g_new (unsigned char, bytes * 4 + 1); - u = string; - len = 0; - - while ((u) && (u - string < bytes)) { - u = e_unicode_get_utf8 (u, &uc); - new[len++] = uc & 0xff; - } - new[len] = '\0'; - return new; - } - - ib = string; - ibl = bytes; - new = ob = g_new (char, ibl * 4 + 4); - obl = ibl * 4; - - while (ibl > 0) { - camel_iconv (ic, &ib, &ibl, &ob, &obl); - if (ibl > 0) { - gint len; - if ((*ib & 0x80) == 0x00) len = 1; - else if ((*ib &0xe0) == 0xc0) len = 2; - else if ((*ib &0xf0) == 0xe0) len = 3; - else if ((*ib &0xf8) == 0xf0) len = 4; - else { - g_warning ("Invalid UTF-8 sequence"); - break; - } - ib += len; - ibl = bytes - (ib - string); - if (ibl > bytes) ibl = 0; - - /* FIXME: this is wrong... what if the destination charset is 16 or 32 bit? */ - *ob++ = '_'; - obl--; - } - } - - /* Make sure to terminate with plenty of padding */ - memset (ob, 0, 4); - - return new; -} - -gchar * -e_utf8_to_iconv_string (iconv_t ic, const gchar *string) -{ - if (!string) return NULL; - return e_utf8_to_iconv_string_sized (ic, string, strlen (string)); -} - -gchar * -e_utf8_from_charset_string_sized (const gchar *charset, const gchar *string, gint bytes) -{ - iconv_t ic; - char *ret; - - if (!string) return NULL; - - ic = camel_iconv_open("utf-8", charset); - ret = e_utf8_from_iconv_string_sized (ic, string, bytes); - camel_iconv_close(ic); - - return ret; -} - -gchar * -e_utf8_from_charset_string (const gchar *charset, const gchar *string) -{ - if (!string) return NULL; - return e_utf8_from_charset_string_sized (charset, string, strlen (string)); -} - -gchar * -e_utf8_to_charset_string_sized (const gchar *charset, const gchar *string, gint bytes) -{ - iconv_t ic; - char *ret; - - if (!string) return NULL; - - ic = camel_iconv_open(charset, "utf-8"); - ret = e_utf8_to_iconv_string_sized (ic, string, bytes); - camel_iconv_close(ic); - - return ret; -} - -gchar * -e_utf8_to_charset_string (const gchar *charset, const gchar *string) -{ - if (!string) return NULL; - return e_utf8_to_charset_string_sized (charset, string, strlen (string)); -} - -gchar * -e_utf8_from_locale_string_sized (const gchar *string, gint bytes) -{ - iconv_t ic; - char *ret; - - if (!string) return NULL; - - ic = camel_iconv_open("utf-8", camel_iconv_locale_charset()); - ret = e_utf8_from_iconv_string_sized (ic, string, bytes); - camel_iconv_close(ic); - - return ret; -} - -gchar * -e_utf8_from_locale_string (const gchar *string) -{ - if (!string) return NULL; - return e_utf8_from_locale_string_sized (string, strlen (string)); -} - -gchar * -e_utf8_to_locale_string_sized (const gchar *string, gint bytes) -{ - iconv_t ic; - char *ret; - - if (!string) return NULL; - - ic = camel_iconv_open(camel_iconv_locale_charset(), "utf-8"); - ret = e_utf8_to_iconv_string_sized (ic, string, bytes); - camel_iconv_close(ic); - - return ret; -} - -gchar * -e_utf8_to_locale_string (const gchar *string) -{ - if (!string) return NULL; - return e_utf8_to_locale_string_sized (string, strlen (string)); -} - -gboolean -e_utf8_is_ascii (const gchar *string) -{ - char c; - - g_return_val_if_fail (string != NULL, FALSE); - - for (; (c = *string); string++) { - if (c & 0x80) - return FALSE; - } - - return TRUE; -} - -gchar * -e_utf8_gtk_entry_get_text (GtkEntry *entry) -{ - return g_strdup (gtk_entry_get_text (entry)); -} - -gchar * -e_utf8_gtk_editable_get_text (GtkEditable *editable) -{ - return gtk_editable_get_chars (editable, 0, -1); -} - -gchar * -e_utf8_gtk_editable_get_chars (GtkEditable *editable, gint start, gint end) -{ - return gtk_editable_get_chars (editable, start, end); -} - -void -e_utf8_gtk_editable_insert_text (GtkEditable *editable, const gchar *text, gint length, gint *position) -{ - gtk_editable_insert_text (editable, text, length, position); -} - -void -e_utf8_gtk_editable_set_text (GtkEditable *editable, const gchar *text) -{ - int position; - - gtk_editable_delete_text(editable, 0, -1); - gtk_editable_insert_text (editable, text, strlen (text), &position); -} - -void -e_utf8_gtk_entry_set_text (GtkEntry *entry, const gchar *text) -{ - if (!text) - gtk_entry_set_text(entry, ""); - else - gtk_entry_set_text (entry, text); -} - -/* - * Translate \U+XXXX\ sequences to utf8 chars - */ - -gchar * -e_utf8_xml1_decode (const gchar *text) -{ - const guchar *c; - gchar *u, *d; - int len, s; - - g_return_val_if_fail (text != NULL, NULL); - - len = strlen (text)+1; - /* len * 2 is absolute maximum */ - u = d = g_malloc (len * 2); - - c = (guchar *)text; - s = 0; - while (s < len) { - if ((s <= (len - 8)) && - (c[s ] == '\\') && - (c[s + 1] == 'U' ) && - (c[s + 2] == '+' ) && - isxdigit (c[s + 3]) && - isxdigit (c[s + 4]) && - isxdigit (c[s + 5]) && - isxdigit (c[s + 6]) && - (c[s + 7] == '\\')) { - /* Valid \U+XXXX\ sequence */ - int unival; - unival = strtol ((char *)(c + s + 3), NULL, 16); - d += e_unichar_to_utf8 (unival, d); - s += 8; - } else if (c[s] > 127) { - /* fixme: We assume iso-8859-1 currently */ - d += e_unichar_to_utf8 (c[s], d); - s += 1; - } else { - *d++ = c[s++]; - } - } - *d++ = '\0'; - u = g_realloc (u, (d - u)); - - return u; -} - -gchar * -e_utf8_xml1_encode (const gchar *text) -{ - gchar *u, *d, *c; - unsigned int unival; - int len; - - g_return_val_if_fail (text != NULL, NULL); - - len = 0; - for (u = e_unicode_get_utf8 (text, &unival); u && unival; u = e_unicode_get_utf8 (u, &unival)) { - if ((unival >= 0x80) || (unival == '\\')) { - len += 8; - } else { - len += 1; - } - } - d = c = (char *)g_new (guchar, len + 1); - - for (u = e_unicode_get_utf8 (text, &unival); u && unival; u = e_unicode_get_utf8 (u, &unival)) { - if ((unival >= 0x80) || (unival == '\\')) { - *c++ = '\\'; - *c++ = 'U'; - *c++ = '+'; - c += sprintf (c, "%04x", unival); - *c++ = '\\'; - } else { - *c++ = unival; - } - } - *c = '\0'; - - return d; -} - -/** - * e_unichar_to_utf8: - * @c: a ISO10646 character code - * @outbuf: output buffer, must have at least 6 bytes of space. - * If %NULL, the length will be computed and returned - * and nothing will be written to @out. - * - * Convert a single character to utf8 - * - * Return value: number of bytes written - **/ - -gint -e_unichar_to_utf8 (gint c, gchar *outbuf) -{ - size_t len = 0; - int first; - int i; - - if (c < 0x80) - { - first = 0; - len = 1; - } - else if (c < 0x800) - { - first = 0xc0; - len = 2; - } - else if (c < 0x10000) - { - first = 0xe0; - len = 3; - } - else if (c < 0x200000) - { - first = 0xf0; - len = 4; - } - else if (c < 0x4000000) - { - first = 0xf8; - len = 5; - } - else - { - first = 0xfc; - len = 6; - } - - if (outbuf) - { - for (i = len - 1; i > 0; --i) - { - outbuf[i] = (c & 0x3f) | 0x80; - c >>= 6; - } - outbuf[0] = c | first; - } - - return len; -} - -gchar * -e_unicode_get_utf8 (const gchar *text, gunichar *out) -{ - *out = g_utf8_get_char (text); - return (*out == (gunichar)-1) ? NULL : g_utf8_next_char (text); -} - -/* - * Canonical decomposition - * - * It is copied here from libunicode, because we do not want malloc - * - */ - -typedef struct -{ - unsigned short ch; - char *expansion; -} e_decomposition; - -static e_decomposition e_decomp_table[] = -{ - { 0x00c0, "\x00\x41\x03\x00\0" }, - { 0x00c1, "\x00\x41\x03\x01\0" }, - { 0x00c2, "\x00\x41\x03\x02\0" }, - { 0x00c3, "\x00\x41\x03\x03\0" }, - { 0x00c4, "\x00\x41\x03\x08\0" }, - { 0x00c5, "\x00\x41\x03\x0a\0" }, - { 0x00c7, "\x00\x43\x03\x27\0" }, - { 0x00c8, "\x00\x45\x03\x00\0" }, - { 0x00c9, "\x00\x45\x03\x01\0" }, - { 0x00ca, "\x00\x45\x03\x02\0" }, - { 0x00cb, "\x00\x45\x03\x08\0" }, - { 0x00cc, "\x00\x49\x03\x00\0" }, - { 0x00cd, "\x00\x49\x03\x01\0" }, - { 0x00ce, "\x00\x49\x03\x02\0" }, - { 0x00cf, "\x00\x49\x03\x08\0" }, - { 0x00d1, "\x00\x4e\x03\x03\0" }, - { 0x00d2, "\x00\x4f\x03\x00\0" }, - { 0x00d3, "\x00\x4f\x03\x01\0" }, - { 0x00d4, "\x00\x4f\x03\x02\0" }, - { 0x00d5, "\x00\x4f\x03\x03\0" }, - { 0x00d6, "\x00\x4f\x03\x08\0" }, - { 0x00d9, "\x00\x55\x03\x00\0" }, - { 0x00da, "\x00\x55\x03\x01\0" }, - { 0x00db, "\x00\x55\x03\x02\0" }, - { 0x00dc, "\x00\x55\x03\x08\0" }, - { 0x00dd, "\x00\x59\x03\x01\0" }, - { 0x00e0, "\x00\x61\x03\x00\0" }, - { 0x00e1, "\x00\x61\x03\x01\0" }, - { 0x00e2, "\x00\x61\x03\x02\0" }, - { 0x00e3, "\x00\x61\x03\x03\0" }, - { 0x00e4, "\x00\x61\x03\x08\0" }, - { 0x00e5, "\x00\x61\x03\x0a\0" }, - { 0x00e7, "\x00\x63\x03\x27\0" }, - { 0x00e8, "\x00\x65\x03\x00\0" }, - { 0x00e9, "\x00\x65\x03\x01\0" }, - { 0x00ea, "\x00\x65\x03\x02\0" }, - { 0x00eb, "\x00\x65\x03\x08\0" }, - { 0x00ec, "\x00\x69\x03\x00\0" }, - { 0x00ed, "\x00\x69\x03\x01\0" }, - { 0x00ee, "\x00\x69\x03\x02\0" }, - { 0x00ef, "\x00\x69\x03\x08\0" }, - { 0x00f1, "\x00\x6e\x03\x03\0" }, - { 0x00f2, "\x00\x6f\x03\x00\0" }, - { 0x00f3, "\x00\x6f\x03\x01\0" }, - { 0x00f4, "\x00\x6f\x03\x02\0" }, - { 0x00f5, "\x00\x6f\x03\x03\0" }, - { 0x00f6, "\x00\x6f\x03\x08\0" }, - { 0x00f9, "\x00\x75\x03\x00\0" }, - { 0x00fa, "\x00\x75\x03\x01\0" }, - { 0x00fb, "\x00\x75\x03\x02\0" }, - { 0x00fc, "\x00\x75\x03\x08\0" }, - { 0x00fd, "\x00\x79\x03\x01\0" }, - { 0x00ff, "\x00\x79\x03\x08\0" }, - { 0x0100, "\x00\x41\x03\x04\0" }, - { 0x0101, "\x00\x61\x03\x04\0" }, - { 0x0102, "\x00\x41\x03\x06\0" }, - { 0x0103, "\x00\x61\x03\x06\0" }, - { 0x0104, "\x00\x41\x03\x28\0" }, - { 0x0105, "\x00\x61\x03\x28\0" }, - { 0x0106, "\x00\x43\x03\x01\0" }, - { 0x0107, "\x00\x63\x03\x01\0" }, - { 0x0108, "\x00\x43\x03\x02\0" }, - { 0x0109, "\x00\x63\x03\x02\0" }, - { 0x010a, "\x00\x43\x03\x07\0" }, - { 0x010b, "\x00\x63\x03\x07\0" }, - { 0x010c, "\x00\x43\x03\x0c\0" }, - { 0x010d, "\x00\x63\x03\x0c\0" }, - { 0x010e, "\x00\x44\x03\x0c\0" }, - { 0x010f, "\x00\x64\x03\x0c\0" }, - { 0x0112, "\x00\x45\x03\x04\0" }, - { 0x0113, "\x00\x65\x03\x04\0" }, - { 0x0114, "\x00\x45\x03\x06\0" }, - { 0x0115, "\x00\x65\x03\x06\0" }, - { 0x0116, "\x00\x45\x03\x07\0" }, - { 0x0117, "\x00\x65\x03\x07\0" }, - { 0x0118, "\x00\x45\x03\x28\0" }, - { 0x0119, "\x00\x65\x03\x28\0" }, - { 0x011a, "\x00\x45\x03\x0c\0" }, - { 0x011b, "\x00\x65\x03\x0c\0" }, - { 0x011c, "\x00\x47\x03\x02\0" }, - { 0x011d, "\x00\x67\x03\x02\0" }, - { 0x011e, "\x00\x47\x03\x06\0" }, - { 0x011f, "\x00\x67\x03\x06\0" }, - { 0x0120, "\x00\x47\x03\x07\0" }, - { 0x0121, "\x00\x67\x03\x07\0" }, - { 0x0122, "\x00\x47\x03\x27\0" }, - { 0x0123, "\x00\x67\x03\x27\0" }, - { 0x0124, "\x00\x48\x03\x02\0" }, - { 0x0125, "\x00\x68\x03\x02\0" }, - { 0x0128, "\x00\x49\x03\x03\0" }, - { 0x0129, "\x00\x69\x03\x03\0" }, - { 0x012a, "\x00\x49\x03\x04\0" }, - { 0x012b, "\x00\x69\x03\x04\0" }, - { 0x012c, "\x00\x49\x03\x06\0" }, - { 0x012d, "\x00\x69\x03\x06\0" }, - { 0x012e, "\x00\x49\x03\x28\0" }, - { 0x012f, "\x00\x69\x03\x28\0" }, - { 0x0130, "\x00\x49\x03\x07\0" }, - { 0x0134, "\x00\x4a\x03\x02\0" }, - { 0x0135, "\x00\x6a\x03\x02\0" }, - { 0x0136, "\x00\x4b\x03\x27\0" }, - { 0x0137, "\x00\x6b\x03\x27\0" }, - { 0x0139, "\x00\x4c\x03\x01\0" }, - { 0x013a, "\x00\x6c\x03\x01\0" }, - { 0x013b, "\x00\x4c\x03\x27\0" }, - { 0x013c, "\x00\x6c\x03\x27\0" }, - { 0x013d, "\x00\x4c\x03\x0c\0" }, - { 0x013e, "\x00\x6c\x03\x0c\0" }, - { 0x0143, "\x00\x4e\x03\x01\0" }, - { 0x0144, "\x00\x6e\x03\x01\0" }, - { 0x0145, "\x00\x4e\x03\x27\0" }, - { 0x0146, "\x00\x6e\x03\x27\0" }, - { 0x0147, "\x00\x4e\x03\x0c\0" }, - { 0x0148, "\x00\x6e\x03\x0c\0" }, - { 0x014c, "\x00\x4f\x03\x04\0" }, - { 0x014d, "\x00\x6f\x03\x04\0" }, - { 0x014e, "\x00\x4f\x03\x06\0" }, - { 0x014f, "\x00\x6f\x03\x06\0" }, - { 0x0150, "\x00\x4f\x03\x0b\0" }, - { 0x0151, "\x00\x6f\x03\x0b\0" }, - { 0x0154, "\x00\x52\x03\x01\0" }, - { 0x0155, "\x00\x72\x03\x01\0" }, - { 0x0156, "\x00\x52\x03\x27\0" }, - { 0x0157, "\x00\x72\x03\x27\0" }, - { 0x0158, "\x00\x52\x03\x0c\0" }, - { 0x0159, "\x00\x72\x03\x0c\0" }, - { 0x015a, "\x00\x53\x03\x01\0" }, - { 0x015b, "\x00\x73\x03\x01\0" }, - { 0x015c, "\x00\x53\x03\x02\0" }, - { 0x015d, "\x00\x73\x03\x02\0" }, - { 0x015e, "\x00\x53\x03\x27\0" }, - { 0x015f, "\x00\x73\x03\x27\0" }, - { 0x0160, "\x00\x53\x03\x0c\0" }, - { 0x0161, "\x00\x73\x03\x0c\0" }, - { 0x0162, "\x00\x54\x03\x27\0" }, - { 0x0163, "\x00\x74\x03\x27\0" }, - { 0x0164, "\x00\x54\x03\x0c\0" }, - { 0x0165, "\x00\x74\x03\x0c\0" }, - { 0x0168, "\x00\x55\x03\x03\0" }, - { 0x0169, "\x00\x75\x03\x03\0" }, - { 0x016a, "\x00\x55\x03\x04\0" }, - { 0x016b, "\x00\x75\x03\x04\0" }, - { 0x016c, "\x00\x55\x03\x06\0" }, - { 0x016d, "\x00\x75\x03\x06\0" }, - { 0x016e, "\x00\x55\x03\x0a\0" }, - { 0x016f, "\x00\x75\x03\x0a\0" }, - { 0x0170, "\x00\x55\x03\x0b\0" }, - { 0x0171, "\x00\x75\x03\x0b\0" }, - { 0x0172, "\x00\x55\x03\x28\0" }, - { 0x0173, "\x00\x75\x03\x28\0" }, - { 0x0174, "\x00\x57\x03\x02\0" }, - { 0x0175, "\x00\x77\x03\x02\0" }, - { 0x0176, "\x00\x59\x03\x02\0" }, - { 0x0177, "\x00\x79\x03\x02\0" }, - { 0x0178, "\x00\x59\x03\x08\0" }, - { 0x0179, "\x00\x5a\x03\x01\0" }, - { 0x017a, "\x00\x7a\x03\x01\0" }, - { 0x017b, "\x00\x5a\x03\x07\0" }, - { 0x017c, "\x00\x7a\x03\x07\0" }, - { 0x017d, "\x00\x5a\x03\x0c\0" }, - { 0x017e, "\x00\x7a\x03\x0c\0" }, - { 0x01a0, "\x00\x4f\x03\x1b\0" }, - { 0x01a1, "\x00\x6f\x03\x1b\0" }, - { 0x01af, "\x00\x55\x03\x1b\0" }, - { 0x01b0, "\x00\x75\x03\x1b\0" }, - { 0x01cd, "\x00\x41\x03\x0c\0" }, - { 0x01ce, "\x00\x61\x03\x0c\0" }, - { 0x01cf, "\x00\x49\x03\x0c\0" }, - { 0x01d0, "\x00\x69\x03\x0c\0" }, - { 0x01d1, "\x00\x4f\x03\x0c\0" }, - { 0x01d2, "\x00\x6f\x03\x0c\0" }, - { 0x01d3, "\x00\x55\x03\x0c\0" }, - { 0x01d4, "\x00\x75\x03\x0c\0" }, - { 0x01d5, "\x00\x55\x03\x08\x03\x04\0" }, - { 0x01d6, "\x00\x75\x03\x08\x03\x04\0" }, - { 0x01d7, "\x00\x55\x03\x08\x03\x01\0" }, - { 0x01d8, "\x00\x75\x03\x08\x03\x01\0" }, - { 0x01d9, "\x00\x55\x03\x08\x03\x0c\0" }, - { 0x01da, "\x00\x75\x03\x08\x03\x0c\0" }, - { 0x01db, "\x00\x55\x03\x08\x03\x00\0" }, - { 0x01dc, "\x00\x75\x03\x08\x03\x00\0" }, - { 0x01de, "\x00\x41\x03\x08\x03\x04\0" }, - { 0x01df, "\x00\x61\x03\x08\x03\x04\0" }, - { 0x01e0, "\x00\x41\x03\x07\x03\x04\0" }, - { 0x01e1, "\x00\x61\x03\x07\x03\x04\0" }, - { 0x01e2, "\x00\xc6\x03\x04\0" }, - { 0x01e3, "\x00\xe6\x03\x04\0" }, - { 0x01e6, "\x00\x47\x03\x0c\0" }, - { 0x01e7, "\x00\x67\x03\x0c\0" }, - { 0x01e8, "\x00\x4b\x03\x0c\0" }, - { 0x01e9, "\x00\x6b\x03\x0c\0" }, - { 0x01ea, "\x00\x4f\x03\x28\0" }, - { 0x01eb, "\x00\x6f\x03\x28\0" }, - { 0x01ec, "\x00\x4f\x03\x28\x03\x04\0" }, - { 0x01ed, "\x00\x6f\x03\x28\x03\x04\0" }, - { 0x01ee, "\x01\xb7\x03\x0c\0" }, - { 0x01ef, "\x02\x92\x03\x0c\0" }, - { 0x01f0, "\x00\x6a\x03\x0c\0" }, - { 0x01f4, "\x00\x47\x03\x01\0" }, - { 0x01f5, "\x00\x67\x03\x01\0" }, - { 0x01fa, "\x00\x41\x03\x0a\x03\x01\0" }, - { 0x01fb, "\x00\x61\x03\x0a\x03\x01\0" }, - { 0x01fc, "\x00\xc6\x03\x01\0" }, - { 0x01fd, "\x00\xe6\x03\x01\0" }, - { 0x01fe, "\x00\xd8\x03\x01\0" }, - { 0x01ff, "\x00\xf8\x03\x01\0" }, - { 0x0200, "\x00\x41\x03\x0f\0" }, - { 0x0201, "\x00\x61\x03\x0f\0" }, - { 0x0202, "\x00\x41\x03\x11\0" }, - { 0x0203, "\x00\x61\x03\x11\0" }, - { 0x0204, "\x00\x45\x03\x0f\0" }, - { 0x0205, "\x00\x65\x03\x0f\0" }, - { 0x0206, "\x00\x45\x03\x11\0" }, - { 0x0207, "\x00\x65\x03\x11\0" }, - { 0x0208, "\x00\x49\x03\x0f\0" }, - { 0x0209, "\x00\x69\x03\x0f\0" }, - { 0x020a, "\x00\x49\x03\x11\0" }, - { 0x020b, "\x00\x69\x03\x11\0" }, - { 0x020c, "\x00\x4f\x03\x0f\0" }, - { 0x020d, "\x00\x6f\x03\x0f\0" }, - { 0x020e, "\x00\x4f\x03\x11\0" }, - { 0x020f, "\x00\x6f\x03\x11\0" }, - { 0x0210, "\x00\x52\x03\x0f\0" }, - { 0x0211, "\x00\x72\x03\x0f\0" }, - { 0x0212, "\x00\x52\x03\x11\0" }, - { 0x0213, "\x00\x72\x03\x11\0" }, - { 0x0214, "\x00\x55\x03\x0f\0" }, - { 0x0215, "\x00\x75\x03\x0f\0" }, - { 0x0216, "\x00\x55\x03\x11\0" }, - { 0x0217, "\x00\x75\x03\x11\0" }, - { 0x0340, "\x03\x00\0" }, - { 0x0341, "\x03\x01\0" }, - { 0x0343, "\x03\x13\0" }, - { 0x0344, "\x03\x08\x03\x01\0" }, - { 0x0374, "\x02\xb9\0" }, - { 0x037e, "\x00\x3b\0" }, - { 0x0385, "\x00\xa8\x03\x01\0" }, - { 0x0386, "\x03\x91\x03\x01\0" }, - { 0x0387, "\x00\xb7\0" }, - { 0x0388, "\x03\x95\x03\x01\0" }, - { 0x0389, "\x03\x97\x03\x01\0" }, - { 0x038a, "\x03\x99\x03\x01\0" }, - { 0x038c, "\x03\x9f\x03\x01\0" }, - { 0x038e, "\x03\xa5\x03\x01\0" }, - { 0x038f, "\x03\xa9\x03\x01\0" }, - { 0x0390, "\x03\xb9\x03\x08\x03\x01\0" }, - { 0x03aa, "\x03\x99\x03\x08\0" }, - { 0x03ab, "\x03\xa5\x03\x08\0" }, - { 0x03ac, "\x03\xb1\x03\x01\0" }, - { 0x03ad, "\x03\xb5\x03\x01\0" }, - { 0x03ae, "\x03\xb7\x03\x01\0" }, - { 0x03af, "\x03\xb9\x03\x01\0" }, - { 0x03b0, "\x03\xc5\x03\x08\x03\x01\0" }, - { 0x03ca, "\x03\xb9\x03\x08\0" }, - { 0x03cb, "\x03\xc5\x03\x08\0" }, - { 0x03cc, "\x03\xbf\x03\x01\0" }, - { 0x03cd, "\x03\xc5\x03\x01\0" }, - { 0x03ce, "\x03\xc9\x03\x01\0" }, - { 0x03d3, "\x03\xd2\x03\x01\0" }, - { 0x03d4, "\x03\xd2\x03\x08\0" }, - { 0x0401, "\x04\x15\x03\x08\0" }, - { 0x0403, "\x04\x13\x03\x01\0" }, - { 0x0407, "\x04\x06\x03\x08\0" }, - { 0x040c, "\x04\x1a\x03\x01\0" }, - { 0x040e, "\x04\x23\x03\x06\0" }, - { 0x0419, "\x04\x18\x03\x06\0" }, - { 0x0439, "\x04\x38\x03\x06\0" }, - { 0x0451, "\x04\x35\x03\x08\0" }, - { 0x0453, "\x04\x33\x03\x01\0" }, - { 0x0457, "\x04\x56\x03\x08\0" }, - { 0x045c, "\x04\x3a\x03\x01\0" }, - { 0x045e, "\x04\x43\x03\x06\0" }, - { 0x0476, "\x04\x74\x03\x0f\0" }, - { 0x0477, "\x04\x75\x03\x0f\0" }, - { 0x04c1, "\x04\x16\x03\x06\0" }, - { 0x04c2, "\x04\x36\x03\x06\0" }, - { 0x04d0, "\x04\x10\x03\x06\0" }, - { 0x04d1, "\x04\x30\x03\x06\0" }, - { 0x04d2, "\x04\x10\x03\x08\0" }, - { 0x04d3, "\x04\x30\x03\x08\0" }, - { 0x04d6, "\x04\x15\x03\x06\0" }, - { 0x04d7, "\x04\x35\x03\x06\0" }, - { 0x04da, "\x04\xd8\x03\x08\0" }, - { 0x04db, "\x04\xd9\x03\x08\0" }, - { 0x04dc, "\x04\x16\x03\x08\0" }, - { 0x04dd, "\x04\x36\x03\x08\0" }, - { 0x04de, "\x04\x17\x03\x08\0" }, - { 0x04df, "\x04\x37\x03\x08\0" }, - { 0x04e2, "\x04\x18\x03\x04\0" }, - { 0x04e3, "\x04\x38\x03\x04\0" }, - { 0x04e4, "\x04\x18\x03\x08\0" }, - { 0x04e5, "\x04\x38\x03\x08\0" }, - { 0x04e6, "\x04\x1e\x03\x08\0" }, - { 0x04e7, "\x04\x3e\x03\x08\0" }, - { 0x04ea, "\x04\xe8\x03\x08\0" }, - { 0x04eb, "\x04\xe9\x03\x08\0" }, - { 0x04ee, "\x04\x23\x03\x04\0" }, - { 0x04ef, "\x04\x43\x03\x04\0" }, - { 0x04f0, "\x04\x23\x03\x08\0" }, - { 0x04f1, "\x04\x43\x03\x08\0" }, - { 0x04f2, "\x04\x23\x03\x0b\0" }, - { 0x04f3, "\x04\x43\x03\x0b\0" }, - { 0x04f4, "\x04\x27\x03\x08\0" }, - { 0x04f5, "\x04\x47\x03\x08\0" }, - { 0x04f8, "\x04\x2b\x03\x08\0" }, - { 0x04f9, "\x04\x4b\x03\x08\0" }, - { 0x0929, "\x09\x28\x09\x3c\0" }, - { 0x0931, "\x09\x30\x09\x3c\0" }, - { 0x0934, "\x09\x33\x09\x3c\0" }, - { 0x0958, "\x09\x15\x09\x3c\0" }, - { 0x0959, "\x09\x16\x09\x3c\0" }, - { 0x095a, "\x09\x17\x09\x3c\0" }, - { 0x095b, "\x09\x1c\x09\x3c\0" }, - { 0x095c, "\x09\x21\x09\x3c\0" }, - { 0x095d, "\x09\x22\x09\x3c\0" }, - { 0x095e, "\x09\x2b\x09\x3c\0" }, - { 0x095f, "\x09\x2f\x09\x3c\0" }, - { 0x09b0, "\x09\xac\x09\xbc\0" }, - { 0x09cb, "\x09\xc7\x09\xbe\0" }, - { 0x09cc, "\x09\xc7\x09\xd7\0" }, - { 0x09dc, "\x09\xa1\x09\xbc\0" }, - { 0x09dd, "\x09\xa2\x09\xbc\0" }, - { 0x09df, "\x09\xaf\x09\xbc\0" }, - { 0x0a59, "\x0a\x16\x0a\x3c\0" }, - { 0x0a5a, "\x0a\x17\x0a\x3c\0" }, - { 0x0a5b, "\x0a\x1c\x0a\x3c\0" }, - { 0x0a5c, "\x0a\x21\x0a\x3c\0" }, - { 0x0a5e, "\x0a\x2b\x0a\x3c\0" }, - { 0x0b48, "\x0b\x47\x0b\x56\0" }, - { 0x0b4b, "\x0b\x47\x0b\x3e\0" }, - { 0x0b4c, "\x0b\x47\x0b\x57\0" }, - { 0x0b5c, "\x0b\x21\x0b\x3c\0" }, - { 0x0b5d, "\x0b\x22\x0b\x3c\0" }, - { 0x0b5f, "\x0b\x2f\x0b\x3c\0" }, - { 0x0b94, "\x0b\x92\x0b\xd7\0" }, - { 0x0bca, "\x0b\xc6\x0b\xbe\0" }, - { 0x0bcb, "\x0b\xc7\x0b\xbe\0" }, - { 0x0bcc, "\x0b\xc6\x0b\xd7\0" }, - { 0x0c48, "\x0c\x46\x0c\x56\0" }, - { 0x0cc0, "\x0c\xbf\x0c\xd5\0" }, - { 0x0cc7, "\x0c\xc6\x0c\xd5\0" }, - { 0x0cc8, "\x0c\xc6\x0c\xd6\0" }, - { 0x0cca, "\x0c\xc6\x0c\xc2\0" }, - { 0x0ccb, "\x0c\xc6\x0c\xc2\x0c\xd5\0" }, - { 0x0d4a, "\x0d\x46\x0d\x3e\0" }, - { 0x0d4b, "\x0d\x47\x0d\x3e\0" }, - { 0x0d4c, "\x0d\x46\x0d\x57\0" }, - { 0x0e33, "\x0e\x4d\x0e\x32\0" }, - { 0x0eb3, "\x0e\xcd\x0e\xb2\0" }, - { 0x0f43, "\x0f\x42\x0f\xb7\0" }, - { 0x0f4d, "\x0f\x4c\x0f\xb7\0" }, - { 0x0f52, "\x0f\x51\x0f\xb7\0" }, - { 0x0f57, "\x0f\x56\x0f\xb7\0" }, - { 0x0f5c, "\x0f\x5b\x0f\xb7\0" }, - { 0x0f69, "\x0f\x40\x0f\xb5\0" }, - { 0x0f73, "\x0f\x71\x0f\x72\0" }, - { 0x0f75, "\x0f\x71\x0f\x74\0" }, - { 0x0f76, "\x0f\xb2\x0f\x80\0" }, - { 0x0f78, "\x0f\xb3\x0f\x80\0" }, - { 0x0f81, "\x0f\x71\x0f\x80\0" }, - { 0x0f93, "\x0f\x92\x0f\xb7\0" }, - { 0x0f9d, "\x0f\x9c\x0f\xb7\0" }, - { 0x0fa2, "\x0f\xa1\x0f\xb7\0" }, - { 0x0fa7, "\x0f\xa6\x0f\xb7\0" }, - { 0x0fac, "\x0f\xab\x0f\xb7\0" }, - { 0x0fb9, "\x0f\x90\x0f\xb5\0" }, - { 0x1e00, "\x00\x41\x03\x25\0" }, - { 0x1e01, "\x00\x61\x03\x25\0" }, - { 0x1e02, "\x00\x42\x03\x07\0" }, - { 0x1e03, "\x00\x62\x03\x07\0" }, - { 0x1e04, "\x00\x42\x03\x23\0" }, - { 0x1e05, "\x00\x62\x03\x23\0" }, - { 0x1e06, "\x00\x42\x03\x31\0" }, - { 0x1e07, "\x00\x62\x03\x31\0" }, - { 0x1e08, "\x00\x43\x03\x27\x03\x01\0" }, - { 0x1e09, "\x00\x63\x03\x27\x03\x01\0" }, - { 0x1e0a, "\x00\x44\x03\x07\0" }, - { 0x1e0b, "\x00\x64\x03\x07\0" }, - { 0x1e0c, "\x00\x44\x03\x23\0" }, - { 0x1e0d, "\x00\x64\x03\x23\0" }, - { 0x1e0e, "\x00\x44\x03\x31\0" }, - { 0x1e0f, "\x00\x64\x03\x31\0" }, - { 0x1e10, "\x00\x44\x03\x27\0" }, - { 0x1e11, "\x00\x64\x03\x27\0" }, - { 0x1e12, "\x00\x44\x03\x2d\0" }, - { 0x1e13, "\x00\x64\x03\x2d\0" }, - { 0x1e14, "\x00\x45\x03\x04\x03\x00\0" }, - { 0x1e15, "\x00\x65\x03\x04\x03\x00\0" }, - { 0x1e16, "\x00\x45\x03\x04\x03\x01\0" }, - { 0x1e17, "\x00\x65\x03\x04\x03\x01\0" }, - { 0x1e18, "\x00\x45\x03\x2d\0" }, - { 0x1e19, "\x00\x65\x03\x2d\0" }, - { 0x1e1a, "\x00\x45\x03\x30\0" }, - { 0x1e1b, "\x00\x65\x03\x30\0" }, - { 0x1e1c, "\x00\x45\x03\x27\x03\x06\0" }, - { 0x1e1d, "\x00\x65\x03\x27\x03\x06\0" }, - { 0x1e1e, "\x00\x46\x03\x07\0" }, - { 0x1e1f, "\x00\x66\x03\x07\0" }, - { 0x1e20, "\x00\x47\x03\x04\0" }, - { 0x1e21, "\x00\x67\x03\x04\0" }, - { 0x1e22, "\x00\x48\x03\x07\0" }, - { 0x1e23, "\x00\x68\x03\x07\0" }, - { 0x1e24, "\x00\x48\x03\x23\0" }, - { 0x1e25, "\x00\x68\x03\x23\0" }, - { 0x1e26, "\x00\x48\x03\x08\0" }, - { 0x1e27, "\x00\x68\x03\x08\0" }, - { 0x1e28, "\x00\x48\x03\x27\0" }, - { 0x1e29, "\x00\x68\x03\x27\0" }, - { 0x1e2a, "\x00\x48\x03\x2e\0" }, - { 0x1e2b, "\x00\x68\x03\x2e\0" }, - { 0x1e2c, "\x00\x49\x03\x30\0" }, - { 0x1e2d, "\x00\x69\x03\x30\0" }, - { 0x1e2e, "\x00\x49\x03\x08\x03\x01\0" }, - { 0x1e2f, "\x00\x69\x03\x08\x03\x01\0" }, - { 0x1e30, "\x00\x4b\x03\x01\0" }, - { 0x1e31, "\x00\x6b\x03\x01\0" }, - { 0x1e32, "\x00\x4b\x03\x23\0" }, - { 0x1e33, "\x00\x6b\x03\x23\0" }, - { 0x1e34, "\x00\x4b\x03\x31\0" }, - { 0x1e35, "\x00\x6b\x03\x31\0" }, - { 0x1e36, "\x00\x4c\x03\x23\0" }, - { 0x1e37, "\x00\x6c\x03\x23\0" }, - { 0x1e38, "\x00\x4c\x03\x23\x03\x04\0" }, - { 0x1e39, "\x00\x6c\x03\x23\x03\x04\0" }, - { 0x1e3a, "\x00\x4c\x03\x31\0" }, - { 0x1e3b, "\x00\x6c\x03\x31\0" }, - { 0x1e3c, "\x00\x4c\x03\x2d\0" }, - { 0x1e3d, "\x00\x6c\x03\x2d\0" }, - { 0x1e3e, "\x00\x4d\x03\x01\0" }, - { 0x1e3f, "\x00\x6d\x03\x01\0" }, - { 0x1e40, "\x00\x4d\x03\x07\0" }, - { 0x1e41, "\x00\x6d\x03\x07\0" }, - { 0x1e42, "\x00\x4d\x03\x23\0" }, - { 0x1e43, "\x00\x6d\x03\x23\0" }, - { 0x1e44, "\x00\x4e\x03\x07\0" }, - { 0x1e45, "\x00\x6e\x03\x07\0" }, - { 0x1e46, "\x00\x4e\x03\x23\0" }, - { 0x1e47, "\x00\x6e\x03\x23\0" }, - { 0x1e48, "\x00\x4e\x03\x31\0" }, - { 0x1e49, "\x00\x6e\x03\x31\0" }, - { 0x1e4a, "\x00\x4e\x03\x2d\0" }, - { 0x1e4b, "\x00\x6e\x03\x2d\0" }, - { 0x1e4c, "\x00\x4f\x03\x03\x03\x01\0" }, - { 0x1e4d, "\x00\x6f\x03\x03\x03\x01\0" }, - { 0x1e4e, "\x00\x4f\x03\x03\x03\x08\0" }, - { 0x1e4f, "\x00\x6f\x03\x03\x03\x08\0" }, - { 0x1e50, "\x00\x4f\x03\x04\x03\x00\0" }, - { 0x1e51, "\x00\x6f\x03\x04\x03\x00\0" }, - { 0x1e52, "\x00\x4f\x03\x04\x03\x01\0" }, - { 0x1e53, "\x00\x6f\x03\x04\x03\x01\0" }, - { 0x1e54, "\x00\x50\x03\x01\0" }, - { 0x1e55, "\x00\x70\x03\x01\0" }, - { 0x1e56, "\x00\x50\x03\x07\0" }, - { 0x1e57, "\x00\x70\x03\x07\0" }, - { 0x1e58, "\x00\x52\x03\x07\0" }, - { 0x1e59, "\x00\x72\x03\x07\0" }, - { 0x1e5a, "\x00\x52\x03\x23\0" }, - { 0x1e5b, "\x00\x72\x03\x23\0" }, - { 0x1e5c, "\x00\x52\x03\x23\x03\x04\0" }, - { 0x1e5d, "\x00\x72\x03\x23\x03\x04\0" }, - { 0x1e5e, "\x00\x52\x03\x31\0" }, - { 0x1e5f, "\x00\x72\x03\x31\0" }, - { 0x1e60, "\x00\x53\x03\x07\0" }, - { 0x1e61, "\x00\x73\x03\x07\0" }, - { 0x1e62, "\x00\x53\x03\x23\0" }, - { 0x1e63, "\x00\x73\x03\x23\0" }, - { 0x1e64, "\x00\x53\x03\x01\x03\x07\0" }, - { 0x1e65, "\x00\x73\x03\x01\x03\x07\0" }, - { 0x1e66, "\x00\x53\x03\x0c\x03\x07\0" }, - { 0x1e67, "\x00\x73\x03\x0c\x03\x07\0" }, - { 0x1e68, "\x00\x53\x03\x23\x03\x07\0" }, - { 0x1e69, "\x00\x73\x03\x23\x03\x07\0" }, - { 0x1e6a, "\x00\x54\x03\x07\0" }, - { 0x1e6b, "\x00\x74\x03\x07\0" }, - { 0x1e6c, "\x00\x54\x03\x23\0" }, - { 0x1e6d, "\x00\x74\x03\x23\0" }, - { 0x1e6e, "\x00\x54\x03\x31\0" }, - { 0x1e6f, "\x00\x74\x03\x31\0" }, - { 0x1e70, "\x00\x54\x03\x2d\0" }, - { 0x1e71, "\x00\x74\x03\x2d\0" }, - { 0x1e72, "\x00\x55\x03\x24\0" }, - { 0x1e73, "\x00\x75\x03\x24\0" }, - { 0x1e74, "\x00\x55\x03\x30\0" }, - { 0x1e75, "\x00\x75\x03\x30\0" }, - { 0x1e76, "\x00\x55\x03\x2d\0" }, - { 0x1e77, "\x00\x75\x03\x2d\0" }, - { 0x1e78, "\x00\x55\x03\x03\x03\x01\0" }, - { 0x1e79, "\x00\x75\x03\x03\x03\x01\0" }, - { 0x1e7a, "\x00\x55\x03\x04\x03\x08\0" }, - { 0x1e7b, "\x00\x75\x03\x04\x03\x08\0" }, - { 0x1e7c, "\x00\x56\x03\x03\0" }, - { 0x1e7d, "\x00\x76\x03\x03\0" }, - { 0x1e7e, "\x00\x56\x03\x23\0" }, - { 0x1e7f, "\x00\x76\x03\x23\0" }, - { 0x1e80, "\x00\x57\x03\x00\0" }, - { 0x1e81, "\x00\x77\x03\x00\0" }, - { 0x1e82, "\x00\x57\x03\x01\0" }, - { 0x1e83, "\x00\x77\x03\x01\0" }, - { 0x1e84, "\x00\x57\x03\x08\0" }, - { 0x1e85, "\x00\x77\x03\x08\0" }, - { 0x1e86, "\x00\x57\x03\x07\0" }, - { 0x1e87, "\x00\x77\x03\x07\0" }, - { 0x1e88, "\x00\x57\x03\x23\0" }, - { 0x1e89, "\x00\x77\x03\x23\0" }, - { 0x1e8a, "\x00\x58\x03\x07\0" }, - { 0x1e8b, "\x00\x78\x03\x07\0" }, - { 0x1e8c, "\x00\x58\x03\x08\0" }, - { 0x1e8d, "\x00\x78\x03\x08\0" }, - { 0x1e8e, "\x00\x59\x03\x07\0" }, - { 0x1e8f, "\x00\x79\x03\x07\0" }, - { 0x1e90, "\x00\x5a\x03\x02\0" }, - { 0x1e91, "\x00\x7a\x03\x02\0" }, - { 0x1e92, "\x00\x5a\x03\x23\0" }, - { 0x1e93, "\x00\x7a\x03\x23\0" }, - { 0x1e94, "\x00\x5a\x03\x31\0" }, - { 0x1e95, "\x00\x7a\x03\x31\0" }, - { 0x1e96, "\x00\x68\x03\x31\0" }, - { 0x1e97, "\x00\x74\x03\x08\0" }, - { 0x1e98, "\x00\x77\x03\x0a\0" }, - { 0x1e99, "\x00\x79\x03\x0a\0" }, - { 0x1e9b, "\x01\x7f\x03\x07\0" }, - { 0x1ea0, "\x00\x41\x03\x23\0" }, - { 0x1ea1, "\x00\x61\x03\x23\0" }, - { 0x1ea2, "\x00\x41\x03\x09\0" }, - { 0x1ea3, "\x00\x61\x03\x09\0" }, - { 0x1ea4, "\x00\x41\x03\x02\x03\x01\0" }, - { 0x1ea5, "\x00\x61\x03\x02\x03\x01\0" }, - { 0x1ea6, "\x00\x41\x03\x02\x03\x00\0" }, - { 0x1ea7, "\x00\x61\x03\x02\x03\x00\0" }, - { 0x1ea8, "\x00\x41\x03\x02\x03\x09\0" }, - { 0x1ea9, "\x00\x61\x03\x02\x03\x09\0" }, - { 0x1eaa, "\x00\x41\x03\x02\x03\x03\0" }, - { 0x1eab, "\x00\x61\x03\x02\x03\x03\0" }, - { 0x1eac, "\x00\x41\x03\x23\x03\x02\0" }, - { 0x1ead, "\x00\x61\x03\x23\x03\x02\0" }, - { 0x1eae, "\x00\x41\x03\x06\x03\x01\0" }, - { 0x1eaf, "\x00\x61\x03\x06\x03\x01\0" }, - { 0x1eb0, "\x00\x41\x03\x06\x03\x00\0" }, - { 0x1eb1, "\x00\x61\x03\x06\x03\x00\0" }, - { 0x1eb2, "\x00\x41\x03\x06\x03\x09\0" }, - { 0x1eb3, "\x00\x61\x03\x06\x03\x09\0" }, - { 0x1eb4, "\x00\x41\x03\x06\x03\x03\0" }, - { 0x1eb5, "\x00\x61\x03\x06\x03\x03\0" }, - { 0x1eb6, "\x00\x41\x03\x23\x03\x06\0" }, - { 0x1eb7, "\x00\x61\x03\x23\x03\x06\0" }, - { 0x1eb8, "\x00\x45\x03\x23\0" }, - { 0x1eb9, "\x00\x65\x03\x23\0" }, - { 0x1eba, "\x00\x45\x03\x09\0" }, - { 0x1ebb, "\x00\x65\x03\x09\0" }, - { 0x1ebc, "\x00\x45\x03\x03\0" }, - { 0x1ebd, "\x00\x65\x03\x03\0" }, - { 0x1ebe, "\x00\x45\x03\x02\x03\x01\0" }, - { 0x1ebf, "\x00\x65\x03\x02\x03\x01\0" }, - { 0x1ec0, "\x00\x45\x03\x02\x03\x00\0" }, - { 0x1ec1, "\x00\x65\x03\x02\x03\x00\0" }, - { 0x1ec2, "\x00\x45\x03\x02\x03\x09\0" }, - { 0x1ec3, "\x00\x65\x03\x02\x03\x09\0" }, - { 0x1ec4, "\x00\x45\x03\x02\x03\x03\0" }, - { 0x1ec5, "\x00\x65\x03\x02\x03\x03\0" }, - { 0x1ec6, "\x00\x45\x03\x23\x03\x02\0" }, - { 0x1ec7, "\x00\x65\x03\x23\x03\x02\0" }, - { 0x1ec8, "\x00\x49\x03\x09\0" }, - { 0x1ec9, "\x00\x69\x03\x09\0" }, - { 0x1eca, "\x00\x49\x03\x23\0" }, - { 0x1ecb, "\x00\x69\x03\x23\0" }, - { 0x1ecc, "\x00\x4f\x03\x23\0" }, - { 0x1ecd, "\x00\x6f\x03\x23\0" }, - { 0x1ece, "\x00\x4f\x03\x09\0" }, - { 0x1ecf, "\x00\x6f\x03\x09\0" }, - { 0x1ed0, "\x00\x4f\x03\x02\x03\x01\0" }, - { 0x1ed1, "\x00\x6f\x03\x02\x03\x01\0" }, - { 0x1ed2, "\x00\x4f\x03\x02\x03\x00\0" }, - { 0x1ed3, "\x00\x6f\x03\x02\x03\x00\0" }, - { 0x1ed4, "\x00\x4f\x03\x02\x03\x09\0" }, - { 0x1ed5, "\x00\x6f\x03\x02\x03\x09\0" }, - { 0x1ed6, "\x00\x4f\x03\x02\x03\x03\0" }, - { 0x1ed7, "\x00\x6f\x03\x02\x03\x03\0" }, - { 0x1ed8, "\x00\x4f\x03\x23\x03\x02\0" }, - { 0x1ed9, "\x00\x6f\x03\x23\x03\x02\0" }, - { 0x1eda, "\x00\x4f\x03\x1b\x03\x01\0" }, - { 0x1edb, "\x00\x6f\x03\x1b\x03\x01\0" }, - { 0x1edc, "\x00\x4f\x03\x1b\x03\x00\0" }, - { 0x1edd, "\x00\x6f\x03\x1b\x03\x00\0" }, - { 0x1ede, "\x00\x4f\x03\x1b\x03\x09\0" }, - { 0x1edf, "\x00\x6f\x03\x1b\x03\x09\0" }, - { 0x1ee0, "\x00\x4f\x03\x1b\x03\x03\0" }, - { 0x1ee1, "\x00\x6f\x03\x1b\x03\x03\0" }, - { 0x1ee2, "\x00\x4f\x03\x1b\x03\x23\0" }, - { 0x1ee3, "\x00\x6f\x03\x1b\x03\x23\0" }, - { 0x1ee4, "\x00\x55\x03\x23\0" }, - { 0x1ee5, "\x00\x75\x03\x23\0" }, - { 0x1ee6, "\x00\x55\x03\x09\0" }, - { 0x1ee7, "\x00\x75\x03\x09\0" }, - { 0x1ee8, "\x00\x55\x03\x1b\x03\x01\0" }, - { 0x1ee9, "\x00\x75\x03\x1b\x03\x01\0" }, - { 0x1eea, "\x00\x55\x03\x1b\x03\x00\0" }, - { 0x1eeb, "\x00\x75\x03\x1b\x03\x00\0" }, - { 0x1eec, "\x00\x55\x03\x1b\x03\x09\0" }, - { 0x1eed, "\x00\x75\x03\x1b\x03\x09\0" }, - { 0x1eee, "\x00\x55\x03\x1b\x03\x03\0" }, - { 0x1eef, "\x00\x75\x03\x1b\x03\x03\0" }, - { 0x1ef0, "\x00\x55\x03\x1b\x03\x23\0" }, - { 0x1ef1, "\x00\x75\x03\x1b\x03\x23\0" }, - { 0x1ef2, "\x00\x59\x03\x00\0" }, - { 0x1ef3, "\x00\x79\x03\x00\0" }, - { 0x1ef4, "\x00\x59\x03\x23\0" }, - { 0x1ef5, "\x00\x79\x03\x23\0" }, - { 0x1ef6, "\x00\x59\x03\x09\0" }, - { 0x1ef7, "\x00\x79\x03\x09\0" }, - { 0x1ef8, "\x00\x59\x03\x03\0" }, - { 0x1ef9, "\x00\x79\x03\x03\0" }, - { 0x1f00, "\x03\xb1\x03\x13\0" }, - { 0x1f01, "\x03\xb1\x03\x14\0" }, - { 0x1f02, "\x03\xb1\x03\x13\x03\x00\0" }, - { 0x1f03, "\x03\xb1\x03\x14\x03\x00\0" }, - { 0x1f04, "\x03\xb1\x03\x13\x03\x01\0" }, - { 0x1f05, "\x03\xb1\x03\x14\x03\x01\0" }, - { 0x1f06, "\x03\xb1\x03\x13\x03\x42\0" }, - { 0x1f07, "\x03\xb1\x03\x14\x03\x42\0" }, - { 0x1f08, "\x03\x91\x03\x13\0" }, - { 0x1f09, "\x03\x91\x03\x14\0" }, - { 0x1f0a, "\x03\x91\x03\x13\x03\x00\0" }, - { 0x1f0b, "\x03\x91\x03\x14\x03\x00\0" }, - { 0x1f0c, "\x03\x91\x03\x13\x03\x01\0" }, - { 0x1f0d, "\x03\x91\x03\x14\x03\x01\0" }, - { 0x1f0e, "\x03\x91\x03\x13\x03\x42\0" }, - { 0x1f0f, "\x03\x91\x03\x14\x03\x42\0" }, - { 0x1f10, "\x03\xb5\x03\x13\0" }, - { 0x1f11, "\x03\xb5\x03\x14\0" }, - { 0x1f12, "\x03\xb5\x03\x13\x03\x00\0" }, - { 0x1f13, "\x03\xb5\x03\x14\x03\x00\0" }, - { 0x1f14, "\x03\xb5\x03\x13\x03\x01\0" }, - { 0x1f15, "\x03\xb5\x03\x14\x03\x01\0" }, - { 0x1f18, "\x03\x95\x03\x13\0" }, - { 0x1f19, "\x03\x95\x03\x14\0" }, - { 0x1f1a, "\x03\x95\x03\x13\x03\x00\0" }, - { 0x1f1b, "\x03\x95\x03\x14\x03\x00\0" }, - { 0x1f1c, "\x03\x95\x03\x13\x03\x01\0" }, - { 0x1f1d, "\x03\x95\x03\x14\x03\x01\0" }, - { 0x1f20, "\x03\xb7\x03\x13\0" }, - { 0x1f21, "\x03\xb7\x03\x14\0" }, - { 0x1f22, "\x03\xb7\x03\x13\x03\x00\0" }, - { 0x1f23, "\x03\xb7\x03\x14\x03\x00\0" }, - { 0x1f24, "\x03\xb7\x03\x13\x03\x01\0" }, - { 0x1f25, "\x03\xb7\x03\x14\x03\x01\0" }, - { 0x1f26, "\x03\xb7\x03\x13\x03\x42\0" }, - { 0x1f27, "\x03\xb7\x03\x14\x03\x42\0" }, - { 0x1f28, "\x03\x97\x03\x13\0" }, - { 0x1f29, "\x03\x97\x03\x14\0" }, - { 0x1f2a, "\x03\x97\x03\x13\x03\x00\0" }, - { 0x1f2b, "\x03\x97\x03\x14\x03\x00\0" }, - { 0x1f2c, "\x03\x97\x03\x13\x03\x01\0" }, - { 0x1f2d, "\x03\x97\x03\x14\x03\x01\0" }, - { 0x1f2e, "\x03\x97\x03\x13\x03\x42\0" }, - { 0x1f2f, "\x03\x97\x03\x14\x03\x42\0" }, - { 0x1f30, "\x03\xb9\x03\x13\0" }, - { 0x1f31, "\x03\xb9\x03\x14\0" }, - { 0x1f32, "\x03\xb9\x03\x13\x03\x00\0" }, - { 0x1f33, "\x03\xb9\x03\x14\x03\x00\0" }, - { 0x1f34, "\x03\xb9\x03\x13\x03\x01\0" }, - { 0x1f35, "\x03\xb9\x03\x14\x03\x01\0" }, - { 0x1f36, "\x03\xb9\x03\x13\x03\x42\0" }, - { 0x1f37, "\x03\xb9\x03\x14\x03\x42\0" }, - { 0x1f38, "\x03\x99\x03\x13\0" }, - { 0x1f39, "\x03\x99\x03\x14\0" }, - { 0x1f3a, "\x03\x99\x03\x13\x03\x00\0" }, - { 0x1f3b, "\x03\x99\x03\x14\x03\x00\0" }, - { 0x1f3c, "\x03\x99\x03\x13\x03\x01\0" }, - { 0x1f3d, "\x03\x99\x03\x14\x03\x01\0" }, - { 0x1f3e, "\x03\x99\x03\x13\x03\x42\0" }, - { 0x1f3f, "\x03\x99\x03\x14\x03\x42\0" }, - { 0x1f40, "\x03\xbf\x03\x13\0" }, - { 0x1f41, "\x03\xbf\x03\x14\0" }, - { 0x1f42, "\x03\xbf\x03\x13\x03\x00\0" }, - { 0x1f43, "\x03\xbf\x03\x14\x03\x00\0" }, - { 0x1f44, "\x03\xbf\x03\x13\x03\x01\0" }, - { 0x1f45, "\x03\xbf\x03\x14\x03\x01\0" }, - { 0x1f48, "\x03\x9f\x03\x13\0" }, - { 0x1f49, "\x03\x9f\x03\x14\0" }, - { 0x1f4a, "\x03\x9f\x03\x13\x03\x00\0" }, - { 0x1f4b, "\x03\x9f\x03\x14\x03\x00\0" }, - { 0x1f4c, "\x03\x9f\x03\x13\x03\x01\0" }, - { 0x1f4d, "\x03\x9f\x03\x14\x03\x01\0" }, - { 0x1f50, "\x03\xc5\x03\x13\0" }, - { 0x1f51, "\x03\xc5\x03\x14\0" }, - { 0x1f52, "\x03\xc5\x03\x13\x03\x00\0" }, - { 0x1f53, "\x03\xc5\x03\x14\x03\x00\0" }, - { 0x1f54, "\x03\xc5\x03\x13\x03\x01\0" }, - { 0x1f55, "\x03\xc5\x03\x14\x03\x01\0" }, - { 0x1f56, "\x03\xc5\x03\x13\x03\x42\0" }, - { 0x1f57, "\x03\xc5\x03\x14\x03\x42\0" }, - { 0x1f59, "\x03\xa5\x03\x14\0" }, - { 0x1f5b, "\x03\xa5\x03\x14\x03\x00\0" }, - { 0x1f5d, "\x03\xa5\x03\x14\x03\x01\0" }, - { 0x1f5f, "\x03\xa5\x03\x14\x03\x42\0" }, - { 0x1f60, "\x03\xc9\x03\x13\0" }, - { 0x1f61, "\x03\xc9\x03\x14\0" }, - { 0x1f62, "\x03\xc9\x03\x13\x03\x00\0" }, - { 0x1f63, "\x03\xc9\x03\x14\x03\x00\0" }, - { 0x1f64, "\x03\xc9\x03\x13\x03\x01\0" }, - { 0x1f65, "\x03\xc9\x03\x14\x03\x01\0" }, - { 0x1f66, "\x03\xc9\x03\x13\x03\x42\0" }, - { 0x1f67, "\x03\xc9\x03\x14\x03\x42\0" }, - { 0x1f68, "\x03\xa9\x03\x13\0" }, - { 0x1f69, "\x03\xa9\x03\x14\0" }, - { 0x1f6a, "\x03\xa9\x03\x13\x03\x00\0" }, - { 0x1f6b, "\x03\xa9\x03\x14\x03\x00\0" }, - { 0x1f6c, "\x03\xa9\x03\x13\x03\x01\0" }, - { 0x1f6d, "\x03\xa9\x03\x14\x03\x01\0" }, - { 0x1f6e, "\x03\xa9\x03\x13\x03\x42\0" }, - { 0x1f6f, "\x03\xa9\x03\x14\x03\x42\0" }, - { 0x1f70, "\x03\xb1\x03\x00\0" }, - { 0x1f71, "\x03\xb1\x03\x01\0" }, - { 0x1f72, "\x03\xb5\x03\x00\0" }, - { 0x1f73, "\x03\xb5\x03\x01\0" }, - { 0x1f74, "\x03\xb7\x03\x00\0" }, - { 0x1f75, "\x03\xb7\x03\x01\0" }, - { 0x1f76, "\x03\xb9\x03\x00\0" }, - { 0x1f77, "\x03\xb9\x03\x01\0" }, - { 0x1f78, "\x03\xbf\x03\x00\0" }, - { 0x1f79, "\x03\xbf\x03\x01\0" }, - { 0x1f7a, "\x03\xc5\x03\x00\0" }, - { 0x1f7b, "\x03\xc5\x03\x01\0" }, - { 0x1f7c, "\x03\xc9\x03\x00\0" }, - { 0x1f7d, "\x03\xc9\x03\x01\0" }, - { 0x1f80, "\x03\xb1\x03\x13\x03\x45\0" }, - { 0x1f81, "\x03\xb1\x03\x14\x03\x45\0" }, - { 0x1f82, "\x03\xb1\x03\x13\x03\x00\x03\x45\0" }, - { 0x1f83, "\x03\xb1\x03\x14\x03\x00\x03\x45\0" }, - { 0x1f84, "\x03\xb1\x03\x13\x03\x01\x03\x45\0" }, - { 0x1f85, "\x03\xb1\x03\x14\x03\x01\x03\x45\0" }, - { 0x1f86, "\x03\xb1\x03\x13\x03\x42\x03\x45\0" }, - { 0x1f87, "\x03\xb1\x03\x14\x03\x42\x03\x45\0" }, - { 0x1f88, "\x03\x91\x03\x13\x03\x45\0" }, - { 0x1f89, "\x03\x91\x03\x14\x03\x45\0" }, - { 0x1f8a, "\x03\x91\x03\x13\x03\x00\x03\x45\0" }, - { 0x1f8b, "\x03\x91\x03\x14\x03\x00\x03\x45\0" }, - { 0x1f8c, "\x03\x91\x03\x13\x03\x01\x03\x45\0" }, - { 0x1f8d, "\x03\x91\x03\x14\x03\x01\x03\x45\0" }, - { 0x1f8e, "\x03\x91\x03\x13\x03\x42\x03\x45\0" }, - { 0x1f8f, "\x03\x91\x03\x14\x03\x42\x03\x45\0" }, - { 0x1f90, "\x03\xb7\x03\x13\x03\x45\0" }, - { 0x1f91, "\x03\xb7\x03\x14\x03\x45\0" }, - { 0x1f92, "\x03\xb7\x03\x13\x03\x00\x03\x45\0" }, - { 0x1f93, "\x03\xb7\x03\x14\x03\x00\x03\x45\0" }, - { 0x1f94, "\x03\xb7\x03\x13\x03\x01\x03\x45\0" }, - { 0x1f95, "\x03\xb7\x03\x14\x03\x01\x03\x45\0" }, - { 0x1f96, "\x03\xb7\x03\x13\x03\x42\x03\x45\0" }, - { 0x1f97, "\x03\xb7\x03\x14\x03\x42\x03\x45\0" }, - { 0x1f98, "\x03\x97\x03\x13\x03\x45\0" }, - { 0x1f99, "\x03\x97\x03\x14\x03\x45\0" }, - { 0x1f9a, "\x03\x97\x03\x13\x03\x00\x03\x45\0" }, - { 0x1f9b, "\x03\x97\x03\x14\x03\x00\x03\x45\0" }, - { 0x1f9c, "\x03\x97\x03\x13\x03\x01\x03\x45\0" }, - { 0x1f9d, "\x03\x97\x03\x14\x03\x01\x03\x45\0" }, - { 0x1f9e, "\x03\x97\x03\x13\x03\x42\x03\x45\0" }, - { 0x1f9f, "\x03\x97\x03\x14\x03\x42\x03\x45\0" }, - { 0x1fa0, "\x03\xc9\x03\x13\x03\x45\0" }, - { 0x1fa1, "\x03\xc9\x03\x14\x03\x45\0" }, - { 0x1fa2, "\x03\xc9\x03\x13\x03\x00\x03\x45\0" }, - { 0x1fa3, "\x03\xc9\x03\x14\x03\x00\x03\x45\0" }, - { 0x1fa4, "\x03\xc9\x03\x13\x03\x01\x03\x45\0" }, - { 0x1fa5, "\x03\xc9\x03\x14\x03\x01\x03\x45\0" }, - { 0x1fa6, "\x03\xc9\x03\x13\x03\x42\x03\x45\0" }, - { 0x1fa7, "\x03\xc9\x03\x14\x03\x42\x03\x45\0" }, - { 0x1fa8, "\x03\xa9\x03\x13\x03\x45\0" }, - { 0x1fa9, "\x03\xa9\x03\x14\x03\x45\0" }, - { 0x1faa, "\x03\xa9\x03\x13\x03\x00\x03\x45\0" }, - { 0x1fab, "\x03\xa9\x03\x14\x03\x00\x03\x45\0" }, - { 0x1fac, "\x03\xa9\x03\x13\x03\x01\x03\x45\0" }, - { 0x1fad, "\x03\xa9\x03\x14\x03\x01\x03\x45\0" }, - { 0x1fae, "\x03\xa9\x03\x13\x03\x42\x03\x45\0" }, - { 0x1faf, "\x03\xa9\x03\x14\x03\x42\x03\x45\0" }, - { 0x1fb0, "\x03\xb1\x03\x06\0" }, - { 0x1fb1, "\x03\xb1\x03\x04\0" }, - { 0x1fb2, "\x03\xb1\x03\x00\x03\x45\0" }, - { 0x1fb3, "\x03\xb1\x03\x45\0" }, - { 0x1fb4, "\x03\xb1\x03\x01\x03\x45\0" }, - { 0x1fb6, "\x03\xb1\x03\x42\0" }, - { 0x1fb7, "\x03\xb1\x03\x42\x03\x45\0" }, - { 0x1fb8, "\x03\x91\x03\x06\0" }, - { 0x1fb9, "\x03\x91\x03\x04\0" }, - { 0x1fba, "\x03\x91\x03\x00\0" }, - { 0x1fbb, "\x03\x91\x03\x01\0" }, - { 0x1fbc, "\x03\x91\x03\x45\0" }, - { 0x1fbe, "\x03\xb9\0" }, - { 0x1fc1, "\x00\xa8\x03\x42\0" }, - { 0x1fc2, "\x03\xb7\x03\x00\x03\x45\0" }, - { 0x1fc3, "\x03\xb7\x03\x45\0" }, - { 0x1fc4, "\x03\xb7\x03\x01\x03\x45\0" }, - { 0x1fc6, "\x03\xb7\x03\x42\0" }, - { 0x1fc7, "\x03\xb7\x03\x42\x03\x45\0" }, - { 0x1fc8, "\x03\x95\x03\x00\0" }, - { 0x1fc9, "\x03\x95\x03\x01\0" }, - { 0x1fca, "\x03\x97\x03\x00\0" }, - { 0x1fcb, "\x03\x97\x03\x01\0" }, - { 0x1fcc, "\x03\x97\x03\x45\0" }, - { 0x1fcd, "\x1f\xbf\x03\x00\0" }, - { 0x1fce, "\x1f\xbf\x03\x01\0" }, - { 0x1fcf, "\x1f\xbf\x03\x42\0" }, - { 0x1fd0, "\x03\xb9\x03\x06\0" }, - { 0x1fd1, "\x03\xb9\x03\x04\0" }, - { 0x1fd2, "\x03\xb9\x03\x08\x03\x00\0" }, - { 0x1fd3, "\x03\xb9\x03\x08\x03\x01\0" }, - { 0x1fd6, "\x03\xb9\x03\x42\0" }, - { 0x1fd7, "\x03\xb9\x03\x08\x03\x42\0" }, - { 0x1fd8, "\x03\x99\x03\x06\0" }, - { 0x1fd9, "\x03\x99\x03\x04\0" }, - { 0x1fda, "\x03\x99\x03\x00\0" }, - { 0x1fdb, "\x03\x99\x03\x01\0" }, - { 0x1fdd, "\x1f\xfe\x03\x00\0" }, - { 0x1fde, "\x1f\xfe\x03\x01\0" }, - { 0x1fdf, "\x1f\xfe\x03\x42\0" }, - { 0x1fe0, "\x03\xc5\x03\x06\0" }, - { 0x1fe1, "\x03\xc5\x03\x04\0" }, - { 0x1fe2, "\x03\xc5\x03\x08\x03\x00\0" }, - { 0x1fe3, "\x03\xc5\x03\x08\x03\x01\0" }, - { 0x1fe4, "\x03\xc1\x03\x13\0" }, - { 0x1fe5, "\x03\xc1\x03\x14\0" }, - { 0x1fe6, "\x03\xc5\x03\x42\0" }, - { 0x1fe7, "\x03\xc5\x03\x08\x03\x42\0" }, - { 0x1fe8, "\x03\xa5\x03\x06\0" }, - { 0x1fe9, "\x03\xa5\x03\x04\0" }, - { 0x1fea, "\x03\xa5\x03\x00\0" }, - { 0x1feb, "\x03\xa5\x03\x01\0" }, - { 0x1fec, "\x03\xa1\x03\x14\0" }, - { 0x1fed, "\x00\xa8\x03\x00\0" }, - { 0x1fee, "\x00\xa8\x03\x01\0" }, - { 0x1fef, "\x00\x60\0" }, - { 0x1ff2, "\x03\xc9\x03\x00\x03\x45\0" }, - { 0x1ff3, "\x03\xc9\x03\x45\0" }, - { 0x1ff4, "\x03\xc9\x03\x01\x03\x45\0" }, - { 0x1ff6, "\x03\xc9\x03\x42\0" }, - { 0x1ff7, "\x03\xc9\x03\x42\x03\x45\0" }, - { 0x1ff8, "\x03\x9f\x03\x00\0" }, - { 0x1ff9, "\x03\x9f\x03\x01\0" }, - { 0x1ffa, "\x03\xa9\x03\x00\0" }, - { 0x1ffb, "\x03\xa9\x03\x01\0" }, - { 0x1ffc, "\x03\xa9\x03\x45\0" }, - { 0x1ffd, "\x00\xb4\0" }, - { 0x2000, "\x20\x02\0" }, - { 0x2001, "\x20\x03\0" }, - { 0x2126, "\x03\xa9\0" }, - { 0x212a, "\x00\x4b\0" }, - { 0x212b, "\x00\x41\x03\x0a\0" }, - { 0x2204, "\x22\x03\x03\x38\0" }, - { 0x2209, "\x22\x08\x03\x38\0" }, - { 0x220c, "\x22\x0b\x03\x38\0" }, - { 0x2224, "\x22\x23\x03\x38\0" }, - { 0x2226, "\x22\x25\x03\x38\0" }, - { 0x2241, "\x00\x7e\x03\x38\0" }, - { 0x2244, "\x22\x43\x03\x38\0" }, - { 0x2247, "\x22\x45\x03\x38\0" }, - { 0x2249, "\x22\x48\x03\x38\0" }, - { 0x2260, "\x00\x3d\x03\x38\0" }, - { 0x2262, "\x22\x61\x03\x38\0" }, - { 0x226d, "\x22\x4d\x03\x38\0" }, - { 0x226e, "\x00\x3c\x03\x38\0" }, - { 0x226f, "\x00\x3e\x03\x38\0" }, - { 0x2270, "\x22\x64\x03\x38\0" }, - { 0x2271, "\x22\x65\x03\x38\0" }, - { 0x2274, "\x22\x72\x03\x38\0" }, - { 0x2275, "\x22\x73\x03\x38\0" }, - { 0x2278, "\x22\x76\x03\x38\0" }, - { 0x2279, "\x22\x77\x03\x38\0" }, - { 0x2280, "\x22\x7a\x03\x38\0" }, - { 0x2281, "\x22\x7b\x03\x38\0" }, - { 0x2284, "\x22\x82\x03\x38\0" }, - { 0x2285, "\x22\x83\x03\x38\0" }, - { 0x2288, "\x22\x86\x03\x38\0" }, - { 0x2289, "\x22\x87\x03\x38\0" }, - { 0x22ac, "\x22\xa2\x03\x38\0" }, - { 0x22ad, "\x22\xa8\x03\x38\0" }, - { 0x22ae, "\x22\xa9\x03\x38\0" }, - { 0x22af, "\x22\xab\x03\x38\0" }, - { 0x22e0, "\x22\x7c\x03\x38\0" }, - { 0x22e1, "\x22\x7d\x03\x38\0" }, - { 0x22e2, "\x22\x91\x03\x38\0" }, - { 0x22e3, "\x22\x92\x03\x38\0" }, - { 0x22ea, "\x22\xb2\x03\x38\0" }, - { 0x22eb, "\x22\xb3\x03\x38\0" }, - { 0x22ec, "\x22\xb4\x03\x38\0" }, - { 0x22ed, "\x22\xb5\x03\x38\0" }, - { 0x2329, "\x30\x08\0" }, - { 0x232a, "\x30\x09\0" }, - { 0x304c, "\x30\x4b\x30\x99\0" }, - { 0x304e, "\x30\x4d\x30\x99\0" }, - { 0x3050, "\x30\x4f\x30\x99\0" }, - { 0x3052, "\x30\x51\x30\x99\0" }, - { 0x3054, "\x30\x53\x30\x99\0" }, - { 0x3056, "\x30\x55\x30\x99\0" }, - { 0x3058, "\x30\x57\x30\x99\0" }, - { 0x305a, "\x30\x59\x30\x99\0" }, - { 0x305c, "\x30\x5b\x30\x99\0" }, - { 0x305e, "\x30\x5d\x30\x99\0" }, - { 0x3060, "\x30\x5f\x30\x99\0" }, - { 0x3062, "\x30\x61\x30\x99\0" }, - { 0x3065, "\x30\x64\x30\x99\0" }, - { 0x3067, "\x30\x66\x30\x99\0" }, - { 0x3069, "\x30\x68\x30\x99\0" }, - { 0x3070, "\x30\x6f\x30\x99\0" }, - { 0x3071, "\x30\x6f\x30\x9a\0" }, - { 0x3073, "\x30\x72\x30\x99\0" }, - { 0x3074, "\x30\x72\x30\x9a\0" }, - { 0x3076, "\x30\x75\x30\x99\0" }, - { 0x3077, "\x30\x75\x30\x9a\0" }, - { 0x3079, "\x30\x78\x30\x99\0" }, - { 0x307a, "\x30\x78\x30\x9a\0" }, - { 0x307c, "\x30\x7b\x30\x99\0" }, - { 0x307d, "\x30\x7b\x30\x9a\0" }, - { 0x3094, "\x30\x46\x30\x99\0" }, - { 0x309e, "\x30\x9d\x30\x99\0" }, - { 0x30ac, "\x30\xab\x30\x99\0" }, - { 0x30ae, "\x30\xad\x30\x99\0" }, - { 0x30b0, "\x30\xaf\x30\x99\0" }, - { 0x30b2, "\x30\xb1\x30\x99\0" }, - { 0x30b4, "\x30\xb3\x30\x99\0" }, - { 0x30b6, "\x30\xb5\x30\x99\0" }, - { 0x30b8, "\x30\xb7\x30\x99\0" }, - { 0x30ba, "\x30\xb9\x30\x99\0" }, - { 0x30bc, "\x30\xbb\x30\x99\0" }, - { 0x30be, "\x30\xbd\x30\x99\0" }, - { 0x30c0, "\x30\xbf\x30\x99\0" }, - { 0x30c2, "\x30\xc1\x30\x99\0" }, - { 0x30c5, "\x30\xc4\x30\x99\0" }, - { 0x30c7, "\x30\xc6\x30\x99\0" }, - { 0x30c9, "\x30\xc8\x30\x99\0" }, - { 0x30d0, "\x30\xcf\x30\x99\0" }, - { 0x30d1, "\x30\xcf\x30\x9a\0" }, - { 0x30d3, "\x30\xd2\x30\x99\0" }, - { 0x30d4, "\x30\xd2\x30\x9a\0" }, - { 0x30d6, "\x30\xd5\x30\x99\0" }, - { 0x30d7, "\x30\xd5\x30\x9a\0" }, - { 0x30d9, "\x30\xd8\x30\x99\0" }, - { 0x30da, "\x30\xd8\x30\x9a\0" }, - { 0x30dc, "\x30\xdb\x30\x99\0" }, - { 0x30dd, "\x30\xdb\x30\x9a\0" }, - { 0x30f4, "\x30\xa6\x30\x99\0" }, - { 0x30f7, "\x30\xef\x30\x99\0" }, - { 0x30f8, "\x30\xf0\x30\x99\0" }, - { 0x30f9, "\x30\xf1\x30\x99\0" }, - { 0x30fa, "\x30\xf2\x30\x99\0" }, - { 0x30fe, "\x30\xfd\x30\x99\0" }, - { 0xf900, "\x8c\x48\0" }, - { 0xf901, "\x66\xf4\0" }, - { 0xf902, "\x8e\xca\0" }, - { 0xf903, "\x8c\xc8\0" }, - { 0xf904, "\x6e\xd1\0" }, - { 0xf905, "\x4e\x32\0" }, - { 0xf906, "\x53\xe5\0" }, - { 0xf907, "\x9f\x9c\0" }, - { 0xf908, "\x9f\x9c\0" }, - { 0xf909, "\x59\x51\0" }, - { 0xf90a, "\x91\xd1\0" }, - { 0xf90b, "\x55\x87\0" }, - { 0xf90c, "\x59\x48\0" }, - { 0xf90d, "\x61\xf6\0" }, - { 0xf90e, "\x76\x69\0" }, - { 0xf90f, "\x7f\x85\0" }, - { 0xf910, "\x86\x3f\0" }, - { 0xf911, "\x87\xba\0" }, - { 0xf912, "\x88\xf8\0" }, - { 0xf913, "\x90\x8f\0" }, - { 0xf914, "\x6a\x02\0" }, - { 0xf915, "\x6d\x1b\0" }, - { 0xf916, "\x70\xd9\0" }, - { 0xf917, "\x73\xde\0" }, - { 0xf918, "\x84\x3d\0" }, - { 0xf919, "\x91\x6a\0" }, - { 0xf91a, "\x99\xf1\0" }, - { 0xf91b, "\x4e\x82\0" }, - { 0xf91c, "\x53\x75\0" }, - { 0xf91d, "\x6b\x04\0" }, - { 0xf91e, "\x72\x1b\0" }, - { 0xf91f, "\x86\x2d\0" }, - { 0xf920, "\x9e\x1e\0" }, - { 0xf921, "\x5d\x50\0" }, - { 0xf922, "\x6f\xeb\0" }, - { 0xf923, "\x85\xcd\0" }, - { 0xf924, "\x89\x64\0" }, - { 0xf925, "\x62\xc9\0" }, - { 0xf926, "\x81\xd8\0" }, - { 0xf927, "\x88\x1f\0" }, - { 0xf928, "\x5e\xca\0" }, - { 0xf929, "\x67\x17\0" }, - { 0xf92a, "\x6d\x6a\0" }, - { 0xf92b, "\x72\xfc\0" }, - { 0xf92c, "\x90\xce\0" }, - { 0xf92d, "\x4f\x86\0" }, - { 0xf92e, "\x51\xb7\0" }, - { 0xf92f, "\x52\xde\0" }, - { 0xf930, "\x64\xc4\0" }, - { 0xf931, "\x6a\xd3\0" }, - { 0xf932, "\x72\x10\0" }, - { 0xf933, "\x76\xe7\0" }, - { 0xf934, "\x80\x01\0" }, - { 0xf935, "\x86\x06\0" }, - { 0xf936, "\x86\x5c\0" }, - { 0xf937, "\x8d\xef\0" }, - { 0xf938, "\x97\x32\0" }, - { 0xf939, "\x9b\x6f\0" }, - { 0xf93a, "\x9d\xfa\0" }, - { 0xf93b, "\x78\x8c\0" }, - { 0xf93c, "\x79\x7f\0" }, - { 0xf93d, "\x7d\xa0\0" }, - { 0xf93e, "\x83\xc9\0" }, - { 0xf93f, "\x93\x04\0" }, - { 0xf940, "\x9e\x7f\0" }, - { 0xf941, "\x8a\xd6\0" }, - { 0xf942, "\x58\xdf\0" }, - { 0xf943, "\x5f\x04\0" }, - { 0xf944, "\x7c\x60\0" }, - { 0xf945, "\x80\x7e\0" }, - { 0xf946, "\x72\x62\0" }, - { 0xf947, "\x78\xca\0" }, - { 0xf948, "\x8c\xc2\0" }, - { 0xf949, "\x96\xf7\0" }, - { 0xf94a, "\x58\xd8\0" }, - { 0xf94b, "\x5c\x62\0" }, - { 0xf94c, "\x6a\x13\0" }, - { 0xf94d, "\x6d\xda\0" }, - { 0xf94e, "\x6f\x0f\0" }, - { 0xf94f, "\x7d\x2f\0" }, - { 0xf950, "\x7e\x37\0" }, - { 0xf951, "\x96\xfb\0" }, - { 0xf952, "\x52\xd2\0" }, - { 0xf953, "\x80\x8b\0" }, - { 0xf954, "\x51\xdc\0" }, - { 0xf955, "\x51\xcc\0" }, - { 0xf956, "\x7a\x1c\0" }, - { 0xf957, "\x7d\xbe\0" }, - { 0xf958, "\x83\xf1\0" }, - { 0xf959, "\x96\x75\0" }, - { 0xf95a, "\x8b\x80\0" }, - { 0xf95b, "\x62\xcf\0" }, - { 0xf95c, "\x6a\x02\0" }, - { 0xf95d, "\x8a\xfe\0" }, - { 0xf95e, "\x4e\x39\0" }, - { 0xf95f, "\x5b\xe7\0" }, - { 0xf960, "\x60\x12\0" }, - { 0xf961, "\x73\x87\0" }, - { 0xf962, "\x75\x70\0" }, - { 0xf963, "\x53\x17\0" }, - { 0xf964, "\x78\xfb\0" }, - { 0xf965, "\x4f\xbf\0" }, - { 0xf966, "\x5f\xa9\0" }, - { 0xf967, "\x4e\x0d\0" }, - { 0xf968, "\x6c\xcc\0" }, - { 0xf969, "\x65\x78\0" }, - { 0xf96a, "\x7d\x22\0" }, - { 0xf96b, "\x53\xc3\0" }, - { 0xf96c, "\x58\x5e\0" }, - { 0xf96d, "\x77\x01\0" }, - { 0xf96e, "\x84\x49\0" }, - { 0xf96f, "\x8a\xaa\0" }, - { 0xf970, "\x6b\xba\0" }, - { 0xf971, "\x8f\xb0\0" }, - { 0xf972, "\x6c\x88\0" }, - { 0xf973, "\x62\xfe\0" }, - { 0xf974, "\x82\xe5\0" }, - { 0xf975, "\x63\xa0\0" }, - { 0xf976, "\x75\x65\0" }, - { 0xf977, "\x4e\xae\0" }, - { 0xf978, "\x51\x69\0" }, - { 0xf979, "\x51\xc9\0" }, - { 0xf97a, "\x68\x81\0" }, - { 0xf97b, "\x7c\xe7\0" }, - { 0xf97c, "\x82\x6f\0" }, - { 0xf97d, "\x8a\xd2\0" }, - { 0xf97e, "\x91\xcf\0" }, - { 0xf97f, "\x52\xf5\0" }, - { 0xf980, "\x54\x42\0" }, - { 0xf981, "\x59\x73\0" }, - { 0xf982, "\x5e\xec\0" }, - { 0xf983, "\x65\xc5\0" }, - { 0xf984, "\x6f\xfe\0" }, - { 0xf985, "\x79\x2a\0" }, - { 0xf986, "\x95\xad\0" }, - { 0xf987, "\x9a\x6a\0" }, - { 0xf988, "\x9e\x97\0" }, - { 0xf989, "\x9e\xce\0" }, - { 0xf98a, "\x52\x9b\0" }, - { 0xf98b, "\x66\xc6\0" }, - { 0xf98c, "\x6b\x77\0" }, - { 0xf98d, "\x8f\x62\0" }, - { 0xf98e, "\x5e\x74\0" }, - { 0xf98f, "\x61\x90\0" }, - { 0xf990, "\x62\x00\0" }, - { 0xf991, "\x64\x9a\0" }, - { 0xf992, "\x6f\x23\0" }, - { 0xf993, "\x71\x49\0" }, - { 0xf994, "\x74\x89\0" }, - { 0xf995, "\x79\xca\0" }, - { 0xf996, "\x7d\xf4\0" }, - { 0xf997, "\x80\x6f\0" }, - { 0xf998, "\x8f\x26\0" }, - { 0xf999, "\x84\xee\0" }, - { 0xf99a, "\x90\x23\0" }, - { 0xf99b, "\x93\x4a\0" }, - { 0xf99c, "\x52\x17\0" }, - { 0xf99d, "\x52\xa3\0" }, - { 0xf99e, "\x54\xbd\0" }, - { 0xf99f, "\x70\xc8\0" }, - { 0xf9a0, "\x88\xc2\0" }, - { 0xf9a1, "\x8a\xaa\0" }, - { 0xf9a2, "\x5e\xc9\0" }, - { 0xf9a3, "\x5f\xf5\0" }, - { 0xf9a4, "\x63\x7b\0" }, - { 0xf9a5, "\x6b\xae\0" }, - { 0xf9a6, "\x7c\x3e\0" }, - { 0xf9a7, "\x73\x75\0" }, - { 0xf9a8, "\x4e\xe4\0" }, - { 0xf9a9, "\x56\xf9\0" }, - { 0xf9aa, "\x5b\xe7\0" }, - { 0xf9ab, "\x5d\xba\0" }, - { 0xf9ac, "\x60\x1c\0" }, - { 0xf9ad, "\x73\xb2\0" }, - { 0xf9ae, "\x74\x69\0" }, - { 0xf9af, "\x7f\x9a\0" }, - { 0xf9b0, "\x80\x46\0" }, - { 0xf9b1, "\x92\x34\0" }, - { 0xf9b2, "\x96\xf6\0" }, - { 0xf9b3, "\x97\x48\0" }, - { 0xf9b4, "\x98\x18\0" }, - { 0xf9b5, "\x4f\x8b\0" }, - { 0xf9b6, "\x79\xae\0" }, - { 0xf9b7, "\x91\xb4\0" }, - { 0xf9b8, "\x96\xb8\0" }, - { 0xf9b9, "\x60\xe1\0" }, - { 0xf9ba, "\x4e\x86\0" }, - { 0xf9bb, "\x50\xda\0" }, - { 0xf9bc, "\x5b\xee\0" }, - { 0xf9bd, "\x5c\x3f\0" }, - { 0xf9be, "\x65\x99\0" }, - { 0xf9bf, "\x6a\x02\0" }, - { 0xf9c0, "\x71\xce\0" }, - { 0xf9c1, "\x76\x42\0" }, - { 0xf9c2, "\x84\xfc\0" }, - { 0xf9c3, "\x90\x7c\0" }, - { 0xf9c4, "\x9f\x8d\0" }, - { 0xf9c5, "\x66\x88\0" }, - { 0xf9c6, "\x96\x2e\0" }, - { 0xf9c7, "\x52\x89\0" }, - { 0xf9c8, "\x67\x7b\0" }, - { 0xf9c9, "\x67\xf3\0" }, - { 0xf9ca, "\x6d\x41\0" }, - { 0xf9cb, "\x6e\x9c\0" }, - { 0xf9cc, "\x74\x09\0" }, - { 0xf9cd, "\x75\x59\0" }, - { 0xf9ce, "\x78\x6b\0" }, - { 0xf9cf, "\x7d\x10\0" }, - { 0xf9d0, "\x98\x5e\0" }, - { 0xf9d1, "\x51\x6d\0" }, - { 0xf9d2, "\x62\x2e\0" }, - { 0xf9d3, "\x96\x78\0" }, - { 0xf9d4, "\x50\x2b\0" }, - { 0xf9d5, "\x5d\x19\0" }, - { 0xf9d6, "\x6d\xea\0" }, - { 0xf9d7, "\x8f\x2a\0" }, - { 0xf9d8, "\x5f\x8b\0" }, - { 0xf9d9, "\x61\x44\0" }, - { 0xf9da, "\x68\x17\0" }, - { 0xf9db, "\x73\x87\0" }, - { 0xf9dc, "\x96\x86\0" }, - { 0xf9dd, "\x52\x29\0" }, - { 0xf9de, "\x54\x0f\0" }, - { 0xf9df, "\x5c\x65\0" }, - { 0xf9e0, "\x66\x13\0" }, - { 0xf9e1, "\x67\x4e\0" }, - { 0xf9e2, "\x68\xa8\0" }, - { 0xf9e3, "\x6c\xe5\0" }, - { 0xf9e4, "\x74\x06\0" }, - { 0xf9e5, "\x75\xe2\0" }, - { 0xf9e6, "\x7f\x79\0" }, - { 0xf9e7, "\x88\xcf\0" }, - { 0xf9e8, "\x88\xe1\0" }, - { 0xf9e9, "\x91\xcc\0" }, - { 0xf9ea, "\x96\xe2\0" }, - { 0xf9eb, "\x53\x3f\0" }, - { 0xf9ec, "\x6e\xba\0" }, - { 0xf9ed, "\x54\x1d\0" }, - { 0xf9ee, "\x71\xd0\0" }, - { 0xf9ef, "\x74\x98\0" }, - { 0xf9f0, "\x85\xfa\0" }, - { 0xf9f1, "\x96\xa3\0" }, - { 0xf9f2, "\x9c\x57\0" }, - { 0xf9f3, "\x9e\x9f\0" }, - { 0xf9f4, "\x67\x97\0" }, - { 0xf9f5, "\x6d\xcb\0" }, - { 0xf9f6, "\x81\xe8\0" }, - { 0xf9f7, "\x7a\xcb\0" }, - { 0xf9f8, "\x7b\x20\0" }, - { 0xf9f9, "\x7c\x92\0" }, - { 0xf9fa, "\x72\xc0\0" }, - { 0xf9fb, "\x70\x99\0" }, - { 0xf9fc, "\x8b\x58\0" }, - { 0xf9fd, "\x4e\xc0\0" }, - { 0xf9fe, "\x83\x36\0" }, - { 0xf9ff, "\x52\x3a\0" }, - { 0xfa00, "\x52\x07\0" }, - { 0xfa01, "\x5e\xa6\0" }, - { 0xfa02, "\x62\xd3\0" }, - { 0xfa03, "\x7c\xd6\0" }, - { 0xfa04, "\x5b\x85\0" }, - { 0xfa05, "\x6d\x1e\0" }, - { 0xfa06, "\x66\xb4\0" }, - { 0xfa07, "\x8f\x3b\0" }, - { 0xfa08, "\x88\x4c\0" }, - { 0xfa09, "\x96\x4d\0" }, - { 0xfa0a, "\x89\x8b\0" }, - { 0xfa0b, "\x5e\xd3\0" }, - { 0xfa0c, "\x51\x40\0" }, - { 0xfa0d, "\x55\xc0\0" }, - { 0xfa10, "\x58\x5a\0" }, - { 0xfa12, "\x66\x74\0" }, - { 0xfa15, "\x51\xde\0" }, - { 0xfa16, "\x73\x2a\0" }, - { 0xfa17, "\x76\xca\0" }, - { 0xfa18, "\x79\x3c\0" }, - { 0xfa19, "\x79\x5e\0" }, - { 0xfa1a, "\x79\x65\0" }, - { 0xfa1b, "\x79\x8f\0" }, - { 0xfa1c, "\x97\x56\0" }, - { 0xfa1d, "\x7c\xbe\0" }, - { 0xfa1e, "\x7f\xbd\0" }, - { 0xfa20, "\x86\x12\0" }, - { 0xfa22, "\x8a\xf8\0" }, - { 0xfa25, "\x90\x38\0" }, - { 0xfa26, "\x90\xfd\0" }, - { 0xfa2a, "\x98\xef\0" }, - { 0xfa2b, "\x98\xfc\0" }, - { 0xfa2c, "\x99\x28\0" }, - { 0xfa2d, "\x9d\xb4\0" }, - { 0xfb1f, "\x05\xf2\x05\xb7\0" }, - { 0xfb2a, "\x05\xe9\x05\xc1\0" }, - { 0xfb2b, "\x05\xe9\x05\xc2\0" }, - { 0xfb2c, "\x05\xe9\x05\xbc\x05\xc1\0" }, - { 0xfb2d, "\x05\xe9\x05\xbc\x05\xc2\0" }, - { 0xfb2e, "\x05\xd0\x05\xb7\0" }, - { 0xfb2f, "\x05\xd0\x05\xb8\0" }, - { 0xfb30, "\x05\xd0\x05\xbc\0" }, - { 0xfb31, "\x05\xd1\x05\xbc\0" }, - { 0xfb32, "\x05\xd2\x05\xbc\0" }, - { 0xfb33, "\x05\xd3\x05\xbc\0" }, - { 0xfb34, "\x05\xd4\x05\xbc\0" }, - { 0xfb35, "\x05\xd5\x05\xbc\0" }, - { 0xfb36, "\x05\xd6\x05\xbc\0" }, - { 0xfb38, "\x05\xd8\x05\xbc\0" }, - { 0xfb39, "\x05\xd9\x05\xbc\0" }, - { 0xfb3a, "\x05\xda\x05\xbc\0" }, - { 0xfb3b, "\x05\xdb\x05\xbc\0" }, - { 0xfb3c, "\x05\xdc\x05\xbc\0" }, - { 0xfb3e, "\x05\xde\x05\xbc\0" }, - { 0xfb40, "\x05\xe0\x05\xbc\0" }, - { 0xfb41, "\x05\xe1\x05\xbc\0" }, - { 0xfb43, "\x05\xe3\x05\xbc\0" }, - { 0xfb44, "\x05\xe4\x05\xbc\0" }, - { 0xfb46, "\x05\xe6\x05\xbc\0" }, - { 0xfb47, "\x05\xe7\x05\xbc\0" }, - { 0xfb48, "\x05\xe8\x05\xbc\0" }, - { 0xfb49, "\x05\xe9\x05\xbc\0" }, - { 0xfb4a, "\x05\xea\x05\xbc\0" }, - { 0xfb4b, "\x05\xd5\x05\xb9\0" }, - { 0xfb4c, "\x05\xd1\x05\xbf\0" }, - { 0xfb4d, "\x05\xdb\x05\xbf\0" }, - { 0xfb4e, "\x05\xe4\x05\xbf\0" } -}; - -/* - * WARNING! - * - * NO BUFFER CHECKING AHEAD! - * - */ - -static gint -e_canonical_decomposition (gunichar ch, gunichar * buf) -{ - gint len = 0; - - if (ch <= 0xffff) - { - int start = 0; - int end = sizeof (e_decomp_table) / sizeof (e_decomp_table[0]); - while (start != end) - { - int half = (start + end) / 2; - if (ch == e_decomp_table[half].ch) { - /* Found it. */ - int i; - /* We store as a double-nul terminated string. */ - for (len = 0; (e_decomp_table[half].expansion[len] || e_decomp_table[half].expansion[len + 1]); len += 2) ; - - /* We've counted twice as many bytes as there are - characters. */ - len /= 2; - - for (i = 0; i < len; i ++) { - buf[i] = (e_decomp_table[half].expansion[2 * i] << 8) | e_decomp_table[half].expansion[2 * i + 1]; - } - break; - } else if (ch > e_decomp_table[half].ch) { - if (start == half) break; - start = half; - } else { - if (end == half) break; - end = half; - } - } - } - - if (len == 0) - { - /* Not in our table. */ - *buf = ch; - len = 1; - } - - /* Supposedly following the Unicode 2.1.9 table means that the - decompositions come out in canonical order. I haven't tested - this, but we rely on it here. */ - return len; -} - -static gunichar -e_stripped_char (gunichar ch) -{ - gunichar decomp[MAX_DECOMP]; - GUnicodeType utype; - gint dlen; - - utype = g_unichar_type (ch); - - switch (utype) { - case G_UNICODE_CONTROL: - case G_UNICODE_FORMAT: - case G_UNICODE_UNASSIGNED: - case G_UNICODE_COMBINING_MARK: - /* Ignore those */ - return 0; - default: - /* Convert to lowercase, fall through */ - ch = g_unichar_tolower (ch); - case G_UNICODE_LOWERCASE_LETTER: - dlen = e_canonical_decomposition (ch, decomp); - if (dlen > 0) return *decomp; - break; - } - - return 0; -} - -gchar * -e_xml_get_translated_utf8_string_prop_by_name (const xmlNode *parent, const xmlChar *prop_name) -{ - xmlChar *prop; - gchar *ret_val = NULL; - gchar *combined_name; - - g_return_val_if_fail (parent != NULL, NULL); - g_return_val_if_fail (prop_name != NULL, NULL); - - prop = xmlGetProp ((xmlNode *) parent, prop_name); - if (prop != NULL) { - ret_val = g_strdup ((char *)prop); - xmlFree (prop); - return ret_val; - } - - combined_name = g_strdup_printf("_%s", prop_name); - prop = xmlGetProp ((xmlNode *) parent, (unsigned char *)combined_name); - if (prop != NULL) { - ret_val = g_strdup (gettext ((char *)prop)); - xmlFree (prop); - } - g_free(combined_name); - - return ret_val; -} diff --git a/widgets/misc/e-unicode.h b/widgets/misc/e-unicode.h deleted file mode 100644 index b745876b6d..0000000000 --- a/widgets/misc/e-unicode.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * e-unicode.h - utf-8 support functions for gal - * - * 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 - * - * - * Authors: - * Lauris Kaplinski - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _E_UNICODE_H_ -#define _E_UNICODE_H_ - -#include -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define G_UTF8_IN_GAL - -/* - * UTF-8 searching implementations - * - * e_utf8_strstrcase - case insensitive search - * e_utf8_strstrcasedecomp - case insensitive and decompositing search (i.e. accented - * letters are treated equal to their base letters, explicit accent marks (unicode - * not ascii/iso ones) are ignored). - */ - -const gchar *e_utf8_strstrcase (const gchar *haystack, - const gchar *needle); -const gchar *e_utf8_strstrcasedecomp (const gchar *haystack, - const gchar *needle); -gchar *e_utf8_from_gtk_event_key (GtkWidget *widget, - guint keyval, - const gchar *string); -gchar *e_utf8_from_iconv_string (iconv_t ic, - const gchar *string); -gchar *e_utf8_from_iconv_string_sized (iconv_t ic, - const gchar *string, - gint bytes); -gchar *e_utf8_to_iconv_string (iconv_t ic, - const gchar *string); -gchar *e_utf8_to_iconv_string_sized (iconv_t ic, - const gchar *string, - gint bytes); -gchar *e_utf8_from_charset_string (const gchar *charset, - const gchar *string); -gchar *e_utf8_from_charset_string_sized (const gchar *charset, - const gchar *string, - gint bytes); -gchar *e_utf8_to_charset_string (const gchar *charset, - const gchar *string); -gchar *e_utf8_to_charset_string_sized (const gchar *charset, - const gchar *string, - gint bytes); -gchar *e_utf8_from_locale_string (const gchar *string); -gchar *e_utf8_from_locale_string_sized (const gchar *string, - gint bytes); -gchar *e_utf8_to_locale_string (const gchar *string); -gchar *e_utf8_to_locale_string_sized (const gchar *string, - gint bytes); -gboolean e_utf8_is_ascii (const gchar *string); -/* - * These are simple wrappers that save us some typing - */ - -/* NB! This return newly allocated string, not const as gtk+ one */ -gchar *e_utf8_gtk_entry_get_text (GtkEntry *entry); -void e_utf8_gtk_entry_set_text (GtkEntry *entry, - const gchar *text); -gchar *e_utf8_gtk_editable_get_text (GtkEditable *editable); -void e_utf8_gtk_editable_set_text (GtkEditable *editable, - const gchar *text); -gchar *e_utf8_gtk_editable_get_chars (GtkEditable *editable, - gint start, - gint end); -void e_utf8_gtk_editable_insert_text (GtkEditable *editable, - const gchar *text, - gint length, - gint *position); -gchar *e_utf8_xml1_decode (const gchar *text); -gchar *e_utf8_xml1_encode (const gchar *text); -gint e_unichar_to_utf8 (gint c, - gchar *outbuf); -gchar *e_unicode_get_utf8 (const gchar *text, - gunichar *out); -guint32 gdk_keyval_to_unicode (guint keysym); -gchar *e_xml_get_translated_utf8_string_prop_by_name (const xmlNode *parent, - const xmlChar *prop_name); - -G_END_DECLS - -#endif - - 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 + * + * + * Authors: + * Yang Wu + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include +#include + +#include "a11y/gal-a11y-util.h" +#include "table/e-cell-popup.h" +#include + +#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 */ + "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 + * + * + * Authors: + * Yang Wu + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_CELL_POPUP_H__ +#define __GAL_A11Y_E_CELL_POPUP_H__ + +#include +#include
+#include
+#include + +#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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_CELL_REGISTRY_H__ +#define __GAL_A11Y_E_CELL_REGISTRY_H__ + +#include +#include +#include
+#include
+ +#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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include + +#include + +#include "a11y/gal-a11y-util.h" +#include "table/e-cell-text.h" +#include + +#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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_CELL_TEXT_H__ +#define __GAL_A11Y_E_CELL_TEXT_H__ + +#include +#include
+#include
+#include
+ +#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 + * + * + * Authors: + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include "table/e-cell-toggle.h" +#include "table/e-table-model.h" +#include + +#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 + * + * + * 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 +#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 + * + * + * Authors: + * Tim Wo + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include + +#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 + +#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 + * + * + * Authors: + * Tim Wo + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_CELL_TREE_H__ +#define __GAL_A11Y_E_CELL_TREE_H__ + +#include +#include
+#include
+#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 + * + * + * Authors: + * Eric Zhao + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * Copyright (C) 2004 Sun Microsystem, Inc. + * + */ + +#include + +#include + +#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 + * + * + * Authors: + * Eric Zhao + * + * 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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include + +#include + +#include "a11y/gal-a11y-util.h" +#include "table/e-table.h" +#include "table/e-tree.h" +#include + +#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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_CELL_H__ +#define __GAL_A11Y_E_CELL_H__ + +#include +#include
+#include
+ +#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 + * + * + * Authors: + * Yuedong Du + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include + +#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 + * + * + * Authors: + * Yuedong Du + * + * 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 +#include + +#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 + * + * + * Authors: + * Yuedong Du + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include + +#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 + +#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 + * + * + * 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 +#include
+#include + +#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 + * + * + * Authors: + * Li Yuan + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include +#include +#include +#include +#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 + * + * + * Authors: + * Li Yuan + * + * 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 +#include + +#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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TABLE_FACTORY_H__ +#define __GAL_A11Y_E_TABLE_FACTORY_H__ + +#include +#include + +#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 + * + * + * Authors: + * Yuedong Du + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include + +#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 + * + * + * Authors: + * Yuedong Du + * + * 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 +#include + +#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 + * + * + * Authors: + * Christopher James Lahey + * Bolian Yin + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include + +#include + +#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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TABLE_ITEM_H__ +#define __GAL_A11Y_E_TABLE_ITEM_H__ + +#include +#include
+#include + +#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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TABLE_H__ +#define __GAL_A11Y_E_TABLE_H__ + +#include +#include +#include + +#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 + * + * + * Authors: + * Yuedong Du + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#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 + * + * + * Authors: + * Yuedong Du + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TREE_FACTORY_H__ +#define __GAL_A11Y_E_TREE_FACTORY_H__ + +#include +#include + +#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 + * + * + * Authors: + * Yuedong Du + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#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 + * + * + * Authors: + * Yuedong Du + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TREE_H__ +#define __GAL_A11Y_E_TREE_H__ + +#include +#include +#include + +#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 #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 + * + * + * Authors: + * Damon Chaplin + * + * 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 +#endif + +#include "e-cell-date-edit.h" + +#include +#include +#include + +#include +#include + +#include "e-table-item.h" +#include "e-cell-text.h" + +#include + +#include + +/* This depends on ECalendar which is why I didn't put it in gal. */ +#include + +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 + * + * + * Authors: + * Damon Chaplin + * + * 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 +#include
+ +#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 #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 -/* #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 + * + * + * Authors: + * Damon Chaplin + * + * 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 +#endif + +#include + +#include +#include +#include +#include + +#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 + * + * + * Authors: + * Damon Chaplin + * + * 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
+ +#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 -#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 #include -#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 #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 #include -#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 #include -#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 -#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 #include -#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 #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 #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 -#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 #include -#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 #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 #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 #include -#include "a11y/e-table/gal-a11y-e-table.h" +#include "a11y/gal-a11y-e-table.h" #include #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 #include -#include "a11y/e-table/gal-a11y-e-tree.h" +#include "a11y/gal-a11y-e-tree.h" #include #include "e-util/e-util.h" #include "misc/e-canvas.h" diff --git a/widgets/text/Makefile.am b/widgets/text/Makefile.am index fbe03c828f..e035d8714d 100644 --- a/widgets/text/Makefile.am +++ b/widgets/text/Makefile.am @@ -1,7 +1,3 @@ -if OS_WIN32 -WIN32_BOOTSTRAP_LIBS = $(top_builddir)/win32/libemiscwidgets.la -endif - INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/widgets \ @@ -15,22 +11,29 @@ privsolib_LTLIBRARIES = libetext.la libetext_la_SOURCES = \ e-text-model-repos.c \ e-text-model.c \ - e-text.c + e-text.c \ + e-reflow.c \ + e-reflow-model.c \ + a11y/gal-a11y-e-text-factory.c \ + a11y/gal-a11y-e-text.c libetextincludedir = $(privincludedir)/text libetextinclude_HEADERS = \ e-text-model-repos.h \ e-text-model.h \ - e-text.h + e-text.h \ + e-reflow.h \ + e-reflow-model.h \ + a11y/gal-a11y-e-text-factory.h \ + a11y/gal-a11y-e-text.h libetext_la_LDFLAGS = $(NO_UNDEFINED) libetext_la_LIBADD = \ - $(WIN32_BOOTSTRAP_LIBS) \ - $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/a11y/libevolution-a11y.la \ - $(top_builddir)/widgets/table/libetable.la \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/widgets/misc/libemiscwidgets.la \ $(E_UTIL_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(REGEX_LIBS) diff --git a/widgets/text/a11y/gal-a11y-e-text-factory.c b/widgets/text/a11y/gal-a11y-e-text-factory.c new file mode 100644 index 0000000000..e1f835e912 --- /dev/null +++ b/widgets/text/a11y/gal-a11y-e-text-factory.c @@ -0,0 +1,101 @@ +/* + * 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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include +#include "text/e-text.h" +#include "gal-a11y-e-text-factory.h" +#include "gal-a11y-e-text.h" + +#define CS_CLASS(factory) (G_TYPE_INSTANCE_GET_CLASS ((factory), C_TYPE_STREAM, GalA11yETextFactoryClass)) +static AtkObjectFactoryClass *parent_class; +#define PARENT_TYPE (ATK_TYPE_OBJECT_FACTORY) + +/* Static functions */ + +static GType +gal_a11y_e_text_factory_get_accessible_type (void) +{ + return GAL_A11Y_TYPE_E_TEXT; +} + +static AtkObject* +gal_a11y_e_text_factory_create_accessible (GObject *obj) +{ + AtkObject *atk_object; + + g_return_val_if_fail (E_IS_TEXT (obj), NULL); + + atk_object = g_object_new (GAL_A11Y_TYPE_E_TEXT, NULL); + atk_object_initialize (atk_object, obj); + + return atk_object; +} + +static void +gal_a11y_e_text_factory_class_init (GalA11yETextFactoryClass *klass) +{ + AtkObjectFactoryClass *factory_class = ATK_OBJECT_FACTORY_CLASS (klass); + + parent_class = g_type_class_ref (PARENT_TYPE); + + factory_class->create_accessible = gal_a11y_e_text_factory_create_accessible; + factory_class->get_accessible_type = gal_a11y_e_text_factory_get_accessible_type; +} + +static void +gal_a11y_e_text_factory_init (GalA11yETextFactory *factory) +{ +} + +/** + * gal_a11y_e_text_factory_get_type: + * @void: + * + * Registers the &GalA11yETextFactory class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yETextFactory class. + **/ +GType +gal_a11y_e_text_factory_get_type (void) +{ + static GType type = 0; + + if (!type) { + GTypeInfo info = { + sizeof (GalA11yETextFactoryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gal_a11y_e_text_factory_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yETextFactory), + 0, + (GInstanceInitFunc) gal_a11y_e_text_factory_init, + NULL /* value_text */ + }; + + type = g_type_register_static (PARENT_TYPE, "GalA11yETextFactory", &info, 0); + } + + return type; +} diff --git a/widgets/text/a11y/gal-a11y-e-text-factory.h b/widgets/text/a11y/gal-a11y-e-text-factory.h new file mode 100644 index 0000000000..ce4d4d0a65 --- /dev/null +++ b/widgets/text/a11y/gal-a11y-e-text-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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TEXT_FACTORY_H__ +#define __GAL_A11Y_E_TEXT_FACTORY_H__ + +#include +#include + +#define GAL_A11Y_TYPE_E_TEXT_FACTORY (gal_a11y_e_text_factory_get_type ()) +#define GAL_A11Y_E_TEXT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TEXT_FACTORY, GalA11yETextFactory)) +#define GAL_A11Y_E_TEXT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TEXT_FACTORY, GalA11yETextFactoryClass)) +#define GAL_A11Y_IS_E_TEXT_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TEXT_FACTORY)) +#define GAL_A11Y_IS_E_TEXT_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TEXT_FACTORY)) + +typedef struct _GalA11yETextFactory GalA11yETextFactory; +typedef struct _GalA11yETextFactoryClass GalA11yETextFactoryClass; + +struct _GalA11yETextFactory { + AtkObjectFactory object; +}; + +struct _GalA11yETextFactoryClass { + AtkObjectFactoryClass parent_class; +}; + + +/* Standard Glib function */ +GType gal_a11y_e_text_factory_get_type (void); + +#endif /* ! __GAL_A11Y_E_TEXT_FACTORY_H__ */ diff --git a/widgets/text/a11y/gal-a11y-e-text.c b/widgets/text/a11y/gal-a11y-e-text.c new file mode 100644 index 0000000000..4eeb7811fc --- /dev/null +++ b/widgets/text/a11y/gal-a11y-e-text.c @@ -0,0 +1,1134 @@ +/* + * 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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include + +#include + +#include + +#include "a11y/gal-a11y-util.h" +#include "text/e-text.h" +#include "text/e-text-model-repos.h" + +#include "gal-a11y-e-text.h" +#include "gal-a11y-e-text-factory.h" + +#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETextClass)) +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) ((GalA11yETextPrivate *) (((char *) object) + priv_offset)) +#define PARENT_TYPE (parent_type) + +struct _GalA11yETextPrivate { + int dummy; +}; + +static void +et_dispose (GObject *object) +{ + if (parent_class->dispose) + parent_class->dispose (object); +} + +/* Static functions */ + +static void +et_get_extents (AtkComponent *component, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coord_type) +{ + EText *item = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (component))); + double real_width; + double real_height; + int fake_width; + int fake_height; + + if (component_parent_iface && + component_parent_iface->get_extents) + component_parent_iface->get_extents (component, + x, + y, + &fake_width, + &fake_height, + coord_type); + + g_object_get (item, + "text_width", &real_width, + "text_height", &real_height, + NULL); + + if (width) + *width = real_width; + if (height) + *height = real_height; +} + +static const gchar * +et_get_full_text (AtkText *text) +{ + EText *etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); + ETextModel *model; + const char *full_text; + + g_object_get (etext, "model", &model, NULL); + + full_text = e_text_model_get_text (model); + + return full_text; +} + +static void +et_set_full_text (AtkEditableText *text, + const char *full_text) +{ + EText *etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); + ETextModel *model; + + g_object_get (etext, "model", &model, NULL); + + e_text_model_set_text (model, full_text); +} + +static gchar * +et_get_text (AtkText *text, + gint start_offset, + gint end_offset) +{ + gint start, end, real_start, real_end, len; + const char *full_text = et_get_full_text (text); + if (full_text == NULL) + return NULL; + len = g_utf8_strlen (full_text, -1); + + start = MIN (MAX (0, start_offset), len); + end = MIN (MAX (-1, end_offset), len); + + if (end_offset == -1) + end = strlen (full_text); + else + end = g_utf8_offset_to_pointer (full_text, end) - full_text; + + start = g_utf8_offset_to_pointer (full_text, start) - full_text; + + real_start = MIN (start, end); + real_end = MAX (start, end); + + return g_strndup (full_text + real_start, real_end - real_start); +} + +static gboolean +is_a_seperator (gunichar c) +{ + return g_unichar_ispunct(c) || g_unichar_isspace(c); +} + +static gint +find_word_start (const char *text, + gint begin_offset, + gint step) +{ + gint offset; + char *at_offset; + gunichar current, previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset); + current = g_utf8_get_char_validated (at_offset, -1); + at_offset = g_utf8_offset_to_pointer (text, offset-1); + previous = g_utf8_get_char_validated (at_offset, -1); + if ((! is_a_seperator (current)) && is_a_seperator (previous)) + break; + offset += step; + } + + return offset; +} + +static gint +find_word_end (const char *text, + gint begin_offset, + gint step) +{ + gint offset; + char *at_offset; + gunichar current, previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset); + current = g_utf8_get_char_validated (at_offset, -1); + at_offset = g_utf8_offset_to_pointer (text, offset-1); + previous = g_utf8_get_char_validated (at_offset, -1); + if (is_a_seperator (current) && (! is_a_seperator (previous))) + break; + offset += step; + } + + return offset; +} + +static gint +find_sentence_start (const char *text, + gint begin_offset, + gint step) +{ + gint offset, last_word_end, len; + char *at_offset; + gunichar ch; + int i; + + offset = find_word_start (text, begin_offset, step); + len = g_utf8_strlen (text, -1); + + while (offset>0 && offset 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset - 1); + previous = g_utf8_get_char_validated (at_offset, -1); + if (previous == '.' || previous == '!' || previous == '?') + break; + offset += step; + } + + return offset; +} + +static gint +find_line_start (const char *text, + gint begin_offset, + gint step) +{ + gint offset; + char *at_offset; + gunichar previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset - 1); + previous = g_utf8_get_char_validated (at_offset, -1); + if (previous == '\n' || previous == '\r') + break; + offset += step; + } + + return offset; +} + +static gint +find_line_end (const char *text, + gint begin_offset, + gint step) +{ + gint offset; + char *at_offset; + gunichar current; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset >= 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset); + current = g_utf8_get_char_validated (at_offset, -1); + if (current == '\n' || current == '\r') + break; + offset += step; + } + + return offset; +} + +static gchar * +et_get_text_after_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + gint start, end, len; + const char *full_text = et_get_full_text (text); + g_return_val_if_fail (full_text, NULL); + + switch (boundary_type) + { + case ATK_TEXT_BOUNDARY_CHAR: + start = offset + 1; + end = offset + 2; + break; + case ATK_TEXT_BOUNDARY_WORD_START: + start = find_word_start (full_text, offset + 1, 1); + end = find_word_start (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_WORD_END: + start = find_word_end (full_text, offset + 1, 1); + end = find_word_end (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_START: + start = find_sentence_start (full_text, offset + 1, 1); + end = find_sentence_start (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_END: + start = find_sentence_end (full_text, offset + 1, 1); + end = find_sentence_end (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_START: + start = find_line_start (full_text, offset + 1, 1); + end = find_line_start (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_END: + start = find_line_end (full_text, offset + 1, 1); + end = find_line_end (full_text, start + 1, 1); + break; + default: + return NULL; + } + + len = g_utf8_strlen (full_text, -1); + if (start_offset) + *start_offset = MIN (MAX (0, start), len); + if (end_offset) + *end_offset = MIN (MAX (0, end), len); + return et_get_text (text, start, end); +} + +static gchar * +et_get_text_at_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + gint start, end, len; + const char *full_text = et_get_full_text (text); + g_return_val_if_fail (full_text, NULL); + + switch (boundary_type) + { + case ATK_TEXT_BOUNDARY_CHAR: + start = offset; + end = offset + 1; + break; + case ATK_TEXT_BOUNDARY_WORD_START: + start = find_word_start (full_text, offset - 1, -1); + end = find_word_start (full_text, offset, 1); + break; + case ATK_TEXT_BOUNDARY_WORD_END: + start = find_word_end (full_text, offset, -1); + end = find_word_end (full_text, offset + 1, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_START: + start = find_sentence_start (full_text, offset - 1, -1); + end = find_sentence_start (full_text, offset, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_END: + start = find_sentence_end (full_text, offset, -1); + end = find_sentence_end (full_text, offset + 1, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_START: + start = find_line_start (full_text, offset - 1, -1); + end = find_line_start (full_text, offset, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_END: + start = find_line_end (full_text, offset, -1); + end = find_line_end (full_text, offset + 1, 1); + break; + default: + return NULL; + } + + len = g_utf8_strlen (full_text, -1); + if (start_offset) + *start_offset = MIN (MAX (0, start), len); + if (end_offset) + *end_offset = MIN (MAX (0, end), len); + return et_get_text (text, start, end); +} + +static gunichar +et_get_character_at_offset (AtkText *text, + gint offset) +{ + const char *full_text = et_get_full_text (text); + char *at_offset; + + at_offset = g_utf8_offset_to_pointer (full_text, offset); + return g_utf8_get_char_validated (at_offset, -1); +} + + +static gchar* +et_get_text_before_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + gint start, end, len; + const char *full_text = et_get_full_text (text); + g_return_val_if_fail (full_text, NULL); + + switch (boundary_type) + { + case ATK_TEXT_BOUNDARY_CHAR: + start = offset - 1; + end = offset; + break; + case ATK_TEXT_BOUNDARY_WORD_START: + end = find_word_start (full_text, offset - 1, -1); + start = find_word_start (full_text, end - 1, -1) ; + break; + case ATK_TEXT_BOUNDARY_WORD_END: + end = find_word_end (full_text, offset, -1); + start = find_word_end (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_START: + end = find_sentence_start (full_text, offset, -1); + start = find_sentence_start (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_END: + end = find_sentence_end (full_text, offset, -1); + start = find_sentence_end (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_LINE_START: + end = find_line_start (full_text, offset, -1); + start = find_line_start (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_LINE_END: + end = find_line_end (full_text, offset, -1); + start = find_line_end (full_text, end - 1, -1); + break; + default: + return NULL; + } + + len = g_utf8_strlen (full_text, -1); + if (start_offset) + *start_offset = MIN (MAX (0, start), len); + if (end_offset) + *end_offset = MIN (MAX (0, end), len); + return et_get_text (text, start, end); +} + +static gint +et_get_caret_offset (AtkText *text) +{ + GObject *obj; + EText *etext; + int offset; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text), -1); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return -1; + + g_return_val_if_fail (E_IS_TEXT (obj), -1); + etext = E_TEXT (obj); + + g_object_get (etext, "cursor_pos", &offset, NULL); + return offset; +} + + +static AtkAttributeSet* +et_get_run_attributes (AtkText *text, + gint offset, + gint *start_offset, + gint *end_offset) +{ + /* Unimplemented */ + return NULL; +} + + +static AtkAttributeSet* +et_get_default_attributes (AtkText *text) +{ + /* Unimplemented */ + return NULL; +} + + +static void +et_get_character_extents (AtkText *text, + gint offset, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coords) +{ + GObject *obj; + EText *etext; + GnomeCanvas *canvas; + gint x_widget, y_widget, x_window, y_window; + GdkWindow *window; + GtkWidget *widget; + PangoRectangle pango_pos; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT(obj); + canvas = GNOME_CANVAS_ITEM(etext)->canvas; + widget = GTK_WIDGET(canvas); + window = widget->window; + gdk_window_get_origin (window, &x_widget, &y_widget); + + pango_layout_index_to_pos (etext->layout, offset, &pango_pos); + pango_pos.x = PANGO_PIXELS (pango_pos.x); + pango_pos.y = PANGO_PIXELS (pango_pos.y); + pango_pos.width = (pango_pos.width + PANGO_SCALE / 2) / PANGO_SCALE; + pango_pos.height = (pango_pos.height + PANGO_SCALE / 2) / PANGO_SCALE; + + *x = pango_pos.x + x_widget; + *y = pango_pos.y + y_widget; + + *width = pango_pos.width; + *height = pango_pos.height; + + if (etext->draw_borders) { + *x += 3; /*BORDER_INDENT;*/ + *y += 3; /*BORDER_INDENT;*/ + } + + *x += etext->xofs; + *y += etext->yofs; + + if (etext->editing) { + *x -= etext->xofs_edit; + *y -= etext->yofs_edit; + } + + *x += etext->cx; + *y += etext->cy; + + if (coords == ATK_XY_WINDOW) { + window = gdk_window_get_toplevel (window); + gdk_window_get_origin (window, &x_window, &y_window); + *x -= x_window; + *y -= y_window; + } + else if (coords == ATK_XY_SCREEN) { + } + else { + *x = 0; + *y = 0; + *height = 0; + *width = 0; + } +} + + +static gint +et_get_character_count (AtkText *text) +{ + const char *full_text = et_get_full_text (text); + + return g_utf8_strlen (full_text, -1); +} + + +static gint +et_get_offset_at_point (AtkText *text, + gint x, + gint y, + AtkCoordType coords) +{ + GObject *obj; + EText *etext; + GnomeCanvas *canvas; + gint x_widget, y_widget, x_window, y_window; + GdkWindow *window; + GtkWidget *widget; + int index; + int trailing; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text), -1); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return -1; + g_return_val_if_fail (E_IS_TEXT (obj), -1); + etext = E_TEXT(obj); + canvas = GNOME_CANVAS_ITEM(etext)->canvas; + widget = GTK_WIDGET(canvas); + window = widget->window; + gdk_window_get_origin (window, &x_widget, &y_widget); + + if (coords == ATK_XY_SCREEN) { + x = x - x_widget; + y = y - y_widget; + } + else if (coords == ATK_XY_WINDOW) { + window = gdk_window_get_toplevel (window); + gdk_window_get_origin (window, &x_window, &y_window); + x = x - x_widget + x_window; + y = y - y_widget + y_window; + } + else + return -1; + + if (etext->draw_borders) { + x -= 3; /*BORDER_INDENT;*/ + y -= 3; /*BORDER_INDENT;*/ + } + + x -= etext->xofs; + y -= etext->yofs; + + if (etext->editing) { + x += etext->xofs_edit; + y += etext->yofs_edit; + } + + x -= etext->cx; + y -= etext->cy; + + pango_layout_xy_to_index (etext->layout, + x * PANGO_SCALE - PANGO_SCALE / 2, + y * PANGO_SCALE - PANGO_SCALE / 2, + &index, + &trailing); + + return g_utf8_pointer_to_offset (etext->text, etext->text + index + trailing); +} + + +static gint +et_get_n_selections (AtkText *text) +{ + EText *etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); + if (etext->selection_start != + etext->selection_end) + return 1; + return 0; +} + + +static gchar* +et_get_selection (AtkText *text, + gint selection_num, + gint *start_offset, + gint *end_offset) +{ + gint start, end, real_start, real_end, len; + EText *etext; + if (selection_num == 0) { + const char *full_text = et_get_full_text (text); + if (full_text == NULL) + return NULL; + len = g_utf8_strlen (full_text, -1); + etext = E_TEXT (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text))); + start = MIN (etext->selection_start, etext->selection_end); + end = MAX (etext->selection_start, etext->selection_end); + start = MIN (MAX (0, start), len); + end = MIN (MAX (0, end), len); + if (start != end) { + if (start_offset) + *start_offset = start; + if (end_offset) + *end_offset = end; + real_start = g_utf8_offset_to_pointer (full_text, start) - full_text; + real_end = g_utf8_offset_to_pointer (full_text, end) - full_text; + return g_strndup (full_text + real_start, real_end - real_start); + } + } + + return NULL; +} + + +static gboolean +et_add_selection (AtkText *text, + gint start_offset, + gint end_offset) +{ + GObject *obj; + EText *etext; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + etext = E_TEXT (obj); + + g_return_val_if_fail (start_offset >= 0, FALSE); + g_return_val_if_fail (start_offset >= -1, FALSE); + if (end_offset == -1) + end_offset = et_get_character_count (text); + + if (start_offset != end_offset) { + gint real_start, real_end; + real_start = MIN (start_offset, end_offset); + real_end = MAX (start_offset, end_offset); + etext->selection_start = real_start; + etext->selection_end = real_end; + + gnome_canvas_item_grab_focus (GNOME_CANVAS_ITEM (etext)); + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (etext)); + + g_signal_emit_by_name (ATK_OBJECT (text), "text_selection_changed"); + + return TRUE; + } + + return FALSE; +} + + +static gboolean +et_remove_selection (AtkText *text, + gint selection_num) +{ + GObject *obj; + EText *etext; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + etext = E_TEXT (obj); + + if (selection_num == 0 + && etext->selection_start != etext->selection_end) { + etext->selection_end = etext->selection_start; + g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed"); + return TRUE; + } + + return FALSE; +} + + +static gboolean +et_set_selection (AtkText *text, + gint selection_num, + gint start_offset, + gint end_offset) +{ + GObject *obj; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + if (selection_num == 0) + return et_add_selection (text, start_offset, end_offset); + return FALSE; +} + + +static gboolean +et_set_caret_offset (AtkText *text, + gint offset) +{ + GObject *obj; + EText *etext; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + etext = E_TEXT (obj); + + if (offset < -1) + return FALSE; + else { + ETextEventProcessorCommand command; + + if (offset == -1) + offset = et_get_character_count (text); + + command.action = E_TEP_MOVE; + command.position = E_TEP_VALUE; + command.value = offset; + command.time = GDK_CURRENT_TIME; + g_signal_emit_by_name (etext->tep, "command", &command); + return TRUE; + } +} + +static gboolean +et_set_run_attributes (AtkEditableText *text, + AtkAttributeSet *attrib_set, + gint start_offset, + gint end_offset) +{ + /* Unimplemented */ + return FALSE; +} + +static void +et_set_text_contents (AtkEditableText *text, + const gchar *string) +{ + et_set_full_text (text, string); +} + +static void +et_insert_text (AtkEditableText *text, + const gchar *string, + gint length, + gint *position) +{ + /* Utf8 unimplemented */ + char *result; + + const char *full_text = et_get_full_text (ATK_TEXT (text)); + if (full_text == NULL) + return; + + result = g_strdup_printf ("%.*s%.*s%s", *position, full_text, length, string, full_text + *position); + + et_set_full_text (text, result); + + *position += length; + + g_free (result); +} + +static void +et_copy_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GObject *obj; + EText *etext; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT (obj); + + if (start_pos != end_pos) { + etext->selection_start = start_pos; + etext->selection_end = end_pos; + e_text_copy_clipboard (etext); + } +} + +static void +et_delete_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GObject *obj; + EText *etext; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE(text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT (obj); + + etext->selection_start = start_pos; + etext->selection_end = end_pos; + + e_text_delete_selection (etext); +} + +static void +et_cut_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + et_copy_text (text, start_pos, end_pos); + et_delete_text (text, start_pos, end_pos); +} + +static void +et_paste_text (AtkEditableText *text, + gint position) +{ + GObject *obj; + EText *etext; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT (obj); + + g_object_set (etext, "cursor_pos", position, NULL); + e_text_paste_clipboard (etext); +} + +static void +et_atk_component_iface_init (AtkComponentIface *iface) +{ + iface->get_extents = et_get_extents; +} + +static void +et_atk_text_iface_init (AtkTextIface *iface) +{ + iface->get_text = et_get_text; + iface->get_text_after_offset = et_get_text_after_offset; + iface->get_text_at_offset = et_get_text_at_offset; + iface->get_character_at_offset = et_get_character_at_offset; + iface->get_text_before_offset = et_get_text_before_offset; + iface->get_caret_offset = et_get_caret_offset; + iface->get_run_attributes = et_get_run_attributes; + iface->get_default_attributes = et_get_default_attributes; + iface->get_character_extents = et_get_character_extents; + iface->get_character_count = et_get_character_count; + iface->get_offset_at_point = et_get_offset_at_point; + iface->get_n_selections = et_get_n_selections; + iface->get_selection = et_get_selection; + iface->add_selection = et_add_selection; + iface->remove_selection = et_remove_selection; + iface->set_selection = et_set_selection; + iface->set_caret_offset = et_set_caret_offset; +} + +static void +et_atk_editable_text_iface_init (AtkEditableTextIface *iface) +{ + iface->set_run_attributes = et_set_run_attributes; + iface->set_text_contents = et_set_text_contents; + iface->insert_text = et_insert_text; + iface->copy_text = et_copy_text; + iface->cut_text = et_cut_text; + iface->delete_text = et_delete_text; + iface->paste_text = et_paste_text; +} + +static void +_et_reposition_cb (ETextModel *model, + ETextModelReposFn fn, + gpointer repos_data, + gpointer user_data) +{ + AtkObject *accessible; + AtkText *text; + + accessible = ATK_OBJECT (user_data); + text = ATK_TEXT (accessible); + + if (fn == e_repos_delete_shift) { + EReposDeleteShift *info = (EReposDeleteShift *) repos_data; + g_signal_emit_by_name (text, "text-changed::delete", info->pos, info->len); + } + else if (fn == e_repos_insert_shift) { + EReposInsertShift *info = (EReposInsertShift *) repos_data; + g_signal_emit_by_name (text, "text-changed::insert", info->pos, info->len); + } +} + +static void +_et_command_cb (ETextEventProcessor *tep, + ETextEventProcessorCommand *command, + gpointer user_data) +{ + AtkObject *accessible; + AtkText *text; + + accessible = ATK_OBJECT (user_data); + text = ATK_TEXT (accessible); + + switch (command->action) { + case E_TEP_MOVE: + g_signal_emit_by_name (text, "text-caret-moved", et_get_caret_offset (text)); + break; + case E_TEP_SELECT: + g_signal_emit_by_name (text, "text-selection-changed"); + break; + default: + break; + } +} + +static void +et_real_initialize (AtkObject *obj, + gpointer data) +{ + EText *etext; + + ATK_OBJECT_CLASS (parent_class)->initialize (obj, data); + + g_return_if_fail (GAL_A11Y_IS_E_TEXT (obj)); + g_return_if_fail (E_IS_TEXT (data)); + + etext = E_TEXT (data); + + /* Set up signal callbacks */ + g_signal_connect (etext->model, "reposition", + G_CALLBACK (_et_reposition_cb), obj); + + if (etext->tep) + g_signal_connect_after (etext->tep, "command", + (GCallback) _et_command_cb, obj); + + obj->role = ATK_ROLE_TEXT; +} + +static void +et_class_init (GalA11yETextClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); + + quark_accessible_object = g_quark_from_static_string ("gtk-accessible-object"); + parent_class = g_type_class_ref (PARENT_TYPE); + component_parent_iface = g_type_interface_peek(parent_class, ATK_TYPE_COMPONENT); + object_class->dispose = et_dispose; + atk_class->initialize = et_real_initialize; +} + +static void +et_init (GalA11yEText *a11y) +{ +#if 0 + GalA11yETextPrivate *priv; + + priv = GET_PRIVATE (a11y); +#endif +} + +/** + * gal_a11y_e_text_get_type: + * @void: + * + * Registers the &GalA11yEText class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yEText class. + **/ +GType +gal_a11y_e_text_get_type (void) +{ + static GType type = 0; + + if (!type) { + AtkObjectFactory *factory; + + GTypeInfo info = { + sizeof (GalA11yETextClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) et_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yEText), + 0, + (GInstanceInitFunc) et_init, + NULL /* value_text */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) et_atk_component_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + static const GInterfaceInfo atk_text_info = { + (GInterfaceInitFunc) et_atk_text_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + static const GInterfaceInfo atk_editable_text_info = { + (GInterfaceInitFunc) et_atk_editable_text_iface_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, "GalA11yEText", &info, 0, + sizeof (GalA11yETextPrivate), &priv_offset); + + g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info); + 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); + } + + return type; +} + +void +gal_a11y_e_text_init (void) +{ + if (atk_get_root ()) + atk_registry_set_factory_type (atk_get_default_registry (), + E_TYPE_TEXT, + gal_a11y_e_text_factory_get_type ()); + +} + diff --git a/widgets/text/a11y/gal-a11y-e-text.h b/widgets/text/a11y/gal-a11y-e-text.h new file mode 100644 index 0000000000..5cebd0ff83 --- /dev/null +++ b/widgets/text/a11y/gal-a11y-e-text.h @@ -0,0 +1,57 @@ +/* + * + * 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 + * + * + * Authors: + * Christopher James Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __GAL_A11Y_E_TEXT_H__ +#define __GAL_A11Y_E_TEXT_H__ + +#include +#include
+ +#define GAL_A11Y_TYPE_E_TEXT (gal_a11y_e_text_get_type ()) +#define GAL_A11Y_E_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_TEXT, GalA11yEText)) +#define GAL_A11Y_E_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_TEXT, GalA11yETextClass)) +#define GAL_A11Y_IS_E_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_TEXT)) +#define GAL_A11Y_IS_E_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_TEXT)) + +typedef struct _GalA11yEText GalA11yEText; +typedef struct _GalA11yETextClass GalA11yETextClass; +typedef struct _GalA11yETextPrivate GalA11yETextPrivate; + +/* This struct should actually be larger as this isn't what we derive from. + * The GalA11yETextPrivate comes right after the parent class structure. + **/ +struct _GalA11yEText { + AtkObject object; +}; + +struct _GalA11yETextClass { + AtkObject parent_class; +}; + + +/* Standard Glib function */ +GType gal_a11y_e_text_get_type (void); + +void gal_a11y_e_text_init (void); + +#endif /* ! __GAL_A11Y_E_TEXT_H__ */ diff --git a/widgets/text/e-reflow-model.c b/widgets/text/e-reflow-model.c new file mode 100644 index 0000000000..eae3d43324 --- /dev/null +++ b/widgets/text/e-reflow-model.c @@ -0,0 +1,350 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * + * 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 + * + * + * Authors: + * Chris Lahey + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ +#include + +#include "e-util/e-util.h" + +#include "e-reflow-model.h" + +G_DEFINE_TYPE (EReflowModel, e_reflow_model, G_TYPE_OBJECT) + +#define d(x) + +d(static gint depth = 0;) + + +enum { + MODEL_CHANGED, + COMPARISON_CHANGED, + MODEL_ITEMS_INSERTED, + MODEL_ITEM_CHANGED, + MODEL_ITEM_REMOVED, + LAST_SIGNAL +}; + +static guint e_reflow_model_signals [LAST_SIGNAL] = { 0, }; + +/** + * e_reflow_model_set_width: + * @e_reflow_model: The e-reflow-model to operate on + * @width: The new value for the width of each item. + */ +void +e_reflow_model_set_width (EReflowModel *e_reflow_model, int width) +{ + g_return_if_fail (e_reflow_model != NULL); + g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); + + E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->set_width (e_reflow_model, width); +} + +/** + * e_reflow_model_count: + * @e_reflow_model: The e-reflow-model to operate on + * + * Returns: the number of items in the reflow model. + */ +int +e_reflow_model_count (EReflowModel *e_reflow_model) +{ + g_return_val_if_fail (e_reflow_model != NULL, 0); + g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), 0); + + return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->count (e_reflow_model); +} + +/** + * e_reflow_model_height: + * @e_reflow_model: The e-reflow-model to operate on + * @n: The item number to get the height of. + * @parent: The parent GnomeCanvasItem. + * + * Returns: the height of the nth item. + */ +int +e_reflow_model_height (EReflowModel *e_reflow_model, int n, GnomeCanvasGroup *parent) +{ + g_return_val_if_fail (e_reflow_model != NULL, 0); + g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), 0); + + return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->height (e_reflow_model, n, parent); +} + +/** + * e_reflow_model_incarnate: + * @e_reflow_model: The e-reflow-model to operate on + * @n: The item to create. + * @parent: The parent GnomeCanvasItem to create a child of. + * + * Create a GnomeCanvasItem to represent the nth piece of data. + * + * Returns: the new GnomeCanvasItem. + */ +GnomeCanvasItem * +e_reflow_model_incarnate (EReflowModel *e_reflow_model, int n, GnomeCanvasGroup *parent) +{ + g_return_val_if_fail (e_reflow_model != NULL, NULL); + g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), NULL); + + return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->incarnate (e_reflow_model, n, parent); +} + +/** + * e_reflow_model_compare: + * @e_reflow_model: The e-reflow-model to operate on + * @n1: The first item to compare + * @n2: The second item to compare + * + * Compares item n1 and item n2 to see which should come first. + * + * Returns: strcmp like semantics for the comparison value. + */ +int +e_reflow_model_compare (EReflowModel *e_reflow_model, int n1, int n2) +{ +#if 0 + g_return_val_if_fail (e_reflow_model != NULL, 0); + g_return_val_if_fail (E_IS_REFLOW_MODEL (e_reflow_model), 0); +#endif + + return E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->compare (e_reflow_model, n1, n2); +} + +/** + * e_reflow_model_reincarnate: + * @e_reflow_model: The e-reflow-model to operate on + * @n: The item to create. + * @item: The item to reuse. + * + * Update item to represent the nth piece of data. + */ +void +e_reflow_model_reincarnate (EReflowModel *e_reflow_model, int n, GnomeCanvasItem *item) +{ + g_return_if_fail (e_reflow_model != NULL); + g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); + + E_REFLOW_MODEL_GET_CLASS (e_reflow_model)->reincarnate (e_reflow_model, n, item); +} + +static void +e_reflow_model_class_init (EReflowModelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + e_reflow_model_signals [MODEL_CHANGED] = + g_signal_new ("model_changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EReflowModelClass, model_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + e_reflow_model_signals [COMPARISON_CHANGED] = + g_signal_new ("comparison_changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EReflowModelClass, comparison_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + e_reflow_model_signals [MODEL_ITEMS_INSERTED] = + g_signal_new ("model_items_inserted", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EReflowModelClass, model_items_inserted), + NULL, NULL, + e_marshal_NONE__INT_INT, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); + + e_reflow_model_signals [MODEL_ITEM_CHANGED] = + g_signal_new ("model_item_changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EReflowModelClass, model_item_changed), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + + e_reflow_model_signals [MODEL_ITEM_REMOVED] = + g_signal_new ("model_item_removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EReflowModelClass, model_item_removed), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + + klass->set_width = NULL; + klass->count = NULL; + klass->height = NULL; + klass->incarnate = NULL; + klass->reincarnate = NULL; + + klass->model_changed = NULL; + klass->comparison_changed = NULL; + klass->model_items_inserted = NULL; + klass->model_item_removed = NULL; + klass->model_item_changed = NULL; +} + +static void +e_reflow_model_init (EReflowModel *e_reflow_model) +{ +} + +#if d(!)0 +static void +print_tabs (void) +{ + int i; + for (i = 0; i < depth; i++) + g_print("\t"); +} +#endif + +/** + * e_reflow_model_changed: + * @e_reflow_model: the reflow model to notify of the change + * + * Use this function to notify any views of this reflow model that + * the contents of the reflow model have changed. This will emit + * the signal "model_changed" on the @e_reflow_model object. + * + * It is preferable to use the e_reflow_model_item_changed() signal to + * notify of smaller changes than to invalidate the entire model, as + * the views might have ways of caching the information they render + * from the model. + */ +void +e_reflow_model_changed (EReflowModel *e_reflow_model) +{ + g_return_if_fail (e_reflow_model != NULL); + g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); + + d(print_tabs()); + d(g_print("Emitting model_changed on model 0x%p.\n", e_reflow_model)); + d(depth++); + g_signal_emit (e_reflow_model, + e_reflow_model_signals [MODEL_CHANGED], 0); + d(depth--); +} + +/** + * e_reflow_model_comparison_changed: + * @e_reflow_model: the reflow model to notify of the change + * + * Use this function to notify any views of this reflow model that the + * sorting has changed. The actual contents of the items hasn't, so + * there's no need to re-query the model for the heights of the + * individual items. + */ +void +e_reflow_model_comparison_changed (EReflowModel *e_reflow_model) +{ + g_return_if_fail (e_reflow_model != NULL); + g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); + + d(print_tabs()); + d(g_print("Emitting comparison_changed on model 0x%p.\n", e_reflow_model)); + d(depth++); + g_signal_emit (e_reflow_model, + e_reflow_model_signals [COMPARISON_CHANGED], 0); + d(depth--); +} + +/** + * e_reflow_model_items_inserted: + * @e_reflow_model: The model changed. + * @position: The position the items were insert in. + * @count: The number of items inserted. + * + * Use this function to notify any views of the reflow model that a number of items have been inserted. + **/ +void +e_reflow_model_items_inserted (EReflowModel *e_reflow_model, int position, int count) +{ + g_return_if_fail (e_reflow_model != NULL); + g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); + + d(print_tabs()); + d(g_print("Emitting items_inserted on model 0x%p, position=%d, count=%d.\n", e_reflow_model, position, count)); + d(depth++); + g_signal_emit (e_reflow_model, + e_reflow_model_signals [MODEL_ITEMS_INSERTED], 0, + position, count); + d(depth--); +} + +/** + * e_reflow_model_item_removed: + * @e_reflow_model: The model changed. + * @n: The position from which the items were removed. + * + * Use this function to notify any views of the reflow model that an + * item has been removed. + **/ +void +e_reflow_model_item_removed (EReflowModel *e_reflow_model, + int n) +{ + g_return_if_fail (e_reflow_model != NULL); + g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); + + d(print_tabs()); + d(g_print("Emitting item_removed on model 0x%p, n=%d.\n", e_reflow_model, n)); + d(depth++); + g_signal_emit (e_reflow_model, + e_reflow_model_signals [MODEL_ITEM_REMOVED], 0, + n); + d(depth--); +} + + +/** + * e_reflow_model_item_changed: + * @e_reflow_model: the reflow model to notify of the change + * @item: the item that was changed in the model. + * + * Use this function to notify any views of the reflow model that the + * contents of item @item have changed in model such that the height + * has changed or the item needs to be reincarnated. This function + * will emit the "model_item_changed" signal on the @e_reflow_model + * object + */ +void +e_reflow_model_item_changed (EReflowModel *e_reflow_model, int n) +{ + g_return_if_fail (e_reflow_model != NULL); + g_return_if_fail (E_IS_REFLOW_MODEL (e_reflow_model)); + + d(print_tabs()); + d(g_print("Emitting item_changed on model 0x%p, n=%d.\n", e_reflow_model, n)); + d(depth++); + g_signal_emit (e_reflow_model, + e_reflow_model_signals [MODEL_ITEM_CHANGED], 0, + n); + d(depth--); +} diff --git a/widgets/text/e-reflow-model.h b/widgets/text/e-reflow-model.h new file mode 100644 index 0000000000..7482e5079f --- /dev/null +++ b/widgets/text/e-reflow-model.h @@ -0,0 +1,112 @@ +/* + * + * 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 + * + * + * Authors: + * Chris Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef _E_REFLOW_MODEL_H_ +#define _E_REFLOW_MODEL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define E_REFLOW_MODEL_TYPE (e_reflow_model_get_type ()) +#define E_REFLOW_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_REFLOW_MODEL_TYPE, EReflowModel)) +#define E_REFLOW_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_REFLOW_MODEL_TYPE, EReflowModelClass)) +#define E_IS_REFLOW_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_REFLOW_MODEL_TYPE)) +#define E_IS_REFLOW_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_REFLOW_MODEL_TYPE)) +#define E_REFLOW_MODEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_REFLOW_MODEL_TYPE, EReflowModelClass)) + +typedef struct { + GObject base; +} EReflowModel; + +typedef struct { + GObjectClass parent_class; + + /* + * Virtual methods + */ + void (*set_width) (EReflowModel *etm, int width); + + int (*count) (EReflowModel *etm); + int (*height) (EReflowModel *etm, int n, GnomeCanvasGroup *parent); + GnomeCanvasItem *(*incarnate) (EReflowModel *etm, int n, GnomeCanvasGroup *parent); + int (*compare) (EReflowModel *etm, int n1, int n2); + void (*reincarnate) (EReflowModel *etm, int n, GnomeCanvasItem *item); + + /* + * Signals + */ + + /* + * These all come after the change has been made. + * Major structural changes: model_changed + * Changes to the sorting of elements: comparison_changed + * Changes only in an item: item_changed + */ + void (*model_changed) (EReflowModel *etm); + void (*comparison_changed) (EReflowModel *etm); + void (*model_items_inserted) (EReflowModel *etm, int position, int count); + void (*model_item_removed) (EReflowModel *etm, int position); + void (*model_item_changed) (EReflowModel *etm, int n); +} EReflowModelClass; + +GType e_reflow_model_get_type (void); + +/**/ +void e_reflow_model_set_width (EReflowModel *e_reflow_model, + int width); +int e_reflow_model_count (EReflowModel *e_reflow_model); +int e_reflow_model_height (EReflowModel *e_reflow_model, + int n, + GnomeCanvasGroup *parent); +GnomeCanvasItem *e_reflow_model_incarnate (EReflowModel *e_reflow_model, + int n, + GnomeCanvasGroup *parent); +int e_reflow_model_compare (EReflowModel *e_reflow_model, + int n1, + int n2); +void e_reflow_model_reincarnate (EReflowModel *e_reflow_model, + int n, + GnomeCanvasItem *item); + +/* + * Routines for emitting signals on the e_reflow + */ +void e_reflow_model_changed (EReflowModel *e_reflow_model); +void e_reflow_model_comparison_changed (EReflowModel *e_reflow_model); +void e_reflow_model_items_inserted (EReflowModel *e_reflow_model, + int position, + int count); +void e_reflow_model_item_removed (EReflowModel *e_reflow_model, + int n); +void e_reflow_model_item_changed (EReflowModel *e_reflow_model, + int n); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _E_REFLOW_MODEL_H_ */ diff --git a/widgets/text/e-reflow.c b/widgets/text/e-reflow.c new file mode 100644 index 0000000000..c17b970a23 --- /dev/null +++ b/widgets/text/e-reflow.c @@ -0,0 +1,1534 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * 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 + * + * + * Authors: + * Chris Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ +#include + +#include +#include + +#include +#include + +#include "text/e-text.h" +#include +#include "e-util/e-util.h" +#include "e-util/e-unicode.h" + +#include "misc/e-canvas.h" +#include "misc/e-canvas-utils.h" +#include "e-reflow.h" +#include "misc/e-selection-model-simple.h" + +static gboolean e_reflow_event (GnomeCanvasItem *item, GdkEvent *event); +static void e_reflow_realize (GnomeCanvasItem *item); +static void e_reflow_unrealize (GnomeCanvasItem *item); +static void e_reflow_draw (GnomeCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height); +static void e_reflow_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags); +static double e_reflow_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item); +static void e_reflow_reflow (GnomeCanvasItem *item, int flags); +static void set_empty(EReflow *reflow); + +static void e_reflow_resize_children (GnomeCanvasItem *item); + +#define E_REFLOW_DIVIDER_WIDTH 2 +#define E_REFLOW_BORDER_WIDTH 7 +#define E_REFLOW_FULL_GUTTER (E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH * 2) + +G_DEFINE_TYPE (EReflow, e_reflow, GNOME_TYPE_CANVAS_GROUP) + +/* The arguments we take */ +enum { + PROP_0, + PROP_MINIMUM_WIDTH, + PROP_WIDTH, + PROP_HEIGHT, + PROP_EMPTY_MESSAGE, + PROP_MODEL, + PROP_COLUMN_WIDTH +}; + +enum { + SELECTION_EVENT, + COLUMN_WIDTH_CHANGED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = {0, }; + +static gint +er_compare (int i1, int i2, gpointer user_data) +{ + EReflow *reflow = user_data; + return e_reflow_model_compare (reflow->model, i1, i2); +} + +static gint +e_reflow_pick_line (EReflow *reflow, double x) +{ + x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; + x /= reflow->column_width + E_REFLOW_FULL_GUTTER; + return x; +} + +static int +er_find_item (EReflow *reflow, GnomeCanvasItem *item) +{ + int i; + for (i = 0; i < reflow->count; i++) { + if (reflow->items[i] == item) + return i; + } + return -1; +} + +static void +e_reflow_resize_children (GnomeCanvasItem *item) +{ + EReflow *reflow; + int i; + int count; + + reflow = E_REFLOW (item); + + count = reflow->count; + for (i = 0; i < count; i++) { + if (reflow->items[i]) + gnome_canvas_item_set(reflow->items[i], + "width", (double) reflow->column_width, + NULL); + } +} + +static inline void +e_reflow_update_selection_row (EReflow *reflow, int row) +{ + if (reflow->items[row]) { + g_object_set(reflow->items[row], + "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), row), + NULL); + } else if (e_selection_model_is_row_selected (E_SELECTION_MODEL (reflow->selection), row)) { + reflow->items[row] = e_reflow_model_incarnate (reflow->model, row, GNOME_CANVAS_GROUP (reflow)); + g_object_set (reflow->items[row], + "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), row), + "width", (double) reflow->column_width, + NULL); + } +} + +static void +e_reflow_update_selection (EReflow *reflow) +{ + int i; + int count; + + count = reflow->count; + for (i = 0; i < count; i++) { + e_reflow_update_selection_row (reflow, i); + } +} + +static void +selection_changed (ESelectionModel *selection, EReflow *reflow) +{ + e_reflow_update_selection (reflow); +} + +static void +selection_row_changed (ESelectionModel *selection, int row, EReflow *reflow) +{ + e_reflow_update_selection_row (reflow, row); +} + +static gboolean +do_adjustment (gpointer user_data) +{ + int row; + GtkAdjustment *adj ; + gfloat value, min_value, max_value; + EReflow *reflow = user_data; + + row = reflow->cursor_row; + if (row == -1) + return FALSE; + + adj = gtk_layout_get_hadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (reflow)->canvas)); + value = adj->value; + + if ((!reflow->items) || (!reflow->items[row])) + return TRUE; + min_value = reflow->items[row]->x2 - adj->page_size; + max_value = reflow->items[row]->x1; + + if (value < min_value) + value = min_value; + + if (value > max_value) + value = max_value; + + if (value != adj->value) { + adj->value = value; + gtk_adjustment_value_changed (adj); + } + + reflow->do_adjustment_idle_id = 0; + + return FALSE; +} + +static void +cursor_changed (ESelectionModel *selection, int row, int col, EReflow *reflow) +{ + int count = reflow->count; + int old_cursor = reflow->cursor_row; + + if (old_cursor < count && old_cursor >= 0) { + if (reflow->items[old_cursor]) { + g_object_set (reflow->items[old_cursor], + "has_cursor", FALSE, + NULL); + } + } + + reflow->cursor_row = row; + + if (row < count && row >= 0) { + if (reflow->items[row]) { + g_object_set (reflow->items[row], + "has_cursor", TRUE, + NULL); + } else { + reflow->items[row] = e_reflow_model_incarnate (reflow->model, row, GNOME_CANVAS_GROUP (reflow)); + g_object_set (reflow->items[row], + "has_cursor", TRUE, + "width", (double) reflow->column_width, + NULL); + } + } + + if (reflow->do_adjustment_idle_id == 0) + reflow->do_adjustment_idle_id = g_idle_add (do_adjustment, reflow); + +} + + +static void +incarnate (EReflow *reflow) +{ + int column_width; + int first_column; + int last_column; + int first_cell; + int last_cell; + int i; + GtkAdjustment *adjustment = gtk_layout_get_hadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (reflow)->canvas)); + + column_width = reflow->column_width; + + first_column = adjustment->value - 1 + E_REFLOW_BORDER_WIDTH; + first_column /= column_width + E_REFLOW_FULL_GUTTER; + + last_column = adjustment->value + adjustment->page_size + 1 - E_REFLOW_BORDER_WIDTH - E_REFLOW_DIVIDER_WIDTH; + last_column /= column_width + E_REFLOW_FULL_GUTTER; + last_column ++; + + if (first_column >= 0 && first_column < reflow->column_count) + first_cell = reflow->columns[first_column]; + else + first_cell = 0; + + if (last_column >= 0 && last_column < reflow->column_count) + last_cell = reflow->columns[last_column]; + else + last_cell = reflow->count; + + for (i = first_cell; i < last_cell; i++) { + int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i); + if (reflow->items[unsorted] == NULL) { + if (reflow->model) { + reflow->items[unsorted] = e_reflow_model_incarnate (reflow->model, unsorted, GNOME_CANVAS_GROUP (reflow)); + g_object_set (reflow->items[unsorted], + "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), unsorted), + "width", (double) reflow->column_width, + NULL); + } + } + } + reflow->incarnate_idle_id = 0; +} + +static gboolean +invoke_incarnate (gpointer user_data) +{ + EReflow *reflow = user_data; + incarnate (reflow); + return FALSE; +} + +static void +queue_incarnate (EReflow *reflow) +{ + if (reflow->incarnate_idle_id == 0) + reflow->incarnate_idle_id = + g_idle_add_full (25, invoke_incarnate, reflow, NULL); +} + +static void +reflow_columns (EReflow *reflow) +{ + GSList *list; + int count; + int start; + int i; + int column_count, column_start; + double running_height; + + if (reflow->reflow_from_column <= 1) { + start = 0; + column_count = 1; + column_start = 0; + } + else { + /* we start one column before the earliest new entry, + so we can handle the case where the new entry is + inserted at the start of the column */ + column_start = reflow->reflow_from_column - 1; + start = reflow->columns[column_start]; + column_count = column_start + 1; + } + + list = NULL; + + running_height = E_REFLOW_BORDER_WIDTH; + + count = reflow->count - start; + for (i = start; i < count; i++) { + int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i); + if (i != 0 && running_height + reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH > reflow->height) { + list = g_slist_prepend (list, GINT_TO_POINTER(i)); + column_count ++; + running_height = E_REFLOW_BORDER_WIDTH * 2 + reflow->heights[unsorted]; + } else + running_height += reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH; + } + + reflow->column_count = column_count; + reflow->columns = g_renew (int, reflow->columns, column_count); + column_count --; + + for (; column_count > column_start; column_count--) { + GSList *to_free; + reflow->columns[column_count] = GPOINTER_TO_INT(list->data); + to_free = list; + list = list->next; + g_slist_free_1 (to_free); + } + reflow->columns[column_start] = start; + + queue_incarnate (reflow); + + reflow->need_reflow_columns = FALSE; + reflow->reflow_from_column = -1; +} + +static void +item_changed (EReflowModel *model, int i, EReflow *reflow) +{ + if (i < 0 || i >= reflow->count) + return; + + reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow)); + if (reflow->items[i] != NULL) + e_reflow_model_reincarnate (model, i, reflow->items[i]); + e_sorter_array_clean (reflow->sorter); + reflow->reflow_from_column = -1; + reflow->need_reflow_columns = TRUE; + e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow)); +} + +static void +item_removed (EReflowModel *model, int i, EReflow *reflow) +{ + int c; + int sorted; + + if (i < 0 || i >= reflow->count) + return; + + sorted = e_sorter_model_to_sorted (E_SORTER (reflow->sorter), i); + for (c = reflow->column_count - 1; c >= 0; c--) { + int start_of_column = reflow->columns[c]; + + if (start_of_column <= sorted) { + if (reflow->reflow_from_column == -1 + || reflow->reflow_from_column > c) { + reflow->reflow_from_column = c; + } + break; + } + } + + if (reflow->items[i]) + gtk_object_destroy (GTK_OBJECT (reflow->items[i])); + + memmove (reflow->heights + i, reflow->heights + i + 1, (reflow->count - i - 1) * sizeof (int)); + memmove (reflow->items + i, reflow->items + i + 1, (reflow->count - i - 1) * sizeof (GnomeCanvasItem *)); + + reflow->count --; + + reflow->heights [reflow->count] = 0; + reflow->items [reflow->count] = NULL; + + reflow->need_reflow_columns = TRUE; + set_empty (reflow); + e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow)); + + e_sorter_array_set_count (reflow->sorter, reflow->count); + + e_selection_model_simple_delete_rows (E_SELECTION_MODEL_SIMPLE (reflow->selection), i, 1); +} + +static void +items_inserted (EReflowModel *model, int position, int count, EReflow *reflow) +{ + int i, oldcount; + + if (position < 0 || position > reflow->count) + return; + + oldcount = reflow->count; + + reflow->count += count; + + if (reflow->count > reflow->allocated_count) { + while (reflow->count > reflow->allocated_count) + reflow->allocated_count += 256; + reflow->heights = g_renew (int, reflow->heights, reflow->allocated_count); + reflow->items = g_renew (GnomeCanvasItem *, reflow->items, reflow->allocated_count); + } + memmove (reflow->heights + position + count, reflow->heights + position, (reflow->count - position - count) * sizeof (int)); + memmove (reflow->items + position + count, reflow->items + position, (reflow->count - position - count) * sizeof (GnomeCanvasItem *)); + for (i = position; i < position + count; i++) { + reflow->items[i] = NULL; + reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow)); + } + + e_selection_model_simple_set_row_count (E_SELECTION_MODEL_SIMPLE (reflow->selection), reflow->count); + if (position == oldcount) + e_sorter_array_append (reflow->sorter, count); + else + e_sorter_array_set_count (reflow->sorter, reflow->count); + + for (i = position; i < position + count; i ++) { + int sorted = e_sorter_model_to_sorted (E_SORTER (reflow->sorter), i); + int c; + + for (c = reflow->column_count - 1; c >= 0; c--) { + int start_of_column = reflow->columns[c]; + + if (start_of_column <= sorted) { + if (reflow->reflow_from_column == -1 + || reflow->reflow_from_column > c) { + reflow->reflow_from_column = c; + } + break; + } + } + } + + reflow->need_reflow_columns = TRUE; + set_empty (reflow); + e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow)); +} + +static void +model_changed (EReflowModel *model, EReflow *reflow) +{ + int i; + int count; + int oldcount; + + count = reflow->count; + oldcount = count; + + for (i = 0; i < count; i++) { + if (reflow->items[i]) + gtk_object_destroy (GTK_OBJECT (reflow->items[i])); + } + g_free (reflow->items); + g_free (reflow->heights); + reflow->count = e_reflow_model_count (model); + reflow->allocated_count = reflow->count; + reflow->items = g_new (GnomeCanvasItem *, reflow->count); + reflow->heights = g_new (int, reflow->count); + + count = reflow->count; + for (i = 0; i < count; i++) { + reflow->items[i] = NULL; + reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow)); + } + + e_selection_model_simple_set_row_count (E_SELECTION_MODEL_SIMPLE (reflow->selection), count); + e_sorter_array_set_count (reflow->sorter, reflow->count); + + reflow->need_reflow_columns = TRUE; + if (oldcount > reflow->count) + reflow_columns (reflow); + set_empty (reflow); + e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow)); +} + +static void +comparison_changed (EReflowModel *model, EReflow *reflow) +{ + e_sorter_array_clean (reflow->sorter); + reflow->reflow_from_column = -1; + reflow->need_reflow_columns = TRUE; + e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow)); +} + +static void +set_empty(EReflow *reflow) +{ + if (reflow->count == 0) { + if (reflow->empty_text) { + if (reflow->empty_message) { + gnome_canvas_item_set(reflow->empty_text, + "width", reflow->minimum_width, + "text", reflow->empty_message, + NULL); + e_canvas_item_move_absolute(reflow->empty_text, + reflow->minimum_width / 2, + 0); + } else { + gtk_object_destroy(GTK_OBJECT(reflow->empty_text)); + reflow->empty_text = NULL; + } + } else { + if (reflow->empty_message) { + reflow->empty_text = + gnome_canvas_item_new(GNOME_CANVAS_GROUP(reflow), + e_text_get_type(), + "anchor", GTK_ANCHOR_N, + "width", reflow->minimum_width, + "clip", TRUE, + "use_ellipsis", TRUE, + "justification", GTK_JUSTIFY_CENTER, + "text", reflow->empty_message, + "draw_background", FALSE, + NULL); + e_canvas_item_move_absolute(reflow->empty_text, + reflow->minimum_width / 2, + 0); + } + } + } else { + if (reflow->empty_text) { + gtk_object_destroy(GTK_OBJECT(reflow->empty_text)); + reflow->empty_text = NULL; + } + } +} + +static void +disconnect_model (EReflow *reflow) +{ + if (reflow->model == NULL) + return; + + g_signal_handler_disconnect (reflow->model, + reflow->model_changed_id); + g_signal_handler_disconnect (reflow->model, + reflow->comparison_changed_id); + g_signal_handler_disconnect (reflow->model, + reflow->model_items_inserted_id); + g_signal_handler_disconnect (reflow->model, + reflow->model_item_removed_id); + g_signal_handler_disconnect (reflow->model, + reflow->model_item_changed_id); + g_object_unref (reflow->model); + + reflow->model_changed_id = 0; + reflow->comparison_changed_id = 0; + reflow->model_items_inserted_id = 0; + reflow->model_item_removed_id = 0; + reflow->model_item_changed_id = 0; + reflow->model = NULL; +} + +static void +disconnect_selection (EReflow *reflow) +{ + if (reflow->selection == NULL) + return; + + g_signal_handler_disconnect (reflow->selection, + reflow->selection_changed_id); + g_signal_handler_disconnect (reflow->selection, + reflow->selection_row_changed_id); + g_signal_handler_disconnect (reflow->selection, + reflow->cursor_changed_id); + g_object_unref (reflow->selection); + + reflow->selection_changed_id = 0; + reflow->selection_row_changed_id = 0; + reflow->cursor_changed_id = 0; + reflow->selection = NULL; +} + +static void +connect_model (EReflow *reflow, EReflowModel *model) +{ + if (reflow->model != NULL) + disconnect_model (reflow); + + if (model == NULL) + return; + + reflow->model = model; + g_object_ref (reflow->model); + reflow->model_changed_id = + g_signal_connect (reflow->model, "model_changed", + G_CALLBACK (model_changed), reflow); + reflow->comparison_changed_id = + g_signal_connect (reflow->model, "comparison_changed", + G_CALLBACK (comparison_changed), reflow); + reflow->model_items_inserted_id = + g_signal_connect (reflow->model, "model_items_inserted", + G_CALLBACK (items_inserted), reflow); + reflow->model_item_removed_id = + g_signal_connect (reflow->model, "model_item_removed", + G_CALLBACK (item_removed), reflow); + reflow->model_item_changed_id = + g_signal_connect (reflow->model, "model_item_changed", + G_CALLBACK (item_changed), reflow); + model_changed (model, reflow); +} + +static void +adjustment_changed (GtkAdjustment *adjustment, EReflow *reflow) +{ + queue_incarnate (reflow); +} + +static void +disconnect_adjustment (EReflow *reflow) +{ + if (reflow->adjustment == NULL) + return; + + g_signal_handler_disconnect (reflow->adjustment, + reflow->adjustment_changed_id); + g_signal_handler_disconnect (reflow->adjustment, + reflow->adjustment_value_changed_id); + + g_object_unref (reflow->adjustment); + + reflow->adjustment_changed_id = 0; + reflow->adjustment_value_changed_id = 0; + reflow->adjustment = NULL; +} + +static void +connect_adjustment (EReflow *reflow, GtkAdjustment *adjustment) +{ + if (reflow->adjustment != NULL) + disconnect_adjustment (reflow); + + if (adjustment == NULL) + return; + + reflow->adjustment = adjustment; + reflow->adjustment_changed_id = + g_signal_connect (adjustment, "changed", + G_CALLBACK (adjustment_changed), reflow); + reflow->adjustment_value_changed_id = + g_signal_connect (adjustment, "value_changed", + G_CALLBACK (adjustment_changed), reflow); + g_object_ref (adjustment); +} + +#if 0 +static void +set_scroll_adjustments (GtkLayout *layout, GtkAdjustment *hadj, GtkAdjustment *vadj, EReflow *reflow) +{ + connect_adjustment (reflow, hadj); +} + +static void +connect_set_adjustment (EReflow *reflow) +{ + reflow->set_scroll_adjustments_id = + g_signal_connect (GNOME_CANVAS_ITEM (reflow)->canvas, + "set_scroll_adjustments", + G_CALLBACK (set_scroll_adjustments), reflow); +} +#endif + +static void +disconnect_set_adjustment (EReflow *reflow) +{ + if (reflow->set_scroll_adjustments_id != 0) { + g_signal_handler_disconnect (GNOME_CANVAS_ITEM (reflow)->canvas, + reflow->set_scroll_adjustments_id); + reflow->set_scroll_adjustments_id = 0; + } +} + +static void +column_width_changed (EReflow *reflow) +{ + g_signal_emit (reflow, signals[COLUMN_WIDTH_CHANGED], 0, reflow->column_width); +} + + + + +/* Virtual functions */ +static void +e_reflow_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GnomeCanvasItem *item; + EReflow *reflow; + + item = GNOME_CANVAS_ITEM (object); + reflow = E_REFLOW (object); + + switch (prop_id){ + case PROP_HEIGHT: + reflow->height = g_value_get_double (value); + reflow->need_reflow_columns = TRUE; + e_canvas_item_request_reflow(item); + break; + case PROP_MINIMUM_WIDTH: + reflow->minimum_width = g_value_get_double (value); + if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS(object)) + set_empty(reflow); + e_canvas_item_request_reflow(item); + break; + case PROP_EMPTY_MESSAGE: + g_free(reflow->empty_message); + reflow->empty_message = g_strdup(g_value_get_string (value)); + if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS(object)) + set_empty(reflow); + break; + case PROP_MODEL: + connect_model (reflow, (EReflowModel *) g_value_get_object (value)); + break; + case PROP_COLUMN_WIDTH: + if (reflow->column_width != g_value_get_double (value)) { + GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); + double old_width = reflow->column_width; + + reflow->column_width = g_value_get_double (value); + adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2; + adjustment->page_increment = adjustment->page_size - adjustment->step_increment; + gtk_adjustment_changed(adjustment); + e_reflow_resize_children(item); + e_canvas_item_request_reflow(item); + + reflow->need_column_resize = TRUE; + gnome_canvas_item_request_update(item); + + if (old_width != reflow->column_width) + column_width_changed (reflow); + } + break; + } +} + +static void +e_reflow_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + EReflow *reflow; + + reflow = E_REFLOW (object); + + switch (prop_id) { + case PROP_MINIMUM_WIDTH: + g_value_set_double (value, reflow->minimum_width); + break; + case PROP_WIDTH: + g_value_set_double (value, reflow->width); + break; + case PROP_HEIGHT: + g_value_set_double (value, reflow->height); + break; + case PROP_EMPTY_MESSAGE: + g_value_set_string (value, reflow->empty_message); + break; + case PROP_MODEL: + g_value_set_object (value, reflow->model); + break; + case PROP_COLUMN_WIDTH: + g_value_set_double (value, reflow->column_width); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +e_reflow_dispose (GObject *object) +{ + EReflow *reflow = E_REFLOW(object); + + g_free (reflow->items); + g_free (reflow->heights); + g_free (reflow->columns); + + reflow->items = NULL; + reflow->heights = NULL; + reflow->columns = NULL; + reflow->count = 0; + reflow->allocated_count = 0; + + if (reflow->incarnate_idle_id) + g_source_remove (reflow->incarnate_idle_id); + reflow->incarnate_idle_id = 0; + + if (reflow->do_adjustment_idle_id) + g_source_remove (reflow->do_adjustment_idle_id); + reflow->do_adjustment_idle_id = 0; + + disconnect_model (reflow); + disconnect_selection (reflow); + + g_free(reflow->empty_message); + reflow->empty_message = NULL; + + if (reflow->sorter) { + g_object_unref (reflow->sorter); + reflow->sorter = NULL; + } + + G_OBJECT_CLASS(e_reflow_parent_class)->dispose (object); +} + +static void +e_reflow_realize (GnomeCanvasItem *item) +{ + EReflow *reflow; + GtkAdjustment *adjustment; + int count; + int i; + + reflow = E_REFLOW (item); + + if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->realize) + (* GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->realize) (item); + + reflow->arrow_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); + reflow->default_cursor = gdk_cursor_new (GDK_LEFT_PTR); + + count = reflow->count; + for(i = 0; i < count; i++) { + if (reflow->items[i]) + gnome_canvas_item_set(reflow->items[i], + "width", reflow->column_width, + NULL); + } + + set_empty(reflow); + + reflow->need_reflow_columns = TRUE; + e_canvas_item_request_reflow(item); + + adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); + +#if 0 + connect_set_adjustment (reflow); +#endif + connect_adjustment (reflow, adjustment); + + adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2; + adjustment->page_increment = adjustment->page_size - adjustment->step_increment; + gtk_adjustment_changed(adjustment); + + if (!item->canvas->aa) { + } +} + +static void +e_reflow_unrealize (GnomeCanvasItem *item) +{ + EReflow *reflow; + + reflow = E_REFLOW (item); + + if (!item->canvas->aa) { + } + + gdk_cursor_unref (reflow->arrow_cursor); + gdk_cursor_unref (reflow->default_cursor); + reflow->arrow_cursor = NULL; + reflow->default_cursor = NULL; + + g_free (reflow->columns); + reflow->columns = NULL; + + disconnect_set_adjustment (reflow); + disconnect_adjustment (reflow); + + if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->unrealize) + (* GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->unrealize) (item); +} + +static gboolean +e_reflow_event (GnomeCanvasItem *item, GdkEvent *event) +{ + EReflow *reflow; + int return_val = FALSE; + + reflow = E_REFLOW (item); + + switch( event->type ) + { + case GDK_KEY_PRESS: + return_val = e_selection_model_key_press(reflow->selection, (GdkEventKey *) event); + break; +#if 0 + if (event->key.keyval == GDK_Tab || + event->key.keyval == GDK_KP_Tab || + event->key.keyval == GDK_ISO_Left_Tab) { + int i; + int count; + count = reflow->count; + for (i = 0; i < count; i++) { + int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i); + GnomeCanvasItem *item = reflow->items[unsorted]; + EFocus has_focus; + if (item) { + g_object_get(item, + "has_focus", &has_focus, + NULL); + if (has_focus) { + if (event->key.state & GDK_SHIFT_MASK) { + if (i == 0) + return FALSE; + i--; + } else { + if (i == count - 1) + return FALSE; + i++; + } + + unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i); + if (reflow->items[unsorted] == NULL) { + reflow->items[unsorted] = e_reflow_model_incarnate (reflow->model, unsorted, GNOME_CANVAS_GROUP (reflow)); + } + + item = reflow->items[unsorted]; + gnome_canvas_item_set(item, + "has_focus", (event->key.state & GDK_SHIFT_MASK) ? E_FOCUS_END : E_FOCUS_START, + NULL); + return TRUE; + } + } + } + } +#endif + case GDK_BUTTON_PRESS: + switch(event->button.button) + { + case 1: + { + GdkEventButton *button = (GdkEventButton *) event; + double n_x; + n_x = button->x; + n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; + n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER)); + + if ( button->y >= E_REFLOW_BORDER_WIDTH && button->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) { + /* don't allow to drag the first line*/ + if (e_reflow_pick_line(reflow, button->x) == 0) + return TRUE; + reflow->which_column_dragged = e_reflow_pick_line(reflow, button->x); + reflow->start_x = reflow->which_column_dragged * (reflow->column_width + E_REFLOW_FULL_GUTTER) - E_REFLOW_DIVIDER_WIDTH / 2; + reflow->temp_column_width = reflow->column_width; + reflow->column_drag = TRUE; + + gnome_canvas_item_grab (item, + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK, + reflow->arrow_cursor, + button->time); + + reflow->previous_temp_column_width = -1; + reflow->need_column_resize = TRUE; + gnome_canvas_item_request_update(item); + return TRUE; + } + } + break; + case 4: + { + GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); + gdouble new_value = adjustment->value; + new_value -= adjustment->step_increment; + gtk_adjustment_set_value(adjustment, new_value); + } + break; + case 5: + { + GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); + gdouble new_value = adjustment->value; + new_value += adjustment->step_increment; + if ( new_value > adjustment->upper - adjustment->page_size ) + new_value = adjustment->upper - adjustment->page_size; + gtk_adjustment_set_value(adjustment, new_value); + } + break; + } + break; + case GDK_BUTTON_RELEASE: + if (reflow->column_drag) { + gdouble old_width = reflow->column_width; + GdkEventButton *button = (GdkEventButton *) event; + GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); + reflow->temp_column_width = reflow->column_width + + (button->x - reflow->start_x)/(reflow->which_column_dragged - e_reflow_pick_line(reflow, adjustment->value)); + if ( reflow->temp_column_width < 50 ) + reflow->temp_column_width = 50; + reflow->column_drag = FALSE; + if ( old_width != reflow->temp_column_width ) { + gtk_adjustment_set_value(adjustment, adjustment->value + e_reflow_pick_line(reflow, adjustment->value) * (reflow->temp_column_width - reflow->column_width)); + reflow->column_width = reflow->temp_column_width; + adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2; + adjustment->page_increment = adjustment->page_size - adjustment->step_increment; + gtk_adjustment_changed(adjustment); + e_reflow_resize_children(item); + e_canvas_item_request_reflow(item); + gnome_canvas_request_redraw(item->canvas, 0, 0, reflow->width, reflow->height); + column_width_changed (reflow); + } + reflow->need_column_resize = TRUE; + gnome_canvas_item_request_update(item); + gnome_canvas_item_ungrab (item, button->time); + return TRUE; + } + break; + case GDK_MOTION_NOTIFY: + if (reflow->column_drag) { + double old_width = reflow->temp_column_width; + GdkEventMotion *motion = (GdkEventMotion *) event; + GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas)); + reflow->temp_column_width = reflow->column_width + + (motion->x - reflow->start_x)/(reflow->which_column_dragged - e_reflow_pick_line(reflow, adjustment->value)); + if (reflow->temp_column_width < 50) + reflow->temp_column_width = 50; + if (old_width != reflow->temp_column_width) { + reflow->need_column_resize = TRUE; + gnome_canvas_item_request_update(item); + } + return TRUE; + } else { + GdkEventMotion *motion = (GdkEventMotion *) event; + double n_x; + + n_x = motion->x; + n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; + n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER)); + + if ( motion->y >= E_REFLOW_BORDER_WIDTH && motion->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) { + if ( reflow->default_cursor_shown ) { + gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->arrow_cursor); + reflow->default_cursor_shown = FALSE; + } + } else + if ( ! reflow->default_cursor_shown ) { + gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->default_cursor); + reflow->default_cursor_shown = TRUE; + } + + } + break; + case GDK_ENTER_NOTIFY: + if (!reflow->column_drag) { + GdkEventCrossing *crossing = (GdkEventCrossing *) event; + double n_x; + n_x = crossing->x; + n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; + n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER)); + + if ( crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) { + if ( reflow->default_cursor_shown ) { + gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->arrow_cursor); + reflow->default_cursor_shown = FALSE; + } + } + } + break; + case GDK_LEAVE_NOTIFY: + if (!reflow->column_drag) { + GdkEventCrossing *crossing = (GdkEventCrossing *) event; + double n_x; + n_x = crossing->x; + n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; + n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER)); + if ( !( crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) ) { + if ( ! reflow->default_cursor_shown ) { + gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->default_cursor); + reflow->default_cursor_shown = TRUE; + } + } + } + break; + default: + break; + } + if (return_val) + return return_val; + else if (GNOME_CANVAS_ITEM_CLASS( e_reflow_parent_class )->event) + return (* GNOME_CANVAS_ITEM_CLASS( e_reflow_parent_class )->event) (item, event); + else + return FALSE; +} + +static void e_reflow_draw (GnomeCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height) +{ + int x_rect, y_rect, width_rect, height_rect; + gdouble running_width; + EReflow *reflow = E_REFLOW(item); + int i; + double column_width; + + if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->draw) + GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->draw (item, drawable, x, y, width, height); + column_width = reflow->column_width; + running_width = E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; + x_rect = running_width; + y_rect = E_REFLOW_BORDER_WIDTH; + width_rect = E_REFLOW_DIVIDER_WIDTH; + height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2); + + /* Compute first column to draw. */ + i = x; + i /= column_width + E_REFLOW_FULL_GUTTER; + running_width += i * (column_width + E_REFLOW_FULL_GUTTER); + + for ( ; i < reflow->column_count; i++) { + if ( running_width > x + width ) + break; + x_rect = running_width; + gtk_paint_flat_box(GTK_WIDGET(item->canvas)->style, + drawable, + GTK_STATE_ACTIVE, + GTK_SHADOW_NONE, + NULL, + GTK_WIDGET(item->canvas), + "reflow", + x_rect - x, + y_rect - y, + width_rect, + height_rect); + running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; + } + if (reflow->column_drag) { + int start_line = e_reflow_pick_line(reflow, + gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas))->value); + i = x - start_line * (column_width + E_REFLOW_FULL_GUTTER); + running_width = start_line * (column_width + E_REFLOW_FULL_GUTTER); + column_width = reflow->temp_column_width; + running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER); + i += start_line * (column_width + E_REFLOW_FULL_GUTTER); + running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; + x_rect = running_width; + y_rect = E_REFLOW_BORDER_WIDTH; + width_rect = E_REFLOW_DIVIDER_WIDTH; + height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2); + + /* Compute first column to draw. */ + i /= column_width + E_REFLOW_FULL_GUTTER; + running_width += i * (column_width + E_REFLOW_FULL_GUTTER); + + for ( ; i < reflow->column_count; i++) { + if ( running_width > x + width ) + break; + x_rect = running_width; + gdk_draw_rectangle(drawable, + GTK_WIDGET(item->canvas)->style->fg_gc[GTK_STATE_NORMAL], + TRUE, + x_rect - x, + y_rect - y, + width_rect - 1, + height_rect - 1); + running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; + } + } +} + +static void +e_reflow_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags) +{ + EReflow *reflow; + double x0, x1, y0, y1; + + reflow = E_REFLOW (item); + + if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->update) + GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->update (item, affine, clip_path, flags); + + x0 = item->x1; + y0 = item->y1; + x1 = item->x2; + y1 = item->y2; + if ( x1 < x0 + reflow->width ) + x1 = x0 + reflow->width; + if ( y1 < y0 + reflow->height ) + y1 = y0 + reflow->height; + item->x2 = x1; + item->y2 = y1; + + if (reflow->need_height_update) { + x0 = item->x1; + y0 = item->y1; + x1 = item->x2; + y1 = item->y2; + if ( x0 > 0 ) + x0 = 0; + if ( y0 > 0 ) + y0 = 0; + if ( x1 < E_REFLOW(item)->width ) + x1 = E_REFLOW(item)->width; + if ( x1 < E_REFLOW(item)->height ) + x1 = E_REFLOW(item)->height; + + gnome_canvas_request_redraw(item->canvas, x0, y0, x1, y1); + reflow->need_height_update = FALSE; + } else if (reflow->need_column_resize) { + int x_rect, y_rect, width_rect, height_rect; + int start_line = e_reflow_pick_line(reflow, + gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas))->value); + gdouble running_width; + int i; + double column_width; + + if ( reflow->previous_temp_column_width != -1 ) { + running_width = start_line * (reflow->column_width + E_REFLOW_FULL_GUTTER); + column_width = reflow->previous_temp_column_width; + running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER); + running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; + y_rect = E_REFLOW_BORDER_WIDTH; + width_rect = E_REFLOW_DIVIDER_WIDTH; + height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2); + + for ( i = 0; i < reflow->column_count; i++) { + x_rect = running_width; + gnome_canvas_request_redraw(item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect); + running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; + } + } + + if ( reflow->temp_column_width != -1 ) { + running_width = start_line * (reflow->column_width + E_REFLOW_FULL_GUTTER); + column_width = reflow->temp_column_width; + running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER); + running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; + y_rect = E_REFLOW_BORDER_WIDTH; + width_rect = E_REFLOW_DIVIDER_WIDTH; + height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2); + + for ( i = 0; i < reflow->column_count; i++) { + x_rect = running_width; + gnome_canvas_request_redraw(item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect); + running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH; + } + } + + reflow->previous_temp_column_width = reflow->temp_column_width; + reflow->need_column_resize = FALSE; + } +} + +static double +e_reflow_point (GnomeCanvasItem *item, + double x, double y, int cx, int cy, + GnomeCanvasItem **actual_item) +{ + double distance = 1; + + *actual_item = NULL; + + if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->point) + distance = GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->point (item, x, y, cx, cy, actual_item); + if ((int) (distance * item->canvas->pixels_per_unit + 0.5) <= item->canvas->close_enough && *actual_item) + return distance; + + *actual_item = item; + return 0; +#if 0 + if (y >= E_REFLOW_BORDER_WIDTH && y <= reflow->height - E_REFLOW_BORDER_WIDTH) { + float n_x; + n_x = x; + n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH; + n_x = fmod(n_x, (reflow->column_width + E_REFLOW_FULL_GUTTER)); + if (n_x < E_REFLOW_FULL_GUTTER) { + *actual_item = item; + return 0; + } + } + return distance; +#endif +} + +static void +e_reflow_reflow( GnomeCanvasItem *item, int flags ) +{ + EReflow *reflow = E_REFLOW(item); + gdouble old_width; + gdouble running_width; + gdouble running_height; + int next_column; + int i; + + if (! (GTK_OBJECT_FLAGS (reflow) & GNOME_CANVAS_ITEM_REALIZED)) + return; + + if (reflow->need_reflow_columns) { + reflow_columns (reflow); + } + + old_width = reflow->width; + + running_width = E_REFLOW_BORDER_WIDTH; + running_height = E_REFLOW_BORDER_WIDTH; + + next_column = 1; + + for (i = 0; i < reflow->count; i++) { + int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i); + if (next_column < reflow->column_count && i == reflow->columns[next_column]) { + running_height = E_REFLOW_BORDER_WIDTH; + running_width += reflow->column_width + E_REFLOW_FULL_GUTTER; + next_column ++; + } + + if (unsorted >= 0 && reflow->items[unsorted]) { + e_canvas_item_move_absolute(GNOME_CANVAS_ITEM(reflow->items[unsorted]), + (double) running_width, + (double) running_height); + running_height += reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH; + } + } + reflow->width = running_width + reflow->column_width + E_REFLOW_BORDER_WIDTH; + if ( reflow->width < reflow->minimum_width ) + reflow->width = reflow->minimum_width; + if (old_width != reflow->width) + e_canvas_item_request_parent_reflow(item); +} + +static int +e_reflow_selection_event_real (EReflow *reflow, GnomeCanvasItem *item, GdkEvent *event) +{ + int row; + int return_val = TRUE; + switch (event->type) { + case GDK_BUTTON_PRESS: + switch (event->button.button) { + case 1: /* Fall through. */ + case 2: + row = er_find_item (reflow, item); + if (event->button.button == 1) { + reflow->maybe_did_something = + e_selection_model_maybe_do_something(reflow->selection, row, 0, event->button.state); + reflow->maybe_in_drag = TRUE; + } else { + e_selection_model_do_something(reflow->selection, row, 0, event->button.state); + } + break; + case 3: + row = er_find_item (reflow, item); + e_selection_model_right_click_down(reflow->selection, row, 0, 0); + break; + default: + return_val = FALSE; + break; + } + break; + case GDK_BUTTON_RELEASE: + if (event->button.button == 1) { + if (reflow->maybe_in_drag) { + reflow->maybe_in_drag = FALSE; + if (!reflow->maybe_did_something) { + row = er_find_item (reflow, item); + e_selection_model_do_something(reflow->selection, row, 0, event->button.state); + } + } + } + break; + case GDK_KEY_PRESS: + return_val = e_selection_model_key_press(reflow->selection, (GdkEventKey *) event); + break; + default: + return_val = FALSE; + break; + } + + return return_val; +} + +static void +e_reflow_class_init (EReflowClass *klass) +{ + GObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GObjectClass*) klass; + item_class = (GnomeCanvasItemClass *) klass; + + object_class->set_property = e_reflow_set_property; + object_class->get_property = e_reflow_get_property; + object_class->dispose = e_reflow_dispose; + + /* GnomeCanvasItem method overrides */ + item_class->event = e_reflow_event; + item_class->realize = e_reflow_realize; + item_class->unrealize = e_reflow_unrealize; + item_class->draw = e_reflow_draw; + item_class->update = e_reflow_update; + item_class->point = e_reflow_point; + + klass->selection_event = e_reflow_selection_event_real; + klass->column_width_changed = NULL; + + g_object_class_install_property (object_class, PROP_MINIMUM_WIDTH, + g_param_spec_double ("minimum_width", + _( "Minimum width" ), + _( "Minimum Width" ), + 0.0, G_MAXDOUBLE, 0.0, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_WIDTH, + g_param_spec_double ("width", + _( "Width" ), + _( "Width" ), + 0.0, G_MAXDOUBLE, 0.0, + G_PARAM_READABLE)); + + + g_object_class_install_property (object_class, PROP_HEIGHT, + g_param_spec_double ("height", + _( "Height" ), + _( "Height" ), + 0.0, G_MAXDOUBLE, 0.0, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_EMPTY_MESSAGE, + g_param_spec_string ("empty_message", + _( "Empty message" ), + _( "Empty message" ), + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_MODEL, + g_param_spec_object ("model", + _( "Reflow model" ), + _( "Reflow model" ), + E_REFLOW_MODEL_TYPE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_COLUMN_WIDTH, + g_param_spec_double ("column_width", + _( "Column width" ), + _( "Column width" ), + 0.0, G_MAXDOUBLE, 150.0, + G_PARAM_READWRITE)); + + signals [SELECTION_EVENT] = + g_signal_new ("selection_event", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EReflowClass, selection_event), + NULL, NULL, + e_marshal_INT__OBJECT_BOXED, + G_TYPE_INT, 2, G_TYPE_OBJECT, + GDK_TYPE_EVENT); + + signals [COLUMN_WIDTH_CHANGED] = + g_signal_new ("column_width_changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EReflowClass, column_width_changed), + NULL, NULL, + g_cclosure_marshal_VOID__DOUBLE, + G_TYPE_NONE, 1, G_TYPE_DOUBLE); +} + +static void +e_reflow_init (EReflow *reflow) +{ + reflow->model = NULL; + reflow->items = NULL; + reflow->heights = NULL; + reflow->count = 0; + + reflow->columns = NULL; + reflow->column_count = 0; + + reflow->empty_text = NULL; + reflow->empty_message = NULL; + + reflow->minimum_width = 10; + reflow->width = 10; + reflow->height = 10; + + reflow->column_width = 150; + + reflow->column_drag = FALSE; + + reflow->need_height_update = FALSE; + reflow->need_column_resize = FALSE; + reflow->need_reflow_columns = FALSE; + + reflow->maybe_did_something = FALSE; + reflow->maybe_in_drag = FALSE; + + reflow->default_cursor_shown = TRUE; + reflow->arrow_cursor = NULL; + reflow->default_cursor = NULL; + + reflow->cursor_row = -1; + + reflow->incarnate_idle_id = 0; + reflow->do_adjustment_idle_id = 0; + reflow->set_scroll_adjustments_id = 0; + + reflow->selection = E_SELECTION_MODEL (e_selection_model_simple_new()); + reflow->sorter = e_sorter_array_new (er_compare, reflow); + + g_object_set (reflow->selection, + "sorter", reflow->sorter, + NULL); + + reflow->selection_changed_id = + g_signal_connect(reflow->selection, "selection_changed", + G_CALLBACK (selection_changed), reflow); + reflow->selection_row_changed_id = + g_signal_connect(reflow->selection, "selection_row_changed", + G_CALLBACK (selection_row_changed), reflow); + reflow->cursor_changed_id = + g_signal_connect(reflow->selection, "cursor_changed", + G_CALLBACK (cursor_changed), reflow); + + e_canvas_item_set_reflow_callback(GNOME_CANVAS_ITEM(reflow), e_reflow_reflow); +} diff --git a/widgets/text/e-reflow.h b/widgets/text/e-reflow.h new file mode 100644 index 0000000000..afdc9edb67 --- /dev/null +++ b/widgets/text/e-reflow.h @@ -0,0 +1,146 @@ +/* + * 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 + * + * + * Authors: + * Chris Lahey + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __E_REFLOW_H__ +#define __E_REFLOW_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +/* EReflow - A canvas item container. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + * minimum_width double RW minimum width of the reflow. width >= minimum_width + * width double R width of the reflow + * height double RW height of the reflow + */ + +#define E_REFLOW_TYPE (e_reflow_get_type ()) +#define E_REFLOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_REFLOW_TYPE, EReflow)) +#define E_REFLOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_REFLOW_TYPE, EReflowClass)) +#define E_IS_REFLOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_REFLOW_TYPE)) +#define E_IS_REFLOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_REFLOW_TYPE)) + + +typedef struct EReflowPriv EReflowPriv; + +typedef struct _EReflow EReflow; +typedef struct _EReflowClass EReflowClass; + +struct _EReflow +{ + GnomeCanvasGroup parent; + + /* item specific fields */ + EReflowModel *model; + guint model_changed_id; + guint comparison_changed_id; + guint model_items_inserted_id; + guint model_item_removed_id; + guint model_item_changed_id; + + ESelectionModel *selection; + guint selection_changed_id; + guint selection_row_changed_id; + guint cursor_changed_id; + ESorterArray *sorter; + + GtkAdjustment *adjustment; + guint adjustment_changed_id; + guint adjustment_value_changed_id; + guint set_scroll_adjustments_id; + + int *heights; + GnomeCanvasItem **items; + int count; + int allocated_count; + + int *columns; + gint column_count; /* Number of columnns */ + + GnomeCanvasItem *empty_text; + gchar *empty_message; + + double minimum_width; + double width; + double height; + + double column_width; + + int incarnate_idle_id; + int do_adjustment_idle_id; + + /* These are all for when the column is being dragged. */ + gdouble start_x; + gint which_column_dragged; + double temp_column_width; + double previous_temp_column_width; + + int cursor_row; + + int reflow_from_column; + + guint column_drag : 1; + + guint need_height_update : 1; + guint need_column_resize : 1; + guint need_reflow_columns : 1; + + guint default_cursor_shown : 1; + + guint maybe_did_something : 1; + guint maybe_in_drag : 1; + GdkCursor *arrow_cursor; + GdkCursor *default_cursor; +}; + +struct _EReflowClass +{ + GnomeCanvasGroupClass parent_class; + + int (*selection_event) (EReflow *reflow, GnomeCanvasItem *item, GdkEvent *event); + void (*column_width_changed) (EReflow *reflow, double width); +}; + +/* + * To be added to a reflow, an item must have the argument "width" as + * a Read/Write argument and "height" as a Read Only argument. It + * should also do an ECanvas parent reflow request if its size + * changes. + */ +GType e_reflow_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __E_REFLOW_H__ */ diff --git a/widgets/text/e-text.c b/widgets/text/e-text.c index 0890b46243..3ce0065210 100644 --- a/widgets/text/e-text.c +++ b/widgets/text/e-text.c @@ -46,10 +46,10 @@ #include #include -#include "a11y/e-text/gal-a11y-e-text.h" +#include "a11y/gal-a11y-e-text.h" #include "misc/e-canvas.h" #include "misc/e-canvas-utils.h" -#include "misc/e-unicode.h" +#include "e-util/e-unicode.h" #include #include "e-util/e-text-event-processor-emacs-like.h" #include "e-util/e-util.h" -- cgit