1/************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28// MARKER(update_precomp.py): autogen include statement, do not remove 29#include "precompiled_vcl.hxx" 30 31#include "aqua/salinst.h" 32 33#include "aqua11ytextwrapper.h" 34#include "aqua11ytextattributeswrapper.h" 35#include "aqua11yutil.h" 36 37#include <com/sun/star/accessibility/AccessibleTextType.hpp> 38#include <com/sun/star/awt/Rectangle.hpp> 39 40using namespace ::com::sun::star::accessibility; 41using namespace ::com::sun::star::awt; 42using namespace ::com::sun::star::lang; 43using namespace ::com::sun::star::uno; 44using namespace ::rtl; 45 46// Wrapper for XAccessibleText, XAccessibleEditableText and XAccessibleMultiLineText 47 48@implementation AquaA11yTextWrapper : NSObject 49 50+(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper { 51 return CreateNSString ( [ wrapper accessibleText ] -> getText() ); 52} 53 54+(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value 55{ 56 // TODO 57 (void)wrapper; 58 (void)value; 59} 60 61+(id)numberOfCharactersAttributeForElement:(AquaA11yWrapper *)wrapper { 62 return [ NSNumber numberWithLong: [ wrapper accessibleText ] -> getCharacterCount() ]; 63} 64 65+(id)selectedTextAttributeForElement:(AquaA11yWrapper *)wrapper { 66 return CreateNSString ( [ wrapper accessibleText ] -> getSelectedText() ); 67} 68 69+(void)setSelectedTextAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value { 70 if ( [ wrapper accessibleEditableText ] != nil ) { 71 NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ]; 72 OUString newText = GetOUString ( (NSString *) value ); 73 NSRange selectedTextRange = [ [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: wrapper ] rangeValue ]; 74 try { 75 [ wrapper accessibleEditableText ] -> replaceText ( selectedTextRange.location, selectedTextRange.location + selectedTextRange.length, newText ); 76 } catch ( const Exception & e ) { 77 // empty 78 } 79 [ pool release ]; 80 } 81} 82 83+(id)selectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper { 84 sal_Int32 start = [ wrapper accessibleText ] -> getSelectionStart(); 85 sal_Int32 end = [ wrapper accessibleText ] -> getSelectionEnd(); 86 if ( start != end ) { 87 return [ NSValue valueWithRange: NSMakeRange ( start, end - start ) ]; // true selection 88 } else { 89 long caretPos = [ wrapper accessibleText ] -> getCaretPosition(); 90 if ( caretPos < 0 || caretPos > [ wrapper accessibleText ] -> getCharacterCount() ) { 91 return nil; 92 } 93 return [ NSValue valueWithRange: NSMakeRange ( caretPos, 0 ) ]; // insertion point 94 } 95} 96 97+(void)setSelectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value { 98 NSRange range = [ value rangeValue ]; 99 try { 100 [ wrapper accessibleText ] -> setSelection ( range.location, range.location + range.length ); 101 } catch ( const Exception & e ) { 102 // empty 103 } 104} 105 106+(id)visibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper { 107 // the OOo a11y API returns only the visible portion... 108 return [ NSValue valueWithRange: NSMakeRange ( 0, [ wrapper accessibleText ] -> getCharacterCount() ) ]; 109} 110 111+(void)setVisibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value 112{ 113 // do nothing 114 (void)wrapper; 115 (void)value; 116} 117 118+(id)sharedTextUIElementsAttributeForElement:(AquaA11yWrapper *)wrapper 119{ 120 (void)wrapper; 121 return [ [ NSArray alloc ] init ]; // unsupported 122} 123 124+(id)sharedCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper 125{ 126 (void)wrapper; 127 return [ NSValue valueWithRange: NSMakeRange ( 0, 0 ) ]; // unsupported 128} 129 130+(void)addAttributeNamesTo:(NSMutableArray *)attributeNames { 131 [ attributeNames addObjectsFromArray: [ AquaA11yTextWrapper specialAttributeNames ] ]; 132} 133 134+(NSArray *)specialAttributeNames { 135 return [ NSArray arrayWithObjects: 136 NSAccessibilityValueAttribute, 137 NSAccessibilityNumberOfCharactersAttribute, 138 NSAccessibilitySelectedTextAttribute, 139 NSAccessibilitySelectedTextRangeAttribute, 140 NSAccessibilityVisibleCharacterRangeAttribute, 141 NSAccessibilitySharedTextUIElementsAttribute, 142 NSAccessibilitySharedCharacterRangeAttribute, 143 nil ]; 144} 145 146+(void)addParameterizedAttributeNamesTo:(NSMutableArray *)attributeNames { 147 [ attributeNames addObjectsFromArray: [ AquaA11yTextWrapper specialParameterizedAttributeNames ] ]; 148} 149 150+(NSArray *)specialParameterizedAttributeNames { 151 return [ NSArray arrayWithObjects: 152 NSAccessibilityStringForRangeParameterizedAttribute, 153 NSAccessibilityAttributedStringForRangeParameterizedAttribute, 154 NSAccessibilityRangeForIndexParameterizedAttribute, 155 NSAccessibilityRangeForPositionParameterizedAttribute, 156 NSAccessibilityBoundsForRangeParameterizedAttribute, 157 NSAccessibilityStyleRangeForIndexParameterizedAttribute, 158 NSAccessibilityRTFForRangeParameterizedAttribute, 159 NSAccessibilityLineForIndexParameterizedAttribute, 160 NSAccessibilityRangeForLineParameterizedAttribute, 161 nil ]; 162} 163 164+(id)lineForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index { 165 NSNumber * lineNumber = nil; 166 try { 167 sal_Int32 line = [ wrapper accessibleMultiLineText ] -> getLineNumberAtIndex ( (sal_Int32) [ index intValue ] ); 168 lineNumber = [ NSNumber numberWithInt: line ]; 169 } catch ( IndexOutOfBoundsException & e ) { 170 // empty 171 } 172 return lineNumber; 173} 174 175+(id)rangeForLineAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)line { 176 NSValue * range = nil; 177 try { 178 TextSegment textSegment = [ wrapper accessibleMultiLineText ] -> getTextAtLineNumber ( [ line intValue ] ); 179 range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ]; 180 } catch ( IndexOutOfBoundsException & e ) { 181 // empty 182 } 183 return range; 184} 185 186+(id)stringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range { 187 int loc = [ range rangeValue ].location; 188 int len = [ range rangeValue ].length; 189 NSMutableString * textRange = [ [ NSMutableString alloc ] init ]; 190 try { 191 [ textRange appendString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ]; 192 } catch ( IndexOutOfBoundsException & e ) { 193 // empty 194 } 195 return textRange; 196} 197 198+(id)attributedStringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range { 199 return [ AquaA11yTextAttributesWrapper createAttributedStringForElement: wrapper inOrigRange: range ]; 200} 201 202+(id)rangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index { 203 NSValue * range = nil; 204 try { 205 TextSegment textSegment = [ wrapper accessibleText ] -> getTextBeforeIndex ( [ index intValue ], AccessibleTextType::GLYPH ); 206 range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ]; 207 } catch ( IndexOutOfBoundsException & e ) { 208 // empty 209 } catch ( IllegalArgumentException & e ) { 210 // empty 211 } 212 return range; 213} 214 215+(id)rangeForPositionAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)point { 216 NSValue * value = nil; 217 sal_Int32 index = [ wrapper accessibleText ] -> getIndexAtPoint ( [ AquaA11yUtil nsPointToVclPoint: point ] ); 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