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