atk/atkeditabletext.c atk/atktext.c atk/atktext.h atk/atkutil.h
[platform/upstream/atk.git] / atk / atktext.c
1 /* ATK - The Accessibility Toolkit for GTK+
2  * Copyright 2001 Sun Microsystems Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "atktext.h"
21 #include "atkmarshal.h"
22
23 enum {
24   TEXT_CHANGED,
25   CARET_MOVED,
26   LAST_SIGNAL
27 };
28
29 struct _AtkTextIfaceClass
30 {
31   GObjectClass parent;
32 };
33
34 typedef struct _AtkTextIfaceClass AtkTextIfaceClass;
35
36 static void atk_text_base_init (gpointer *g_class);
37
38 static guint atk_text_signals[LAST_SIGNAL] = { 0 };
39
40 GType
41 atk_text_get_type ()
42 {
43   static GType type = 0;
44
45   if (!type) 
46     {
47       static const GTypeInfo tinfo =
48       {
49         sizeof (AtkTextIface),
50         (GBaseInitFunc) atk_text_base_init,
51         (GBaseFinalizeFunc) NULL,
52         (GClassInitFunc) NULL /* atk_text_interface_init */ ,
53         (GClassFinalizeFunc) NULL,
54
55       };
56
57       type = g_type_register_static (G_TYPE_INTERFACE, "AtkText", &tinfo, 0);
58     }
59
60   return type;
61 }
62
63 static void
64 atk_text_base_init (gpointer *g_class)
65 {
66   static gboolean initialized = FALSE;
67   
68   if (! initialized)
69     {
70       /* 
71        * Note that text_changed signal supports details "insert", "delete", 
72        * possibly "replace". 
73        */
74       
75       atk_text_signals[TEXT_CHANGED] =
76         g_signal_new ("text_changed",
77                       ATK_TYPE_TEXT,
78                       G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
79                       G_STRUCT_OFFSET (AtkTextIface, text_changed), 
80                       (GSignalAccumulator) NULL, NULL,
81                       atk_marshal_VOID__INT_INT,
82                       G_TYPE_NONE,
83                       2, G_TYPE_INT, G_TYPE_INT);
84       
85       atk_text_signals[CARET_MOVED] =
86         g_signal_new ("text_caret_moved",
87                       ATK_TYPE_TEXT,
88                       G_SIGNAL_RUN_LAST,
89                       G_STRUCT_OFFSET (AtkTextIface, caret_changed),
90                       (GSignalAccumulator) NULL, NULL,
91                       g_cclosure_marshal_VOID__INT,
92                       G_TYPE_NONE,
93                       1, G_TYPE_INT);
94       
95       initialized = TRUE;
96     }
97 }
98
99 /**
100  * atk_text_get_text:
101  * @text: an #AtkText
102  * @start_offset: start position
103  * @end_offset: end position
104  *
105  * Gets the specified text.
106  *
107  * Returns: the text from @start_offset up to, but not including @end_offset.
108  **/
109 gchar*
110 atk_text_get_text (AtkText      *text,
111                    gint         start_offset,
112                    gint         end_offset)
113 {
114   AtkTextIface *iface;
115
116   g_return_val_if_fail (text != NULL, NULL);
117   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
118
119   iface = ATK_TEXT_GET_IFACE (text);
120
121   if (iface->get_text)
122     return (*(iface->get_text)) (text, start_offset, end_offset);
123   else
124     return NULL;
125 }
126
127 /**
128  * atk_text_get_character_at_offset:
129  * @text: an #AtkText
130  * @offset: position
131  *
132  * Gets the specified text.
133  *
134  * Returns: the character at @offset.
135  **/
136 gunichar
137 atk_text_get_character_at_offset (AtkText      *text,
138                                   gint         offset)
139 {
140   AtkTextIface *iface;
141
142   g_return_val_if_fail (text != NULL, (gunichar) 0);
143   g_return_val_if_fail (ATK_IS_TEXT (text), (gunichar) 0);
144
145   iface = ATK_TEXT_GET_IFACE (text);
146
147   if (iface->get_character_at_offset)
148     return (*(iface->get_character_at_offset)) (text, offset);
149   else
150     return (gunichar) 0;
151 }
152
153 /**
154  * atk_text_get_text_after_offset:
155  * @text: an #AtkText
156  * @offset: position
157  * @boundary_type: An #AtkTextBoundary
158  * @startOffset: the start offset of the returned string.
159  * @endOffset: the end offset of the returned string.
160  *
161  * Gets the specified text.
162  * If the boundary type is ATK_TEXT_BOUNDARY_WORD_START or
163  * ATK_TEXT_BOUNDARY_WORD_END part of a word may be returned.
164  * If the boundary type is ATK_TEXT_BOUNDARY_SENTENCE_START the start point 
165  * will be the offset and will continue to the start of the next sentence. 
166  * The first word may not be a complete word. Similarly for 
167  * ATK_TEXT_BOUNDARY_SENTENCE_END, ATK_TEXT_BOUNDARY_LINE_START and
168  * ATK_TEXT_BOUNDARY_LINE_END
169  *
170  * Returns: the text after @offset up to the specified @boundary_type.
171  **/
172 gchar*
173 atk_text_get_text_after_offset (AtkText          *text,
174                                 gint             offset,
175                                 AtkTextBoundary  boundary_type,
176                                 gint             *startOffset,
177                                 gint             *endOffset)
178 {
179   AtkTextIface *iface;
180
181   g_return_val_if_fail (text != NULL, NULL);
182   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
183
184   iface = ATK_TEXT_GET_IFACE (text);
185
186   if (iface->get_text_after_offset)
187     return (*(iface->get_text_after_offset)) (text, offset, boundary_type, startOffset, endOffset);
188   else
189     return NULL;
190 }
191
192 /**
193  * atk_text_get_text_at_offset:
194  * @text: an #AtkText
195  * @offset: position
196  * @boundary_type: An #AtkTextBoundary
197  * @startOffset: the start offset of the returned string.
198  * @endOffset: the end offset of the returned string.
199  *
200  * Gets the specified text.
201  * If the boundary_type is ATK_TEXT_BOUNDARY_WORD_START or 
202  * ATK_TEXT_BOUNDARY_WORD_END a complete word is returned; 
203  * if the boundary type is  ATK_TEXT_BOUNDARY_SENTENCE_START or 
204  * ATK_TEXT_BOUNDARY_SENTENCE_END a complete sentence
205  * is returned; if the boundary type is ATK_TEXT_BOUNDARY_LINE_START or
206  * ATK_TEXT_BOUNDARY_LINE_END a complete line is returned.
207  *
208  * Returns: the text at @offset up to the specified @boundary_type.
209  **/
210 gchar*
211 atk_text_get_text_at_offset (AtkText          *text,
212                              gint             offset,
213                              AtkTextBoundary  boundary_type,
214                              gint             *startOffset,
215                              gint             *endOffset)
216 {
217   AtkTextIface *iface;
218
219   g_return_val_if_fail (text != NULL, NULL);
220   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
221
222   iface = ATK_TEXT_GET_IFACE (text);
223
224   if (iface->get_text_at_offset)
225     return (*(iface->get_text_at_offset)) (text, offset, boundary_type, startOffset, endOffset);
226   else
227     return NULL;
228 }
229
230 /**
231  * atk_text_get_text_before_offset:
232  * @text: an #AtkText
233  * @offset: position
234  * @boundary_type: An #AtkTextBoundary
235  * @startOffset: the start offset of the returned string.
236  * @endOffset: the end offset of the returned string.
237  *
238  * Gets the specified text.
239  * If the boundary type is ATK_TEXT_BOUNDARY_WORD_START or
240  * ATK_TEXT_BOUNDARY_WORD_END part of a word may be returned.
241  * If the boundary type is ATK_TEXT_BOUNDARY_SENTENCE_START the start point 
242  * will be at the start of the sentence, and will continue to the offset. 
243  * The last word may not be a complete word. Similarly for 
244  * ATK_TEXT_BOUNDARY_SENTENCE_END, ATK_TEXT_BOUNDARY_LINE_START and
245  * ATK_TEXT_BOUNDARY_LINE_END
246  *
247  * Returns: the text before @offset starting from the specified @boundary_type.
248  **/
249 gchar*
250 atk_text_get_text_before_offset (AtkText          *text,
251                                  gint             offset,
252                                  AtkTextBoundary  boundary_type,
253                                  gint             *startOffset,
254                                  gint             *endOffset)
255 {
256   AtkTextIface *iface;
257
258   g_return_val_if_fail (text != NULL, NULL);
259   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
260
261   iface = ATK_TEXT_GET_IFACE (text);
262
263   if (iface->get_text_before_offset)
264     return (*(iface->get_text_before_offset)) (text, offset, boundary_type, startOffset, endOffset);
265   else
266     return NULL;
267 }
268
269 /**
270  * atk_text_get_caret_offset:
271  * @text: an #AtkText
272  *
273  * Gets the offset position of the caret (cursor).
274  *
275  * Returns: the offset position of the caret (cursor).
276  **/
277 gint
278 atk_text_get_caret_offset (AtkText *text)
279 {
280   AtkTextIface *iface;
281
282   g_return_val_if_fail (text != NULL, -1);
283   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
284
285   iface = ATK_TEXT_GET_IFACE (text);
286
287   if (iface->get_caret_offset)
288     return (*(iface->get_caret_offset)) (text);
289   else
290     return -1;
291 }
292
293 /**
294  * atk_text_get_character_extents:
295  * @text: an #AtkText
296  * @offset: position
297  * @x: x-position of character
298  * @y: y-position of character
299  * @length: length of character
300  * @width: width of character
301  * @coords: specify whether coordinates are relative to the screen or widget window 
302  *
303  * Given an @offset, the @x, @y, @length, and @width values are filled
304  * appropriately. 
305  **/
306 void
307 atk_text_get_character_extents (AtkText *text,
308                                 gint offset,
309                                 gint *x,
310                                 gint *y,
311                                 gint *length,
312                                 gint *width,
313                                 AtkCoordType coords)
314 {
315   AtkTextIface *iface;
316
317   g_return_if_fail (text != NULL);
318   g_return_if_fail (ATK_IS_TEXT (text));
319
320   iface = ATK_TEXT_GET_IFACE (text);
321
322   if (iface->get_character_extents)
323     (*(iface->get_character_extents)) (text, offset, x, y, length, width, coords);
324   else
325     {
326       *x = 0;
327       *x = 0;
328       *length = 0;
329       *width = 0;
330     }
331 }
332
333 /**
334  *atk_text_ref_run_attributes:
335  *@text: an #AtkText
336  *@offset: the offset at which to get the attributes
337  *@start_offset: the address to put the start offset of the range
338  *@end_offset: the address to put the end offset of the range
339  *
340  *Creates an #AtkAttributeSet which consists of the attributes explicitly
341  *set at the position @offset in the text. @start_offset and @end_offset are
342  *set to the start and end of the range around @offset where the attributes are
343  *invariant. See the ATK_ATTRIBUTE macros, such as #ATK_ATTRIBUTE_LEFT_MARGIN
344  *for types of text attributes that can be returned. Note that other 
345  *attributes that do not have corresponding macros may also be returned.
346  *
347  *Returns: an #AtkAttributeSet which contains the attributes explicitly set
348  *at @offset
349  **/
350 AtkAttributeSet* atk_text_ref_run_attributes              (AtkText          *text,
351                                                            gint             offset,
352                                                            gint             *start_offset,
353                                                            gint             *end_offset)
354 {
355   AtkTextIface *iface;
356
357   g_return_val_if_fail (text != NULL, NULL);
358   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
359
360   iface = ATK_TEXT_GET_IFACE (text);
361
362   if (iface->ref_run_attributes)
363     return (*(iface->ref_run_attributes)) (text, offset, start_offset, end_offset);
364   else
365     return NULL;
366 }
367
368 /**
369  * atk_text_get_character_count:
370  * @text: an #AtkText
371  *
372  * Gets the character count.
373  *
374  * Returns: the number of characters.
375  **/
376 gint
377 atk_text_get_character_count (AtkText *text)
378 {
379   AtkTextIface *iface;
380
381   g_return_val_if_fail (text != NULL, -1);
382   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
383
384   iface = ATK_TEXT_GET_IFACE (text);
385
386   if (iface->get_character_count)
387     return (*(iface->get_character_count)) (text);
388   else
389     return -1;
390 }
391
392 /**
393  * atk_text_get_offset_at_point:
394  * @text: an #AtkText
395  * @x: screen x-position of character
396  * @y: screen y-position of character
397  * @coords: specify whether coordinates are relative to the screen or
398  * widget window 
399  *
400  * Gets the offset of the character located at coordinates @x and @y. @x and @y
401  * are interpreted as being relative to the screen or this widget's window
402  * depending on @coords.
403  *
404  * Returns: the offset to the character which is located at
405  * the specified @x and @y coordinates.
406  **/
407 gint
408 atk_text_get_offset_at_point (AtkText *text,
409                               gint x,
410                               gint y,
411                               AtkCoordType coords)
412 {
413   AtkTextIface *iface;
414
415   g_return_val_if_fail (text != NULL, -1);
416   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
417
418   iface = ATK_TEXT_GET_IFACE (text);
419
420   if (iface->get_offset_at_point)
421     return (*(iface->get_offset_at_point)) (text, x, y, coords);
422   else
423     return -1;
424 }
425
426 /**
427  * atk_text_get_n_selections:
428  * @text: an #AtkText
429  *
430  * Gets the number of selected regions.
431  *
432  * Returns: The number of selected regions, or -1 if a failure
433  *   occurred.
434  **/
435 gint
436 atk_text_get_n_selections (AtkText *text)
437 {
438   AtkTextIface *iface;
439
440   g_return_val_if_fail (text != NULL, -1);
441   g_return_val_if_fail (ATK_IS_TEXT (text), -1);
442
443   iface = ATK_TEXT_GET_IFACE (text);
444
445   if (iface->get_n_selections)
446     return (*(iface->get_n_selections)) (text);
447   else
448     return -1;
449 }
450
451 /**
452  * atk_text_get_selection:
453  * @text: an #AtkText
454  * @selection_num: The selection number.  The selected regions are
455  * assigned numbers that correspond to how far the region is from the
456  * start of the text.  The selected region closest to the beginning
457  * of the text region is assigned the number 0, etc.  Note that adding,
458  * moving or deleting a selected region can change the numbering.
459  * @start_offset: passes back the start position of the selected region
460  * @end_offset: passes back the end position of the selected region
461  *
462  * Gets the text from the specified selection.
463  *
464  * Returns: the selected text.
465  **/
466 gchar*
467 atk_text_get_selection (AtkText *text, gint selection_num,
468    gint *start_offset, gint *end_offset)
469 {
470   AtkTextIface *iface;
471
472   g_return_val_if_fail (text != NULL, NULL);
473   g_return_val_if_fail (ATK_IS_TEXT (text), NULL);
474
475   iface = ATK_TEXT_GET_IFACE (text);
476
477   if (iface->get_selection)
478   {
479     return (*(iface->get_selection)) (text, selection_num,
480        start_offset, end_offset);
481   }
482   else
483     return NULL;
484 }
485
486 /**
487  * atk_text_add_selection:
488  * @text: an #AtkText
489  * @start_offset: the start position of the selected region
490  * @end_offset: the end position of the selected region
491  *
492  * Adds a selection bounded by the specified offsets.
493  *
494  * Returns: %TRUE if success, %FALSE otherwise
495  **/
496 gboolean
497 atk_text_add_selection (AtkText *text, gint start_offset,
498    gint end_offset)
499 {
500   AtkTextIface *iface;
501
502   g_return_val_if_fail (text != NULL, FALSE);
503   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
504
505   iface = ATK_TEXT_GET_IFACE (text);
506
507   if (iface->add_selection)
508     return (*(iface->add_selection)) (text, start_offset, end_offset);
509   else
510     return FALSE;
511 }
512
513 /**
514  * atk_text_remove_selection:
515  * @text: an #AtkText
516  * @selection_num: The selection number.  The selected regions are
517  * assigned numbers that correspond to how far the region is from the
518  * start of the text.  The selected region closest to the beginning
519  * of the text region is assigned the number 0, etc.  Note that adding,
520  * moving or deleting a selected region can change the numbering.
521  *
522  * Removes the specified selection.
523  *
524  * Returns: %TRUE if success, %FALSE otherwise
525  **/
526 gboolean
527 atk_text_remove_selection (AtkText *text, gint selection_num)
528 {
529   AtkTextIface *iface;
530
531   g_return_val_if_fail (text != NULL, FALSE);
532   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
533
534   iface = ATK_TEXT_GET_IFACE (text);
535
536   if (iface->remove_selection)
537     return (*(iface->remove_selection)) (text, selection_num);
538   else
539     return FALSE;
540 }
541
542 /**
543  * atk_text_set_selection:
544  * @text: an #AtkText
545  * @selection_num: The selection number.  The selected regions are
546  * assigned numbers that correspond to how far the region is from the
547  * start of the text.  The selected region closest to the beginning
548  * of the text region is assigned the number 0, etc.  Note that adding,
549  * moving or deleting a selected region can change the numbering.
550  * @start_offset: the new start position of the selection
551  * @end_offset: the new end position of the selection
552  *
553  * Changes the start and end offset of the specified selection.
554  *
555  * Returns: %TRUE if success, %FALSE otherwise
556  **/
557 gboolean
558 atk_text_set_selection (AtkText *text, gint selection_num,
559    gint start_offset, gint end_offset)
560 {
561   AtkTextIface *iface;
562
563   g_return_val_if_fail (text != NULL, FALSE);
564   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
565
566   iface = ATK_TEXT_GET_IFACE (text);
567
568   if (iface->set_selection)
569   {
570     return (*(iface->set_selection)) (text, selection_num,
571        start_offset, end_offset);
572   }
573   else
574     return FALSE;
575 }
576
577 /**
578  * atk_text_set_caret_offset:
579  * @text: an #AtkText
580  * @offset: position
581  *
582  * Sets the caret (cursor) position to the specified @offset.
583  *
584  * Returns: %TRUE if success, %FALSE otherwise.
585  **/
586 gboolean
587 atk_text_set_caret_offset (AtkText *text,
588                            gint    offset)
589 {
590   AtkTextIface *iface;
591
592   g_return_val_if_fail (text != NULL, FALSE);
593   g_return_val_if_fail (ATK_IS_TEXT (text), FALSE);
594
595   iface = ATK_TEXT_GET_IFACE (text);
596
597   if (iface->set_caret_offset)
598     {
599       return (*(iface->set_caret_offset)) (text, offset);
600     }
601   else
602     {
603       return FALSE;
604     }
605 }
606
607 /**
608  * AtkAttributeSet_free:
609  * @attrib_set: The #AtkAttributeSet to free
610  *
611  * Frees the memory used by an #AtkAttributeSet, including all its
612  * #AtkAttributes.
613  **/
614 void
615 AtkAttributeSet_free(AtkAttributeSet *attrib_set)
616 {
617   gint index;
618
619   if (attrib_set == NULL)
620     return;
621
622   for (index = 0; index < g_slist_length(attrib_set); index++)
623   {
624     g_free(((AtkAttribute*) (g_slist_nth(attrib_set,index)->data))->name);
625     g_free(((AtkAttribute*) (g_slist_nth(attrib_set,index)->data))->value);
626   }
627   g_slist_free(attrib_set);
628 }