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 <osx/saldata.hxx>
23
24#include <osx/a11ywrapper.h>
25#include <osx/a11ylistener.hxx>
26#include <osx/a11yfactory.h>
27#include <osx/a11yfocustracker.hxx>
28
29#include <quartz/utils.h>
30
31#include "a11yfocuslistener.hxx"
32#include "a11yactionwrapper.h"
33#include "a11ycomponentwrapper.h"
34#include "a11yselectionwrapper.h"
35#include "a11ytablewrapper.h"
36#include "a11ytextwrapper.h"
37#include "a11yvaluewrapper.h"
38#include "a11yrolehelper.h"
39
40#include <com/sun/star/accessibility/AccessibleRole.hpp>
41#include <com/sun/star/accessibility/AccessibleStateType.hpp>
42#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
43#include <com/sun/star/awt/Size.hpp>
44#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
45#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
46#include <com/sun/star/lang/DisposedException.hpp>
47
48#include <sal/log.hxx>
49#include <osl/diagnose.h>
50
51using namespace ::com::sun::star::accessibility;
52using namespace ::com::sun::star::awt;
53using namespace ::com::sun::star::lang;
54using namespace ::com::sun::star::uno;
55
56@interface SalFrameWindow : NSWindow
57{
58}
59-(Reference<XAccessibleContext>)accessibleContext;
60@end
61
62static bool isPopupMenuOpen = false;
63
64static std::ostream &operator<<(std::ostream &s, NSObject *obj) {
65    return s << [[obj description] UTF8String];
66}
67
68@implementation AquaA11yWrapper : NSView
69
70#pragma mark -
71#pragma mark Init and dealloc
72
73-(id)initWithAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
74    self = [ super init ];
75    if ( self ) {
76        [ self setDefaults: rxAccessibleContext ];
77    }
78    return self;
79}
80
81-(void) setDefaults: (Reference < XAccessibleContext >) rxAccessibleContext {
82    mpReferenceWrapper = new ReferenceWrapper;
83    mActsAsRadioGroup = NO;
84    mpReferenceWrapper -> rAccessibleContext = rxAccessibleContext;
85    mIsTableCell = NO;
86    // Querying all supported interfaces
87    try {
88        // XAccessibleComponent
89        mpReferenceWrapper->rAccessibleComponent.set( rxAccessibleContext, UNO_QUERY );
90        // XAccessibleExtendedComponent
91        mpReferenceWrapper->rAccessibleExtendedComponent.set( rxAccessibleContext, UNO_QUERY );
92        // XAccessibleSelection
93        mpReferenceWrapper->rAccessibleSelection.set( rxAccessibleContext, UNO_QUERY );
94        // XAccessibleTable
95        mpReferenceWrapper->rAccessibleTable.set( rxAccessibleContext, UNO_QUERY );
96        // XAccessibleText
97        mpReferenceWrapper->rAccessibleText.set( rxAccessibleContext, UNO_QUERY );
98        // XAccessibleEditableText
99        mpReferenceWrapper->rAccessibleEditableText.set( rxAccessibleContext, UNO_QUERY );
100        // XAccessibleValue
101        mpReferenceWrapper->rAccessibleValue.set( rxAccessibleContext, UNO_QUERY );
102        // XAccessibleAction
103        mpReferenceWrapper->rAccessibleAction.set( rxAccessibleContext, UNO_QUERY );
104        // XAccessibleTextAttributes
105        mpReferenceWrapper->rAccessibleTextAttributes.set( rxAccessibleContext, UNO_QUERY );
106        // XAccessibleMultiLineText
107        mpReferenceWrapper->rAccessibleMultiLineText.set( rxAccessibleContext, UNO_QUERY );
108        // XAccessibleTextMarkup
109        mpReferenceWrapper->rAccessibleTextMarkup.set( rxAccessibleContext, UNO_QUERY );
110        // XAccessibleEventBroadcaster
111        #if 0
112        /* #i102033# NSAccessibility does not seemt to know an equivalent for transient children.
113           That means we need to cache this, else e.g. tree list boxes are not accessible (moreover
114           it crashes by notifying dead objects - which would seemt o be another bug)
115
116           FIXME:
117           Unfortunately this can increase memory consumption drastically until the non transient parent
118           is destroyed and finally all the transients are released.
119        */
120        if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) )
121        #endif
122        {
123            Reference< XAccessibleEventBroadcaster > xBroadcaster(rxAccessibleContext, UNO_QUERY);
124            if( xBroadcaster.is() ) {
125                /*
126                 * We intentionally do not hold a reference to the event listener in the wrapper object,
127                 * but let the listener control the life cycle of the wrapper instead ..
128                 */
129                xBroadcaster->addAccessibleEventListener( new AquaA11yEventListener( self, rxAccessibleContext -> getAccessibleRole() ) );
130            }
131        }
132        // TABLE_CELL
133        if ( rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TABLE_CELL ) {
134            mIsTableCell = YES;
135        }
136    } catch ( const Exception ) {
137    }
138}
139
140-(void)dealloc {
141    if ( mpReferenceWrapper ) {
142        delete mpReferenceWrapper;
143    }
144    [ super dealloc ];
145}
146
147#pragma mark -
148#pragma mark Utility Section
149
150// generates selectors for attribute name AXAttributeNameHere
151// (getter without parameter) attributeNameHereAttribute
152// (getter with parameter)    attributeNameHereAttributeForParameter:
153// (setter)                   setAttributeNameHereAttributeForElement:to:
154-(SEL)selectorForAttribute:(NSString *)attribute asGetter:(BOOL)asGetter withGetterParameter:(BOOL)withGetterParameter {
155    SEL selector = static_cast<SEL>(nil);
156    NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
157    @try {
158        // step 1: create method name from attribute name
159        NSMutableString * methodName = [ NSMutableString string ];
160        if ( ! asGetter ) {
161            [ methodName appendString: @"set" ];
162        }
163        NSRange const aRange = { 2, 1 };
164        NSString * firstChar = [ attribute substringWithRange: aRange ]; // drop leading "AX" and get first char
165        if ( asGetter ) {
166            [ methodName appendString: [ firstChar lowercaseString ] ];
167        } else {
168            [ methodName appendString: firstChar ];
169        }
170        [ methodName appendString: [ attribute substringFromIndex: 3 ] ]; // append rest of attribute name
171        // append rest of method name
172        [ methodName appendString: @"Attribute" ];
173        if ( ! asGetter ) {
174            [ methodName appendString: @"ForElement:to:" ];
175        } else if ( asGetter && withGetterParameter ) {
176            [ methodName appendString: @"ForParameter:" ];
177        }
178        // step 2: create selector
179        selector = NSSelectorFromString ( methodName );
180    } @catch ( id  ) {
181        selector = static_cast<SEL>(nil);
182    }
183    [ pool release ];
184    return selector;
185}
186
187-(Reference < XAccessible >)getFirstRadioButtonInGroup {
188    Reference < XAccessibleRelationSet > rxAccessibleRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
189    if( rxAccessibleRelationSet.is() )
190    {
191        AccessibleRelation relationMemberOf = rxAccessibleRelationSet -> getRelationByType ( AccessibleRelationType::MEMBER_OF );
192        if ( relationMemberOf.RelationType == AccessibleRelationType::MEMBER_OF && relationMemberOf.TargetSet.hasElements() )
193            return Reference < XAccessible > ( relationMemberOf.TargetSet[0], UNO_QUERY );
194    }
195    return Reference < XAccessible > ();
196}
197
198-(BOOL)isFirstRadioButtonInGroup {
199    Reference < XAccessible > rFirstMateAccessible = [ self getFirstRadioButtonInGroup ];
200    if ( rFirstMateAccessible.is() && rFirstMateAccessible -> getAccessibleContext().get() == [ self accessibleContext ] ) {
201        return YES;
202    }
203    return NO;
204}
205
206#pragma mark -
207#pragma mark Attribute Value Getters
208// ( called via Reflection by accessibilityAttributeValue )
209
210/*
211    Radiobutton grouping is done differently in NSAccessibility and the UNO-API. In UNO related radio buttons share an entry in their
212    RelationSet. In NSAccessibility the relationship is expressed through the hierarchy. An AXRadioGroup contains two or more AXRadioButton
213    objects. Since this group is not available in the UNO hierarchy, an extra wrapper is used for it. This wrapper shares almost all
214    attributes with the first radio button of the group, except for the role, subrole, role description, parent and children attributes.
215    So in this five methods there is a special treatment for radio buttons and groups.
216*/
217
218-(id)roleAttribute {
219    if ( mActsAsRadioGroup ) {
220        return NSAccessibilityRadioGroupRole;
221    }
222    else {
223        return [ AquaA11yRoleHelper getNativeRoleFrom: [ self accessibleContext ] ];
224    }
225}
226
227-(id)subroleAttribute {
228    if ( mActsAsRadioGroup ) {
229        return @"";
230    } else {
231        NSString * subRole = [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ];
232        if ( ! [ subRole isEqualToString: @"" ] ) {
233            return subRole;
234        } else {
235            [ subRole release ];
236            SAL_WNODEPRECATED_DECLARATIONS_PUSH
237                //TODO: 10.10 accessibilityAttributeValue:
238            return [ super accessibilityAttributeValue: NSAccessibilitySubroleAttribute ];
239            SAL_WNODEPRECATED_DECLARATIONS_POP
240        }
241    }
242}
243
244-(id)titleAttribute {
245    return CreateNSString ( [ self accessibleContext ] -> getAccessibleName() );
246}
247
248-(id)descriptionAttribute {
249    if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
250        return [ self titleAttribute ];
251    } else if ( [ self accessibleExtendedComponent ] ) {
252        return [ AquaA11yComponentWrapper descriptionAttributeForElement: self ];
253    } else {
254        return CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() );
255    }
256}
257
258-(id)enabledAttribute {
259    if ( [ self accessibleContext ] -> getAccessibleStateSet().is() ) {
260        return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::ENABLED ) ];
261    } else {
262        return nil;
263    }
264}
265
266-(id)focusedAttribute {
267    if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
268        id isFocused = nil;
269        Reference < XAccessible > rxParent = [ self accessibleContext ] -> getAccessibleParent();
270        if ( rxParent.is() ) {
271            Reference < XAccessibleContext > rxContext = rxParent -> getAccessibleContext();
272            if ( rxContext.is() && rxContext -> getAccessibleStateSet().is() ) {
273                isFocused = [ NSNumber numberWithBool: rxContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::FOCUSED ) ];
274            }
275        }
276        return isFocused;
277    } else if ( [ self accessibleContext ] -> getAccessibleStateSet().is() ) {
278        return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::FOCUSED ) ];
279    } else {
280        return nil;
281    }
282}
283
284-(id)parentAttribute {
285    if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON && ! mActsAsRadioGroup ) {
286        Reference < XAccessible > rxAccessible = [ self getFirstRadioButtonInGroup ];
287        if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
288            Reference < XAccessibleContext > rxAccessibleContext = rxAccessible -> getAccessibleContext();
289            id parent_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: YES asRadioGroup: YES ];
290            [ parent_wrapper autorelease ];
291            return NSAccessibilityUnignoredAncestor( parent_wrapper );
292        }
293        return nil;
294    }
295    try {
296        Reference< XAccessible > xParent( [ self accessibleContext ] -> getAccessibleParent() );
297        if ( xParent.is() ) {
298            Reference< XAccessibleContext > xContext( xParent -> getAccessibleContext() );
299            if ( xContext.is() ) {
300                id parent_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xContext ];
301                [ parent_wrapper autorelease ];
302                return NSAccessibilityUnignoredAncestor( parent_wrapper );
303            }
304        }
305    } catch (const Exception&) {
306    }
307
308    OSL_ASSERT( false );
309    return nil;
310}
311
312-(id)childrenAttribute {
313    if ( mActsAsRadioGroup ) {
314        NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
315        Reference < XAccessibleRelationSet > rxAccessibleRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
316        AccessibleRelation const relationMemberOf = rxAccessibleRelationSet -> getRelationByType ( AccessibleRelationType::MEMBER_OF );
317        if ( relationMemberOf.RelationType == AccessibleRelationType::MEMBER_OF && relationMemberOf.TargetSet.hasElements() ) {
318            for ( const auto& i : relationMemberOf.TargetSet ) {
319                Reference < XAccessible > rMateAccessible( i, UNO_QUERY );
320                if ( rMateAccessible.is() ) {
321                    Reference< XAccessibleContext > rMateAccessibleContext( rMateAccessible -> getAccessibleContext() );
322                    if ( rMateAccessibleContext.is() ) {
323                        id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rMateAccessibleContext ];
324                        [ children addObject: wrapper ];
325                        [ wrapper release ];
326                    }
327                }
328            }
329        }
330        return children;
331    } else if ( [ self accessibleTable ] )
332    {
333        AquaA11yTableWrapper* pTable = [self isKindOfClass: [AquaA11yTableWrapper class]] ? static_cast<AquaA11yTableWrapper*>(self) : nil;
334        return [ AquaA11yTableWrapper childrenAttributeForElement: pTable ];
335    } else {
336        try {
337            NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
338            Reference< XAccessibleContext > xContext( [ self accessibleContext ] );
339
340            sal_Int32 cnt = xContext -> getAccessibleChildCount();
341            for ( sal_Int32 i = 0; i < cnt; i++ ) {
342                Reference< XAccessible > xChild( xContext -> getAccessibleChild( i ) );
343                if( xChild.is() ) {
344                    Reference< XAccessibleContext > xChildContext( xChild -> getAccessibleContext() );
345                    // the menubar is already accessible (including Apple- and Application-Menu) through NSApplication => omit it here
346                    if ( xChildContext.is() && AccessibleRole::MENU_BAR != xChildContext -> getAccessibleRole() ) {
347                        id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xChildContext ];
348                        [ children addObject: wrapper ];
349                        [ wrapper release ];
350                    }
351                }
352            }
353
354            // if not already acting as RadioGroup now is the time to replace RadioButtons with RadioGroups and remove RadioButtons
355            if ( ! mActsAsRadioGroup ) {
356                NSEnumerator * enumerator = [ children objectEnumerator ];
357                AquaA11yWrapper * element;
358                while ( ( element = static_cast<AquaA11yWrapper *>([ enumerator nextObject ]) ) ) {
359                    if ( [ element accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON ) {
360                        if ( [ element isFirstRadioButtonInGroup ] ) {
361                            id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ element accessibleContext ] createIfNotExists: YES asRadioGroup: YES ];
362                            [ children replaceObjectAtIndex: [ children indexOfObjectIdenticalTo: element ] withObject: wrapper ];
363                        }
364                        [ children removeObject: element ];
365                    }
366                }
367            }
368
369            [ children autorelease ];
370            return NSAccessibilityUnignoredChildren( children );
371        } catch (const Exception &) {
372            // TODO: Log
373            return nil;
374        }
375    }
376}
377
378-(id)windowAttribute {
379    // go upstairs until reaching the broken connection
380    AquaA11yWrapper * aWrapper = self;
381    int loops = 0;
382    while ( [ aWrapper accessibleContext ] -> getAccessibleParent().is() ) {
383        AquaA11yWrapper *aTentativeParentWrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ aWrapper accessibleContext ] -> getAccessibleParent() -> getAccessibleContext() ];
384        // Quick-and-dirty fix for infinite loop after fixing crash in
385        // fdo#47275
386        if ( aTentativeParentWrapper == aWrapper )
387            break;
388        // Even dirtier fix for infinite loop in fdo#55156
389        if ( loops++ == 100 )
390            break;
391        aWrapper = aTentativeParentWrapper;
392        [ aWrapper autorelease ];
393    }
394    // get associated NSWindow
395    NSWindow* theWindow = [ aWrapper windowForParent ];
396    return theWindow;
397}
398
399-(id)topLevelUIElementAttribute {
400    return [ self windowAttribute ];
401}
402
403-(id)sizeAttribute {
404    if ( [ self accessibleComponent ] ) {
405        return [ AquaA11yComponentWrapper sizeAttributeForElement: self ];
406    } else {
407        return nil;
408    }
409}
410
411-(id)positionAttribute {
412    if ( [ self accessibleComponent ] ) {
413        return [ AquaA11yComponentWrapper positionAttributeForElement: self ];
414    } else {
415        return nil;
416    }
417}
418
419-(id)helpAttribute {
420    return CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() );
421}
422
423-(id)roleDescriptionAttribute {
424    if ( mActsAsRadioGroup ) {
425        return [ AquaA11yRoleHelper getRoleDescriptionFrom: NSAccessibilityRadioGroupRole with: @"" ];
426	} else if( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON ) {
427		// FIXME: VO should read this because of hierarchy, this is just a workaround
428		// get parent and its children
429		AquaA11yWrapper * parent = [ self parentAttribute ];
430		NSArray * children = [ parent childrenAttribute ];
431		// find index of self
432		int index = 1;
433		NSEnumerator * enumerator = [ children objectEnumerator ];
434		AquaA11yWrapper * child = nil;
435		while ( ( child = [ enumerator nextObject ] ) ) {
436			if ( self == child ) {
437				break;
438			}
439			index++;
440		}
441		// build string
442		NSNumber * nIndex = [ NSNumber numberWithInt: index ];
443		NSNumber * nGroupsize = [ NSNumber numberWithInt: [ children count ] ];
444		NSMutableString * value = [ [ NSMutableString alloc ] init ];
445		[ value appendString: @"radio button " ];
446		[ value appendString: [ nIndex stringValue ] ];
447		[ value appendString: @" of " ];
448		[ value appendString: [ nGroupsize stringValue ] ];
449		// clean up and return string
450		[ nIndex release ];
451		[ nGroupsize release ];
452		[ children release ];
453		return value;
454    } else {
455        return [ AquaA11yRoleHelper getRoleDescriptionFrom:
456                [ AquaA11yRoleHelper getNativeRoleFrom: [ self accessibleContext ] ]
457                with: [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ] ];
458    }
459}
460
461-(id)valueAttribute {
462    if ( [ [ self roleAttribute ] isEqualToString: NSAccessibilityMenuItemRole ] ) {
463        return nil;
464    } else if ( [ self accessibleText ] ) {
465        return [ AquaA11yTextWrapper valueAttributeForElement: self ];
466    } else if ( [ self accessibleValue ] ) {
467        return [ AquaA11yValueWrapper valueAttributeForElement: self ];
468    } else {
469        return nil;
470    }
471}
472
473-(id)minValueAttribute {
474    if ( [ self accessibleValue ] ) {
475        return [ AquaA11yValueWrapper minValueAttributeForElement: self ];
476    } else {
477        return nil;
478    }
479}
480
481-(id)maxValueAttribute {
482    if ( [ self accessibleValue ] ) {
483        return [ AquaA11yValueWrapper maxValueAttributeForElement: self ];
484    } else {
485        return nil;
486    }
487}
488
489-(id)contentsAttribute {
490    return [ self childrenAttribute ];
491}
492
493-(id)selectedChildrenAttribute {
494    return [ AquaA11ySelectionWrapper selectedChildrenAttributeForElement: self ];
495}
496
497-(id)numberOfCharactersAttribute {
498    if ( [ self accessibleText ] ) {
499        return [ AquaA11yTextWrapper numberOfCharactersAttributeForElement: self ];
500    } else {
501        return nil;
502    }
503}
504
505-(id)selectedTextAttribute {
506    if ( [ self accessibleText ] ) {
507        return [ AquaA11yTextWrapper selectedTextAttributeForElement: self ];
508    } else {
509        return nil;
510    }
511}
512
513-(id)selectedTextRangeAttribute {
514    if ( [ self accessibleText ] ) {
515        return [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: self ];
516    } else {
517        return nil;
518    }
519}
520
521-(id)visibleCharacterRangeAttribute {
522    if ( [ self accessibleText ] ) {
523        return [ AquaA11yTextWrapper visibleCharacterRangeAttributeForElement: self ];
524    } else {
525        return nil;
526    }
527}
528
529-(id)tabsAttribute {
530    return self; // TODO ???
531}
532
533-(id)sharedTextUIElementsAttribute {
534    if ( [ self accessibleText ] ) {
535        return [ AquaA11yTextWrapper sharedTextUIElementsAttributeForElement: self ];
536    } else {
537        return nil;
538    }
539}
540
541-(id)sharedCharacterRangeAttribute {
542    if ( [ self accessibleText ] ) {
543        return [ AquaA11yTextWrapper sharedCharacterRangeAttributeForElement: self ];
544    } else {
545        return nil;
546    }
547}
548
549-(id)expandedAttribute {
550    return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::EXPANDED ) ];
551}
552
553-(id)selectedAttribute {
554    return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::SELECTED ) ];
555}
556
557-(id)stringForRangeAttributeForParameter:(id)range {
558    if ( [ self accessibleText ] ) {
559        return [ AquaA11yTextWrapper stringForRangeAttributeForElement: self forParameter: range ];
560    } else {
561        return nil;
562    }
563}
564
565-(id)attributedStringForRangeAttributeForParameter:(id)range {
566    if ( [ self accessibleText ] ) {
567        return [ AquaA11yTextWrapper attributedStringForRangeAttributeForElement: self forParameter: range ];
568    } else {
569        return nil;
570    }
571}
572
573-(id)rangeForIndexAttributeForParameter:(id)index {
574    if ( [ self accessibleText ] ) {
575        return [ AquaA11yTextWrapper rangeForIndexAttributeForElement: self forParameter: index ];
576    } else {
577        return nil;
578    }
579}
580
581-(id)rangeForPositionAttributeForParameter:(id)point {
582    if ( [ self accessibleText ] ) {
583        return [ AquaA11yTextWrapper rangeForPositionAttributeForElement: self forParameter: point ];
584    } else {
585        return nil;
586    }
587}
588
589-(id)boundsForRangeAttributeForParameter:(id)range {
590    if ( [ self accessibleText ] ) {
591        return [ AquaA11yTextWrapper boundsForRangeAttributeForElement: self forParameter: range ];
592    } else {
593        return nil;
594    }
595}
596
597-(id)styleRangeForIndexAttributeForParameter:(id)index {
598    if ( [ self accessibleText ] ) {
599        return [ AquaA11yTextWrapper styleRangeForIndexAttributeForElement: self forParameter: index ];
600    } else {
601        return nil;
602    }
603}
604
605-(id)rTFForRangeAttributeForParameter:(id)range {
606    if ( [ self accessibleText ] ) {
607        return [ AquaA11yTextWrapper rTFForRangeAttributeForElement: self forParameter: range ];
608    } else {
609        return nil;
610    }
611}
612
613-(id)orientationAttribute {
614    NSString * orientation = nil;
615    Reference < XAccessibleStateSet > stateSet = [ self accessibleContext ] -> getAccessibleStateSet();
616    if ( stateSet -> contains ( AccessibleStateType::HORIZONTAL ) ) {
617        orientation = NSAccessibilityHorizontalOrientationValue;
618    } else if ( stateSet -> contains ( AccessibleStateType::VERTICAL ) ) {
619        orientation = NSAccessibilityVerticalOrientationValue;
620    }
621    return orientation;
622}
623
624-(id)titleUIElementAttribute {
625    if ( [ self accessibleContext ] -> getAccessibleRelationSet().is() ) {
626        NSString * title = [ self titleAttribute ];
627        id titleElement = nil;
628        if ( [ title length ] == 0 ) {
629            AccessibleRelation relationLabeledBy = [ self accessibleContext ] -> getAccessibleRelationSet() -> getRelationByType ( AccessibleRelationType::LABELED_BY );
630            if ( relationLabeledBy.RelationType == AccessibleRelationType::LABELED_BY && relationLabeledBy.TargetSet.hasElements()  ) {
631                Reference < XAccessible > rxAccessible ( relationLabeledBy.TargetSet[0], UNO_QUERY );
632                titleElement = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessible -> getAccessibleContext() ];
633            }
634        }
635        if ( title ) {
636            [ title release ];
637        }
638        return titleElement;
639    } else {
640        return nil;
641    }
642}
643
644-(id)servesAsTitleForUIElementsAttribute {
645    if ( [ self accessibleContext ] -> getAccessibleRelationSet().is() ) {
646        id titleForElement = nil;
647        AccessibleRelation relationLabelFor = [ self accessibleContext ] -> getAccessibleRelationSet() -> getRelationByType ( AccessibleRelationType::LABEL_FOR );
648        if ( relationLabelFor.RelationType == AccessibleRelationType::LABEL_FOR && relationLabelFor.TargetSet.hasElements() ) {
649            Reference < XAccessible > rxAccessible ( relationLabelFor.TargetSet[0], UNO_QUERY );
650            titleForElement = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessible -> getAccessibleContext() ];
651        }
652        return titleForElement;
653    } else {
654        return nil;
655    }
656}
657
658-(id)lineForIndexAttributeForParameter:(id)index {
659    if ( [ self accessibleMultiLineText ] ) {
660        return [ AquaA11yTextWrapper lineForIndexAttributeForElement: self forParameter: index ];
661    } else {
662        return nil;
663    }
664}
665
666-(id)rangeForLineAttributeForParameter:(id)line {
667    if ( [ self accessibleMultiLineText ] ) {
668        return [ AquaA11yTextWrapper rangeForLineAttributeForElement: self forParameter: line ];
669    } else {
670        return nil;
671    }
672}
673
674#pragma mark -
675#pragma mark Accessibility Protocol
676
677-(id)accessibilityAttributeValue:(NSString *)attribute {
678    SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeValue:" << attribute << "]");
679    // #i90575# guard NSAccessibility protocol against unwanted access
680    if ( isPopupMenuOpen ) {
681        return nil;
682    }
683
684    id value = nil;
685    // if we are no longer in the wrapper repository, we have been disposed
686    AquaA11yWrapper * theWrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ self accessibleContext ] createIfNotExists: NO ];
687    if ( theWrapper || mIsTableCell ) {
688        try {
689            SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: NO ];
690            if ( [ self respondsToSelector: methodSelector ] ) {
691                value = [ self performSelector: methodSelector ];
692            }
693        } catch ( const DisposedException & ) {
694            mIsTableCell = NO; // just to be sure
695            [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ];
696            return nil;
697        } catch ( const Exception & ) {
698            // empty
699        }
700    }
701    if ( theWrapper ) {
702        [ theWrapper release ]; // the above called method calls retain on the returned Wrapper
703    }
704    return value;
705}
706
707-(BOOL)accessibilityIsIgnored {
708    SAL_INFO("vcl.a11y", "[" << self << " accessibilityIsIgnored]");
709    // #i90575# guard NSAccessibility protocol against unwanted access
710    if ( isPopupMenuOpen ) {
711        return NO;
712    }
713    bool ignored = false;
714    sal_Int16 nRole = [ self accessibleContext ] -> getAccessibleRole();
715    switch ( nRole ) {
716        //case AccessibleRole::PANEL:
717        case AccessibleRole::FRAME:
718        case AccessibleRole::ROOT_PANE:
719        case AccessibleRole::SEPARATOR:
720        case AccessibleRole::FILLER:
721        case AccessibleRole::DIALOG:
722            ignored = true;
723            break;
724        default:
725            ignored = ! ( [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::VISIBLE ) );
726            break;
727    }
728    return ignored; // TODO: to be completed
729}
730
731-(NSArray *)accessibilityAttributeNames {
732    SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeNames]");
733    // #i90575# guard NSAccessibility protocol against unwanted access
734    if ( isPopupMenuOpen ) {
735        return nil;
736    }
737    NSString * nativeSubrole = nil;
738    NSString * title = nil;
739    NSMutableArray * attributeNames = nil;
740    sal_Int32 nAccessibleChildren = 0;
741    try {
742        // Default Attributes
743        attributeNames = [ NSMutableArray arrayWithObjects:
744            NSAccessibilityRoleAttribute,
745            NSAccessibilityDescriptionAttribute,
746            NSAccessibilityParentAttribute,
747            NSAccessibilityWindowAttribute,
748            NSAccessibilityHelpAttribute,
749            NSAccessibilityTopLevelUIElementAttribute,
750            NSAccessibilityRoleDescriptionAttribute,
751            nil ];
752        nativeSubrole = static_cast<NSString *>([ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ]);
753        title = static_cast<NSString *>([ self titleAttribute ]);
754        Reference < XAccessibleRelationSet > rxRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
755        // Special Attributes depending on attribute values
756        if ( nativeSubrole && ! [ nativeSubrole isEqualToString: @"" ] ) {
757            [ attributeNames addObject: NSAccessibilitySubroleAttribute ];
758        }
759        try
760        {
761            nAccessibleChildren = [ self accessibleContext ] -> getAccessibleChildCount();
762            if (  nAccessibleChildren > 0 ) {
763                [ attributeNames addObject: NSAccessibilityChildrenAttribute ];
764        }
765        }
766        catch( DisposedException& ) {}
767        catch( RuntimeException& ) {}
768
769        if ( title && ! [ title isEqualToString: @"" ] ) {
770            [ attributeNames addObject: NSAccessibilityTitleAttribute ];
771        }
772        if ( [ title length ] == 0 && rxRelationSet.is() && rxRelationSet -> containsRelation ( AccessibleRelationType::LABELED_BY ) ) {
773            [ attributeNames addObject: NSAccessibilityTitleUIElementAttribute ];
774        }
775        if ( rxRelationSet.is() && rxRelationSet -> containsRelation ( AccessibleRelationType::LABEL_FOR ) ) {
776            [ attributeNames addObject: NSAccessibilityServesAsTitleForUIElementsAttribute ];
777        }
778        // Special Attributes depending on interface
779        if( [self accessibleContext ] -> getAccessibleRole() == AccessibleRole::TABLE )
780            [AquaA11yTableWrapper addAttributeNamesTo: attributeNames object: self];
781
782        if ( [ self accessibleText ] ) {
783            [ AquaA11yTextWrapper addAttributeNamesTo: attributeNames ];
784        }
785        if ( [ self accessibleComponent ] ) {
786            [ AquaA11yComponentWrapper addAttributeNamesTo: attributeNames ];
787        }
788        if ( [ self accessibleSelection ] ) {
789            [ AquaA11ySelectionWrapper addAttributeNamesTo: attributeNames ];
790        }
791        if ( [ self accessibleValue ] ) {
792            [ AquaA11yValueWrapper addAttributeNamesTo: attributeNames ];
793        }
794        [ nativeSubrole release ];
795        [ title release ];
796        return attributeNames;
797    } catch ( DisposedException & ) { // Object is no longer available
798        if ( nativeSubrole ) {
799            [ nativeSubrole release ];
800        }
801        if ( title ) {
802            [ title release ];
803        }
804        if ( attributeNames ) {
805            [ attributeNames release ];
806        }
807        [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ];
808        return [ [ NSArray alloc ] init ];
809    }
810}
811
812-(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
813    SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeIsSettable:" << attribute << "]");
814    bool isSettable = false;
815    if ( [ self accessibleText ] ) {
816        isSettable = [ AquaA11yTextWrapper isAttributeSettable: attribute forElement: self ];
817    }
818    if ( ! isSettable && [ self accessibleComponent ] ) {
819        isSettable = [ AquaA11yComponentWrapper isAttributeSettable: attribute forElement: self ];
820    }
821    if ( ! isSettable && [ self accessibleSelection ] ) {
822        isSettable = [ AquaA11ySelectionWrapper isAttributeSettable: attribute forElement: self ];
823    }
824    if ( ! isSettable && [ self accessibleValue ] ) {
825        isSettable = [ AquaA11yValueWrapper isAttributeSettable: attribute forElement: self ];
826    }
827    return isSettable; // TODO: to be completed
828}
829
830-(NSArray *)accessibilityParameterizedAttributeNames {
831    SAL_INFO("vcl.a11y", "[" << self << " accessibilityParameterizedAttributeNames]");
832    NSMutableArray * attributeNames = [ [ NSMutableArray alloc ] init ];
833    // Special Attributes depending on interface
834    if ( [ self accessibleText ] ) {
835        [ AquaA11yTextWrapper addParameterizedAttributeNamesTo: attributeNames ];
836    }
837    return attributeNames; // TODO: to be completed
838}
839
840-(id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
841    SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeValue:" << attribute << " forParameter:" << (static_cast<NSObject*>(parameter)) << "]");
842    SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: YES ];
843    if ( [ self respondsToSelector: methodSelector ] ) {
844        return [ self performSelector: methodSelector withObject: parameter ];
845    }
846    return nil; // TODO: to be completed
847}
848
849-(BOOL)accessibilitySetOverrideValue:(id)value forAttribute:(NSString *)attribute
850{
851    SAL_INFO("vcl.a11y", "[" << self << " accessibilitySetOverrideValue:" << (static_cast<NSObject*>(value)) << " forAttribute:" << attribute << "]");
852    return NO; // TODO
853}
854
855-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
856    SAL_INFO("vcl.a11y", "[" << self << " accessibilitySetValue:" << (static_cast<NSObject*>(value)) << " forAttribute:" << attribute << "]");
857    SEL methodSelector = [ self selectorForAttribute: attribute asGetter: NO withGetterParameter: NO ];
858    if ( [ AquaA11yComponentWrapper respondsToSelector: methodSelector ] ) {
859        [ AquaA11yComponentWrapper performSelector: methodSelector withObject: self withObject: value ];
860    }
861    if ( [ AquaA11yTextWrapper respondsToSelector: methodSelector ] ) {
862        [ AquaA11yTextWrapper performSelector: methodSelector withObject: self withObject: value ];
863    }
864    if ( [ AquaA11ySelectionWrapper respondsToSelector: methodSelector ] ) {
865        [ AquaA11ySelectionWrapper performSelector: methodSelector withObject: self withObject: value ];
866    }
867    if ( [ AquaA11yValueWrapper respondsToSelector: methodSelector ] ) {
868        [ AquaA11yValueWrapper performSelector: methodSelector withObject: self withObject: value ];
869    }
870}
871
872-(id)accessibilityFocusedUIElement {
873    SAL_INFO("vcl.a11y", "[" << self << " accessibilityFocusedUIElement]");
874    // #i90575# guard NSAccessibility protocol against unwanted access
875    if ( isPopupMenuOpen ) {
876        return nil;
877    }
878
879    // as this seems to be the first API call on a newly created SalFrameView object,
880    // make sure self gets registered in the repository ..
881    [ self accessibleContext ];
882
883    AquaA11yWrapper * focusedUIElement = AquaA11yFocusListener::get()->getFocusedUIElement();
884//    AquaA11yWrapper * ancestor = focusedUIElement;
885
886      // Make sure the focused object is a descendant of self
887//    do  {
888//       if( self == ancestor )
889    return focusedUIElement;
890
891//       ancestor = [ ancestor accessibilityAttributeValue: NSAccessibilityParentAttribute ];
892//    }  while( nil != ancestor );
893
894    return self;
895}
896
897-(NSString *)accessibilityActionDescription:(NSString *)action {
898    SAL_INFO("vcl.a11y", "[" << self << " accessibilityActionDescription:" << action << "]");
899    return NSAccessibilityActionDescription(action);
900}
901
902-(AquaA11yWrapper *)actionResponder {
903    AquaA11yWrapper * wrapper = nil;
904    // get some information
905    NSString * role = static_cast<NSString *>([ self accessibilityAttributeValue: NSAccessibilityRoleAttribute ]);
906    id enabledAttr = [ self enabledAttribute ];
907    bool enabled = [ enabledAttr boolValue ];
908    NSView * parent = static_cast<NSView *>([ self accessibilityAttributeValue: NSAccessibilityParentAttribute ]);
909    AquaA11yWrapper * parentAsWrapper = nil;
910    if ( [ parent isKindOfClass: [ AquaA11yWrapper class ] ] ) {
911        parentAsWrapper = static_cast<AquaA11yWrapper *>(parent);
912    }
913    SAL_WNODEPRECATED_DECLARATIONS_PUSH
914        //TODO: 10.10 accessibilityAttributeValue:
915    NSString * parentRole = static_cast<NSString *>([ parent accessibilityAttributeValue: NSAccessibilityRoleAttribute ]);
916    SAL_WNODEPRECATED_DECLARATIONS_POP
917    // if we are a textarea inside a combobox, then the combobox is the action responder
918    if ( enabled
919      && [ role isEqualToString: NSAccessibilityTextAreaRole ]
920      && [ parentRole isEqualToString: NSAccessibilityComboBoxRole ]
921      && parentAsWrapper ) {
922        wrapper = parentAsWrapper;
923    } else if ( enabled && [ self accessibleAction ] ) {
924        wrapper = self ;
925    }
926    [ parentRole release ];
927    [ enabledAttr release ];
928    [ role release ];
929    return wrapper;
930}
931
932-(void)accessibilityPerformAction:(NSString *)action {
933    SAL_INFO("vcl.a11y", "[" << self << " accessibilityPerformAction:" << action << "]");
934    AquaA11yWrapper * actionResponder = [ self actionResponder ];
935    if ( actionResponder ) {
936        [ AquaA11yActionWrapper doAction: action ofElement: actionResponder ];
937    }
938}
939
940-(NSArray *)accessibilityActionNames {
941    SAL_INFO("vcl.a11y", "[" << self << " accessibilityActionNames]");
942    NSArray * actionNames = nil;
943    AquaA11yWrapper * actionResponder = [ self actionResponder ];
944    if ( actionResponder ) {
945        actionNames = [ AquaA11yActionWrapper actionNamesForElement: actionResponder ];
946    } else {
947        actionNames = [ [ NSArray alloc ] init ];
948    }
949    return actionNames;
950}
951
952#pragma mark -
953#pragma mark Hit Test
954
955-(BOOL)isViewElement:(NSObject *)viewElement hitByPoint:(NSPoint)point {
956    bool hit = false;
957    NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
958    SAL_WNODEPRECATED_DECLARATIONS_PUSH
959        //TODO: 10.10 accessibilityAttributeValue:
960    NSValue * position = [ viewElement accessibilityAttributeValue: NSAccessibilityPositionAttribute ];
961    NSValue * size = [ viewElement accessibilityAttributeValue: NSAccessibilitySizeAttribute ];
962    SAL_WNODEPRECATED_DECLARATIONS_POP
963    if ( position && size ) {
964        float minX = [ position pointValue ].x;
965        float minY = [ position pointValue ].y;
966        float maxX = minX + [ size sizeValue ].width;
967        float maxY = minY + [ size sizeValue ].height;
968        if ( minX < point.x && maxX > point.x && minY < point.y && maxY > point.y ) {
969            hit = true;
970        }
971    }
972    [ pool release ];
973    return hit;
974}
975
976static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point,
977                                                 Reference < XAccessibleContext > const & rxAccessibleContext ) {
978    Reference < XAccessibleContext > hitChild;
979    Reference < XAccessibleContext > emptyReference;
980    try {
981        Reference < XAccessibleComponent > rxAccessibleComponent ( rxAccessibleContext, UNO_QUERY );
982        if ( rxAccessibleComponent.is() ) {
983            css::awt::Point location = rxAccessibleComponent -> getLocationOnScreen();
984            css::awt::Point hitPoint ( point.X - location.X , point.Y - location.Y);
985            Reference < XAccessible > rxAccessible = rxAccessibleComponent -> getAccessibleAtPoint ( hitPoint );
986            if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() &&
987                 rxAccessible -> getAccessibleContext() -> getAccessibleChildCount() == 0 ) {
988                hitChild = rxAccessible -> getAccessibleContext();
989            }
990        }
991
992        // iterate the hierarchy looking doing recursive hit testing.
993        // apparently necessary as a special treatment for e.g. comboboxes
994        if ( !hitChild.is() ) {
995            bool bSafeToIterate = true;
996            sal_Int32 nCount = rxAccessibleContext -> getAccessibleChildCount();
997
998            if (nCount < 0 || nCount > SAL_MAX_UINT16 /* slow enough for anyone */)
999                bSafeToIterate = false;
1000            else { // manages descendants is an horror from the a11y standards guys.
1001                Reference< XAccessibleStateSet > xStateSet;
1002                xStateSet = rxAccessibleContext -> getAccessibleStateSet();
1003                if (xStateSet.is() && xStateSet -> contains(AccessibleStateType::MANAGES_DESCENDANTS ) )
1004                    bSafeToIterate = false;
1005            }
1006
1007            if( bSafeToIterate ) {
1008                for ( int i = 0; i < rxAccessibleContext -> getAccessibleChildCount(); i++ ) {
1009                    Reference < XAccessible > rxAccessibleChild = rxAccessibleContext -> getAccessibleChild ( i );
1010                    if ( rxAccessibleChild.is() && rxAccessibleChild -> getAccessibleContext().is() && rxAccessibleChild -> getAccessibleContext() -> getAccessibleRole() != AccessibleRole::LIST ) {
1011                        Reference < XAccessibleContext > myHitChild = hitTestRunner ( point, rxAccessibleChild -> getAccessibleContext() );
1012                        if ( myHitChild.is() ) {
1013                            hitChild = myHitChild;
1014                            break;
1015                        }
1016                    }
1017                }
1018            }
1019        }
1020    } catch ( RuntimeException ) {
1021        return emptyReference;
1022    }
1023    return hitChild;
1024}
1025
1026-(id)accessibilityHitTest:(NSPoint)point {
1027    SAL_INFO("vcl.a11y", "[" << self << " accessibilityHitTest:" << point << "]");
1028    static id wrapper = nil;
1029    if ( nil != wrapper ) {
1030        [ wrapper release ];
1031        wrapper = nil;
1032    }
1033    Reference < XAccessibleContext > hitChild;
1034    NSRect screenRect = [ [ NSScreen mainScreen ] frame ];
1035    css::awt::Point hitPoint ( static_cast<sal_Int32>(point.x) , static_cast<sal_Int32>(screenRect.size.height - point.y) );
1036    // check child windows first
1037    NSWindow * window = static_cast<NSWindow *>([ self accessibilityAttributeValue: NSAccessibilityWindowAttribute ]);
1038    NSArray * childWindows = [ window childWindows ];
1039    if ( [ childWindows count ] > 0 ) {
1040        NSWindow * element = nil;
1041        NSEnumerator * enumerator = [ childWindows objectEnumerator ];
1042        while ( ( element = [ enumerator nextObject ] ) && !hitChild.is() ) {
1043            if ( [ element isKindOfClass: [ SalFrameWindow class ] ] && [ self isViewElement: element hitByPoint: point ] ) {
1044                // we have a child window that is hit
1045                Reference < XAccessibleRelationSet > relationSet = [ static_cast<SalFrameWindow *>(element) accessibleContext ] -> getAccessibleRelationSet();
1046                if ( relationSet.is() && relationSet -> containsRelation ( AccessibleRelationType::SUB_WINDOW_OF )) {
1047                    // we have a valid relation to the parent element
1048                    AccessibleRelation const relation = relationSet -> getRelationByType ( AccessibleRelationType::SUB_WINDOW_OF );
1049                    for ( const auto & i : relation.TargetSet ) {
1050                        Reference < XAccessible > rxAccessible ( i, UNO_QUERY );
1051                        if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
1052                            // hit test for children of parent
1053                            hitChild = hitTestRunner ( hitPoint, rxAccessible -> getAccessibleContext() );
1054                            if (hitChild.is())
1055                                break;
1056                        }
1057                    }
1058                }
1059            }
1060        }
1061    }
1062    // nothing hit yet, so check ourself
1063    if ( ! hitChild.is() ) {
1064        if ( !mpReferenceWrapper ) {
1065            [ self setDefaults: [ self accessibleContext ] ];
1066        }
1067        hitChild = hitTestRunner ( hitPoint, mpReferenceWrapper -> rAccessibleContext );
1068    }
1069    if ( hitChild.is() ) {
1070        wrapper = [ AquaA11yFactory wrapperForAccessibleContext: hitChild ];
1071    }
1072    if ( wrapper ) {
1073        [ wrapper retain ]; // TODO: retain only when transient ?
1074    }
1075    return wrapper;
1076}
1077
1078#pragma mark -
1079#pragma mark Access Methods
1080
1081-(XAccessibleAction *)accessibleAction {
1082    return mpReferenceWrapper -> rAccessibleAction.get();
1083}
1084
1085-(XAccessibleContext *)accessibleContext {
1086    return mpReferenceWrapper -> rAccessibleContext.get();
1087}
1088
1089-(XAccessibleComponent *)accessibleComponent {
1090    return mpReferenceWrapper -> rAccessibleComponent.get();
1091}
1092
1093-(XAccessibleExtendedComponent *)accessibleExtendedComponent {
1094    return mpReferenceWrapper -> rAccessibleExtendedComponent.get();
1095}
1096
1097-(XAccessibleSelection *)accessibleSelection {
1098    return mpReferenceWrapper -> rAccessibleSelection.get();
1099}
1100
1101-(XAccessibleTable *)accessibleTable {
1102    return mpReferenceWrapper -> rAccessibleTable.get();
1103}
1104
1105-(XAccessibleText *)accessibleText {
1106    return mpReferenceWrapper -> rAccessibleText.get();
1107}
1108
1109-(XAccessibleEditableText *)accessibleEditableText {
1110    return mpReferenceWrapper -> rAccessibleEditableText.get();
1111}
1112
1113-(XAccessibleValue *)accessibleValue {
1114    return mpReferenceWrapper -> rAccessibleValue.get();
1115}
1116
1117-(XAccessibleTextAttributes *)accessibleTextAttributes {
1118    return mpReferenceWrapper -> rAccessibleTextAttributes.get();
1119}
1120
1121-(XAccessibleMultiLineText *)accessibleMultiLineText {
1122    return mpReferenceWrapper -> rAccessibleMultiLineText.get();
1123}
1124
1125-(XAccessibleTextMarkup *)accessibleTextMarkup {
1126    return mpReferenceWrapper -> rAccessibleTextMarkup.get();
1127}
1128
1129-(NSWindow*)windowForParent {
1130    return [self window];
1131}
1132
1133-(void)setActsAsRadioGroup:(BOOL)actsAsRadioGroup {
1134    mActsAsRadioGroup = actsAsRadioGroup;
1135}
1136
1137-(BOOL)actsAsRadioGroup {
1138    return mActsAsRadioGroup;
1139}
1140
1141+(void)setPopupMenuOpen:(BOOL)popupMenuOpen {
1142    isPopupMenuOpen = popupMenuOpen;
1143}
1144
1145@end
1146
1147/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1148