update dev300-m58
[ooovba.git] / vcl / aqua / source / a11y / aqua11ywrapper.mm
blob99bcbd20f69848c7743555a0477dfc671f041951
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  * 
5  * Copyright 2008 by Sun Microsystems, Inc.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * $RCSfile: aqua11ywrapper.mm,v $
10  *
11  * $Revision: 1.3 $
12  *
13  * This file is part of OpenOffice.org.
14  *
15  * OpenOffice.org is free software: you can redistribute it and/or modify
16  * it under the terms of the GNU Lesser General Public License version 3
17  * only, as published by the Free Software Foundation.
18  *
19  * OpenOffice.org is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Lesser General Public License version 3 for more details
23  * (a copy is included in the LICENSE file that accompanied this code).
24  *
25  * You should have received a copy of the GNU Lesser General Public License
26  * version 3 along with OpenOffice.org.  If not, see
27  * <http://www.openoffice.org/license.html>
28  * for a copy of the LGPLv3 License.
29  *
30  ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_vcl.hxx"
35 #include "salinst.h"
36 #include "aqua11ywrapper.h"
37 #include "aqua11yactionwrapper.h"
38 #include "aqua11ycomponentwrapper.h"
39 #include "aqua11ylistener.hxx"
40 #include "aqua11yselectionwrapper.h"
41 #include "aqua11ytablewrapper.h"
42 #include "aqua11ytextwrapper.h"
43 #include "aqua11yvaluewrapper.h"
44 #include "aqua11yfactory.h"
45 #include "aqua11yfocuslistener.hxx"
46 #include "aqua11yfocustracker.hxx"
47 #include "aqua11yrolehelper.h"
48 #include <com/sun/star/accessibility/AccessibleRole.hpp>
49 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
50 #include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
51 #include <com/sun/star/awt/Size.hpp>
52 #include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
53 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
54 #include <com/sun/star/lang/DisposedException.hpp>
56 using namespace ::com::sun::star::accessibility;
57 using namespace ::com::sun::star::awt;
58 using namespace ::com::sun::star::lang;
59 using namespace ::com::sun::star::uno;
61 @interface SalFrameWindow : NSWindow
64 -(Reference<XAccessibleContext>)accessibleContext;
65 @end
67 static MacOSBOOL isPopupMenuOpen = NO;
69 @implementation AquaA11yWrapper : NSView
71 #pragma mark -
72 #pragma mark Init and dealloc
74 -(id)initWithAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
75     self = [ super init ];
76     if ( self != nil ) {
77         [ self setDefaults: rxAccessibleContext ];
78     }
79     return self;
82 -(void) setDefaults: (Reference < XAccessibleContext >) rxAccessibleContext {
83     mDefaultFontsize = 0.0;
84     mpDefaultFontname = nil;
85     mpReferenceWrapper = new ReferenceWrapper;
86     mActsAsRadioGroup = NO;
87     mpReferenceWrapper -> rAccessibleContext = rxAccessibleContext;
88     mIsTableCell = NO;
89     // Querying all supported interfaces
90     try {
91         // XAccessibleComponent
92         mpReferenceWrapper -> rAccessibleComponent = Reference < XAccessibleComponent > ( rxAccessibleContext, UNO_QUERY );
93         // XAccessibleExtendedComponent
94         mpReferenceWrapper -> rAccessibleExtendedComponent = Reference < XAccessibleExtendedComponent > ( rxAccessibleContext, UNO_QUERY );
95         // XAccessibleSelection
96         mpReferenceWrapper -> rAccessibleSelection = Reference< XAccessibleSelection > ( rxAccessibleContext, UNO_QUERY );
97         // XAccessibleTable
98         mpReferenceWrapper -> rAccessibleTable = Reference < XAccessibleTable > ( rxAccessibleContext, UNO_QUERY );
99         // XAccessibleText
100         mpReferenceWrapper -> rAccessibleText = Reference < XAccessibleText > ( rxAccessibleContext, UNO_QUERY );
101         // XAccessibleEditableText
102         mpReferenceWrapper -> rAccessibleEditableText = Reference < XAccessibleEditableText > ( rxAccessibleContext, UNO_QUERY );
103         // XAccessibleValue
104         mpReferenceWrapper -> rAccessibleValue = Reference < XAccessibleValue > ( rxAccessibleContext, UNO_QUERY );
105         // XAccessibleAction
106         mpReferenceWrapper -> rAccessibleAction = Reference < XAccessibleAction > ( rxAccessibleContext, UNO_QUERY );
107         // XAccessibleTextAttributes
108         mpReferenceWrapper -> rAccessibleTextAttributes = Reference < XAccessibleTextAttributes > ( rxAccessibleContext, UNO_QUERY );
109         // XAccessibleMultiLineText
110         mpReferenceWrapper -> rAccessibleMultiLineText = Reference < XAccessibleMultiLineText > ( rxAccessibleContext, UNO_QUERY );
111         // XAccessibleEventBroadcaster
112         if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) ) {
113             Reference< XAccessibleEventBroadcaster > xBroadcaster(rxAccessibleContext, UNO_QUERY);
114             if( xBroadcaster.is() ) {
115                 /*
116                  * We intentionally do not hold a reference to the event listener in the wrapper object,
117                  * but let the listener control the life cycle of the wrapper instead ..
118                  */
119                 xBroadcaster->addEventListener( new AquaA11yEventListener( self, rxAccessibleContext -> getAccessibleRole() ) );
120             }
121         }
122         // TABLE_CELL
123         if ( rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TABLE_CELL ) {
124             mIsTableCell = YES;
125         }
126     } catch ( const Exception ) {
127     }
130 -(void)dealloc {
131     if ( mpReferenceWrapper != nil ) {
132         delete mpReferenceWrapper;
133     }
134     if ( mpDefaultFontname != nil ) {
135         [ mpDefaultFontname release ];
136     }
137     [ super dealloc ];
140 #pragma mark -
141 #pragma mark Utility Section
143 // generates selectors for attribute name AXAttributeNameHere
144 // (getter without parameter) attributeNameHereAttribute
145 // (getter with parameter)    attributeNameHereAttributeForParameter:
146 // (setter)                   setAttributeNameHereAttributeForElement:to:
147 -(SEL)selectorForAttribute:(NSString *)attribute asGetter:(MacOSBOOL)asGetter withGetterParameter:(MacOSBOOL)withGetterParameter {
148     SEL selector = nil;
149     NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
150     @try {
151         // step 1: create method name from attribute name
152         NSMutableString * methodName = [ NSMutableString string ];
153         if ( ! asGetter ) {
154             [ methodName appendString: @"set" ];
155         }
156         NSString * firstChar = [ attribute substringWithRange: NSMakeRange ( 2, 1 ) ]; // drop leading "AX" and get first char
157         if ( asGetter ) {
158             [ methodName appendString: [ firstChar lowercaseString ] ]; 
159         } else {
160             [ methodName appendString: firstChar ]; 
161         }
162         [ methodName appendString: [ attribute substringFromIndex: 3 ] ]; // append rest of attribute name
163         // append rest of method name
164         [ methodName appendString: @"Attribute" ];
165         if ( ! asGetter ) {
166             [ methodName appendString: @"ForElement:to:" ];
167         } else if ( asGetter && withGetterParameter ) {
168             [ methodName appendString: @"ForParameter:" ];
169         }
170         // step 2: create selector
171         selector = NSSelectorFromString ( methodName );
172     } @catch ( id exception ) {
173         selector = nil;
174     }
175     [ pool release ];
176     return selector;
179 -(Reference < XAccessible >)getFirstRadioButtonInGroup {
180     Reference < XAccessibleRelationSet > rxAccessibleRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
181     if( rxAccessibleRelationSet.is() )
182     {
183         AccessibleRelation relationMemberOf = rxAccessibleRelationSet -> getRelationByType ( AccessibleRelationType::MEMBER_OF );
184         if ( relationMemberOf.RelationType == AccessibleRelationType::MEMBER_OF && relationMemberOf.TargetSet.hasElements() )
185             return Reference < XAccessible > ( relationMemberOf.TargetSet[0], UNO_QUERY );
186     }
187     return Reference < XAccessible > ();
190 -(MacOSBOOL)isFirstRadioButtonInGroup {
191     Reference < XAccessible > rFirstMateAccessible = [ self getFirstRadioButtonInGroup ];
192     if ( rFirstMateAccessible.is() && rFirstMateAccessible -> getAccessibleContext().get() == [ self accessibleContext ] ) {
193         return YES;
194     }
195     return NO;
198 #pragma mark -
199 #pragma mark Attribute Value Getters
200 // ( called via Reflection by accessibilityAttributeValue )
203     Radiobutton grouping is done differently in NSAccessibility and the UNO-API. In UNO related radio buttons share an entry in their
204     RelationSet. In NSAccessibility the relationship is axpressed through the hierarchy. A AXRadioGroup contains two or more AXRadioButton 
205     objects. Since this group is not available in the UNO hierarchy, an extra wrapper is used for it. This wrapper shares almost all 
206     attributes with the first radio button of the group, except for the role, subrole, role description, parent and children attributes. 
207     So in this five methods there is a special treatment for radio buttons and groups.
210 -(id)roleAttribute {
211     if ( mActsAsRadioGroup ) {
212         return NSAccessibilityRadioGroupRole;
213     } else {
214         return [ AquaA11yRoleHelper getNativeRoleFrom: [ self accessibleContext ] ];
215     }
218 -(id)subroleAttribute {
219     if ( mActsAsRadioGroup ) {
220         return @"";
221     } else {
222         NSString * subRole = [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ];
223         if ( ! [ subRole isEqualToString: @"" ] ) {
224             return subRole;
225         } else {
226             [ subRole release ];
227             return [ super accessibilityAttributeValue: NSAccessibilitySubroleAttribute ];
228         }
229     }
232 -(id)titleAttribute {
233     return CreateNSString ( [ self accessibleContext ] -> getAccessibleName() );
236 -(id)descriptionAttribute {
237     if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
238         return [ self titleAttribute ];
239     } else if ( [ self accessibleExtendedComponent ] != nil ) {
240         return [ AquaA11yComponentWrapper descriptionAttributeForElement: self ];
241     } else {
242         return CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() );
243     }
246 -(id)enabledAttribute {
247     if ( [ self accessibleContext ] -> getAccessibleStateSet().is() ) {
248         return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::ENABLED ) ];
249     } else {
250         return nil;
251     }
254 -(id)focusedAttribute {
255     if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
256         id isFocused = nil;
257         Reference < XAccessible > rxParent = [ self accessibleContext ] -> getAccessibleParent();
258         if ( rxParent.is() ) {
259             Reference < XAccessibleContext > rxContext = rxParent -> getAccessibleContext();
260             if ( rxContext.is() && rxContext -> getAccessibleStateSet().is() ) {
261                 isFocused = [ NSNumber numberWithBool: rxContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::FOCUSED ) ];
262             }
263         }
264         return isFocused;
265     } else if ( [ self accessibleContext ] -> getAccessibleStateSet().is() ) {
266         return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::FOCUSED ) ];
267     } else {
268         return nil;
269     }
272 -(id)parentAttribute {
273     if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON && ! mActsAsRadioGroup ) {
274         Reference < XAccessible > rxAccessible = [ self getFirstRadioButtonInGroup ];
275         if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
276             Reference < XAccessibleContext > rxAccessibleContext = rxAccessible -> getAccessibleContext();
277             id parent_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: YES asRadioGroup: YES ];
278             [ parent_wrapper autorelease ];
279             return NSAccessibilityUnignoredAncestor( parent_wrapper );
280         }
281         return nil;
282     }
283     try {
284         Reference< XAccessible > xParent( [ self accessibleContext ] -> getAccessibleParent() );
285         if ( xParent.is() ) {
286             Reference< XAccessibleContext > xContext( xParent -> getAccessibleContext() );
287             if ( xContext.is() ) {
288                 id parent_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xContext ];
289                 [ parent_wrapper autorelease ];
290                 return NSAccessibilityUnignoredAncestor( parent_wrapper );
291             }
292         }
293     } catch (const Exception&) {
294     }
295     
296     OSL_ASSERT( 0 );
297     return nil;
300 -(id)childrenAttribute {
301     if ( mActsAsRadioGroup ) {
302         NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
303         Reference < XAccessibleRelationSet > rxAccessibleRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
304         AccessibleRelation relationMemberOf = rxAccessibleRelationSet -> getRelationByType ( AccessibleRelationType::MEMBER_OF );
305         if ( relationMemberOf.RelationType == AccessibleRelationType::MEMBER_OF && relationMemberOf.TargetSet.hasElements() ) {
306             for ( int index = 0; index < relationMemberOf.TargetSet.getLength(); index++ ) {
307                 Reference < XAccessible > rMateAccessible = Reference < XAccessible > ( relationMemberOf.TargetSet[index], UNO_QUERY );
308                 if ( rMateAccessible.is() ) {
309                     Reference< XAccessibleContext > rMateAccessibleContext( rMateAccessible -> getAccessibleContext() );
310                     if ( rMateAccessibleContext.is() ) {
311                         id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rMateAccessibleContext ];
312                         [ children addObject: wrapper ];
313                         [ wrapper release ];
314                     }
315                 }
316             }
317         }
318         return children;
319     } else if ( [ self accessibleTable ] != nil ) {
320         return [ AquaA11yTableWrapper childrenAttributeForElement: self ];
321     } else {
322         try {
323             NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
324             Reference< XAccessibleContext > xContext( [ self accessibleContext ] );
325             
326             sal_Int32 cnt = xContext -> getAccessibleChildCount();
327             for ( sal_Int32 i = 0; i < cnt; i++ ) {
328                 Reference< XAccessible > xChild( xContext -> getAccessibleChild( i ) );
329                 if( xChild.is() ) {
330                     Reference< XAccessibleContext > xChildContext( xChild -> getAccessibleContext() );
331                     // the menubar is already accessible (including Apple- and Application-Menu) through NSApplication => omit it here
332                     if ( xChildContext.is() && AccessibleRole::MENU_BAR != xChildContext -> getAccessibleRole() ) {
333                         id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xChildContext ];
334                         [ children addObject: wrapper ];
335                         [ wrapper release ];
336                     }
337                 }
338             }
339             
340             // if not already acting as RadioGroup now is the time to replace RadioButtons with RadioGroups and remove RadioButtons
341             if ( ! mActsAsRadioGroup ) {
342                 NSEnumerator * enumerator = [ children objectEnumerator ];
343                 AquaA11yWrapper * element;
344                 while ( ( element = ( (AquaA11yWrapper *) [ enumerator nextObject ] ) ) ) {
345                     if ( [ element accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON ) {
346                         if ( [ element isFirstRadioButtonInGroup ] ) {
347                             id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ element accessibleContext ] createIfNotExists: YES asRadioGroup: YES ];
348                             [ children replaceObjectAtIndex: [ children indexOfObjectIdenticalTo: element ] withObject: wrapper ];
349                         }
350                         [ children removeObject: element ];
351                     }
352                 }
353             }
355             [ children autorelease ];
356             return NSAccessibilityUnignoredChildren( children );
357         } catch (const Exception &e) {
358             // TODO: Log
359             return nil;
360         }
361     }
364 -(id)windowAttribute {
365     // go upstairs until reaching the broken connection
366     AquaA11yWrapper * aWrapper = self;
367     while ( [ aWrapper accessibleContext ] -> getAccessibleParent().is() ) {
368         aWrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ aWrapper accessibleContext ] -> getAccessibleParent() -> getAccessibleContext() ];
369         [ aWrapper autorelease ];
370     }
371     // get associated NSWindow
372     NSView * theView = [ aWrapper viewElementForParent ];
373     return theView;
376 -(id)topLevelUIElementAttribute {
377     return [ self windowAttribute ];
380 -(id)sizeAttribute {
381     if ( [ self accessibleComponent ] != nil ) {
382         return [ AquaA11yComponentWrapper sizeAttributeForElement: self ];
383     } else {
384         return nil;
385     }
388 -(id)positionAttribute {
389     if ( [ self accessibleComponent ] != nil ) {
390         return [ AquaA11yComponentWrapper positionAttributeForElement: self ];
391     } else {
392         return nil;
393     }
396 -(id)helpAttribute {
397     return CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() );
400 -(id)roleDescriptionAttribute {
401     if ( mActsAsRadioGroup ) {
402         return [ AquaA11yRoleHelper getRoleDescriptionFrom: NSAccessibilityRadioGroupRole with: @"" ];
403         } else if( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON ) {
404                 // FIXME: VO should read this because of hierarchy, this is just a workaround
405                 // get parent and its children
406                 AquaA11yWrapper * parent = [ self parentAttribute ];
407                 NSArray * children = [ parent childrenAttribute ];
408                 // find index of self
409                 int index = 1;
410                 NSEnumerator * enumerator = [ children objectEnumerator ];
411                 AquaA11yWrapper * child = nil;
412                 while ( ( child = [ enumerator nextObject ] ) ) {
413                         if ( self == child ) {
414                                 break;
415                         }
416                         index++;
417                 }
418                 // build string
419                 NSNumber * nIndex = [ NSNumber numberWithInt: index ];
420                 NSNumber * nGroupsize = [ NSNumber numberWithInt: [ children count ] ];
421                 NSMutableString * value = [ [ NSMutableString alloc ] init ];
422                 [ value appendString: @"radio button " ];
423                 [ value appendString: [ nIndex stringValue ] ];
424                 [ value appendString: @" of " ];
425                 [ value appendString: [ nGroupsize stringValue ] ];
426                 // clean up and return string
427                 [ nIndex release ];
428                 [ nGroupsize release ];
429                 [ children release ];
430                 return value;
431     } else {
432         return [ AquaA11yRoleHelper getRoleDescriptionFrom: 
433                 [ AquaA11yRoleHelper getNativeRoleFrom: [ self accessibleContext ] ] 
434                 with: [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ] ];
435     }
438 -(id)valueAttribute {
439     if ( [ [ self roleAttribute ] isEqualToString: NSAccessibilityMenuItemRole ] ) {
440         return nil;
441     } else if ( [ self accessibleText ] != nil ) {
442         return [ AquaA11yTextWrapper valueAttributeForElement: self ];
443     } else if ( [ self accessibleValue ] != nil ) {
444         return [ AquaA11yValueWrapper valueAttributeForElement: self ];
445     } else {
446         return nil;
447     }
450 -(id)minValueAttribute {
451     if ( [ self accessibleValue ] != nil ) {
452         return [ AquaA11yValueWrapper minValueAttributeForElement: self ];
453     } else {
454         return nil;
455     }
458 -(id)maxValueAttribute {
459     if ( [ self accessibleValue ] != nil ) {
460         return [ AquaA11yValueWrapper maxValueAttributeForElement: self ];
461     } else {
462         return nil;
463     }
466 -(id)contentsAttribute {
467     return [ self childrenAttribute ];
470 -(id)selectedChildrenAttribute {
471     return [ AquaA11ySelectionWrapper selectedChildrenAttributeForElement: self ];
474 -(id)numberOfCharactersAttribute {
475     if ( [ self accessibleText ] != nil ) {
476         return [ AquaA11yTextWrapper numberOfCharactersAttributeForElement: self ];
477     } else {
478         return nil;
479     }
482 -(id)selectedTextAttribute {
483     if ( [ self accessibleText ] != nil ) {
484         return [ AquaA11yTextWrapper selectedTextAttributeForElement: self ];
485     } else {
486         return nil;
487     }
490 -(id)selectedTextRangeAttribute {
491     if ( [ self accessibleText ] != nil ) {
492         return [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: self ];
493     } else {
494         return nil;
495     }
498 -(id)visibleCharacterRangeAttribute {
499     if ( [ self accessibleText ] != nil ) {
500         return [ AquaA11yTextWrapper visibleCharacterRangeAttributeForElement: self ];
501     } else {
502         return nil;
503     }
506 -(id)tabsAttribute {
507     return self; // TODO ???
510 -(id)sharedTextUIElementsAttribute {
511     if ( [ self accessibleText ] != nil ) {
512         return [ AquaA11yTextWrapper sharedTextUIElementsAttributeForElement: self ];
513     } else {
514         return nil;
515     }
518 -(id)sharedCharacterRangeAttribute {
519     if ( [ self accessibleText ] != nil ) {
520         return [ AquaA11yTextWrapper sharedCharacterRangeAttributeForElement: self ];
521     } else {
522         return nil;
523     }
526 -(id)expandedAttribute {
527     return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::EXPANDED ) ];
530 -(id)selectedAttribute {
531     return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::SELECTED ) ];
534 -(id)stringForRangeAttributeForParameter:(id)range {
535     if ( [ self accessibleText ] != nil ) {
536         return [ AquaA11yTextWrapper stringForRangeAttributeForElement: self forParameter: range ];
537     } else {
538         return nil;
539     }
542 -(id)attributedStringForRangeAttributeForParameter:(id)range {
543     if ( [ self accessibleText ] != nil ) {
544         return [ AquaA11yTextWrapper attributedStringForRangeAttributeForElement: self forParameter: range ];
545     } else {
546         return nil;
547     }
550 -(id)rangeForIndexAttributeForParameter:(id)index {
551     if ( [ self accessibleText ] != nil ) {
552         return [ AquaA11yTextWrapper rangeForIndexAttributeForElement: self forParameter: index ];
553     } else {
554         return nil;
555     }
558 -(id)rangeForPositionAttributeForParameter:(id)point {
559     if ( [ self accessibleText ] != nil ) {
560         return [ AquaA11yTextWrapper rangeForPositionAttributeForElement: self forParameter: point ];
561     } else {
562         return nil;
563     }
566 -(id)boundsForRangeAttributeForParameter:(id)range {
567     if ( [ self accessibleText ] != nil ) {
568         return [ AquaA11yTextWrapper boundsForRangeAttributeForElement: self forParameter: range ];
569     } else {
570         return nil;
571     }
574 -(id)styleRangeForIndexAttributeForParameter:(id)index {
575     if ( [ self accessibleText ] != nil ) {
576         return [ AquaA11yTextWrapper styleRangeForIndexAttributeForElement: self forParameter: index ];
577     } else {
578         return nil;
579     }
582 -(id)rTFForRangeAttributeForParameter:(id)range {
583     if ( [ self accessibleText ] != nil ) {
584         return [ AquaA11yTextWrapper rTFForRangeAttributeForElement: self forParameter: range ];
585     } else {
586         return nil;
587     }
590 -(id)orientationAttribute {
591     NSString * orientation = nil;
592     Reference < XAccessibleStateSet > stateSet = [ self accessibleContext ] -> getAccessibleStateSet();
593     if ( stateSet -> contains ( AccessibleStateType::HORIZONTAL ) ) {
594         orientation = NSAccessibilityHorizontalOrientationValue;
595     } else if ( stateSet -> contains ( AccessibleStateType::VERTICAL ) ) {
596         orientation = NSAccessibilityVerticalOrientationValue;
597     }
598     return orientation;
601 -(id)titleUIElementAttribute {
602     if ( [ self accessibleContext ] -> getAccessibleRelationSet().is() ) {
603         NSString * title = [ self titleAttribute ];
604         id titleElement = nil;
605         if ( [ title length ] == 0 ) {
606             AccessibleRelation relationLabeledBy = [ self accessibleContext ] -> getAccessibleRelationSet() -> getRelationByType ( AccessibleRelationType::LABELED_BY );
607             if ( relationLabeledBy.RelationType == AccessibleRelationType::LABELED_BY && relationLabeledBy.TargetSet.hasElements()  ) {
608                 Reference < XAccessible > rxAccessible ( relationLabeledBy.TargetSet[0], UNO_QUERY );
609                 titleElement = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessible -> getAccessibleContext() ];
610             }
611         }
612         if ( title != nil ) {
613             [ title release ];
614         }
615         return titleElement;
616     } else {
617         return nil;
618     }
621 -(id)servesAsTitleForUIElementsAttribute {
622     if ( [ self accessibleContext ] -> getAccessibleRelationSet().is() ) {
623         id titleForElement = nil;
624         AccessibleRelation relationLabelFor = [ self accessibleContext ] -> getAccessibleRelationSet() -> getRelationByType ( AccessibleRelationType::LABEL_FOR );
625         if ( relationLabelFor.RelationType == AccessibleRelationType::LABEL_FOR && relationLabelFor.TargetSet.hasElements() ) {
626             Reference < XAccessible > rxAccessible ( relationLabelFor.TargetSet[0], UNO_QUERY );
627             titleForElement = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessible -> getAccessibleContext() ];
628         }
629         return titleForElement;
630     } else {
631         return nil;
632     }
635 -(id)lineForIndexAttributeForParameter:(id)index {
636     if ( [ self accessibleMultiLineText ] != nil ) {
637         return [ AquaA11yTextWrapper lineForIndexAttributeForElement: self forParameter: index ];
638     } else {
639         return nil;
640     }
643 -(id)rangeForLineAttributeForParameter:(id)line {
644     if ( [ self accessibleMultiLineText ] != nil ) {
645         return [ AquaA11yTextWrapper rangeForLineAttributeForElement: self forParameter: line ];
646     } else {
647         return nil;
648     }
651 #pragma mark -
652 #pragma mark Accessibility Protocol
654 -(id)accessibilityAttributeValue:(NSString *)attribute {
655     // #i90575# guard NSAccessibility protocol against unwanted access
656     if ( isPopupMenuOpen ) {
657         return nil;
658     }
659     id value = nil;
660     // if we are no longer in the wrapper repository, we have been disposed
661     AquaA11yWrapper * theWrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ self accessibleContext ] createIfNotExists: NO ];
662     if ( theWrapper != nil || mIsTableCell ) {
663         try {
664             SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: NO ];
665             if ( [ self respondsToSelector: methodSelector ] ) {
666                 value = [ self performSelector: methodSelector ];
667             }
668         } catch ( const DisposedException & e ) {
669             mIsTableCell = NO; // just to be sure
670             [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ];
671             return nil;
672         } catch ( const Exception & e ) {
673             // empty
674         }
675     }
676     if ( theWrapper != nil ) {
677         [ theWrapper release ]; // the above called method calls retain on the returned Wrapper
678     }
679     return value;
682 -(MacOSBOOL)accessibilityIsIgnored {
683     // #i90575# guard NSAccessibility protocol against unwanted access
684     if ( isPopupMenuOpen ) {
685         return nil;
686     }
687     MacOSBOOL ignored = NO;
688     sal_Int16 nRole = [ self accessibleContext ] -> getAccessibleRole();
689     switch ( nRole ) {
690         case AccessibleRole::PANEL:
691         case AccessibleRole::FRAME:
692         case AccessibleRole::ROOT_PANE:
693         case AccessibleRole::SEPARATOR:
694         case AccessibleRole::FILLER:
695         case AccessibleRole::DIALOG:
696             ignored = YES;
697             break;
698         default: 
699             ignored = ! ( [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::VISIBLE ) );
700             break;
701     }
702     return ignored; // TODO: to be completed
705 -(NSArray *)accessibilityAttributeNames {
706     // #i90575# guard NSAccessibility protocol against unwanted access
707     if ( isPopupMenuOpen ) {
708         return nil;
709     }
710     NSString * nativeSubrole = nil;
711     NSString * title = nil;
712     NSMutableArray * attributeNames = nil;
713     try {
714         // Default Attributes
715         attributeNames = [ NSMutableArray arrayWithObjects: 
716             NSAccessibilityRoleAttribute, 
717             NSAccessibilityDescriptionAttribute, 
718             NSAccessibilityParentAttribute, 
719             NSAccessibilityWindowAttribute, 
720             NSAccessibilityHelpAttribute, 
721             NSAccessibilityTopLevelUIElementAttribute, 
722             NSAccessibilityRoleDescriptionAttribute, 
723             nil ];
724         nativeSubrole = (NSString *) [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ];
725         title = (NSString *) [ self titleAttribute ];
726         Reference < XAccessibleRelationSet > rxRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
727         // Special Attributes depending on attribute values
728         if ( nativeSubrole != nil && ! [ nativeSubrole isEqualToString: @"" ] ) {
729             [ attributeNames addObject: NSAccessibilitySubroleAttribute ];
730         }
731         try
732         {
733         if ( [ self accessibleContext ] -> getAccessibleChildCount() > 0 ) {
734             [ attributeNames addObject: NSAccessibilityChildrenAttribute ];
735         }
736         }
737         catch( DisposedException& ) {}
738         catch( RuntimeException& ) {}
739         
740         if ( title != nil && ! [ title isEqualToString: @"" ] ) {
741             [ attributeNames addObject: NSAccessibilityTitleAttribute ];
742         }
743         if ( [ title length ] == 0 && rxRelationSet.is() && rxRelationSet -> containsRelation ( AccessibleRelationType::LABELED_BY ) ) {
744             [ attributeNames addObject: NSAccessibilityTitleUIElementAttribute ];
745         }
746         if ( rxRelationSet.is() && rxRelationSet -> containsRelation ( AccessibleRelationType::LABEL_FOR ) ) {
747             [ attributeNames addObject: NSAccessibilityServesAsTitleForUIElementsAttribute ];
748         }
749         // Special Attributes depending on interface
750         if ( [ self accessibleText ] != nil ) {
751             [ AquaA11yTextWrapper addAttributeNamesTo: attributeNames ];
752         }
753         if ( [ self accessibleComponent ] != nil ) {
754             [ AquaA11yComponentWrapper addAttributeNamesTo: attributeNames ];
755         }
756         if ( [ self accessibleSelection ] != nil ) {
757             [ AquaA11ySelectionWrapper addAttributeNamesTo: attributeNames ];
758         }
759         if ( [ self accessibleValue ] != nil ) {
760             [ AquaA11yValueWrapper addAttributeNamesTo: attributeNames ];
761         }
762         [ nativeSubrole release ];
763         [ title release ];
764         return attributeNames;
765     } catch ( DisposedException & e ) { // Object is no longer available
766         if ( nativeSubrole != nil ) {
767             [ nativeSubrole release ];
768         }
769         if ( title != nil ) {
770             [ title release ];
771         }
772         if ( attributeNames != nil ) {
773             [ attributeNames release ];
774         }
775         [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ];
776         return [ [ NSArray alloc ] init ];
777     }
780 -(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
781     MacOSBOOL isSettable = NO;
782     if ( [ self accessibleText ] != nil ) {
783         isSettable = [ AquaA11yTextWrapper isAttributeSettable: attribute forElement: self ];
784     }
785     if ( ! isSettable && [ self accessibleComponent ] != nil ) {
786         isSettable = [ AquaA11yComponentWrapper isAttributeSettable: attribute forElement: self ];
787     }
788     if ( ! isSettable && [ self accessibleSelection ] != nil ) {
789         isSettable = [ AquaA11ySelectionWrapper isAttributeSettable: attribute forElement: self ];
790     }
791     if ( ! isSettable && [ self accessibleValue ] != nil ) {
792         isSettable = [ AquaA11yValueWrapper isAttributeSettable: attribute forElement: self ];
793     }
794     return isSettable; // TODO: to be completed
797 -(NSArray *)accessibilityParameterizedAttributeNames {
798     NSMutableArray * attributeNames = [ [ NSMutableArray alloc ] init ];
799     // Special Attributes depending on interface
800     if ( [ self accessibleText ] != nil ) {
801         [ AquaA11yTextWrapper addParameterizedAttributeNamesTo: attributeNames ];
802     }
803     return attributeNames; // TODO: to be completed
806 -(id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
807     SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: YES ];
808     if ( [ self respondsToSelector: methodSelector ] ) {
809         return [ self performSelector: methodSelector withObject: parameter ];
810     }
811     return nil; // TODO: to be completed
814 -(MacOSBOOL)accessibilitySetOverrideValue:(id)value forAttribute:(NSString *)attribute {
815     return NO; // TODO
818 -(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
819     SEL methodSelector = [ self selectorForAttribute: attribute asGetter: NO withGetterParameter: NO ];
820     if ( [ AquaA11yComponentWrapper respondsToSelector: methodSelector ] ) {
821         [ AquaA11yComponentWrapper performSelector: methodSelector withObject: self withObject: value ];
822     }
823     if ( [ AquaA11yTextWrapper respondsToSelector: methodSelector ] ) {
824         [ AquaA11yTextWrapper performSelector: methodSelector withObject: self withObject: value ];
825     }
826     if ( [ AquaA11ySelectionWrapper respondsToSelector: methodSelector ] ) {
827         [ AquaA11ySelectionWrapper performSelector: methodSelector withObject: self withObject: value ];
828     }
829     if ( [ AquaA11yValueWrapper respondsToSelector: methodSelector ] ) {
830         [ AquaA11yValueWrapper performSelector: methodSelector withObject: self withObject: value ];
831     }
834 -(id)accessibilityFocusedUIElement {
835     // #i90575# guard NSAccessibility protocol against unwanted access
836     if ( isPopupMenuOpen ) {
837         return nil;
838     }
840     // as this seems to be the first API call on a newly created SalFrameView object,
841     // make sure self gets registered in the repository ..
842     [ self accessibleContext ]; 
844     AquaA11yWrapper * focusedUIElement = AquaA11yFocusListener::get()->getFocusedUIElement();
845 //    AquaA11yWrapper * ancestor = focusedUIElement;
846             
847       // Make sure the focused object is a descendant of self
848 //    do  {
849 //       if( self == ancestor )
850              return focusedUIElement;
851         
852 //       ancestor = [ ancestor accessibilityAttributeValue: NSAccessibilityParentAttribute ];
853 //    }  while( nil != ancestor );
854         
855     return self;
858 // TODO: hard-coded like the role descriptions. is there a better way?
859 -(NSString *)accessibilityActionDescription:(NSString *)action {
860     if ( [ action isEqualToString: NSAccessibilityConfirmAction ] ) {
861         return @"confirm";
862     } else if ( [ action isEqualToString: NSAccessibilityDecrementAction ] ) {
863         return @"decrement";
864     } else if ( [ action isEqualToString: NSAccessibilityDeleteAction ] ) {
865         return @"delete";
866     } else if ( [ action isEqualToString: NSAccessibilityIncrementAction ] ) {
867         return @"increment";
868     } else if ( [ action isEqualToString: NSAccessibilityPickAction ] ) {
869         return @"pick";
870     } else if ( [ action isEqualToString: NSAccessibilityPressAction ] ) {
871         return @"press";
872     } else if ( [ action isEqualToString: NSAccessibilityCancelAction ] ) {
873         return @"cancel";
874     } else if ( [ action isEqualToString: NSAccessibilityRaiseAction ] ) {
875         return @"raise";
876     } else if ( [ action isEqualToString: NSAccessibilityShowMenuAction ] ) {
877         return @"show menu";
878     } else {
879         return [ NSString string ];
880     }
883 -(AquaA11yWrapper *)actionResponder {
884     AquaA11yWrapper * wrapper = nil;
885     // get some information
886     NSString * role = (NSString *) [ self accessibilityAttributeValue: NSAccessibilityRoleAttribute ];
887     id enabledAttr = [ self enabledAttribute ];
888     MacOSBOOL enabled = [ enabledAttr boolValue ];
889     NSView * parent = (NSView *) [ self accessibilityAttributeValue: NSAccessibilityParentAttribute ];
890     AquaA11yWrapper * parentAsWrapper = nil;
891     if ( [ parent isKindOfClass: [ AquaA11yWrapper class ] ] ) {
892         parentAsWrapper = (AquaA11yWrapper *) parent;
893     }
894     NSString * parentRole = (NSString *) [ parent accessibilityAttributeValue: NSAccessibilityRoleAttribute ];
895     // if we are a textarea inside a combobox, then the combobox is the action responder
896     if ( enabled 
897       && [ role isEqualToString: NSAccessibilityTextAreaRole ] 
898       && [ parentRole isEqualToString: NSAccessibilityComboBoxRole ] 
899       && parentAsWrapper != nil ) {
900         wrapper = parentAsWrapper;
901     } else if ( enabled && [ self accessibleAction ] != nil ) {
902         wrapper = self ;
903     }
904     [ parentRole release ];
905     [ enabledAttr release ];
906     [ role release ];
907     return wrapper;
910 -(void)accessibilityPerformAction:(NSString *)action {
911     AquaA11yWrapper * actionResponder = [ self actionResponder ];
912     if ( actionResponder != nil ) {
913         [ AquaA11yActionWrapper doAction: action ofElement: actionResponder ];
914     }
917 -(NSArray *)accessibilityActionNames {
918     NSArray * actionNames = nil;
919     AquaA11yWrapper * actionResponder = [ self actionResponder ];
920     if ( actionResponder != nil ) {
921         actionNames = [ AquaA11yActionWrapper actionNamesForElement: actionResponder ];
922     } else {
923         actionNames = [ [ NSArray alloc ] init ];
924     }
925     return actionNames;
928 #pragma mark -
929 #pragma mark Hit Test
931 -(MacOSBOOL)isViewElement:(NSObject *)viewElement hitByPoint:(NSPoint)point {
932     MacOSBOOL hit = NO;
933     NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
934     NSValue * position = [ viewElement accessibilityAttributeValue: NSAccessibilityPositionAttribute ];
935     NSValue * size = [ viewElement accessibilityAttributeValue: NSAccessibilitySizeAttribute ];
936     if ( position != nil && size != nil ) {
937         float minX = [ position pointValue ].x;
938         float minY = [ position pointValue ].y;
939         float maxX = minX + [ size sizeValue ].width;
940         float maxY = minY + [ size sizeValue ].height;
941         if ( minX < point.x && maxX > point.x && minY < point.y && maxY > point.y ) {
942             hit = YES;
943         }
944     }
945     [ pool release ];
946     return hit;
949 Reference < XAccessibleContext > hitTestRunner ( Point point, Reference < XAccessibleContext > rxAccessibleContext ) {
950     Reference < XAccessibleContext > hitChild;
951     Reference < XAccessibleContext > emptyReference;
952     try {
953         Reference < XAccessibleComponent > rxAccessibleComponent ( rxAccessibleContext, UNO_QUERY );
954         if ( rxAccessibleComponent.is() ) {
955             Point location = rxAccessibleComponent -> getLocationOnScreen();
956             Point hitPoint ( point.X - location.X , point.Y - location.Y); 
957             Reference < XAccessible > rxAccessible = rxAccessibleComponent -> getAccessibleAtPoint ( hitPoint );
958             if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
959                 if ( rxAccessible -> getAccessibleContext() -> getAccessibleChildCount() > 0 ) {
960                     hitChild = hitTestRunner ( point, rxAccessible -> getAccessibleContext() );
961                     if ( ! hitChild.is() ) {
962                         hitChild = rxAccessible -> getAccessibleContext();
963                     }
964                 } else {
965                     hitChild = rxAccessible -> getAccessibleContext();
966                 }
967             }
968         } 
969         if ( !hitChild.is() && rxAccessibleContext -> getAccessibleChildCount() > 0 ) { // special treatment for e.g. comboboxes
970             for ( int i = 0; i < rxAccessibleContext -> getAccessibleChildCount(); i++ ) {
971                 Reference < XAccessible > rxAccessibleChild = rxAccessibleContext -> getAccessibleChild ( i );
972                 if ( rxAccessibleChild.is() && rxAccessibleChild -> getAccessibleContext().is() && rxAccessibleChild -> getAccessibleContext() -> getAccessibleRole() != AccessibleRole::LIST ) {
973                     Reference < XAccessibleContext > myHitChild = hitTestRunner ( point, rxAccessibleChild -> getAccessibleContext() );
974                     if ( myHitChild.is() ) {
975                         hitChild = myHitChild;
976                         break;
977                     }
978                 }
979             }
980         }
981     } catch ( RuntimeException ) {
982         return emptyReference;
983     }
984     return hitChild;
987 -(id)accessibilityHitTest:(NSPoint)point {
988     static id wrapper = nil;
989     if ( nil != wrapper ) {
990         [ wrapper release ];
991         wrapper = nil;
992     }
993     Reference < XAccessibleContext > hitChild;
994     NSRect screenRect = [ [ NSScreen mainScreen ] frame ];
995     Point hitPoint ( static_cast<long>(point.x) , static_cast<long>(screenRect.size.height - point.y) ); 
996     // check child windows first
997     NSWindow * window = (NSWindow *) [ self accessibilityAttributeValue: NSAccessibilityWindowAttribute ];
998     NSArray * childWindows = [ window childWindows ];
999     if ( [ childWindows count ] > 0 ) {
1000         NSWindow * element = nil;
1001         NSEnumerator * enumerator = [ childWindows objectEnumerator ];
1002         while ( ( element = [ enumerator nextObject ] ) && hitChild == nil ) {
1003             if ( [ element isKindOfClass: [ SalFrameWindow class ] ] && [ self isViewElement: element hitByPoint: point ] ) {
1004                 // we have a child window that is hit
1005                 Reference < XAccessibleRelationSet > relationSet = [ ( ( SalFrameWindow * ) element ) accessibleContext ] -> getAccessibleRelationSet();
1006                 if ( relationSet.is() && relationSet -> containsRelation ( AccessibleRelationType::SUB_WINDOW_OF )) {
1007                     // we have a valid relation to the parent element
1008                     AccessibleRelation relation = relationSet -> getRelationByType ( AccessibleRelationType::SUB_WINDOW_OF );
1009                     for ( int i = 0; i < relation.TargetSet.getLength() && !hitChild.is(); i++ ) {
1010                         Reference < XAccessible > rxAccessible ( relation.TargetSet [ i ], UNO_QUERY );
1011                         if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
1012                             // hit test for children of parent
1013                             hitChild = hitTestRunner ( hitPoint, rxAccessible -> getAccessibleContext() );
1014                         }
1015                     }
1016                 }
1017             }
1018         }
1019     }
1020     // nothing hit yet, so check ourself
1021     if ( ! hitChild.is() ) {
1022         if ( mpReferenceWrapper == nil ) {
1023             [ self setDefaults: [ self accessibleContext ] ];
1024         }
1025         hitChild = hitTestRunner ( hitPoint, mpReferenceWrapper -> rAccessibleContext );
1026     }
1027     if ( hitChild.is() ) {
1028         wrapper = [ AquaA11yFactory wrapperForAccessibleContext: hitChild ];
1029     }
1030     if ( wrapper != nil ) {
1031         [ wrapper retain ]; // TODO: retain only when transient ?
1032     }
1033     return wrapper;
1036 #pragma mark -
1037 #pragma mark Access Methods
1039 -(XAccessibleAction *)accessibleAction {
1040     return mpReferenceWrapper -> rAccessibleAction.get();
1043 -(XAccessibleContext *)accessibleContext {
1044     return mpReferenceWrapper -> rAccessibleContext.get();
1047 -(XAccessibleComponent *)accessibleComponent {
1048     return mpReferenceWrapper -> rAccessibleComponent.get();
1051 -(XAccessibleExtendedComponent *)accessibleExtendedComponent {
1052     return mpReferenceWrapper -> rAccessibleExtendedComponent.get();
1055 -(XAccessibleSelection *)accessibleSelection {
1056     return mpReferenceWrapper -> rAccessibleSelection.get();
1059 -(XAccessibleTable *)accessibleTable {
1060     return mpReferenceWrapper -> rAccessibleTable.get();
1063 -(XAccessibleText *)accessibleText {
1064     return mpReferenceWrapper -> rAccessibleText.get();
1067 -(XAccessibleEditableText *)accessibleEditableText {
1068     return mpReferenceWrapper -> rAccessibleEditableText.get();
1071 -(XAccessibleValue *)accessibleValue {
1072     return mpReferenceWrapper -> rAccessibleValue.get();
1075 -(XAccessibleTextAttributes *)accessibleTextAttributes {
1076     return mpReferenceWrapper -> rAccessibleTextAttributes.get();
1079 -(XAccessibleMultiLineText *)accessibleMultiLineText {
1080     return mpReferenceWrapper -> rAccessibleMultiLineText.get();
1083 -(NSView *)viewElementForParent {
1084     return self;
1087 // These four are for AXTextAreas only. They are needed, because bold and italic
1088 // attributes have to be bound to a font on the Mac. Our UNO-API instead handles
1089 // and reports them independently. When they occur we bundle them to a font with
1090 // this information here to create a according NSFont.
1091 -(void)setDefaultFontname:(NSString *)fontname {
1092     if ( mpDefaultFontname != nil ) {
1093         [ mpDefaultFontname release ];
1094     }
1095     mpDefaultFontname = fontname;
1098 -(NSString *)defaultFontname {
1099     return mpDefaultFontname;
1102 -(void)setDefaultFontsize:(float)fontsize {
1103     mDefaultFontsize = fontsize;
1106 -(float)defaultFontsize {
1107     return mDefaultFontsize;
1110 -(void)setActsAsRadioGroup:(MacOSBOOL)actsAsRadioGroup {
1111     mActsAsRadioGroup = actsAsRadioGroup;
1114 -(MacOSBOOL)actsAsRadioGroup {
1115     return mActsAsRadioGroup;
1118 +(void)setPopupMenuOpen:(MacOSBOOL)popupMenuOpen {
1119     isPopupMenuOpen = popupMenuOpen;
1122 @end