xref: /aoo42x/main/vcl/unx/gtk/a11y/atktext.cxx (revision 9f62ea84)
1*9f62ea84SAndrew Rist /**************************************************************
2*9f62ea84SAndrew Rist  *
3*9f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*9f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*9f62ea84SAndrew Rist  * distributed with this work for additional information
6*9f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*9f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*9f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
9*9f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*9f62ea84SAndrew Rist  *
11*9f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*9f62ea84SAndrew Rist  *
13*9f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*9f62ea84SAndrew Rist  * software distributed under the License is distributed on an
15*9f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*9f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
17*9f62ea84SAndrew Rist  * specific language governing permissions and limitations
18*9f62ea84SAndrew Rist  * under the License.
19*9f62ea84SAndrew Rist  *
20*9f62ea84SAndrew Rist  *************************************************************/
21*9f62ea84SAndrew Rist 
22*9f62ea84SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_vcl.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include "atkwrapper.hxx"
28cdf0e10cSrcweir #include "atktextattributes.hxx"
29cdf0e10cSrcweir #include <algorithm>
30cdf0e10cSrcweir 
31cdf0e10cSrcweir #include <com/sun/star/accessibility/AccessibleTextType.hpp>
32cdf0e10cSrcweir #include <com/sun/star/accessibility/TextSegment.hpp>
33cdf0e10cSrcweir #include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp>
34cdf0e10cSrcweir #include <com/sun/star/accessibility/XAccessibleText.hpp>
35cdf0e10cSrcweir #include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
36cdf0e10cSrcweir #include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp>
37cdf0e10cSrcweir #include <com/sun/star/text/TextMarkupType.hpp>
38cdf0e10cSrcweir 
39cdf0e10cSrcweir // #define ENABLE_TRACING
40cdf0e10cSrcweir 
41cdf0e10cSrcweir #ifdef ENABLE_TRACING
42cdf0e10cSrcweir #include <stdio.h>
43cdf0e10cSrcweir #endif
44cdf0e10cSrcweir 
45cdf0e10cSrcweir using namespace ::com::sun::star;
46cdf0e10cSrcweir 
47cdf0e10cSrcweir static sal_Int16
text_type_from_boundary(AtkTextBoundary boundary_type)48cdf0e10cSrcweir text_type_from_boundary(AtkTextBoundary boundary_type)
49cdf0e10cSrcweir {
50cdf0e10cSrcweir     switch(boundary_type)
51cdf0e10cSrcweir     {
52cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_CHAR:
53cdf0e10cSrcweir             return accessibility::AccessibleTextType::CHARACTER;
54cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_WORD_START:
55cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_WORD_END:
56cdf0e10cSrcweir             return accessibility::AccessibleTextType::WORD;
57cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_SENTENCE_START:
58cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_SENTENCE_END:
59cdf0e10cSrcweir             return accessibility::AccessibleTextType::SENTENCE;
60cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_LINE_START:
61cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_LINE_END:
62cdf0e10cSrcweir             return accessibility::AccessibleTextType::LINE;
63cdf0e10cSrcweir         default:
64cdf0e10cSrcweir             return -1;
65cdf0e10cSrcweir     }
66cdf0e10cSrcweir }
67cdf0e10cSrcweir 
68cdf0e10cSrcweir /*****************************************************************************/
69cdf0e10cSrcweir 
70cdf0e10cSrcweir static gchar *
adjust_boundaries(accessibility::XAccessibleText * pText,accessibility::TextSegment & rTextSegment,AtkTextBoundary boundary_type,gint * start_offset,gint * end_offset)71cdf0e10cSrcweir adjust_boundaries( accessibility::XAccessibleText* pText,
72cdf0e10cSrcweir                    accessibility::TextSegment& rTextSegment,
73cdf0e10cSrcweir                    AtkTextBoundary  boundary_type,
74cdf0e10cSrcweir                    gint * start_offset, gint * end_offset )
75cdf0e10cSrcweir {
76cdf0e10cSrcweir     accessibility::TextSegment aTextSegment;
77cdf0e10cSrcweir     rtl::OUString aString;
78cdf0e10cSrcweir     gint start = 0, end = 0;
79cdf0e10cSrcweir 
80cdf0e10cSrcweir     if( rTextSegment.SegmentText.getLength() > 0 )
81cdf0e10cSrcweir     {
82cdf0e10cSrcweir         switch(boundary_type)
83cdf0e10cSrcweir         {
84cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_CHAR:
85cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_LINE_START:
86cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_LINE_END:
87cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_SENTENCE_START:
88cdf0e10cSrcweir             start = rTextSegment.SegmentStart;
89cdf0e10cSrcweir             end = rTextSegment.SegmentEnd;
90cdf0e10cSrcweir             aString = rTextSegment.SegmentText;
91cdf0e10cSrcweir             break;
92cdf0e10cSrcweir 
93cdf0e10cSrcweir         // the OOo break iterator behaves as SENTENCE_START
94cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_SENTENCE_END:
95cdf0e10cSrcweir             start = rTextSegment.SegmentStart;
96cdf0e10cSrcweir             end = rTextSegment.SegmentEnd;
97cdf0e10cSrcweir 
98cdf0e10cSrcweir             if( start > 0 )
99cdf0e10cSrcweir                 --start;
100cdf0e10cSrcweir             if( end > 0 && end < pText->getCharacterCount() - 1 )
101cdf0e10cSrcweir                 --end;
102cdf0e10cSrcweir 
103cdf0e10cSrcweir             aString = pText->getTextRange(start, end);
104cdf0e10cSrcweir             break;
105cdf0e10cSrcweir 
106cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_WORD_START:
107cdf0e10cSrcweir             start = rTextSegment.SegmentStart;
108cdf0e10cSrcweir 
109cdf0e10cSrcweir             // Determine the start index of the next segment
110cdf0e10cSrcweir             aTextSegment = pText->getTextBehindIndex(rTextSegment.SegmentEnd,
111cdf0e10cSrcweir                                                      text_type_from_boundary(boundary_type));
112cdf0e10cSrcweir             if( aTextSegment.SegmentText.getLength() > 0 )
113cdf0e10cSrcweir                 end = aTextSegment.SegmentStart;
114cdf0e10cSrcweir             else
115cdf0e10cSrcweir                 end = pText->getCharacterCount();
116cdf0e10cSrcweir 
117cdf0e10cSrcweir             aString = pText->getTextRange(start, end);
118cdf0e10cSrcweir             break;
119cdf0e10cSrcweir 
120cdf0e10cSrcweir         case ATK_TEXT_BOUNDARY_WORD_END:
121cdf0e10cSrcweir             end = rTextSegment.SegmentEnd;
122cdf0e10cSrcweir 
123cdf0e10cSrcweir             // Determine the end index of the previous segment
124cdf0e10cSrcweir             aTextSegment = pText->getTextBeforeIndex(rTextSegment.SegmentStart,
125cdf0e10cSrcweir                                                      text_type_from_boundary(boundary_type));
126cdf0e10cSrcweir             if( aTextSegment.SegmentText.getLength() > 0 )
127cdf0e10cSrcweir                 start = aTextSegment.SegmentEnd;
128cdf0e10cSrcweir             else
129cdf0e10cSrcweir                 start = 0;
130cdf0e10cSrcweir 
131cdf0e10cSrcweir             aString = pText->getTextRange(start, end);
132cdf0e10cSrcweir             break;
133cdf0e10cSrcweir 
134cdf0e10cSrcweir         default:
135cdf0e10cSrcweir             return NULL;
136cdf0e10cSrcweir         }
137cdf0e10cSrcweir     }
138cdf0e10cSrcweir 
139cdf0e10cSrcweir     *start_offset = start;
140cdf0e10cSrcweir     *end_offset   = end;
141cdf0e10cSrcweir 
142cdf0e10cSrcweir #ifdef ENABLE_TRACING
143cdf0e10cSrcweir     fprintf(stderr, "adjust_boundaries( %d, %d, %d ) returns %d, %d\n",
144cdf0e10cSrcweir         rTextSegment.SegmentStart, rTextSegment.SegmentEnd, boundary_type,
145cdf0e10cSrcweir         start, end);
146cdf0e10cSrcweir #endif
147cdf0e10cSrcweir 
148cdf0e10cSrcweir     return OUStringToGChar(aString);
149cdf0e10cSrcweir }
150cdf0e10cSrcweir 
151cdf0e10cSrcweir /*****************************************************************************/
152cdf0e10cSrcweir 
153cdf0e10cSrcweir static accessibility::XAccessibleText*
getText(AtkText * pText)154cdf0e10cSrcweir     getText( AtkText *pText ) throw (uno::RuntimeException)
155cdf0e10cSrcweir {
156cdf0e10cSrcweir     AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
157cdf0e10cSrcweir     if( pWrap )
158cdf0e10cSrcweir     {
159cdf0e10cSrcweir         if( !pWrap->mpText && pWrap->mpContext )
160cdf0e10cSrcweir         {
161cdf0e10cSrcweir             uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleText::static_type(NULL) );
162cdf0e10cSrcweir             pWrap->mpText = reinterpret_cast< accessibility::XAccessibleText * > (any.pReserved);
163cdf0e10cSrcweir             pWrap->mpText->acquire();
164cdf0e10cSrcweir         }
165cdf0e10cSrcweir 
166cdf0e10cSrcweir         return pWrap->mpText;
167cdf0e10cSrcweir     }
168cdf0e10cSrcweir 
169cdf0e10cSrcweir     return NULL;
170cdf0e10cSrcweir }
171cdf0e10cSrcweir 
172cdf0e10cSrcweir /*****************************************************************************/
173cdf0e10cSrcweir 
174cdf0e10cSrcweir static accessibility::XAccessibleTextMarkup*
getTextMarkup(AtkText * pText)175cdf0e10cSrcweir     getTextMarkup( AtkText *pText ) throw (uno::RuntimeException)
176cdf0e10cSrcweir {
177cdf0e10cSrcweir     AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
178cdf0e10cSrcweir     if( pWrap )
179cdf0e10cSrcweir     {
180cdf0e10cSrcweir         if( !pWrap->mpTextMarkup && pWrap->mpContext )
181cdf0e10cSrcweir         {
182cdf0e10cSrcweir             uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextMarkup::static_type(NULL) );
183cdf0e10cSrcweir             /* Since this not a dedicated interface in Atk and thus has not
184cdf0e10cSrcweir              * been queried during wrapper initialization, we need to check
185cdf0e10cSrcweir              * the return value here.
186cdf0e10cSrcweir              */
187cdf0e10cSrcweir             if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
188cdf0e10cSrcweir             {
189cdf0e10cSrcweir 				pWrap->mpTextMarkup = reinterpret_cast< accessibility::XAccessibleTextMarkup * > (any.pReserved);
190cdf0e10cSrcweir 				if( pWrap->mpTextMarkup )
191cdf0e10cSrcweir 					pWrap->mpTextMarkup->acquire();
192cdf0e10cSrcweir 			}
193cdf0e10cSrcweir         }
194cdf0e10cSrcweir 
195cdf0e10cSrcweir         return pWrap->mpTextMarkup;
196cdf0e10cSrcweir     }
197cdf0e10cSrcweir 
198cdf0e10cSrcweir     return NULL;
199cdf0e10cSrcweir }
200cdf0e10cSrcweir 
201cdf0e10cSrcweir /*****************************************************************************/
202cdf0e10cSrcweir 
203cdf0e10cSrcweir static accessibility::XAccessibleTextAttributes*
getTextAttributes(AtkText * pText)204cdf0e10cSrcweir     getTextAttributes( AtkText *pText ) throw (uno::RuntimeException)
205cdf0e10cSrcweir {
206cdf0e10cSrcweir     AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
207cdf0e10cSrcweir     if( pWrap )
208cdf0e10cSrcweir     {
209cdf0e10cSrcweir         if( !pWrap->mpTextAttributes && pWrap->mpContext )
210cdf0e10cSrcweir         {
211cdf0e10cSrcweir             uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextAttributes::static_type(NULL) );
212cdf0e10cSrcweir             /* Since this not a dedicated interface in Atk and thus has not
213cdf0e10cSrcweir              * been queried during wrapper initialization, we need to check
214cdf0e10cSrcweir              * the return value here.
215cdf0e10cSrcweir              */
216cdf0e10cSrcweir             if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
217cdf0e10cSrcweir             {
218cdf0e10cSrcweir                 pWrap->mpTextAttributes = reinterpret_cast< accessibility::XAccessibleTextAttributes * > (any.pReserved);
219cdf0e10cSrcweir                 pWrap->mpTextAttributes->acquire();
220cdf0e10cSrcweir             }
221cdf0e10cSrcweir         }
222cdf0e10cSrcweir 
223cdf0e10cSrcweir         return pWrap->mpTextAttributes;
224cdf0e10cSrcweir     }
225cdf0e10cSrcweir 
226cdf0e10cSrcweir     return NULL;
227cdf0e10cSrcweir }
228cdf0e10cSrcweir 
229cdf0e10cSrcweir /*****************************************************************************/
230cdf0e10cSrcweir 
231cdf0e10cSrcweir static accessibility::XAccessibleMultiLineText*
getMultiLineText(AtkText * pText)232cdf0e10cSrcweir     getMultiLineText( AtkText *pText ) throw (uno::RuntimeException)
233cdf0e10cSrcweir {
234cdf0e10cSrcweir     AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
235cdf0e10cSrcweir     if( pWrap )
236cdf0e10cSrcweir     {
237cdf0e10cSrcweir         if( !pWrap->mpMultiLineText && pWrap->mpContext )
238cdf0e10cSrcweir         {
239cdf0e10cSrcweir             uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleMultiLineText::static_type(NULL) );
240cdf0e10cSrcweir             /* Since this not a dedicated interface in Atk and thus has not
241cdf0e10cSrcweir              * been queried during wrapper initialization, we need to check
242cdf0e10cSrcweir              * the return value here.
243cdf0e10cSrcweir              */
244cdf0e10cSrcweir             if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
245cdf0e10cSrcweir             {
246cdf0e10cSrcweir                 pWrap->mpMultiLineText = reinterpret_cast< accessibility::XAccessibleMultiLineText * > (any.pReserved);
247cdf0e10cSrcweir                 pWrap->mpMultiLineText->acquire();
248cdf0e10cSrcweir             }
249cdf0e10cSrcweir         }
250cdf0e10cSrcweir 
251cdf0e10cSrcweir         return pWrap->mpMultiLineText;
252cdf0e10cSrcweir     }
253cdf0e10cSrcweir 
254cdf0e10cSrcweir     return NULL;
255cdf0e10cSrcweir }
256cdf0e10cSrcweir 
257cdf0e10cSrcweir /*****************************************************************************/
258cdf0e10cSrcweir 
259cdf0e10cSrcweir extern "C" {
260cdf0e10cSrcweir 
261cdf0e10cSrcweir static gchar *
text_wrapper_get_text(AtkText * text,gint start_offset,gint end_offset)262cdf0e10cSrcweir text_wrapper_get_text (AtkText *text,
263cdf0e10cSrcweir                        gint     start_offset,
264cdf0e10cSrcweir                        gint     end_offset)
265cdf0e10cSrcweir {
266cdf0e10cSrcweir     gchar * ret = NULL;
267cdf0e10cSrcweir 
268cdf0e10cSrcweir     g_return_val_if_fail( (end_offset == -1) || (end_offset >= start_offset), NULL );
269cdf0e10cSrcweir 
270cdf0e10cSrcweir     /* at-spi expects the delete event to be send before the deletion happened
271cdf0e10cSrcweir      * so we save the deleted string object in the UNO event notification and
272cdf0e10cSrcweir      * fool libatk-bridge.so here ..
273cdf0e10cSrcweir      */
274cdf0e10cSrcweir     void * pData = g_object_get_data( G_OBJECT(text), "ooo::text_changed::delete" );
275cdf0e10cSrcweir     if( pData != NULL )
276cdf0e10cSrcweir     {
277cdf0e10cSrcweir         accessibility::TextSegment * pTextSegment =
278cdf0e10cSrcweir             reinterpret_cast <accessibility::TextSegment *> (pData);
279cdf0e10cSrcweir 
280cdf0e10cSrcweir         if( pTextSegment->SegmentStart == start_offset &&
281cdf0e10cSrcweir             pTextSegment->SegmentEnd == end_offset )
282cdf0e10cSrcweir         {
283cdf0e10cSrcweir             rtl::OString aUtf8 = rtl::OUStringToOString( pTextSegment->SegmentText, RTL_TEXTENCODING_UTF8 );
284cdf0e10cSrcweir             return g_strdup( aUtf8.getStr() );
285cdf0e10cSrcweir         }
286cdf0e10cSrcweir     }
287cdf0e10cSrcweir 
288cdf0e10cSrcweir     try {
289cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
290cdf0e10cSrcweir         if( pText )
291cdf0e10cSrcweir         {
292cdf0e10cSrcweir             rtl::OUString aText;
293cdf0e10cSrcweir             sal_Int32 n = pText->getCharacterCount();
294cdf0e10cSrcweir 
295cdf0e10cSrcweir             if( -1 == end_offset )
296cdf0e10cSrcweir                 aText = pText->getText();
297cdf0e10cSrcweir             else if( start_offset < n )
298cdf0e10cSrcweir                 aText = pText->getTextRange(start_offset, end_offset);
299cdf0e10cSrcweir 
300cdf0e10cSrcweir             ret = g_strdup( rtl::OUStringToOString(aText, RTL_TEXTENCODING_UTF8 ).getStr() );
301cdf0e10cSrcweir         }
302cdf0e10cSrcweir     }
303cdf0e10cSrcweir     catch(const uno::Exception& e) {
304cdf0e10cSrcweir         g_warning( "Exception in getText()" );
305cdf0e10cSrcweir     }
306cdf0e10cSrcweir 
307cdf0e10cSrcweir #ifdef ENABLE_TRACING
308cdf0e10cSrcweir     fprintf(stderr, "text_wrapper_get_text( %d,%d ) returns %s\n", start_offset, end_offset, ret ? ret : "null" );
309cdf0e10cSrcweir #endif
310cdf0e10cSrcweir     return ret;
311cdf0e10cSrcweir }
312cdf0e10cSrcweir 
313cdf0e10cSrcweir static gchar *
text_wrapper_get_text_after_offset(AtkText * text,gint offset,AtkTextBoundary boundary_type,gint * start_offset,gint * end_offset)314cdf0e10cSrcweir text_wrapper_get_text_after_offset (AtkText          *text,
315cdf0e10cSrcweir                                     gint             offset,
316cdf0e10cSrcweir                                     AtkTextBoundary  boundary_type,
317cdf0e10cSrcweir                                     gint             *start_offset,
318cdf0e10cSrcweir                                     gint             *end_offset)
319cdf0e10cSrcweir {
320cdf0e10cSrcweir     try {
321cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
322cdf0e10cSrcweir         if( pText )
323cdf0e10cSrcweir         {
324cdf0e10cSrcweir             accessibility::TextSegment aTextSegment = pText->getTextBehindIndex(offset, text_type_from_boundary(boundary_type));
325cdf0e10cSrcweir             return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
326cdf0e10cSrcweir         }
327cdf0e10cSrcweir     }
328cdf0e10cSrcweir     catch(const uno::Exception& e) {
329cdf0e10cSrcweir         g_warning( "Exception in get_text_after_offset()" );
330cdf0e10cSrcweir     }
331cdf0e10cSrcweir 
332cdf0e10cSrcweir     return NULL;
333cdf0e10cSrcweir }
334cdf0e10cSrcweir 
335cdf0e10cSrcweir static gchar *
text_wrapper_get_text_at_offset(AtkText * text,gint offset,AtkTextBoundary boundary_type,gint * start_offset,gint * end_offset)336cdf0e10cSrcweir text_wrapper_get_text_at_offset (AtkText          *text,
337cdf0e10cSrcweir                                  gint             offset,
338cdf0e10cSrcweir                                  AtkTextBoundary  boundary_type,
339cdf0e10cSrcweir                                  gint             *start_offset,
340cdf0e10cSrcweir                                  gint             *end_offset)
341cdf0e10cSrcweir {
342cdf0e10cSrcweir     try {
343cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
344cdf0e10cSrcweir         if( pText )
345cdf0e10cSrcweir         {
346cdf0e10cSrcweir             /* If the user presses the 'End' key, the caret will be placed behind the last character,
347cdf0e10cSrcweir              * which is the same index as the first character of the next line. In atk the magic offset
348cdf0e10cSrcweir              * '-2' is used to cover this special case.
349cdf0e10cSrcweir              */
350cdf0e10cSrcweir             if (
351cdf0e10cSrcweir                  -2 == offset &&
352cdf0e10cSrcweir                      (ATK_TEXT_BOUNDARY_LINE_START == boundary_type ||
353cdf0e10cSrcweir                       ATK_TEXT_BOUNDARY_LINE_END == boundary_type)
354cdf0e10cSrcweir                )
355cdf0e10cSrcweir             {
356cdf0e10cSrcweir                 accessibility::XAccessibleMultiLineText* pMultiLineText = getMultiLineText( text );
357cdf0e10cSrcweir                 if( pMultiLineText )
358cdf0e10cSrcweir                 {
359cdf0e10cSrcweir                     accessibility::TextSegment aTextSegment = pMultiLineText->getTextAtLineWithCaret();
360cdf0e10cSrcweir                     return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
361cdf0e10cSrcweir                 }
362cdf0e10cSrcweir             }
363cdf0e10cSrcweir 
364cdf0e10cSrcweir             accessibility::TextSegment aTextSegment = pText->getTextAtIndex(offset, text_type_from_boundary(boundary_type));
365cdf0e10cSrcweir             return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
366cdf0e10cSrcweir         }
367cdf0e10cSrcweir     }
368cdf0e10cSrcweir     catch(const uno::Exception& e) {
369cdf0e10cSrcweir         g_warning( "Exception in get_text_at_offset()" );
370cdf0e10cSrcweir     }
371cdf0e10cSrcweir 
372cdf0e10cSrcweir     return NULL;
373cdf0e10cSrcweir }
374cdf0e10cSrcweir 
375cdf0e10cSrcweir static gunichar
text_wrapper_get_character_at_offset(AtkText * text,gint offset)376cdf0e10cSrcweir text_wrapper_get_character_at_offset (AtkText          *text,
377cdf0e10cSrcweir                                       gint             offset)
378cdf0e10cSrcweir {
379cdf0e10cSrcweir     gint start, end;
380cdf0e10cSrcweir     gunichar uc = 0;
381cdf0e10cSrcweir 
382cdf0e10cSrcweir     gchar * char_as_string =
383cdf0e10cSrcweir         text_wrapper_get_text_at_offset(text, offset, ATK_TEXT_BOUNDARY_CHAR,
384cdf0e10cSrcweir                                         &start, &end);
385cdf0e10cSrcweir     if( char_as_string )
386cdf0e10cSrcweir     {
387cdf0e10cSrcweir         uc = g_utf8_get_char( char_as_string );
388cdf0e10cSrcweir         g_free( char_as_string );
389cdf0e10cSrcweir     }
390cdf0e10cSrcweir 
391cdf0e10cSrcweir     return uc;
392cdf0e10cSrcweir }
393cdf0e10cSrcweir 
394cdf0e10cSrcweir static gchar *
text_wrapper_get_text_before_offset(AtkText * text,gint offset,AtkTextBoundary boundary_type,gint * start_offset,gint * end_offset)395cdf0e10cSrcweir text_wrapper_get_text_before_offset (AtkText          *text,
396cdf0e10cSrcweir                                      gint             offset,
397cdf0e10cSrcweir                                      AtkTextBoundary  boundary_type,
398cdf0e10cSrcweir                                      gint             *start_offset,
399cdf0e10cSrcweir                                      gint             *end_offset)
400cdf0e10cSrcweir {
401cdf0e10cSrcweir     try {
402cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
403cdf0e10cSrcweir         if( pText )
404cdf0e10cSrcweir         {
405cdf0e10cSrcweir             accessibility::TextSegment aTextSegment = pText->getTextBeforeIndex(offset, text_type_from_boundary(boundary_type));
406cdf0e10cSrcweir             return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
407cdf0e10cSrcweir         }
408cdf0e10cSrcweir     }
409cdf0e10cSrcweir     catch(const uno::Exception& e) {
410cdf0e10cSrcweir         g_warning( "Exception in text_before_offset()" );
411cdf0e10cSrcweir     }
412cdf0e10cSrcweir 
413cdf0e10cSrcweir     return NULL;
414cdf0e10cSrcweir }
415cdf0e10cSrcweir 
416cdf0e10cSrcweir static gint
text_wrapper_get_caret_offset(AtkText * text)417cdf0e10cSrcweir text_wrapper_get_caret_offset (AtkText          *text)
418cdf0e10cSrcweir {
419cdf0e10cSrcweir     gint offset = -1;
420cdf0e10cSrcweir 
421cdf0e10cSrcweir     try {
422cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
423cdf0e10cSrcweir         if( pText )
424cdf0e10cSrcweir             offset = pText->getCaretPosition();
425cdf0e10cSrcweir     }
426cdf0e10cSrcweir     catch(const uno::Exception& e) {
427cdf0e10cSrcweir         g_warning( "Exception in getCaretPosition()" );
428cdf0e10cSrcweir     }
429cdf0e10cSrcweir 
430cdf0e10cSrcweir #ifdef ENABLE_TRACING
431cdf0e10cSrcweir     fprintf(stderr, "get_caret_offset(%p) returns %d\n", text, offset);
432cdf0e10cSrcweir #endif
433cdf0e10cSrcweir 
434cdf0e10cSrcweir     return offset;
435cdf0e10cSrcweir }
436cdf0e10cSrcweir 
437cdf0e10cSrcweir static gboolean
text_wrapper_set_caret_offset(AtkText * text,gint offset)438cdf0e10cSrcweir text_wrapper_set_caret_offset (AtkText *text,
439cdf0e10cSrcweir                                gint     offset)
440cdf0e10cSrcweir {
441cdf0e10cSrcweir     try {
442cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
443cdf0e10cSrcweir         if( pText )
444cdf0e10cSrcweir             return pText->setCaretPosition( offset );
445cdf0e10cSrcweir     }
446cdf0e10cSrcweir     catch(const uno::Exception& e) {
447cdf0e10cSrcweir         g_warning( "Exception in setCaretPosition()" );
448cdf0e10cSrcweir     }
449cdf0e10cSrcweir 
450cdf0e10cSrcweir     return FALSE;
451cdf0e10cSrcweir }
452cdf0e10cSrcweir 
453cdf0e10cSrcweir // --> OD 2010-03-04 #i92232#
454cdf0e10cSrcweir AtkAttributeSet*
handle_text_markup_as_run_attribute(accessibility::XAccessibleTextMarkup * pTextMarkup,const gint nTextMarkupType,const gint offset,AtkAttributeSet * pSet,gint * start_offset,gint * end_offset)455cdf0e10cSrcweir handle_text_markup_as_run_attribute( accessibility::XAccessibleTextMarkup* pTextMarkup,
456cdf0e10cSrcweir                                      const gint nTextMarkupType,
457cdf0e10cSrcweir                                      const gint offset,
458cdf0e10cSrcweir                                      AtkAttributeSet* pSet,
459cdf0e10cSrcweir                                      gint *start_offset,
460cdf0e10cSrcweir                                      gint *end_offset )
461cdf0e10cSrcweir {
462cdf0e10cSrcweir     const gint nTextMarkupCount( pTextMarkup->getTextMarkupCount( nTextMarkupType ) );
463cdf0e10cSrcweir     if ( nTextMarkupCount > 0 )
464cdf0e10cSrcweir     {
465cdf0e10cSrcweir         for ( gint nTextMarkupIndex = 0;
466cdf0e10cSrcweir               nTextMarkupIndex < nTextMarkupCount;
467cdf0e10cSrcweir               ++nTextMarkupIndex )
468cdf0e10cSrcweir         {
469cdf0e10cSrcweir             accessibility::TextSegment aTextSegment =
470cdf0e10cSrcweir                 pTextMarkup->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
471cdf0e10cSrcweir             const gint nStartOffsetTextMarkup = aTextSegment.SegmentStart;
472cdf0e10cSrcweir             const gint nEndOffsetTextMarkup = aTextSegment.SegmentEnd;
473cdf0e10cSrcweir             if ( nStartOffsetTextMarkup <= offset )
474cdf0e10cSrcweir             {
475cdf0e10cSrcweir                 if ( offset < nEndOffsetTextMarkup )
476cdf0e10cSrcweir                 {
477cdf0e10cSrcweir                     // text markup at <offset>
478cdf0e10cSrcweir                     *start_offset = ::std::max( *start_offset,
479cdf0e10cSrcweir                                                 nStartOffsetTextMarkup );
480cdf0e10cSrcweir                     *end_offset = ::std::min( *end_offset,
481cdf0e10cSrcweir                                               nEndOffsetTextMarkup );
482cdf0e10cSrcweir                     switch ( nTextMarkupType )
483cdf0e10cSrcweir                     {
484cdf0e10cSrcweir                         case com::sun::star::text::TextMarkupType::SPELLCHECK:
485cdf0e10cSrcweir                         {
486cdf0e10cSrcweir                             pSet = attribute_set_prepend_misspelled( pSet );
487cdf0e10cSrcweir                         }
488cdf0e10cSrcweir                         break;
489cdf0e10cSrcweir                         case com::sun::star::text::TextMarkupType::TRACK_CHANGE_INSERTION:
490cdf0e10cSrcweir                         {
491cdf0e10cSrcweir                             pSet = attribute_set_prepend_tracked_change_insertion( pSet );
492cdf0e10cSrcweir                         }
493cdf0e10cSrcweir                         break;
494cdf0e10cSrcweir                         case com::sun::star::text::TextMarkupType::TRACK_CHANGE_DELETION:
495cdf0e10cSrcweir                         {
496cdf0e10cSrcweir                             pSet = attribute_set_prepend_tracked_change_deletion( pSet );
497cdf0e10cSrcweir                         }
498cdf0e10cSrcweir                         break;
499cdf0e10cSrcweir                         case com::sun::star::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
500cdf0e10cSrcweir                         {
501cdf0e10cSrcweir                             pSet = attribute_set_prepend_tracked_change_formatchange( pSet );
502cdf0e10cSrcweir                         }
503cdf0e10cSrcweir                         break;
504cdf0e10cSrcweir                         default:
505cdf0e10cSrcweir                         {
506cdf0e10cSrcweir                             OSL_ASSERT( false );
507cdf0e10cSrcweir                         }
508cdf0e10cSrcweir                     }
509cdf0e10cSrcweir                     break; // no further iteration needed.
510cdf0e10cSrcweir                 }
511cdf0e10cSrcweir                 else
512cdf0e10cSrcweir                 {
513cdf0e10cSrcweir                     *start_offset = ::std::max( *start_offset,
514cdf0e10cSrcweir                                                 nEndOffsetTextMarkup );
515cdf0e10cSrcweir                     // continue iteration.
516cdf0e10cSrcweir                 }
517cdf0e10cSrcweir             }
518cdf0e10cSrcweir             else
519cdf0e10cSrcweir             {
520cdf0e10cSrcweir                 *end_offset = ::std::min( *end_offset,
521cdf0e10cSrcweir                                           nStartOffsetTextMarkup );
522cdf0e10cSrcweir                 break; // no further iteration.
523cdf0e10cSrcweir             }
524cdf0e10cSrcweir         } // eof iteration over text markups
525cdf0e10cSrcweir     }
526cdf0e10cSrcweir 
527cdf0e10cSrcweir     return pSet;
528cdf0e10cSrcweir }
529cdf0e10cSrcweir // <--
530cdf0e10cSrcweir 
531cdf0e10cSrcweir static AtkAttributeSet *
text_wrapper_get_run_attributes(AtkText * text,gint offset,gint * start_offset,gint * end_offset)532cdf0e10cSrcweir text_wrapper_get_run_attributes( AtkText        *text,
533cdf0e10cSrcweir                                  gint           offset,
534cdf0e10cSrcweir                                  gint           *start_offset,
535cdf0e10cSrcweir                                  gint           *end_offset)
536cdf0e10cSrcweir {
537cdf0e10cSrcweir     AtkAttributeSet *pSet = NULL;
538cdf0e10cSrcweir 
539cdf0e10cSrcweir     try {
540cdf0e10cSrcweir         bool bOffsetsAreValid = false;
541cdf0e10cSrcweir 
542cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
543cdf0e10cSrcweir         accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text );
544cdf0e10cSrcweir         if( pText && pTextAttributes )
545cdf0e10cSrcweir         {
546cdf0e10cSrcweir             uno::Sequence< beans::PropertyValue > aAttributeList =
547cdf0e10cSrcweir                 pTextAttributes->getRunAttributes( offset, uno::Sequence< rtl::OUString > () );
548cdf0e10cSrcweir 
549cdf0e10cSrcweir             pSet = attribute_set_new_from_property_values( aAttributeList, true, text );
550cdf0e10cSrcweir             // --> OD 2009-06-22 #i100938#
551cdf0e10cSrcweir             // - always provide start_offset and end_offset
552cdf0e10cSrcweir //            if( pSet )
553cdf0e10cSrcweir             // <--
554cdf0e10cSrcweir             {
555cdf0e10cSrcweir                 accessibility::TextSegment aTextSegment =
556cdf0e10cSrcweir                     pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
557cdf0e10cSrcweir 
558cdf0e10cSrcweir                 *start_offset = aTextSegment.SegmentStart;
559cdf0e10cSrcweir                 // --> OD 2009-06-22 #i100938#
560cdf0e10cSrcweir                 // Do _not_ increment the end_offset provide by <accessibility::TextSegment> instance
561cdf0e10cSrcweir //                *end_offset = aTextSegment.SegmentEnd + 1; // FIXME: TESTME
562cdf0e10cSrcweir                 *end_offset = aTextSegment.SegmentEnd;
563cdf0e10cSrcweir                 // <--
564cdf0e10cSrcweir                 bOffsetsAreValid = true;
565cdf0e10cSrcweir             }
566cdf0e10cSrcweir         }
567cdf0e10cSrcweir 
568cdf0e10cSrcweir         // Special handling for misspelled text
569cdf0e10cSrcweir         // --> OD 2010-03-01 #i92232#
570cdf0e10cSrcweir         // - add special handling for tracked changes and refactor the
571cdf0e10cSrcweir         //   corresponding code for handling misspelled text.
572cdf0e10cSrcweir         accessibility::XAccessibleTextMarkup* pTextMarkup = getTextMarkup( text );
573cdf0e10cSrcweir         if( pTextMarkup )
574cdf0e10cSrcweir         {
575cdf0e10cSrcweir             // Get attribute run here if it hasn't been done before
576cdf0e10cSrcweir             if( !bOffsetsAreValid )
577cdf0e10cSrcweir             {
578cdf0e10cSrcweir                 accessibility::TextSegment aAttributeTextSegment =
579cdf0e10cSrcweir                     pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
580cdf0e10cSrcweir                 *start_offset = aAttributeTextSegment.SegmentStart;
581cdf0e10cSrcweir                 *end_offset = aAttributeTextSegment.SegmentEnd;
582cdf0e10cSrcweir             }
583cdf0e10cSrcweir             // handle misspelled text
584cdf0e10cSrcweir             pSet = handle_text_markup_as_run_attribute(
585cdf0e10cSrcweir                     pTextMarkup,
586cdf0e10cSrcweir                     com::sun::star::text::TextMarkupType::SPELLCHECK,
587cdf0e10cSrcweir                     offset, pSet, start_offset, end_offset );
588cdf0e10cSrcweir             // handle tracked changes
589cdf0e10cSrcweir             pSet = handle_text_markup_as_run_attribute(
590cdf0e10cSrcweir                     pTextMarkup,
591cdf0e10cSrcweir                     com::sun::star::text::TextMarkupType::TRACK_CHANGE_INSERTION,
592cdf0e10cSrcweir                     offset, pSet, start_offset, end_offset );
593cdf0e10cSrcweir             pSet = handle_text_markup_as_run_attribute(
594cdf0e10cSrcweir                     pTextMarkup,
595cdf0e10cSrcweir                     com::sun::star::text::TextMarkupType::TRACK_CHANGE_DELETION,
596cdf0e10cSrcweir                     offset, pSet, start_offset, end_offset );
597cdf0e10cSrcweir             pSet = handle_text_markup_as_run_attribute(
598cdf0e10cSrcweir                     pTextMarkup,
599cdf0e10cSrcweir                     com::sun::star::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE,
600cdf0e10cSrcweir                     offset, pSet, start_offset, end_offset );
601cdf0e10cSrcweir         }
602cdf0e10cSrcweir         // <--
603cdf0e10cSrcweir     }
604cdf0e10cSrcweir     catch(const uno::Exception& e){
605cdf0e10cSrcweir 
606cdf0e10cSrcweir         g_warning( "Exception in get_run_attributes()" );
607cdf0e10cSrcweir 
608cdf0e10cSrcweir         if( pSet )
609cdf0e10cSrcweir         {
610cdf0e10cSrcweir             atk_attribute_set_free( pSet );
611cdf0e10cSrcweir             pSet = NULL;
612cdf0e10cSrcweir         }
613cdf0e10cSrcweir     }
614cdf0e10cSrcweir 
615cdf0e10cSrcweir     return pSet;
616cdf0e10cSrcweir }
617cdf0e10cSrcweir 
618cdf0e10cSrcweir /*****************************************************************************/
619cdf0e10cSrcweir 
620cdf0e10cSrcweir static AtkAttributeSet *
text_wrapper_get_default_attributes(AtkText * text)621cdf0e10cSrcweir text_wrapper_get_default_attributes( AtkText *text )
622cdf0e10cSrcweir {
623cdf0e10cSrcweir     AtkAttributeSet *pSet = NULL;
624cdf0e10cSrcweir 
625cdf0e10cSrcweir     try {
626cdf0e10cSrcweir         accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text );
627cdf0e10cSrcweir         if( pTextAttributes )
628cdf0e10cSrcweir         {
629cdf0e10cSrcweir             uno::Sequence< beans::PropertyValue > aAttributeList =
630cdf0e10cSrcweir                 pTextAttributes->getDefaultAttributes( uno::Sequence< rtl::OUString > () );
631cdf0e10cSrcweir 
632cdf0e10cSrcweir             pSet = attribute_set_new_from_property_values( aAttributeList, false, text );
633cdf0e10cSrcweir         }
634cdf0e10cSrcweir     }
635cdf0e10cSrcweir     catch(const uno::Exception& e) {
636cdf0e10cSrcweir 
637cdf0e10cSrcweir         g_warning( "Exception in get_default_attributes()" );
638cdf0e10cSrcweir 
639cdf0e10cSrcweir         if( pSet )
640cdf0e10cSrcweir         {
641cdf0e10cSrcweir             atk_attribute_set_free( pSet );
642cdf0e10cSrcweir             pSet = NULL;
643cdf0e10cSrcweir         }
644cdf0e10cSrcweir     }
645cdf0e10cSrcweir 
646cdf0e10cSrcweir     return pSet;
647cdf0e10cSrcweir }
648cdf0e10cSrcweir 
649cdf0e10cSrcweir /*****************************************************************************/
650cdf0e10cSrcweir 
651cdf0e10cSrcweir static void
text_wrapper_get_character_extents(AtkText * text,gint offset,gint * x,gint * y,gint * width,gint * height,AtkCoordType coords)652cdf0e10cSrcweir text_wrapper_get_character_extents( AtkText          *text,
653cdf0e10cSrcweir                                     gint             offset,
654cdf0e10cSrcweir                                     gint             *x,
655cdf0e10cSrcweir                                     gint             *y,
656cdf0e10cSrcweir                                     gint             *width,
657cdf0e10cSrcweir                                     gint             *height,
658cdf0e10cSrcweir                                     AtkCoordType      coords )
659cdf0e10cSrcweir {
660cdf0e10cSrcweir     try {
661cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
662cdf0e10cSrcweir         if( pText )
663cdf0e10cSrcweir         {
664cdf0e10cSrcweir             *x = *y = *width = *height = 0;
665cdf0e10cSrcweir             awt::Rectangle aRect = pText->getCharacterBounds( offset );
666cdf0e10cSrcweir 
667cdf0e10cSrcweir             gint origin_x = 0;
668cdf0e10cSrcweir             gint origin_y = 0;
669cdf0e10cSrcweir 
670cdf0e10cSrcweir             if( coords == ATK_XY_SCREEN )
671cdf0e10cSrcweir             {
672cdf0e10cSrcweir                 g_return_if_fail( ATK_IS_COMPONENT( text ) );
673cdf0e10cSrcweir                 atk_component_get_position( ATK_COMPONENT( text ), &origin_x, &origin_y, coords);
674cdf0e10cSrcweir             }
675cdf0e10cSrcweir 
676cdf0e10cSrcweir             *x = aRect.X + origin_x;
677cdf0e10cSrcweir             *y = aRect.Y + origin_y;
678cdf0e10cSrcweir             *width = aRect.Width;
679cdf0e10cSrcweir             *height = aRect.Height;
680cdf0e10cSrcweir 
681cdf0e10cSrcweir #ifdef ENABLE_TRACING
682cdf0e10cSrcweir             fprintf(stderr, "get_character_extents(%d, %d) returns: %d,%d,%d,%d ",
683cdf0e10cSrcweir                 offset, coords, *x, *y, *width, *height);
684cdf0e10cSrcweir #endif
685cdf0e10cSrcweir         }
686cdf0e10cSrcweir     }
687cdf0e10cSrcweir     catch(const uno::Exception& e) {
688cdf0e10cSrcweir         g_warning( "Exception in getCharacterBounds" );
689cdf0e10cSrcweir     }
690cdf0e10cSrcweir }
691cdf0e10cSrcweir 
692cdf0e10cSrcweir static gint
text_wrapper_get_character_count(AtkText * text)693cdf0e10cSrcweir text_wrapper_get_character_count (AtkText *text)
694cdf0e10cSrcweir {
695cdf0e10cSrcweir     gint rv = 0;
696cdf0e10cSrcweir 
697cdf0e10cSrcweir     try {
698cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
699cdf0e10cSrcweir         if( pText )
700cdf0e10cSrcweir             rv = pText->getCharacterCount();
701cdf0e10cSrcweir     }
702cdf0e10cSrcweir     catch(const uno::Exception& e) {
703cdf0e10cSrcweir         g_warning( "Exception in getCharacterCount" );
704cdf0e10cSrcweir     }
705cdf0e10cSrcweir 
706cdf0e10cSrcweir #ifdef ENABLE_TRACING
707cdf0e10cSrcweir     fprintf(stderr, "get_character_count(%p) returns: %d\n", text, rv);
708cdf0e10cSrcweir #endif
709cdf0e10cSrcweir 
710cdf0e10cSrcweir     return rv;
711cdf0e10cSrcweir }
712cdf0e10cSrcweir 
713cdf0e10cSrcweir static gint
text_wrapper_get_offset_at_point(AtkText * text,gint x,gint y,AtkCoordType coords)714cdf0e10cSrcweir text_wrapper_get_offset_at_point (AtkText     *text,
715cdf0e10cSrcweir                                   gint         x,
716cdf0e10cSrcweir                                   gint         y,
717cdf0e10cSrcweir                                   AtkCoordType coords)
718cdf0e10cSrcweir {
719cdf0e10cSrcweir     try {
720cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
721cdf0e10cSrcweir         if( pText )
722cdf0e10cSrcweir         {
723cdf0e10cSrcweir             gint origin_x = 0;
724cdf0e10cSrcweir             gint origin_y = 0;
725cdf0e10cSrcweir 
726cdf0e10cSrcweir             if( coords == ATK_XY_SCREEN )
727cdf0e10cSrcweir             {
728cdf0e10cSrcweir                 g_return_val_if_fail( ATK_IS_COMPONENT( text ), -1 );
729cdf0e10cSrcweir                 atk_component_get_position( ATK_COMPONENT( text ), &origin_x, &origin_y, coords);
730cdf0e10cSrcweir             }
731cdf0e10cSrcweir 
732cdf0e10cSrcweir             return pText->getIndexAtPoint( awt::Point(x - origin_x, y - origin_y) );
733cdf0e10cSrcweir         }
734cdf0e10cSrcweir     }
735cdf0e10cSrcweir     catch(const uno::Exception& e) {
736cdf0e10cSrcweir         g_warning( "Exception in getIndexAtPoint" );
737cdf0e10cSrcweir     }
738cdf0e10cSrcweir 
739cdf0e10cSrcweir     return -1;
740cdf0e10cSrcweir }
741cdf0e10cSrcweir 
742cdf0e10cSrcweir // FIXME: the whole series of selections API is problematic ...
743cdf0e10cSrcweir 
744cdf0e10cSrcweir static gint
text_wrapper_get_n_selections(AtkText * text)745cdf0e10cSrcweir text_wrapper_get_n_selections (AtkText *text)
746cdf0e10cSrcweir {
747cdf0e10cSrcweir     gint rv = 0;
748cdf0e10cSrcweir 
749cdf0e10cSrcweir     try {
750cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
751cdf0e10cSrcweir         if( pText )
752cdf0e10cSrcweir             rv = ( pText->getSelectionEnd() > pText->getSelectionStart() ) ? 1 : 0;
753cdf0e10cSrcweir     }
754cdf0e10cSrcweir     catch(const uno::Exception& e) {
755cdf0e10cSrcweir         g_warning( "Exception in getSelectionEnd() or getSelectionStart()" );
756cdf0e10cSrcweir     }
757cdf0e10cSrcweir 
758cdf0e10cSrcweir #ifdef ENABLE_TRACING
759cdf0e10cSrcweir     fprintf(stderr, "get_n_selections(%p) returns %d\n", text, rv);
760cdf0e10cSrcweir #endif
761cdf0e10cSrcweir 
762cdf0e10cSrcweir     return rv;
763cdf0e10cSrcweir }
764cdf0e10cSrcweir 
765cdf0e10cSrcweir static gchar *
text_wrapper_get_selection(AtkText * text,gint selection_num,gint * start_offset,gint * end_offset)766cdf0e10cSrcweir text_wrapper_get_selection (AtkText *text,
767cdf0e10cSrcweir                             gint     selection_num,
768cdf0e10cSrcweir                             gint    *start_offset,
769cdf0e10cSrcweir                             gint    *end_offset)
770cdf0e10cSrcweir {
771cdf0e10cSrcweir     g_return_val_if_fail( selection_num == 0, FALSE );
772cdf0e10cSrcweir 
773cdf0e10cSrcweir     try {
774cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
775cdf0e10cSrcweir         if( pText )
776cdf0e10cSrcweir         {
777cdf0e10cSrcweir             *start_offset = pText->getSelectionStart();
778cdf0e10cSrcweir             *end_offset   = pText->getSelectionEnd();
779cdf0e10cSrcweir 
780cdf0e10cSrcweir             return OUStringToGChar( pText->getSelectedText() );
781cdf0e10cSrcweir         }
782cdf0e10cSrcweir     }
783cdf0e10cSrcweir     catch(const uno::Exception& e) {
784cdf0e10cSrcweir         g_warning( "Exception in getSelectionEnd(), getSelectionStart() or getSelectedText()" );
785cdf0e10cSrcweir     }
786cdf0e10cSrcweir 
787cdf0e10cSrcweir     return NULL;
788cdf0e10cSrcweir }
789cdf0e10cSrcweir 
790cdf0e10cSrcweir static gboolean
text_wrapper_add_selection(AtkText * text,gint start_offset,gint end_offset)791cdf0e10cSrcweir text_wrapper_add_selection (AtkText *text,
792cdf0e10cSrcweir                             gint     start_offset,
793cdf0e10cSrcweir                             gint     end_offset)
794cdf0e10cSrcweir {
795cdf0e10cSrcweir     // FIXME: can we try to be more compatible by expanding an
796cdf0e10cSrcweir     //        existing adjacent selection ?
797cdf0e10cSrcweir 
798cdf0e10cSrcweir     try {
799cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
800cdf0e10cSrcweir         if( pText )
801cdf0e10cSrcweir             return pText->setSelection( start_offset, end_offset ); // ?
802cdf0e10cSrcweir     }
803cdf0e10cSrcweir     catch(const uno::Exception& e) {
804cdf0e10cSrcweir         g_warning( "Exception in setSelection()" );
805cdf0e10cSrcweir     }
806cdf0e10cSrcweir 
807cdf0e10cSrcweir     return FALSE;
808cdf0e10cSrcweir }
809cdf0e10cSrcweir 
810cdf0e10cSrcweir static gboolean
text_wrapper_remove_selection(AtkText * text,gint selection_num)811cdf0e10cSrcweir text_wrapper_remove_selection (AtkText *text,
812cdf0e10cSrcweir                                gint     selection_num)
813cdf0e10cSrcweir {
814cdf0e10cSrcweir     g_return_val_if_fail( selection_num == 0, FALSE );
815cdf0e10cSrcweir 
816cdf0e10cSrcweir     try {
817cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
818cdf0e10cSrcweir         if( pText )
819cdf0e10cSrcweir             return pText->setSelection( 0, 0 ); // ?
820cdf0e10cSrcweir     }
821cdf0e10cSrcweir     catch(const uno::Exception& e) {
822cdf0e10cSrcweir         g_warning( "Exception in setSelection()" );
823cdf0e10cSrcweir     }
824cdf0e10cSrcweir 
825cdf0e10cSrcweir     return FALSE;
826cdf0e10cSrcweir }
827cdf0e10cSrcweir 
828cdf0e10cSrcweir static gboolean
text_wrapper_set_selection(AtkText * text,gint selection_num,gint start_offset,gint end_offset)829cdf0e10cSrcweir text_wrapper_set_selection (AtkText *text,
830cdf0e10cSrcweir                             gint     selection_num,
831cdf0e10cSrcweir                             gint     start_offset,
832cdf0e10cSrcweir                             gint     end_offset)
833cdf0e10cSrcweir {
834cdf0e10cSrcweir     g_return_val_if_fail( selection_num == 0, FALSE );
835cdf0e10cSrcweir 
836cdf0e10cSrcweir     try {
837cdf0e10cSrcweir         accessibility::XAccessibleText* pText = getText( text );
838cdf0e10cSrcweir         if( pText )
839cdf0e10cSrcweir             return pText->setSelection( start_offset, end_offset );
840cdf0e10cSrcweir     }
841cdf0e10cSrcweir     catch(const uno::Exception& e) {
842cdf0e10cSrcweir         g_warning( "Exception in setSelection()" );
843cdf0e10cSrcweir     }
844cdf0e10cSrcweir 
845cdf0e10cSrcweir     return FALSE;
846cdf0e10cSrcweir }
847cdf0e10cSrcweir 
848cdf0e10cSrcweir } // extern "C"
849cdf0e10cSrcweir 
850cdf0e10cSrcweir void
textIfaceInit(AtkTextIface * iface)851cdf0e10cSrcweir textIfaceInit (AtkTextIface *iface)
852cdf0e10cSrcweir {
853cdf0e10cSrcweir   g_return_if_fail (iface != NULL);
854cdf0e10cSrcweir 
855cdf0e10cSrcweir   iface->get_text = text_wrapper_get_text;
856cdf0e10cSrcweir   iface->get_character_at_offset = text_wrapper_get_character_at_offset;
857cdf0e10cSrcweir   iface->get_text_before_offset = text_wrapper_get_text_before_offset;
858cdf0e10cSrcweir   iface->get_text_at_offset = text_wrapper_get_text_at_offset;
859cdf0e10cSrcweir   iface->get_text_after_offset = text_wrapper_get_text_after_offset;
860cdf0e10cSrcweir   iface->get_caret_offset = text_wrapper_get_caret_offset;
861cdf0e10cSrcweir   iface->set_caret_offset = text_wrapper_set_caret_offset;
862cdf0e10cSrcweir   iface->get_character_count = text_wrapper_get_character_count;
863cdf0e10cSrcweir   iface->get_n_selections = text_wrapper_get_n_selections;
864cdf0e10cSrcweir   iface->get_selection = text_wrapper_get_selection;
865cdf0e10cSrcweir   iface->add_selection = text_wrapper_add_selection;
866cdf0e10cSrcweir   iface->remove_selection = text_wrapper_remove_selection;
867cdf0e10cSrcweir   iface->set_selection = text_wrapper_set_selection;
868cdf0e10cSrcweir   iface->get_run_attributes = text_wrapper_get_run_attributes;
869cdf0e10cSrcweir   iface->get_default_attributes = text_wrapper_get_default_attributes;
870cdf0e10cSrcweir   iface->get_character_extents = text_wrapper_get_character_extents;
871cdf0e10cSrcweir   iface->get_offset_at_point = text_wrapper_get_offset_at_point;
872cdf0e10cSrcweir }
873