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