update credits
[LibreOffice.git] / vcl / aqua / source / a11y / aqua11ytextwrapper.mm
blobab02eaf7ef3aba964f5fa1337b277ef53a4baf7a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
21 #include "aqua/salinst.h"
22 #include "quartz/utils.h"
23 #include "aqua11ytextwrapper.h"
24 #include "aqua11ytextattributeswrapper.h"
25 #include "aqua11yutil.h"
27 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
28 #include <com/sun/star/awt/Rectangle.hpp>
30 using namespace ::com::sun::star::accessibility;
31 using namespace ::com::sun::star::awt;
32 using namespace ::com::sun::star::lang;
33 using namespace ::com::sun::star::uno;
34 using namespace ::rtl;
36 // Wrapper for XAccessibleText, XAccessibleEditableText and XAccessibleMultiLineText
38 @implementation AquaA11yTextWrapper : NSObject
40 +(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper {
41     return CreateNSString ( [ wrapper accessibleText ] -> getText() );
44 +(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value
46     // TODO
47     (void)wrapper;
48     (void)value;
51 +(id)numberOfCharactersAttributeForElement:(AquaA11yWrapper *)wrapper {
52     return [ NSNumber numberWithLong: [ wrapper accessibleText ] -> getCharacterCount() ];
55 +(id)selectedTextAttributeForElement:(AquaA11yWrapper *)wrapper {
56     return CreateNSString ( [ wrapper accessibleText ] -> getSelectedText() );
59 +(void)setSelectedTextAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
60     if ( [ wrapper accessibleEditableText ] != nil ) {
61         NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
62         OUString newText = GetOUString ( (NSString *) value );
63         NSRange selectedTextRange = [ [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: wrapper ] rangeValue ];
64         try {
65             [ wrapper accessibleEditableText ] -> replaceText ( selectedTextRange.location, selectedTextRange.location + selectedTextRange.length, newText );
66         } catch ( const Exception & e ) {
67             // empty
68         }
69         [ pool release ];
70     }
73 +(id)selectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper {
74     sal_Int32 start = [ wrapper accessibleText ] -> getSelectionStart();
75     sal_Int32 end = [ wrapper accessibleText ] -> getSelectionEnd();
76     if ( start != end ) {
77         return [ NSValue valueWithRange: NSMakeRange ( start, end - start ) ]; // true selection
78     } else {
79         long caretPos = [ wrapper accessibleText ] -> getCaretPosition();
80         if ( caretPos < 0 || caretPos > [ wrapper accessibleText ] -> getCharacterCount() ) {
81             return nil;
82         }
83         return [ NSValue valueWithRange: NSMakeRange ( caretPos, 0 ) ]; // insertion point
84     }
87 +(void)setSelectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
88     NSRange range = [ value rangeValue ];
89     try {
90         [ wrapper accessibleText ] -> setSelection ( range.location, range.location + range.length );
91     } catch ( const Exception & e ) {
92         // empty
93     }
96 +(id)visibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper {
97     // the OOo a11y API returns only the visible portion...
98     return [ NSValue valueWithRange: NSMakeRange ( 0, [ wrapper accessibleText ] -> getCharacterCount() ) ];
101 +(void)setVisibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value
103     // do nothing
104     (void)wrapper;
105     (void)value;
108 +(id)sharedTextUIElementsAttributeForElement:(AquaA11yWrapper *)wrapper
110     (void)wrapper;
111     return [NSArray arrayWithObject:wrapper];
114 +(id)sharedCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper
116     (void)wrapper;
117     return [ NSValue valueWithRange: NSMakeRange ( 0, [wrapper accessibleText]->getCharacterCount() ) ];
120 +(void)addAttributeNamesTo:(NSMutableArray *)attributeNames {
121     [ attributeNames addObjectsFromArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
124 +(NSArray *)specialAttributeNames {
125     return [ NSArray arrayWithObjects: 
126             NSAccessibilityValueAttribute, 
127             NSAccessibilityNumberOfCharactersAttribute, 
128             NSAccessibilitySelectedTextAttribute, 
129             NSAccessibilitySelectedTextRangeAttribute, 
130             NSAccessibilityVisibleCharacterRangeAttribute, 
131             NSAccessibilitySharedTextUIElementsAttribute, 
132             NSAccessibilitySharedCharacterRangeAttribute, 
133             nil ];
136 +(void)addParameterizedAttributeNamesTo:(NSMutableArray *)attributeNames {
137     [ attributeNames addObjectsFromArray: [ AquaA11yTextWrapper specialParameterizedAttributeNames ] ];
140 +(NSArray *)specialParameterizedAttributeNames {
141     return [ NSArray arrayWithObjects: 
142             NSAccessibilityStringForRangeParameterizedAttribute, 
143             NSAccessibilityAttributedStringForRangeParameterizedAttribute, 
144             NSAccessibilityRangeForIndexParameterizedAttribute, 
145             NSAccessibilityRangeForPositionParameterizedAttribute, 
146             NSAccessibilityBoundsForRangeParameterizedAttribute, 
147             NSAccessibilityStyleRangeForIndexParameterizedAttribute, 
148             NSAccessibilityRTFForRangeParameterizedAttribute, 
149             NSAccessibilityLineForIndexParameterizedAttribute, 
150             NSAccessibilityRangeForLineParameterizedAttribute, 
151             nil ];
154 +(id)lineForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
155     NSNumber * lineNumber = nil;
156     try {
157         sal_Int32 line = [ wrapper accessibleMultiLineText ] -> getLineNumberAtIndex ( (sal_Int32) [ index intValue ] );
158         lineNumber = [ NSNumber numberWithInt: line ];
159     } catch ( IndexOutOfBoundsException & e ) {
160         // empty
161     }
162     return lineNumber;
165 +(id)rangeForLineAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)line {
166     NSValue * range = nil;
167     try {
168         TextSegment textSegment = [ wrapper accessibleMultiLineText ] -> getTextAtLineNumber ( [ line intValue ] );
169         range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
170     } catch ( IndexOutOfBoundsException & e ) {
171         // empty
172     }
173     return range;
176 +(id)stringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
177     int loc = [ range rangeValue ].location;
178     int len = [ range rangeValue ].length;
179     NSMutableString * textRange = [ [ NSMutableString alloc ] init ];
180     try {
181         [ textRange appendString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ];
182     } catch ( IndexOutOfBoundsException & e ) {
183         // empty
184     }
185     return textRange;
188 +(id)attributedStringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
189     return [ AquaA11yTextAttributesWrapper createAttributedStringForElement: wrapper inOrigRange: range ];
192 +(id)rangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
193     NSValue * range = nil;
194     try {
195         TextSegment textSegment = [ wrapper accessibleText ] -> getTextBeforeIndex ( [ index intValue ], AccessibleTextType::GLYPH );
196         range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
197     } catch ( IndexOutOfBoundsException & e ) {
198         // empty
199     } catch ( IllegalArgumentException & e ) {
200         // empty
201     }
202     return range;
205 +(id)rangeForPositionAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)point {
206     NSValue * value = nil;
207     sal_Int32 index = [ wrapper accessibleText ] -> getIndexAtPoint ( [ AquaA11yUtil nsPointToVclPoint: point ] );
208     if ( index > -1 ) {
209         value = [ AquaA11yTextWrapper rangeForIndexAttributeForElement: wrapper forParameter: [ NSNumber numberWithLong: index ] ];
210     }
211     return value;
214 +(id)boundsForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
215     NSValue * rect = nil;
216     try {
217         // TODO: this is ugly!!!
218         // the UNP-API can only return the bounds for a single character, not for a range
219         int loc = [ range rangeValue ].location;
220         int len = [ range rangeValue ].length;
221         int minx = 0x7fffffff, miny = 0x7fffffff, maxx = 0, maxy = 0;
222         for ( int i = 0; i < len; i++ ) {
223             Rectangle vclRect = [ wrapper accessibleText ] -> getCharacterBounds ( loc + i );
224             if ( vclRect.X < minx ) {
225                 minx = vclRect.X;
226             }
227             if ( vclRect.Y < miny ) {
228                 miny = vclRect.Y;
229             }
230             if ( vclRect.Width + vclRect.X > maxx ) {
231                 maxx = vclRect.Width + vclRect.X;
232             }
233             if ( vclRect.Height + vclRect.Y > maxy ) {
234                 maxy = vclRect.Height + vclRect.Y;
235             }
236         }
237         if ( [ wrapper accessibleComponent ] != nil ) {
238             // get location on screen (must be added since get CharacterBounds returns values relative to parent)
239             Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen();
240             Point pos ( minx + screenPos.X, miny + screenPos.Y );
241             Point size ( maxx - minx, maxy - miny );
242             NSValue * nsPos = [ AquaA11yUtil vclPointToNSPoint: pos ];
243             rect = [ NSValue valueWithRect: NSMakeRect ( [ nsPos pointValue ].x, [ nsPos pointValue ].y - size.Y, size.X, size.Y ) ];
244             //printf("Range: %s --- Rect: %s\n", [ NSStringFromRange ( [ range rangeValue ] ) UTF8String ], [ NSStringFromRect ( [ rect rectValue ] ) UTF8String ]);
245         }
246     } catch ( IndexOutOfBoundsException & e ) {
247         // empty
248     }
249     return rect;
252 +(id)styleRangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
253     NSValue * range = nil;
254     try {
255         TextSegment textSegment = [ wrapper accessibleText ] -> getTextAtIndex ( [ index intValue ], AccessibleTextType::ATTRIBUTE_RUN );
256         range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
257     } catch ( IndexOutOfBoundsException & e ) {
258         // empty
259     } catch ( IllegalArgumentException & e ) {
260         // empty
261     }
262     return range;
265 +(id)rTFForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
266     NSData * rtfData = nil;
267     NSAttributedString * attrString = (NSAttributedString *) [ AquaA11yTextWrapper attributedStringForRangeAttributeForElement: wrapper forParameter: range ];
268     if ( attrString != nil ) {
269         @try {
270             rtfData = [ attrString RTFFromRange: [ range rangeValue ] documentAttributes: nil ];
271         } @catch ( NSException * e) {
272             // emtpy
273         }
274     }
275     return rtfData;
278 +(BOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper {
279     BOOL isSettable = NO;
280     if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ]
281       || [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ]
282       || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ]
283       || [ attribute isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute ] ) {
284         if ( ! [ [ wrapper accessibilityAttributeValue: NSAccessibilityRoleAttribute ] isEqualToString: NSAccessibilityStaticTextRole ] ) {
285             isSettable = YES;
286         }
287     }
288     return isSettable;
291 @end
293 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */