xref: /AOO41X/main/vcl/aqua/source/a11y/aqua11ytextwrapper.mm (revision 1eb2882219fe8c7a70ad7ebe9dc522e16e8aef6e)
1323de322SAndrew Rist/**************************************************************
2cdf0e10cSrcweir *
3323de322SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4323de322SAndrew Rist * or more contributor license agreements.  See the NOTICE file
5323de322SAndrew Rist * distributed with this work for additional information
6323de322SAndrew Rist * regarding copyright ownership.  The ASF licenses this file
7323de322SAndrew Rist * to you under the Apache License, Version 2.0 (the
8323de322SAndrew Rist * "License"); you may not use this file except in compliance
9323de322SAndrew Rist * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir *
11323de322SAndrew Rist *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir *
13323de322SAndrew Rist * Unless required by applicable law or agreed to in writing,
14323de322SAndrew Rist * software distributed under the License is distributed on an
15323de322SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16323de322SAndrew Rist * KIND, either express or implied.  See the License for the
17323de322SAndrew Rist * specific language governing permissions and limitations
18323de322SAndrew Rist * under the License.
19cdf0e10cSrcweir *
20323de322SAndrew Rist *************************************************************/
21323de322SAndrew Rist
22323de322SAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir// MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir#include "precompiled_vcl.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir#include "aqua/salinst.h"
28cdf0e10cSrcweir
29cdf0e10cSrcweir#include "aqua11ytextwrapper.h"
30cdf0e10cSrcweir#include "aqua11ytextattributeswrapper.h"
31cdf0e10cSrcweir#include "aqua11yutil.h"
32cdf0e10cSrcweir
33cdf0e10cSrcweir#include <com/sun/star/accessibility/AccessibleTextType.hpp>
34cdf0e10cSrcweir#include <com/sun/star/awt/Rectangle.hpp>
35cdf0e10cSrcweir
36cdf0e10cSrcweirusing namespace ::com::sun::star::accessibility;
37cdf0e10cSrcweirusing namespace ::com::sun::star::awt;
38cdf0e10cSrcweirusing namespace ::com::sun::star::lang;
39cdf0e10cSrcweirusing namespace ::com::sun::star::uno;
40cdf0e10cSrcweirusing namespace ::rtl;
41cdf0e10cSrcweir
42cdf0e10cSrcweir// Wrapper for XAccessibleText, XAccessibleEditableText and XAccessibleMultiLineText
43cdf0e10cSrcweir
44cdf0e10cSrcweir@implementation AquaA11yTextWrapper : NSObject
45cdf0e10cSrcweir
46cdf0e10cSrcweir+(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper {
47cdf0e10cSrcweir    return CreateNSString ( [ wrapper accessibleText ] -> getText() );
48cdf0e10cSrcweir}
49cdf0e10cSrcweir
50cdf0e10cSrcweir+(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value
51cdf0e10cSrcweir{
52cdf0e10cSrcweir    // TODO
53cdf0e10cSrcweir    (void)wrapper;
54cdf0e10cSrcweir    (void)value;
55cdf0e10cSrcweir}
56cdf0e10cSrcweir
57cdf0e10cSrcweir+(id)numberOfCharactersAttributeForElement:(AquaA11yWrapper *)wrapper {
58cdf0e10cSrcweir    return [ NSNumber numberWithLong: [ wrapper accessibleText ] -> getCharacterCount() ];
59cdf0e10cSrcweir}
60cdf0e10cSrcweir
61cdf0e10cSrcweir+(id)selectedTextAttributeForElement:(AquaA11yWrapper *)wrapper {
62cdf0e10cSrcweir    return CreateNSString ( [ wrapper accessibleText ] -> getSelectedText() );
63cdf0e10cSrcweir}
64cdf0e10cSrcweir
65cdf0e10cSrcweir+(void)setSelectedTextAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
66cdf0e10cSrcweir    if ( [ wrapper accessibleEditableText ] != nil ) {
67cdf0e10cSrcweir        NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
68cdf0e10cSrcweir        OUString newText = GetOUString ( (NSString *) value );
69cdf0e10cSrcweir        NSRange selectedTextRange = [ [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: wrapper ] rangeValue ];
70cdf0e10cSrcweir        try {
71cdf0e10cSrcweir            [ wrapper accessibleEditableText ] -> replaceText ( selectedTextRange.location, selectedTextRange.location + selectedTextRange.length, newText );
72cdf0e10cSrcweir        } catch ( const Exception & e ) {
73cdf0e10cSrcweir            // empty
74cdf0e10cSrcweir        }
75cdf0e10cSrcweir        [ pool release ];
76cdf0e10cSrcweir    }
77cdf0e10cSrcweir}
78cdf0e10cSrcweir
79cdf0e10cSrcweir+(id)selectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper {
80cdf0e10cSrcweir    sal_Int32 start = [ wrapper accessibleText ] -> getSelectionStart();
81cdf0e10cSrcweir    sal_Int32 end = [ wrapper accessibleText ] -> getSelectionEnd();
82cdf0e10cSrcweir    if ( start != end ) {
83cdf0e10cSrcweir        return [ NSValue valueWithRange: NSMakeRange ( start, end - start ) ]; // true selection
84cdf0e10cSrcweir    } else {
85cdf0e10cSrcweir        long caretPos = [ wrapper accessibleText ] -> getCaretPosition();
86cdf0e10cSrcweir        if ( caretPos < 0 || caretPos > [ wrapper accessibleText ] -> getCharacterCount() ) {
87cdf0e10cSrcweir            return nil;
88cdf0e10cSrcweir        }
89cdf0e10cSrcweir        return [ NSValue valueWithRange: NSMakeRange ( caretPos, 0 ) ]; // insertion point
90cdf0e10cSrcweir    }
91cdf0e10cSrcweir}
92cdf0e10cSrcweir
93cdf0e10cSrcweir+(void)setSelectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
94cdf0e10cSrcweir    NSRange range = [ value rangeValue ];
95cdf0e10cSrcweir    try {
96cdf0e10cSrcweir        [ wrapper accessibleText ] -> setSelection ( range.location, range.location + range.length );
97cdf0e10cSrcweir    } catch ( const Exception & e ) {
98cdf0e10cSrcweir        // empty
99cdf0e10cSrcweir    }
100cdf0e10cSrcweir}
101cdf0e10cSrcweir
102cdf0e10cSrcweir+(id)visibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper {
103cdf0e10cSrcweir    // the OOo a11y API returns only the visible portion...
104cdf0e10cSrcweir    return [ NSValue valueWithRange: NSMakeRange ( 0, [ wrapper accessibleText ] -> getCharacterCount() ) ];
105cdf0e10cSrcweir}
106cdf0e10cSrcweir
107cdf0e10cSrcweir+(void)setVisibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value
108cdf0e10cSrcweir{
109cdf0e10cSrcweir    // do nothing
110cdf0e10cSrcweir    (void)wrapper;
111cdf0e10cSrcweir    (void)value;
112cdf0e10cSrcweir}
113cdf0e10cSrcweir
114cdf0e10cSrcweir+(id)sharedTextUIElementsAttributeForElement:(AquaA11yWrapper *)wrapper
115cdf0e10cSrcweir{
116cdf0e10cSrcweir    (void)wrapper;
117cdf0e10cSrcweir    return [ [ NSArray alloc ] init ]; // unsupported
118cdf0e10cSrcweir}
119cdf0e10cSrcweir
120cdf0e10cSrcweir+(id)sharedCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper
121cdf0e10cSrcweir{
122cdf0e10cSrcweir    (void)wrapper;
123cdf0e10cSrcweir    return [ NSValue valueWithRange: NSMakeRange ( 0, 0 ) ]; // unsupported
124cdf0e10cSrcweir}
125cdf0e10cSrcweir
126cdf0e10cSrcweir+(void)addAttributeNamesTo:(NSMutableArray *)attributeNames {
127cdf0e10cSrcweir    [ attributeNames addObjectsFromArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
128cdf0e10cSrcweir}
129cdf0e10cSrcweir
130cdf0e10cSrcweir+(NSArray *)specialAttributeNames {
131cdf0e10cSrcweir    return [ NSArray arrayWithObjects:
132cdf0e10cSrcweir            NSAccessibilityValueAttribute,
133cdf0e10cSrcweir            NSAccessibilityNumberOfCharactersAttribute,
134cdf0e10cSrcweir            NSAccessibilitySelectedTextAttribute,
135cdf0e10cSrcweir            NSAccessibilitySelectedTextRangeAttribute,
136cdf0e10cSrcweir            NSAccessibilityVisibleCharacterRangeAttribute,
137cdf0e10cSrcweir            NSAccessibilitySharedTextUIElementsAttribute,
138cdf0e10cSrcweir            NSAccessibilitySharedCharacterRangeAttribute,
139cdf0e10cSrcweir            nil ];
140cdf0e10cSrcweir}
141cdf0e10cSrcweir
142cdf0e10cSrcweir+(void)addParameterizedAttributeNamesTo:(NSMutableArray *)attributeNames {
143cdf0e10cSrcweir    [ attributeNames addObjectsFromArray: [ AquaA11yTextWrapper specialParameterizedAttributeNames ] ];
144cdf0e10cSrcweir}
145cdf0e10cSrcweir
146cdf0e10cSrcweir+(NSArray *)specialParameterizedAttributeNames {
147cdf0e10cSrcweir    return [ NSArray arrayWithObjects:
148cdf0e10cSrcweir            NSAccessibilityStringForRangeParameterizedAttribute,
149cdf0e10cSrcweir            NSAccessibilityAttributedStringForRangeParameterizedAttribute,
150cdf0e10cSrcweir            NSAccessibilityRangeForIndexParameterizedAttribute,
151cdf0e10cSrcweir            NSAccessibilityRangeForPositionParameterizedAttribute,
152cdf0e10cSrcweir            NSAccessibilityBoundsForRangeParameterizedAttribute,
153cdf0e10cSrcweir            NSAccessibilityStyleRangeForIndexParameterizedAttribute,
154cdf0e10cSrcweir            NSAccessibilityRTFForRangeParameterizedAttribute,
155cdf0e10cSrcweir            NSAccessibilityLineForIndexParameterizedAttribute,
156cdf0e10cSrcweir            NSAccessibilityRangeForLineParameterizedAttribute,
157cdf0e10cSrcweir            nil ];
158cdf0e10cSrcweir}
159cdf0e10cSrcweir
160cdf0e10cSrcweir+(id)lineForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
161cdf0e10cSrcweir    NSNumber * lineNumber = nil;
162cdf0e10cSrcweir    try {
163cdf0e10cSrcweir        sal_Int32 line = [ wrapper accessibleMultiLineText ] -> getLineNumberAtIndex ( (sal_Int32) [ index intValue ] );
164cdf0e10cSrcweir        lineNumber = [ NSNumber numberWithInt: line ];
165cdf0e10cSrcweir    } catch ( IndexOutOfBoundsException & e ) {
166cdf0e10cSrcweir        // empty
167cdf0e10cSrcweir    }
168cdf0e10cSrcweir    return lineNumber;
169cdf0e10cSrcweir}
170cdf0e10cSrcweir
171cdf0e10cSrcweir+(id)rangeForLineAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)line {
172cdf0e10cSrcweir    NSValue * range = nil;
173cdf0e10cSrcweir    try {
174cdf0e10cSrcweir        TextSegment textSegment = [ wrapper accessibleMultiLineText ] -> getTextAtLineNumber ( [ line intValue ] );
175cdf0e10cSrcweir        range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
176cdf0e10cSrcweir    } catch ( IndexOutOfBoundsException & e ) {
177cdf0e10cSrcweir        // empty
178cdf0e10cSrcweir    }
179cdf0e10cSrcweir    return range;
180cdf0e10cSrcweir}
181cdf0e10cSrcweir
182cdf0e10cSrcweir+(id)stringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
183cdf0e10cSrcweir    int loc = [ range rangeValue ].location;
184cdf0e10cSrcweir    int len = [ range rangeValue ].length;
185cdf0e10cSrcweir    NSMutableString * textRange = [ [ NSMutableString alloc ] init ];
186cdf0e10cSrcweir    try {
187cdf0e10cSrcweir        [ textRange appendString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ];
188cdf0e10cSrcweir    } catch ( IndexOutOfBoundsException & e ) {
189cdf0e10cSrcweir        // empty
190cdf0e10cSrcweir    }
191cdf0e10cSrcweir    return textRange;
192cdf0e10cSrcweir}
193cdf0e10cSrcweir
194cdf0e10cSrcweir+(id)attributedStringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
195cdf0e10cSrcweir    return [ AquaA11yTextAttributesWrapper createAttributedStringForElement: wrapper inOrigRange: range ];
196cdf0e10cSrcweir}
197cdf0e10cSrcweir
198cdf0e10cSrcweir+(id)rangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
199cdf0e10cSrcweir    NSValue * range = nil;
200cdf0e10cSrcweir    try {
201cdf0e10cSrcweir        TextSegment textSegment = [ wrapper accessibleText ] -> getTextBeforeIndex ( [ index intValue ], AccessibleTextType::GLYPH );
202cdf0e10cSrcweir        range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
203cdf0e10cSrcweir    } catch ( IndexOutOfBoundsException & e ) {
204cdf0e10cSrcweir        // empty
205cdf0e10cSrcweir    } catch ( IllegalArgumentException & e ) {
206cdf0e10cSrcweir        // empty
207cdf0e10cSrcweir    }
208cdf0e10cSrcweir    return range;
209cdf0e10cSrcweir}
210cdf0e10cSrcweir
211cdf0e10cSrcweir+(id)rangeForPositionAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)point {
212cdf0e10cSrcweir    NSValue * value = nil;
213*1eb28822SHerbert Dürr    Point aPoint( [ AquaA11yUtil nsPointToVclPoint: point ]);
214*1eb28822SHerbert Dürr    const Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen();
215*1eb28822SHerbert Dürr    aPoint.X -= screenPos.X;
216*1eb28822SHerbert Dürr    aPoint.Y -= screenPos.Y;
217*1eb28822SHerbert Dürr    sal_Int32 index = [ wrapper accessibleText ] -> getIndexAtPoint( aPoint );
218cdf0e10cSrcweir    if ( index > -1 ) {
219cdf0e10cSrcweir        value = [ AquaA11yTextWrapper rangeForIndexAttributeForElement: wrapper forParameter: [ NSNumber numberWithLong: index ] ];
220cdf0e10cSrcweir    }
221cdf0e10cSrcweir    return value;
222cdf0e10cSrcweir}
223cdf0e10cSrcweir
224cdf0e10cSrcweir+(id)boundsForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
225cdf0e10cSrcweir    NSValue * rect = nil;
226cdf0e10cSrcweir    try {
227cdf0e10cSrcweir        // TODO: this is ugly!!!
228cdf0e10cSrcweir        // the UNP-API can only return the bounds for a single character, not for a range
229cdf0e10cSrcweir        int loc = [ range rangeValue ].location;
230cdf0e10cSrcweir        int len = [ range rangeValue ].length;
231cdf0e10cSrcweir        int minx = 0x7fffffff, miny = 0x7fffffff, maxx = 0, maxy = 0;
232cdf0e10cSrcweir        for ( int i = 0; i < len; i++ ) {
233cdf0e10cSrcweir            Rectangle vclRect = [ wrapper accessibleText ] -> getCharacterBounds ( loc + i );
234cdf0e10cSrcweir            if ( vclRect.X < minx ) {
235cdf0e10cSrcweir                minx = vclRect.X;
236cdf0e10cSrcweir            }
237cdf0e10cSrcweir            if ( vclRect.Y < miny ) {
238cdf0e10cSrcweir                miny = vclRect.Y;
239cdf0e10cSrcweir            }
240cdf0e10cSrcweir            if ( vclRect.Width + vclRect.X > maxx ) {
241cdf0e10cSrcweir                maxx = vclRect.Width + vclRect.X;
242cdf0e10cSrcweir            }
243cdf0e10cSrcweir            if ( vclRect.Height + vclRect.Y > maxy ) {
244cdf0e10cSrcweir                maxy = vclRect.Height + vclRect.Y;
245cdf0e10cSrcweir            }
246cdf0e10cSrcweir        }
247cdf0e10cSrcweir        if ( [ wrapper accessibleComponent ] != nil ) {
248cdf0e10cSrcweir            // get location on screen (must be added since get CharacterBounds returns values relative to parent)
249cdf0e10cSrcweir            Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen();
250cdf0e10cSrcweir            Point pos ( minx + screenPos.X, miny + screenPos.Y );
251cdf0e10cSrcweir            Point size ( maxx - minx, maxy - miny );
252cdf0e10cSrcweir            NSValue * nsPos = [ AquaA11yUtil vclPointToNSPoint: pos ];
253cdf0e10cSrcweir            rect = [ NSValue valueWithRect: NSMakeRect ( [ nsPos pointValue ].x, [ nsPos pointValue ].y - size.Y, size.X, size.Y ) ];
254cdf0e10cSrcweir            //printf("Range: %s --- Rect: %s\n", [ NSStringFromRange ( [ range rangeValue ] ) UTF8String ], [ NSStringFromRect ( [ rect rectValue ] ) UTF8String ]);
255cdf0e10cSrcweir        }
256cdf0e10cSrcweir    } catch ( IndexOutOfBoundsException & e ) {
257cdf0e10cSrcweir        // empty
258cdf0e10cSrcweir    }
259cdf0e10cSrcweir    return rect;
260cdf0e10cSrcweir}
261cdf0e10cSrcweir
262cdf0e10cSrcweir+(id)styleRangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
263cdf0e10cSrcweir    NSValue * range = nil;
264cdf0e10cSrcweir    try {
265cdf0e10cSrcweir        TextSegment textSegment = [ wrapper accessibleText ] -> getTextAtIndex ( [ index intValue ], AccessibleTextType::ATTRIBUTE_RUN );
266cdf0e10cSrcweir        range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
267cdf0e10cSrcweir    } catch ( IndexOutOfBoundsException & e ) {
268cdf0e10cSrcweir        // empty
269cdf0e10cSrcweir    } catch ( IllegalArgumentException & e ) {
270cdf0e10cSrcweir        // empty
271cdf0e10cSrcweir    }
272cdf0e10cSrcweir    return range;
273cdf0e10cSrcweir}
274cdf0e10cSrcweir
275cdf0e10cSrcweir+(id)rTFForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
276cdf0e10cSrcweir    NSData * rtfData = nil;
277cdf0e10cSrcweir    NSAttributedString * attrString = (NSAttributedString *) [ AquaA11yTextWrapper attributedStringForRangeAttributeForElement: wrapper forParameter: range ];
278cdf0e10cSrcweir    if ( attrString != nil ) {
279cdf0e10cSrcweir        @try {
280cdf0e10cSrcweir            rtfData = [ attrString RTFFromRange: [ range rangeValue ] documentAttributes: nil ];
281cdf0e10cSrcweir        } @catch ( NSException * e) {
282cdf0e10cSrcweir            // emtpy
283cdf0e10cSrcweir        }
284cdf0e10cSrcweir    }
285cdf0e10cSrcweir    return rtfData;
286cdf0e10cSrcweir}
287cdf0e10cSrcweir
288cdf0e10cSrcweir+(BOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper {
289cdf0e10cSrcweir    BOOL isSettable = NO;
290cdf0e10cSrcweir    if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ]
291cdf0e10cSrcweir      || [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ]
292cdf0e10cSrcweir      || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ]
293cdf0e10cSrcweir      || [ attribute isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute ] ) {
294cdf0e10cSrcweir        if ( ! [ [ wrapper accessibilityAttributeValue: NSAccessibilityRoleAttribute ] isEqualToString: NSAccessibilityStaticTextRole ] ) {
295cdf0e10cSrcweir            isSettable = YES;
296cdf0e10cSrcweir        }
297cdf0e10cSrcweir    }
298cdf0e10cSrcweir    return isSettable;
299cdf0e10cSrcweir}
300cdf0e10cSrcweir
301cdf0e10cSrcweir@end
302