1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2 of the License, or (at your option) version 3.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
14  *
15  *
16  * Authors:
17  *		Christopher James Lahey <clahey@ximian.com>
18  *
19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20  *
21  */
22 
23 #include "evolution-config.h"
24 
25 #include <string.h>
26 
27 #include <atk/atk.h>
28 
29 #include "e-util/e-cell-text.h"
30 #include <glib/gi18n.h>
31 
32 #include "gal-a11y-e-cell-text.h"
33 
34 #define CS_CLASS(a11y) (G_TYPE_INSTANCE_GET_CLASS ((a11y), C_TYPE_STREAM, GalA11yECellTextClass))
35 static AtkObjectClass *parent_class;
36 #define PARENT_TYPE (gal_a11y_e_cell_get_type ())
37 
38 #define GAL_A11Y_E_CELL_TEXT_GET_PRIVATE(obj) \
39 	(G_TYPE_INSTANCE_GET_PRIVATE \
40 	((obj), GAL_A11Y_TYPE_E_CELL_TEXT, GalA11yECellTextPrivate))
41 
42 struct _GalA11yECellTextPrivate {
43 	ECell *cell;
44 };
45 
46 /* Static functions */
47 static void
ect_dispose(GObject * object)48 ect_dispose (GObject *object)
49 {
50 	GObjectClass *g_class;
51 	GalA11yECellText *gaet = GAL_A11Y_E_CELL_TEXT (object);
52 	GalA11yECellTextPrivate *priv;
53 
54 	priv = GAL_A11Y_E_CELL_TEXT_GET_PRIVATE (object);
55 
56 	if (gaet->inserted_id != 0 && priv->cell) {
57 		ECellText *ect = E_CELL_TEXT (priv->cell);
58 
59 		if (ect) {
60 			g_signal_handler_disconnect (ect, gaet->inserted_id);
61 			g_signal_handler_disconnect (ect, gaet->deleted_id);
62 		}
63 
64 		gaet->inserted_id = 0;
65 		gaet->deleted_id = 0;
66 	}
67 
68 	g_clear_object (&priv->cell);
69 
70 	g_class = (GObjectClass *)parent_class;
71 	if (g_class->dispose)
72 		g_class->dispose (object);
73 
74 }
75 
76 static gboolean
ect_check(gpointer a11y)77 ect_check (gpointer a11y)
78 {
79 	GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y);
80 	ETableItem *item = gaec->item;
81 
82 	g_return_val_if_fail ((gaec->item != NULL), FALSE);
83 	g_return_val_if_fail ((gaec->cell_view != NULL), FALSE);
84 	g_return_val_if_fail ((gaec->cell_view->ecell != NULL), FALSE);
85 
86 	if (atk_state_set_contains_state (gaec->state_set, ATK_STATE_DEFUNCT))
87 		return FALSE;
88 
89 	if (gaec->row < 0 || gaec->row >= item->rows
90 		|| gaec->view_col <0 || gaec->view_col >= item->cols
91 		|| gaec->model_col <0 || gaec->model_col >= e_table_model_column_count (item->table_model))
92 		return FALSE;
93 
94 	if (!E_IS_CELL_TEXT (gaec->cell_view->ecell))
95 		return FALSE;
96 
97 	return TRUE;
98 }
99 
100 static const gchar *
ect_get_name(AtkObject * a11y)101 ect_get_name (AtkObject * a11y)
102 {
103 	GalA11yECell *gaec;
104 	gchar *name;
105 
106 	if (!ect_check (a11y))
107 		return NULL;
108 
109 	gaec = GAL_A11Y_E_CELL (a11y);
110 	name = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
111 	if (name != NULL) {
112 		ATK_OBJECT_CLASS (parent_class)->set_name (a11y, name);
113 		g_free (name);
114 	}
115 
116 	if (a11y->name != NULL && strcmp (a11y->name, "")) {
117 		return a11y->name;
118 	} else {
119 		return parent_class->get_name (a11y);
120 	}
121 }
122 
123 static gchar *
ect_get_text(AtkText * text,gint start_offset,gint end_offset)124 ect_get_text (AtkText *text,
125 	      gint start_offset,
126 	      gint end_offset)
127 {
128 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
129 	gchar *full_text;
130 	gchar *ret_val;
131 
132 	if (!ect_check (text))
133 		return NULL;
134 
135 	full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
136 
137 	if (end_offset == -1)
138 		end_offset = strlen (full_text);
139 	else
140 		end_offset = g_utf8_offset_to_pointer (full_text, end_offset) - full_text;
141 
142 	start_offset = g_utf8_offset_to_pointer (full_text, start_offset) - full_text;
143 
144 	ret_val = g_strndup (full_text + start_offset, end_offset - start_offset);
145 
146 	g_free (full_text);
147 
148 	return ret_val;
149 }
150 
151 static gchar *
ect_get_text_after_offset(AtkText * text,gint offset,AtkTextBoundary boundary_type,gint * start_offset,gint * end_offset)152 ect_get_text_after_offset (AtkText *text,
153 			   gint offset,
154 			   AtkTextBoundary boundary_type,
155 			   gint *start_offset,
156 			   gint *end_offset)
157 {
158 	/* Unimplemented */
159 	return NULL;
160 }
161 
162 static gchar *
ect_get_text_at_offset(AtkText * text,gint offset,AtkTextBoundary boundary_type,gint * start_offset,gint * end_offset)163 ect_get_text_at_offset (AtkText *text,
164 			gint offset,
165 			AtkTextBoundary boundary_type,
166 			gint *start_offset,
167 			gint *end_offset)
168 {
169 	/* Unimplemented */
170 	return NULL;
171 }
172 
173 static gunichar
ect_get_character_at_offset(AtkText * text,gint offset)174 ect_get_character_at_offset (AtkText *text,
175 			     gint offset)
176 {
177 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
178 	gunichar ret_val;
179 	gchar *at_offset;
180 	gchar *full_text;
181 
182 	if (!ect_check (text))
183 		return -1;
184 
185 	full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
186 	at_offset = g_utf8_offset_to_pointer (full_text, offset);
187 	ret_val = g_utf8_get_char_validated (at_offset, -1);
188 	g_free (full_text);
189 
190 	return ret_val;
191 }
192 
193 static gchar *
ect_get_text_before_offset(AtkText * text,gint offset,AtkTextBoundary boundary_type,gint * start_offset,gint * end_offset)194 ect_get_text_before_offset (AtkText *text,
195 			    gint offset,
196 			    AtkTextBoundary boundary_type,
197 			    gint *start_offset,
198 			    gint *end_offset)
199 {
200 	/* Unimplemented */
201 	return NULL;
202 }
203 
204 static gint
ect_get_caret_offset(AtkText * text)205 ect_get_caret_offset (AtkText *text)
206 {
207 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
208 	gint start, end;
209 
210 	if (!ect_check (text))
211 		return -1;
212 
213 	if (e_cell_text_get_selection (gaec->cell_view,
214 				       gaec->view_col, gaec->row,
215 				       &start, &end)) {
216 		gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
217 		end = g_utf8_pointer_to_offset (full_text, full_text + end);
218 		g_free (full_text);
219 
220 		return end;
221 	}
222 	else
223 		return -1;
224 }
225 
226 static AtkAttributeSet*
ect_get_run_attributes(AtkText * text,gint offset,gint * start_offset,gint * end_offset)227 ect_get_run_attributes (AtkText *text,
228 			gint offset,
229 			gint *start_offset,
230 			gint *end_offset)
231 {
232 	/* Unimplemented */
233 	return NULL;
234 }
235 
236 static AtkAttributeSet*
ect_get_default_attributes(AtkText * text)237 ect_get_default_attributes (AtkText *text)
238 {
239 	/* Unimplemented */
240 	return NULL;
241 }
242 
243 static void
ect_get_character_extents(AtkText * text,gint offset,gint * x,gint * y,gint * width,gint * height,AtkCoordType coords)244 ect_get_character_extents (AtkText *text,
245 			   gint offset,
246 			   gint *x,
247 			   gint *y,
248 			   gint *width,
249 			   gint *height,
250 			   AtkCoordType coords)
251 {
252 	/* Unimplemented */
253 }
254 
255 static gint
ect_get_character_count(AtkText * text)256 ect_get_character_count (AtkText *text)
257 {
258 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
259 	gint ret_val;
260 	gchar *full_text;
261 
262 	if (!ect_check (text))
263 		return -1;
264 
265 	full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
266 
267 	ret_val = g_utf8_strlen (full_text, -1);
268 	g_free (full_text);
269 	return ret_val;
270 }
271 
272 static gint
ect_get_offset_at_point(AtkText * text,gint x,gint y,AtkCoordType coords)273 ect_get_offset_at_point (AtkText *text,
274 			 gint x,
275 			 gint y,
276 			 AtkCoordType coords)
277 {
278 	/* Unimplemented */
279 	return 0;
280 }
281 
282 static gint
ect_get_n_selections(AtkText * text)283 ect_get_n_selections (AtkText *text)
284 {
285 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
286 	gint selection_start, selection_end;
287 
288 	if (!ect_check (text))
289 		return 0;
290 
291 	if (e_cell_text_get_selection (gaec->cell_view,
292 				       gaec->view_col, gaec->row,
293 				       &selection_start,
294 				       &selection_end)
295 	    && selection_start != selection_end)
296 		return 1;
297 	return 0;
298 }
299 
300 static gchar *
ect_get_selection(AtkText * text,gint selection_num,gint * start_offset,gint * end_offset)301 ect_get_selection (AtkText *text,
302 		   gint selection_num,
303 		   gint *start_offset,
304 		   gint *end_offset)
305 {
306 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
307 	gchar *ret_val;
308 	gint selection_start, selection_end;
309 
310 	if (selection_num == 0
311 	    && e_cell_text_get_selection (gaec->cell_view,
312 					  gaec->view_col, gaec->row,
313 					  &selection_start,
314 					  &selection_end)
315 	    && selection_start != selection_end) {
316 		gint real_start, real_end, len;
317 		gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
318 		len = strlen (full_text);
319 		real_start = MIN (selection_start, selection_end);
320 		real_end   = MAX (selection_start, selection_end);
321 		real_start = MIN (MAX (0, real_start), len);
322 		real_end   = MIN (MAX (0, real_end), len);
323 
324 		ret_val = g_strndup (full_text + real_start, real_end - real_start);
325 
326 		real_start = g_utf8_pointer_to_offset (full_text, full_text + real_start);
327 		real_end   = g_utf8_pointer_to_offset (full_text, full_text + real_end);
328 
329 		if (start_offset)
330 			*start_offset = real_start;
331 		if (end_offset)
332 			*end_offset = real_end;
333 		g_free (full_text);
334 	} else {
335 		if (start_offset)
336 			*start_offset = 0;
337 		if (end_offset)
338 			*end_offset = 0;
339 		ret_val = NULL;
340 	}
341 
342 	return ret_val;
343 }
344 
345 static gboolean
ect_add_selection(AtkText * text,gint start_offset,gint end_offset)346 ect_add_selection (AtkText *text,
347 		   gint start_offset,
348 		   gint end_offset)
349 {
350 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
351 
352 	if (start_offset != end_offset) {
353 		gint real_start, real_end, len;
354 		gchar *full_text =
355 			e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
356 
357 		len = g_utf8_strlen (full_text, -1);
358 		if (end_offset == -1)
359 			end_offset = len;
360 
361 		real_start = MIN (start_offset, end_offset);
362 		real_end   = MAX (start_offset, end_offset);
363 
364 		real_start = MIN (MAX (0, real_start), len);
365 		real_end   = MIN (MAX (0, real_end), len);
366 
367 		real_start = g_utf8_offset_to_pointer (full_text, real_start) - full_text;
368 		real_end   = g_utf8_offset_to_pointer (full_text, real_end) - full_text;
369 		g_free (full_text);
370 
371 		if (e_cell_text_set_selection (gaec->cell_view,
372 					       gaec->view_col, gaec->row,
373 					       real_start, real_end)) {
374 			g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed");
375 			return TRUE;
376 		}
377 	}
378 
379 	return FALSE;
380 }
381 
382 static gboolean
ect_remove_selection(AtkText * text,gint selection_num)383 ect_remove_selection (AtkText *text,
384 		      gint selection_num)
385 {
386 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
387 	gint selection_start, selection_end;
388 
389 	if (selection_num == 0
390 	    && e_cell_text_get_selection (gaec->cell_view,
391 					  gaec->view_col, gaec->row,
392 					  &selection_start,
393 					  &selection_end)
394 	    && selection_start != selection_end
395 	    && e_cell_text_set_selection (gaec->cell_view,
396 					  gaec->view_col, gaec->row,
397 					  selection_end, selection_end)) {
398 		g_signal_emit_by_name (ATK_OBJECT(text), "text_selection_changed");
399 		return TRUE;
400 	}
401 	else
402 		return FALSE;
403 }
404 
405 static gboolean
ect_set_selection(AtkText * text,gint selection_num,gint start_offset,gint end_offset)406 ect_set_selection (AtkText *text,
407 		   gint selection_num,
408 		   gint start_offset,
409 		   gint end_offset)
410 {
411 	if (selection_num == 0) {
412 		atk_text_add_selection (text, start_offset, end_offset);
413 		return TRUE;
414 	}
415 	else
416 		return FALSE;
417 }
418 
419 static gboolean
ect_set_caret_offset(AtkText * text,gint offset)420 ect_set_caret_offset (AtkText *text,
421 		      gint offset)
422 {
423 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
424 	gchar *full_text;
425 	gint len;
426 
427 	full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
428 
429 	len = g_utf8_strlen (full_text, -1);
430 	if (offset == -1)
431 		offset = len;
432 	else
433 		offset = MIN (MAX (0, offset), len);
434 
435 	offset = g_utf8_offset_to_pointer (full_text, offset) - full_text;
436 
437 	g_free (full_text);
438 
439 	return e_cell_text_set_selection (gaec->cell_view,
440 					  gaec->view_col, gaec->row,
441 					  offset, offset);
442 }
443 
444 static gboolean
ect_set_run_attributes(AtkEditableText * text,AtkAttributeSet * attrib_set,gint start_offset,gint end_offset)445 ect_set_run_attributes (AtkEditableText *text,
446 			AtkAttributeSet *attrib_set,
447 			gint start_offset,
448 			gint end_offset)
449 {
450 	/* Unimplemented */
451 	return FALSE;
452 }
453 
454 static void
ect_set_text_contents(AtkEditableText * text,const gchar * string)455 ect_set_text_contents (AtkEditableText *text,
456 		       const gchar *string)
457 {
458 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
459 	ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell);
460 
461 	e_cell_text_set_value (ect, gaec->item->table_model, gaec->model_col, gaec->row, string);
462 	e_table_item_enter_edit (gaec->item, gaec->view_col, gaec->row);
463 }
464 
465 static void
ect_insert_text(AtkEditableText * text,const gchar * string,gint length,gint * position)466 ect_insert_text (AtkEditableText *text,
467 		 const gchar *string,
468 		 gint length,
469 		 gint *position)
470 {
471 	/* Utf8 unimplemented */
472 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
473 	ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell);
474 
475 	gchar *full_text = e_cell_text_get_text_by_view (gaec->cell_view, gaec->model_col, gaec->row);
476 	gchar *result = g_strdup_printf ("%.*s%.*s%s", *position, full_text, length, string, full_text + *position);
477 
478 	e_cell_text_set_value (ect, gaec->item->table_model, gaec->model_col, gaec->row, result);
479 
480 	*position += length;
481 
482 	g_free (result);
483 	g_free (full_text);
484 }
485 
486 static void
ect_copy_text(AtkEditableText * text,gint start_pos,gint end_pos)487 ect_copy_text (AtkEditableText *text,
488 	       gint start_pos,
489 	       gint end_pos)
490 {
491 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
492 	if (start_pos != end_pos
493 	    && atk_text_set_selection (ATK_TEXT (text), 0, start_pos, end_pos))
494 		e_cell_text_copy_clipboard (gaec->cell_view,
495 					    gaec->view_col, gaec->row);
496 }
497 
498 static void
ect_delete_text(AtkEditableText * text,gint start_pos,gint end_pos)499 ect_delete_text (AtkEditableText *text,
500 		 gint start_pos,
501 		 gint end_pos)
502 {
503 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
504 	if (start_pos != end_pos
505 	    && atk_text_set_selection (ATK_TEXT (text), 0, start_pos, end_pos))
506 		e_cell_text_delete_selection (gaec->cell_view,
507 					      gaec->view_col, gaec->row);
508 }
509 
510 static void
ect_cut_text(AtkEditableText * text,gint start_pos,gint end_pos)511 ect_cut_text (AtkEditableText *text,
512 	      gint start_pos,
513 	      gint end_pos)
514 {
515 	ect_copy_text (text, start_pos, end_pos);
516 	ect_delete_text (text, start_pos, end_pos);
517 }
518 
519 static void
ect_paste_text(AtkEditableText * text,gint position)520 ect_paste_text (AtkEditableText *text,
521 		gint position)
522 {
523 	GalA11yECell *gaec = GAL_A11Y_E_CELL (text);
524 
525 	e_table_item_enter_edit (gaec->item, gaec->view_col, gaec->row);
526 
527 	if (atk_text_set_caret_offset (ATK_TEXT (text), position))
528 		e_cell_text_paste_clipboard (gaec->cell_view,
529 					     gaec->view_col, gaec->row);
530 }
531 
532 static void
ect_do_action_edit(AtkAction * action)533 ect_do_action_edit (AtkAction *action)
534 {
535 	GalA11yECell *a11y = GAL_A11Y_E_CELL (action);
536 	ETableModel *e_table_model = a11y->item->table_model;
537 
538 	if (e_table_model_is_cell_editable (e_table_model, a11y->model_col, a11y->row)) {
539 		e_table_item_enter_edit (a11y->item, a11y->view_col, a11y->row);
540 	}
541 }
542 
543 /* text signal handlers */
544 static void
ect_text_inserted_cb(ECellText * text,ECellView * cell_view,gint pos,gint len,gint row,gint model_col,gpointer data)545 ect_text_inserted_cb (ECellText *text, ECellView *cell_view, gint pos, gint len, gint row, gint model_col, gpointer data)
546 {
547 	GalA11yECellText *gaet;
548 	GalA11yECell *gaec;
549 
550 	if (!ect_check (data))
551 		return;
552 	gaet = GAL_A11Y_E_CELL_TEXT (data);
553 	gaec = GAL_A11Y_E_CELL (data);
554 
555 	if (cell_view == gaec->cell_view && row == gaec->row && model_col == gaec->model_col) {
556 		g_signal_emit_by_name (gaet, "text_changed::insert", pos, len);
557 
558 	}
559 }
560 
561 static void
ect_text_deleted_cb(ECellText * text,ECellView * cell_view,gint pos,gint len,gint row,gint model_col,gpointer data)562 ect_text_deleted_cb (ECellText *text, ECellView *cell_view, gint pos, gint len, gint row, gint model_col, gpointer data)
563 {
564 	GalA11yECellText *gaet;
565 	GalA11yECell *gaec;
566 	if (!ect_check (data))
567 		return;
568 	gaet = GAL_A11Y_E_CELL_TEXT (data);
569 	gaec = GAL_A11Y_E_CELL (data);
570 	if (cell_view == gaec->cell_view && row == gaec->row && model_col == gaec->model_col) {
571 		g_signal_emit_by_name (gaet, "text_changed::delete", pos, len);
572 	 }
573 }
574 
575 static void
ect_atk_text_iface_init(AtkTextIface * iface)576 ect_atk_text_iface_init (AtkTextIface *iface)
577 {
578 	iface->get_text                = ect_get_text;
579 	iface->get_text_after_offset   = ect_get_text_after_offset;
580 	iface->get_text_at_offset      = ect_get_text_at_offset;
581 	iface->get_character_at_offset = ect_get_character_at_offset;
582 	iface->get_text_before_offset  = ect_get_text_before_offset;
583 	iface->get_caret_offset        = ect_get_caret_offset;
584 	iface->get_run_attributes      = ect_get_run_attributes;
585 	iface->get_default_attributes  = ect_get_default_attributes;
586 	iface->get_character_extents   = ect_get_character_extents;
587 	iface->get_character_count     = ect_get_character_count;
588 	iface->get_offset_at_point     = ect_get_offset_at_point;
589 	iface->get_n_selections        = ect_get_n_selections;
590 	iface->get_selection           = ect_get_selection;
591 	iface->add_selection           = ect_add_selection;
592 	iface->remove_selection        = ect_remove_selection;
593 	iface->set_selection           = ect_set_selection;
594 	iface->set_caret_offset        = ect_set_caret_offset;
595 }
596 
597 static void
ect_atk_editable_text_iface_init(AtkEditableTextIface * iface)598 ect_atk_editable_text_iface_init (AtkEditableTextIface *iface)
599 {
600 	iface->set_run_attributes = ect_set_run_attributes;
601 	iface->set_text_contents  = ect_set_text_contents;
602 	iface->insert_text        = ect_insert_text;
603 	iface->copy_text          = ect_copy_text;
604 	iface->cut_text           = ect_cut_text;
605 	iface->delete_text        = ect_delete_text;
606 	iface->paste_text         = ect_paste_text;
607 }
608 
609 static void
ect_class_init(GalA11yECellTextClass * klass)610 ect_class_init (GalA11yECellTextClass *klass)
611 {
612 	AtkObjectClass *a11y      = ATK_OBJECT_CLASS (klass);
613 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
614 
615 	g_type_class_add_private (klass, sizeof (GalA11yECellTextPrivate));
616 
617 	parent_class              = g_type_class_ref (PARENT_TYPE);
618 	a11y->get_name            = ect_get_name;
619 	object_class->dispose     = ect_dispose;
620 }
621 
622 static void
ect_action_init(GalA11yECellText * a11y)623 ect_action_init (GalA11yECellText *a11y)
624 {
625 	GalA11yECell *gaec = GAL_A11Y_E_CELL (a11y);
626 	ECellText *ect = E_CELL_TEXT (gaec->cell_view->ecell);
627 	if (ect->editable && e_table_model_is_cell_editable (gaec->cell_view->e_table_model, gaec->model_col, gaec->row))
628 		gal_a11y_e_cell_add_action (gaec,
629 				    "edit",
630 				    /* Translators: description of an "edit" action */
631 				    _("begin editing this cell"),
632 				    NULL,
633 				    (ACTION_FUNC) ect_do_action_edit);
634 }
635 
636 /**
637  * gal_a11y_e_cell_text_get_type:
638  * @void:
639  *
640  * Registers the &GalA11yECellText class if necessary, and returns the type ID
641  * associated to it.
642  *
643  * Return value: The type ID of the &GalA11yECellText class.
644  **/
645 GType
gal_a11y_e_cell_text_get_type(void)646 gal_a11y_e_cell_text_get_type (void)
647 {
648 	static GType type = 0;
649 
650 	if (!type) {
651 		GTypeInfo info = {
652 			sizeof (GalA11yECellTextClass),
653 			(GBaseInitFunc) NULL,
654 			(GBaseFinalizeFunc) NULL,
655 			(GClassInitFunc) ect_class_init,
656 			(GClassFinalizeFunc) NULL,
657 			NULL, /* class_data */
658 			sizeof (GalA11yECellText),
659 			0,
660 			(GInstanceInitFunc) NULL,
661 			NULL /* value_cell_text */
662 		};
663 
664 		static const GInterfaceInfo atk_text_info = {
665 			(GInterfaceInitFunc) ect_atk_text_iface_init,
666 			(GInterfaceFinalizeFunc) NULL,
667 			NULL
668 		};
669 
670 		static const GInterfaceInfo atk_editable_text_info = {
671 			(GInterfaceInitFunc) ect_atk_editable_text_iface_init,
672 			(GInterfaceFinalizeFunc) NULL,
673 			NULL
674 		};
675 
676 		type = g_type_register_static (PARENT_TYPE, "GalA11yECellText", &info, 0);
677 		g_type_add_interface_static (type, ATK_TYPE_TEXT, &atk_text_info);
678 		g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info);
679 		gal_a11y_e_cell_type_add_action_interface (type);
680 	}
681 
682 	return type;
683 }
684 
685 AtkObject *
gal_a11y_e_cell_text_new(ETableItem * item,ECellView * cell_view,AtkObject * parent,gint model_col,gint view_col,gint row)686 gal_a11y_e_cell_text_new (ETableItem *item,
687 			  ECellView  *cell_view,
688 			  AtkObject  *parent,
689 			  gint         model_col,
690 			  gint         view_col,
691 			  gint         row)
692 {
693 	AtkObject *a11y;
694 	GalA11yECell *gaec;
695 	GalA11yECellText *gaet;
696 	GalA11yECellTextPrivate *priv;
697 	ECellText *ect;
698 
699 	a11y = g_object_new (gal_a11y_e_cell_text_get_type (), NULL);
700 
701 	gal_a11y_e_cell_construct (a11y,
702 				   item,
703 				   cell_view,
704 				   parent,
705 				   model_col,
706 				   view_col,
707 				   row);
708 	gaet = GAL_A11Y_E_CELL_TEXT (a11y);
709 
710 	priv = GAL_A11Y_E_CELL_TEXT_GET_PRIVATE (a11y);
711 	priv->cell = g_object_ref (((ECellView *) cell_view)->ecell);
712 
713 	gaet->inserted_id = g_signal_connect (E_CELL_TEXT (priv->cell),
714 						"text_inserted", G_CALLBACK (ect_text_inserted_cb), a11y);
715 	gaet->deleted_id = g_signal_connect (E_CELL_TEXT (priv->cell),
716 					     "text_deleted", G_CALLBACK (ect_text_deleted_cb), a11y);
717 
718 	ect_action_init (gaet);
719 
720 	ect = E_CELL_TEXT (cell_view->ecell);
721 	gaec = GAL_A11Y_E_CELL (a11y);
722 	if (ect->editable && e_table_model_is_cell_editable (gaec->cell_view->e_table_model, gaec->model_col, gaec->row))
723 		gal_a11y_e_cell_add_state (gaec, ATK_STATE_EDITABLE, FALSE);
724 	else
725 		gal_a11y_e_cell_remove_state (gaec, ATK_STATE_EDITABLE, FALSE);
726 
727 	return a11y;
728 }
729