[evolution-patches] bug 47033, gal: AtkText interface implementation for GalA11yEText Part II
- From: Tianyu Tim-Wo <tim wo sun com>
- To: Mike Kestner <mkestner ximian com>
- Cc: sceri-evolution-acc sun com, evolution-patches ximian com
- Subject: [evolution-patches] bug 47033, gal: AtkText interface implementation for GalA11yEText Part II
- Date: Sat, 27 Sep 2003 16:06:59 +0800
Hi Mike,
Would you please review this patch.
This is part 2 of the A11y implementation for e-text.
After applying this patch, we can use gok to manipulate the text and
gnopernicus to read the text.
In this patch 2 files are modified:
1. gal/a11y/e-text/gal-a11y-e-text-factory.c
(gal_a11y_e_text_factory_create_accessible): set the role of the atk
object in the initialization function of GalA11yEText
2. gal/a11y/e-text/gal-a11y-e-text.c
1) (is_a_seperator), (find_word_start), (find_word_end), (find_sentence_start),
(find_sentence_end), (find_line_start), (find_line_end):
7 new private functions, They are all used by text retrieving functions below.
2) (et_get_text_after_offset): implementation added
3) (et_get_text_at_offset): implementation added
4) (et_get_text_before_offset): implementation added
5) (et_get_character_extents): implementation added
6) (et_get_offset_at_point): implementation added
7) (et_set_caret_offset):
use command to modify the cursor position, so that we can be notified and
emit "text-caret-moved" signal in function _et_command_cb.
8) (_et_reposition_cb):
new function to emit "text-changed" signal for the atk object
9) (_et_command_cb):
new function to emit "text-caret-moved" and "text-selection-changed" signals
for the atk object
10) (et_real_initialize):
new function to deal with initialization of GalA11yEText. It set some signal
callbacks and the atk role of the atk object (set GalA11yEText's role to
ATK_ROLE_TEXT).
11) (et_class_init):
override the virtual function "initialize" in baseclass (AtkObject) with
"et_real_initialize"
--
Tianyu Tim-Wo <tim wo sun com>
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gal/ChangeLog,v
retrieving revision 1.808
diff -u -r1.808 ChangeLog
--- ChangeLog 24 Sep 2003 11:25:59 -0000 1.808
+++ ChangeLog 27 Sep 2003 07:46:09 -0000
@@ -1,3 +1,31 @@
+2003-09-27 Tim Wo <tim wo sun com>
+
+ * gal/a11y/e-text/gal-a11y-e-text-factory.c
+ (gal_a11y_e_text_factory_create_accessible): set the role of the
+ atk object in the initialization function of GalA11yEText
+ * gal/a11y/e-text/gal-a11y-e-text.c (is_a_seperator),
+ (find_word_start), (find_word_end), (find_sentence_start),
+ (find_sentence_end), (find_line_start), (find_line_end): 7 new
+ private functions, They are all used by text retrieving functions
+ below.
+ (et_get_text_after_offset): implementation added
+ (et_get_text_at_offset): implementation added
+ (et_get_text_before_offset): implementation added
+ (et_get_character_extents): implementation added
+ (et_get_offset_at_point): implementation added
+ (et_set_caret_offset): use command to modify the cursor position,
+ so that we can be notified and emit "text-caret-moved" signal in
+ function _et_command_cb.
+ (_et_reposition_cb): new function to emit "text-changed" signal
+ for the atk object
+ (_et_command_cb): new function to emit "text-caret-moved" and
+ "text-selection-changed" signals for the atk object
+ (et_real_initialize): new function to deal with initialization of
+ GalA11yEText. It set some signal callbacks and the atk role of
+ the atk object (set GalA11yEText's role to ATK_ROLE_TEXT).
+ (et_class_init): override the virtual function "initialize" in
+ baseclass (AtkObject) with "et_real_initialize"
+
2003-09-22 Tim Wo <tim wo sun com>
* gal/a11y/e-text/gal-a11y-e-text.c (et_get_text): some checking
Index: gal/a11y/e-text/gal-a11y-e-text-factory.c
===================================================================
RCS file: /cvs/gnome/gal/gal/a11y/e-text/gal-a11y-e-text-factory.c,v
retrieving revision 1.1
diff -u -r1.1 gal-a11y-e-text-factory.c
--- gal/a11y/e-text/gal-a11y-e-text-factory.c 30 Nov 2002 07:54:16 -0000 1.1
+++ gal/a11y/e-text/gal-a11y-e-text-factory.c 27 Sep 2003 07:46:09 -0000
@@ -32,7 +32,6 @@
atk_object = g_object_new (GAL_A11Y_TYPE_E_TEXT, NULL);
atk_object_initialize (atk_object, obj);
- atk_object->role = ATK_ROLE_UNKNOWN;
return atk_object;
}
Index: gal/a11y/e-text/gal-a11y-e-text.c
===================================================================
RCS file: /cvs/gnome/gal/gal/a11y/e-text/gal-a11y-e-text.c,v
retrieving revision 1.4
diff -u -r1.4 gal-a11y-e-text.c
--- gal/a11y/e-text/gal-a11y-e-text.c 24 Sep 2003 11:26:00 -0000 1.4
+++ gal/a11y/e-text/gal-a11y-e-text.c 27 Sep 2003 07:46:10 -0000
@@ -16,6 +16,7 @@
#include <atk/atkregistry.h>
#include <atk/atkgobjectaccessible.h>
#include "gal/e-text/e-text.h"
+#include "gal/e-text/e-text-model-repos.h"
#include <gtk/gtkmain.h>
#define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yETextClass))
@@ -131,6 +132,166 @@
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 <len) {
+ last_word_end = find_word_end (text, offset - 1, -1);
+ if (last_word_end == 0)
+ break;
+ for (i = last_word_end; i < offset; i++) {
+ at_offset = g_utf8_offset_to_pointer (text, i);
+ ch = g_utf8_get_char_validated (at_offset, -1);
+ if (ch == '.' || ch == '!' || ch == '?')
+ return offset;
+ }
+
+ offset = find_word_start (text, offset + step, step);
+ }
+
+ return offset;
+}
+
+static gint
+find_sentence_end (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 == '.' || 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,
@@ -138,8 +299,50 @@
gint *start_offset,
gint *end_offset)
{
- /* Unimplemented */
- return NULL;
+ 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;
+ defalut:
+ 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 *
@@ -149,8 +352,50 @@
gint *start_offset,
gint *end_offset)
{
- /* Unimplemented */
- return NULL;
+ 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;
+ defalut:
+ 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
@@ -172,10 +417,51 @@
gint *start_offset,
gint *end_offset)
{
- /* Unimplemented */
- return NULL;
-}
+ 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)
@@ -227,7 +513,69 @@
gint *height,
AtkCoordType coords)
{
- /* Unimplemented */
+ GObject *obj;
+ EText *etext;
+ GnomeCanvas *canvas;
+ gint x_widget, y_widget, x_window, y_window;
+ GdkWindow *window;
+ GtkWidget *widget;
+ int index;
+ int trailing;
+ 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;
+ }
}
@@ -246,8 +594,62 @@
gint y,
AtkCoordType coords)
{
- /* Unimplemented */
- return 0;
+ 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);
}
@@ -348,8 +750,8 @@
g_return_val_if_fail (E_IS_TEXT (obj), FALSE);
etext = E_TEXT (obj);
- if( selection_num == 0
- && etext->selection_start != etext->selection_end ) {
+ 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;
@@ -398,15 +800,18 @@
if (offset < -1)
return FALSE;
- else if (offset == -1)
- gtk_object_set (GTK_OBJECT (etext),
- "cursor_pos", et_get_character_count (text),
- NULL);
- else
- gtk_object_set (GTK_OBJECT (etext),
- "cursor_pos", offset,
- NULL);
- return TRUE;
+ else {
+ if (offset == -1)
+ offset = et_get_character_count (text);
+
+ ETextEventProcessorCommand command;
+ 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
@@ -564,17 +969,84 @@
}
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;
+ }
+}
+
+static void
+et_real_initialize (AtkObject *obj,
+ gpointer data)
+{
+ GalA11yEText *a11y;
+ 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));
+
+ a11y = GAL_A11Y_E_TEXT (obj);
+ etext = E_TEXT (data);
+
+ /* Set up signal callbacks */
+ g_signal_connect (etext->model, "reposition",
+ G_CALLBACK (_et_reposition_cb), obj);
+
+ 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
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]