jdk/src/java.desktop/macosx/native/libawt_lwawt/sun/awt/JavaComponentAccessibility.m
changeset 25859 3317bb8137f4
parent 24140 db4b6390d43c
child 26037 508779ce6619
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 // External Java Accessibility links:
       
    27 //
       
    28 // <http://java.sun.com/j2se/1.4.2/docs/guide/access/index.html>
       
    29 // <http://www-106.ibm.com/developerworks/library/j-access/?n-j-10172>
       
    30 // <http://archives.java.sun.com/archives/java-access.html> (Sun's mailing list for Java accessibility)
       
    31 
       
    32 #import "JavaComponentAccessibility.h"
       
    33 
       
    34 #import "sun_lwawt_macosx_CAccessibility.h"
       
    35 
       
    36 #import <AppKit/AppKit.h>
       
    37 
       
    38 #import <JavaNativeFoundation/JavaNativeFoundation.h>
       
    39 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
       
    40 
       
    41 #import <dlfcn.h>
       
    42 
       
    43 #import "JavaAccessibilityAction.h"
       
    44 #import "JavaAccessibilityUtilities.h"
       
    45 #import "JavaTextAccessibility.h"
       
    46 #import "ThreadUtilities.h"
       
    47 #import "AWTView.h"
       
    48 
       
    49 
       
    50 // these constants are duplicated in CAccessibility.java
       
    51 #define JAVA_AX_ALL_CHILDREN (-1)
       
    52 #define JAVA_AX_SELECTED_CHILDREN (-2)
       
    53 #define JAVA_AX_VISIBLE_CHILDREN (-3)
       
    54 // If the value is >=0, it's an index
       
    55 
       
    56 static JNF_STATIC_MEMBER_CACHE(jm_getChildrenAndRoles, sjc_CAccessibility, "getChildrenAndRoles", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;IZ)[Ljava/lang/Object;");
       
    57 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleComponent, sjc_CAccessibility, "getAccessibleComponent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleComponent;");
       
    58 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleValue, sjc_CAccessibility, "getAccessibleValue", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleValue;");
       
    59 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
       
    60 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleDescription, sjc_CAccessibility, "getAccessibleDescription", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
       
    61 static JNF_STATIC_MEMBER_CACHE(sjm_isFocusTraversable, sjc_CAccessibility, "isFocusTraversable", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Z");
       
    62 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleIndexInParent, sjc_CAccessibility, "getAccessibleIndexInParent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)I");
       
    63 
       
    64 static JNF_CLASS_CACHE(sjc_CAccessible, "sun/lwawt/macosx/CAccessible");
       
    65 
       
    66 static JNF_MEMBER_CACHE(jf_ptr, sjc_CAccessible, "ptr", "J");
       
    67 static JNF_STATIC_MEMBER_CACHE(sjm_getCAccessible, sjc_CAccessible, "getCAccessible", "(Ljavax/accessibility/Accessible;)Lsun/lwawt/macosx/CAccessible;");
       
    68 
       
    69 
       
    70 static jobject sAccessibilityClass = NULL;
       
    71 
       
    72 // sAttributeNamesForRoleCache holds the names of the attributes to which each java
       
    73 // AccessibleRole responds (see AccessibleRole.java).
       
    74 // This cache is queried before attempting to access a given attribute for a particular role.
       
    75 static NSMutableDictionary *sAttributeNamesForRoleCache = nil;
       
    76 static NSObject *sAttributeNamesLOCK = nil;
       
    77 
       
    78 
       
    79 @interface TabGroupAccessibility : JavaComponentAccessibility {
       
    80     NSInteger _numTabs;
       
    81 }
       
    82 
       
    83 - (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext;
       
    84 - (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
       
    85 - (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
       
    86 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
       
    87 
       
    88 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
       
    89 - (NSArray *)accessibilityChildrenAttribute;
       
    90 - (id) accessibilityTabsAttribute;
       
    91 - (BOOL)accessibilityIsTabsAttributeSettable;
       
    92 - (NSArray *)accessibilityContentsAttribute;
       
    93 - (BOOL)accessibilityIsContentsAttributeSettable;
       
    94 - (id) accessibilityValueAttribute;
       
    95 
       
    96 @end
       
    97 
       
    98 
       
    99 @interface TabGroupControlAccessibility : JavaComponentAccessibility {
       
   100     jobject fTabGroupAxContext;
       
   101 }
       
   102 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole;
       
   103 - (jobject)tabGroup;
       
   104 - (void)getActionsWithEnv:(JNIEnv *)env;
       
   105 
       
   106 - (id)accessibilityValueAttribute;
       
   107 @end
       
   108 
       
   109 
       
   110 @interface ScrollAreaAccessibility : JavaComponentAccessibility {
       
   111 
       
   112 }
       
   113 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
       
   114 - (NSArray *)accessibilityContentsAttribute;
       
   115 - (BOOL)accessibilityIsContentsAttributeSettable;
       
   116 - (id)accessibilityVerticalScrollBarAttribute;
       
   117 - (BOOL)accessibilityIsVerticalScrollBarAttributeSettable;
       
   118 - (id)accessibilityHorizontalScrollBarAttribute;
       
   119 - (BOOL)accessibilityIsHorizontalScrollBarAttributeSettable;
       
   120 @end
       
   121 
       
   122 
       
   123 @implementation JavaComponentAccessibility
       
   124 
       
   125 - (NSString *)description
       
   126 {
       
   127     return [NSString stringWithFormat:@"%@(title:'%@', desc:'%@', value:'%@')", [self accessibilityRoleAttribute],
       
   128         [self accessibilityTitleAttribute], [self accessibilityRoleDescriptionAttribute], [self accessibilityValueAttribute]];
       
   129 }
       
   130 
       
   131 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
       
   132 {
       
   133     self = [super init];
       
   134     if (self)
       
   135     {
       
   136         fParent = [parent retain];
       
   137         fView = [view retain];
       
   138         fJavaRole = [javaRole retain];
       
   139 
       
   140         fAccessible = JNFNewGlobalRef(env, accessible);
       
   141         fComponent = JNFNewGlobalRef(env, [(AWTView *)fView awtComponent:env]);
       
   142 
       
   143         fIndex = index;
       
   144 
       
   145         fActions = nil;
       
   146         fActionsLOCK = [[NSObject alloc] init];
       
   147     }
       
   148     return self;
       
   149 }
       
   150 
       
   151 - (void)unregisterFromCocoaAXSystem
       
   152 {
       
   153     AWT_ASSERT_APPKIT_THREAD;
       
   154     static dispatch_once_t initialize_unregisterUniqueId_once;
       
   155     static void (*unregisterUniqueId)(id);
       
   156     dispatch_once(&initialize_unregisterUniqueId_once, ^{
       
   157         void *jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL);
       
   158         unregisterUniqueId = dlsym(jrsFwk, "JRSAccessibilityUnregisterUniqueIdForUIElement");
       
   159     });
       
   160     if (unregisterUniqueId) unregisterUniqueId(self);
       
   161 }
       
   162 
       
   163 - (void)dealloc
       
   164 {
       
   165     [self unregisterFromCocoaAXSystem];
       
   166 
       
   167     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
       
   168 
       
   169     JNFDeleteGlobalRef(env, fAccessible);
       
   170     fAccessible = NULL;
       
   171 
       
   172     JNFDeleteGlobalRef(env, fComponent);
       
   173     fComponent = NULL;
       
   174 
       
   175     [fParent release];
       
   176     fParent = nil;
       
   177 
       
   178     [fNSRole release];
       
   179     fNSRole = nil;
       
   180 
       
   181     [fJavaRole release];
       
   182     fJavaRole = nil;
       
   183 
       
   184     [fView release];
       
   185     fView = nil;
       
   186 
       
   187     [fActions release];
       
   188     fActions = nil;
       
   189 
       
   190     [fActionsLOCK release];
       
   191     fActionsLOCK = nil;
       
   192 
       
   193     [super dealloc];
       
   194 }
       
   195 
       
   196 - (void)postValueChanged
       
   197 {
       
   198     AWT_ASSERT_APPKIT_THREAD;
       
   199     NSAccessibilityPostNotification(self, NSAccessibilityValueChangedNotification);
       
   200 }
       
   201 
       
   202 - (void)postSelectionChanged
       
   203 {
       
   204     AWT_ASSERT_APPKIT_THREAD;
       
   205     NSAccessibilityPostNotification(self, NSAccessibilitySelectedTextChangedNotification);
       
   206 }
       
   207 
       
   208 - (BOOL)isEqual:(id)anObject
       
   209 {
       
   210     if (![anObject isKindOfClass:[self class]]) return NO;
       
   211     JavaComponentAccessibility *accessibility = (JavaComponentAccessibility *)anObject;
       
   212 
       
   213     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   214     return (*env)->IsSameObject(env, accessibility->fAccessible, fAccessible);
       
   215 }
       
   216 
       
   217 - (BOOL)isAccessibleWithEnv:(JNIEnv *)env forAccessible:(jobject)accessible
       
   218 {
       
   219     return (*env)->IsSameObject(env, fAccessible, accessible);
       
   220 }
       
   221 
       
   222 + (void)initialize
       
   223 {
       
   224     if (sAttributeNamesForRoleCache == nil) {
       
   225         sAttributeNamesLOCK = [[NSObject alloc] init];
       
   226         sAttributeNamesForRoleCache = [[NSMutableDictionary alloc] initWithCapacity:10];
       
   227     }
       
   228 
       
   229     if (sRoles == nil) {
       
   230         initializeRoles();
       
   231     }
       
   232 
       
   233     if (sAccessibilityClass == NULL) {
       
   234         JNF_STATIC_MEMBER_CACHE(jm_getAccessibility, sjc_CAccessibility, "getAccessibility", "([Ljava/lang/String;)Lsun/lwawt/macosx/CAccessibility;");
       
   235 
       
   236 #ifdef JAVA_AX_NO_IGNORES
       
   237         NSArray *ignoredKeys = [NSArray array];
       
   238 #else
       
   239         NSArray *ignoredKeys = [sRoles allKeysForObject:JavaAccessibilityIgnore];
       
   240 #endif
       
   241         jobjectArray result = NULL;
       
   242         jsize count = [ignoredKeys count];
       
   243 
       
   244         JNIEnv *env = [ThreadUtilities getJNIEnv];
       
   245 
       
   246         static JNF_CLASS_CACHE(jc_String, "java/lang/String");
       
   247         result = JNFNewObjectArray(env, &jc_String, count);
       
   248         if (!result) {
       
   249             NSLog(@"In %s, can't create Java array of String objects", __FUNCTION__);
       
   250             return;
       
   251         }
       
   252 
       
   253         NSInteger i;
       
   254         for (i = 0; i < count; i++) {
       
   255             jstring jString = JNFNSToJavaString(env, [ignoredKeys objectAtIndex:i]);
       
   256             (*env)->SetObjectArrayElement(env, result, i, jString);
       
   257             (*env)->DeleteLocalRef(env, jString);
       
   258         }
       
   259 
       
   260         sAccessibilityClass = JNFCallStaticObjectMethod(env, jm_getAccessibility, result); // AWT_THREADING Safe (known object)
       
   261     }
       
   262 }
       
   263 
       
   264 + (void)postFocusChanged:(id)message
       
   265 {
       
   266     AWT_ASSERT_APPKIT_THREAD;
       
   267     NSAccessibilityPostNotification([NSApp accessibilityFocusedUIElement], NSAccessibilityFocusedUIElementChangedNotification);
       
   268 }
       
   269 
       
   270 + (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env {
       
   271     if (JNFIsInstanceOf(env, jaccessible, &sjc_CAccessible)) {
       
   272         return jaccessible;
       
   273     }
       
   274     else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
       
   275         return JNFCallStaticObjectMethod(env, sjm_getCAccessible, jaccessible);
       
   276     }
       
   277     return NULL;
       
   278 }
       
   279 
       
   280 + (NSArray *)childrenOfParent:(JavaComponentAccessibility *)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored
       
   281 {
       
   282     jobjectArray jchildrenAndRoles = JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, parent->fAccessible, parent->fComponent, whichChildren, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
       
   283     if (jchildrenAndRoles == NULL) return nil;
       
   284 
       
   285     jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
       
   286     NSMutableArray *children = [NSMutableArray arrayWithCapacity:arrayLen/2]; //childrenAndRoles array contains two elements (child, role) for each child
       
   287 
       
   288     NSInteger i;
       
   289     NSUInteger childIndex = (whichChildren >= 0) ? whichChildren : 0; // if we're getting one particular child, make sure to set its index correctly
       
   290     for(i = 0; i < arrayLen; i+=2)
       
   291     {
       
   292         jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
       
   293         jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
       
   294 
       
   295         NSString *childJavaRole = nil;
       
   296         if (jchildJavaRole != NULL) {
       
   297             childJavaRole = JNFJavaToNSString(env, JNFGetObjectField(env, jchildJavaRole, sjf_key));
       
   298         }
       
   299 
       
   300         JavaComponentAccessibility *child = [self createWithParent:parent accessible:jchild role:childJavaRole index:childIndex withEnv:env withView:parent->fView];
       
   301         [children addObject:child];
       
   302         childIndex++;
       
   303     }
       
   304 
       
   305     return children;
       
   306 }
       
   307 
       
   308 + (JavaComponentAccessibility *)createWithAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env withView:(NSView *)view
       
   309 {
       
   310     jobject jcomponent = [(AWTView *)view awtComponent:env];
       
   311     jint index = JNFCallStaticIntMethod(env, sjm_getAccessibleIndexInParent, jaccessible, jcomponent);
       
   312     NSString *javaRole = getJavaRole(env, jaccessible, jcomponent);
       
   313 
       
   314     return [self createWithAccessible:jaccessible role:javaRole index:index withEnv:env withView:view];
       
   315 }
       
   316 
       
   317 + (JavaComponentAccessibility *) createWithAccessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
       
   318 {
       
   319     return [self createWithParent:nil accessible:jaccessible role:javaRole index:index withEnv:env withView:view];
       
   320 }
       
   321 
       
   322 + (JavaComponentAccessibility *) createWithParent:(JavaComponentAccessibility *)parent accessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
       
   323 {
       
   324     // try to fetch the jCAX from Java, and return autoreleased
       
   325     jobject jCAX = [JavaComponentAccessibility getCAccessible:jaccessible withEnv:env];
       
   326     if (jCAX == NULL) return nil;
       
   327     JavaComponentAccessibility *value = (JavaComponentAccessibility *) jlong_to_ptr(JNFGetLongField(env, jCAX, jf_ptr));
       
   328     if (value != nil) return [[value retain] autorelease];
       
   329 
       
   330     // otherwise, create a new instance
       
   331     JavaComponentAccessibility *newChild = nil;
       
   332     if ([javaRole isEqualToString:@"pagetablist"]) {
       
   333         newChild = [TabGroupAccessibility alloc];
       
   334     } else if ([javaRole isEqualToString:@"scrollpane"]) {
       
   335         newChild = [ScrollAreaAccessibility alloc];
       
   336     } else {
       
   337         NSString *nsRole = [sRoles objectForKey:javaRole];
       
   338         if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] || [nsRole isEqualToString:NSAccessibilityTextAreaRole] || [nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
       
   339             newChild = [JavaTextAccessibility alloc];
       
   340         } else {
       
   341             newChild = [JavaComponentAccessibility alloc];
       
   342         }
       
   343     }
       
   344 
       
   345     // must init freshly -alloc'd object
       
   346     [newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance
       
   347 
       
   348     // must hard retain pointer poked into Java object
       
   349     [newChild retain];
       
   350     JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
       
   351 
       
   352     // return autoreleased instance
       
   353     return [newChild autorelease];
       
   354 }
       
   355 
       
   356 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
       
   357 {
       
   358     static JNF_STATIC_MEMBER_CACHE(jm_getInitialAttributeStates, sjc_CAccessibility, "getInitialAttributeStates", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[Z");
       
   359 
       
   360     NSMutableArray *attributeNames = [NSMutableArray arrayWithCapacity:10];
       
   361     [attributeNames retain];
       
   362 
       
   363     // all elements respond to parent, role, role description, window, topLevelUIElement, help
       
   364     [attributeNames addObject:NSAccessibilityParentAttribute];
       
   365     [attributeNames addObject:NSAccessibilityRoleAttribute];
       
   366     [attributeNames addObject:NSAccessibilityRoleDescriptionAttribute];
       
   367     [attributeNames addObject:NSAccessibilityHelpAttribute];
       
   368 
       
   369     // cmcnote: AXMenu usually doesn't respond to window / topLevelUIElement. But menus within a Java app's window
       
   370     // probably should. Should we use some role other than AXMenu / AXMenuBar for Java menus?
       
   371     [attributeNames addObject:NSAccessibilityWindowAttribute];
       
   372     [attributeNames addObject:NSAccessibilityTopLevelUIElementAttribute];
       
   373 
       
   374     // set accessible subrole
       
   375     NSString *javaRole = [self javaRole];
       
   376     if (javaRole != nil && [javaRole isEqualToString:@"passwordtext"]) {
       
   377         //cmcnote: should turn this into a constant
       
   378         [attributeNames addObject:NSAccessibilitySubroleAttribute];
       
   379     }
       
   380 
       
   381     // Get all the other accessibility attributes states we need in one swell foop.
       
   382     // javaRole isn't pulled in because we need protected access to AccessibleRole.key
       
   383     jbooleanArray attributeStates = JNFCallStaticObjectMethod(env, jm_getInitialAttributeStates, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
   384     if (attributeStates == NULL) return nil;
       
   385     jboolean *attributeStatesArray = (*env)->GetBooleanArrayElements(env, attributeStates, 0);
       
   386     if (attributeStatesArray == NULL) {
       
   387         // Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck.
       
   388         NSLog(@"%s failed calling GetBooleanArrayElements", __FUNCTION__);
       
   389         return nil;
       
   390     }
       
   391 
       
   392     // if there's a component, it can be enabled and it has a size/position
       
   393     if (attributeStatesArray[0]) {
       
   394         [attributeNames addObject:NSAccessibilityEnabledAttribute];
       
   395         [attributeNames addObject:NSAccessibilitySizeAttribute];
       
   396         [attributeNames addObject:NSAccessibilityPositionAttribute];
       
   397     }
       
   398 
       
   399     // According to javadoc, a component that is focusable will return true from isFocusTraversable,
       
   400     // as well as having AccessibleState.FOCUSABLE in it's AccessibleStateSet.
       
   401     // We use the former heuristic; if the component focus-traversable, add a focused attribute
       
   402     // See also: accessibilityIsFocusedAttributeSettable
       
   403     if (attributeStatesArray[1])
       
   404     {
       
   405         [attributeNames addObject:NSAccessibilityFocusedAttribute];
       
   406     }
       
   407 
       
   408     // if it's a pagetab / radiobutton, it has a value but no min/max value.
       
   409     BOOL hasAxValue = attributeStatesArray[2];
       
   410     if ([javaRole isEqualToString:@"pagetab"] || [javaRole isEqualToString:@"radiobutton"]) {
       
   411         [attributeNames addObject:NSAccessibilityValueAttribute];
       
   412     } else {
       
   413         // if not a pagetab/radio button, and it has a value, it has a min/max/current value.
       
   414         if (hasAxValue) {
       
   415             // er, it has a min/max/current value if it's not a button.
       
   416             // See AppKit/NSButtonCellAccessibility.m
       
   417             if (![javaRole isEqualToString:@"pushbutton"]) {
       
   418                 //cmcnote: make this (and "passwordtext") constants instead of magic strings
       
   419                 [attributeNames addObject:NSAccessibilityMinValueAttribute];
       
   420                 [attributeNames addObject:NSAccessibilityMaxValueAttribute];
       
   421                 [attributeNames addObject:NSAccessibilityValueAttribute];
       
   422             }
       
   423         }
       
   424     }
       
   425 
       
   426     // does it have an orientation?
       
   427     if (attributeStatesArray[4]) {
       
   428         [attributeNames addObject:NSAccessibilityOrientationAttribute];
       
   429     }
       
   430 
       
   431     // name
       
   432     if (attributeStatesArray[5]) {
       
   433         [attributeNames addObject:NSAccessibilityTitleAttribute];
       
   434     }
       
   435 
       
   436     // children
       
   437     if (attributeStatesArray[6]) {
       
   438         [attributeNames addObject:NSAccessibilityChildrenAttribute];
       
   439 //        [attributeNames addObject:NSAccessibilitySelectedChildrenAttribute];
       
   440 //        [attributeNames addObject:NSAccessibilityVisibleChildrenAttribute];
       
   441                 //According to AXRoles.txt:
       
   442                 //VisibleChildren: radio group, list, row, table row subrole
       
   443                 //SelectedChildren: list
       
   444     }
       
   445 
       
   446     // Cleanup
       
   447     (*env)->ReleaseBooleanArrayElements(env, attributeStates, attributeStatesArray, JNI_ABORT);
       
   448 
       
   449     return attributeNames;
       
   450 }
       
   451 
       
   452 - (NSDictionary *)getActions:(JNIEnv *)env
       
   453 {
       
   454     @synchronized(fActionsLOCK) {
       
   455         if (fActions == nil) {
       
   456             fActions = [[NSMutableDictionary alloc] initWithCapacity:3];
       
   457             [self getActionsWithEnv:env];
       
   458         }
       
   459     }
       
   460 
       
   461     return fActions;
       
   462 }
       
   463 
       
   464 - (void)getActionsWithEnv:(JNIEnv *)env
       
   465 {
       
   466     static JNF_STATIC_MEMBER_CACHE(jm_getAccessibleAction, sjc_CAccessibility, "getAccessibleAction", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleAction;");
       
   467 
       
   468     // On MacOSX, text doesn't have actions, in java it does.
       
   469     // cmcnote: NOT TRUE - Editable text has AXShowMenu. Textfields have AXConfirm. Static text has no actions.
       
   470     jobject axAction = JNFCallStaticObjectMethod(env, jm_getAccessibleAction, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
   471     if (axAction != NULL) {
       
   472         //+++gdb NOTE: In MacOSX, there is just a single Action, not multiple. In java,
       
   473         //  the first one seems to be the most basic, so this will be used.
       
   474         // cmcnote: NOT TRUE - Sometimes there are multiple actions, eg sliders have AXDecrement AND AXIncrement (radr://3893192)
       
   475         JavaAxAction *action = [[JavaAxAction alloc] initWithEnv:env withAccessibleAction:axAction withIndex:0 withComponent:fComponent];
       
   476         [fActions setObject:action forKey:[self isMenu] ? NSAccessibilityPickAction : NSAccessibilityPressAction];
       
   477         [action release];
       
   478     }
       
   479 }
       
   480 
       
   481 - (jobject)axContextWithEnv:(JNIEnv *)env
       
   482 {
       
   483     return getAxContext(env, fAccessible, fComponent);
       
   484 }
       
   485 
       
   486 - (id)parent
       
   487 {
       
   488     static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleParent, sjc_CAccessibility, "getAccessibleParent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
       
   489 
       
   490     if(fParent == nil) {
       
   491         JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   492 
       
   493         jobject jparent = JNFCallStaticObjectMethod(env, sjm_getAccessibleParent, fAccessible, fComponent);
       
   494 
       
   495         if (jparent == NULL) {
       
   496             fParent = fView;
       
   497         } else {
       
   498             fParent = [JavaComponentAccessibility createWithAccessible:jparent withEnv:env withView:fView];
       
   499             if (fParent == nil) {
       
   500                 fParent = fView;
       
   501             }
       
   502         }
       
   503         [fParent retain];
       
   504     }
       
   505     return fParent;
       
   506 }
       
   507 
       
   508 - (NSView *)view
       
   509 {
       
   510     return fView;
       
   511 }
       
   512 
       
   513 - (NSWindow *)window
       
   514 {
       
   515     return [[self view] window];
       
   516 }
       
   517 
       
   518 - (NSString *)javaRole
       
   519 {
       
   520     if(fJavaRole == nil) {
       
   521         JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   522         fJavaRole = getJavaRole(env, fAccessible, fComponent);
       
   523         [fJavaRole retain];
       
   524     }
       
   525     return fJavaRole;
       
   526 }
       
   527 
       
   528 - (BOOL)isMenu
       
   529 {
       
   530     id role = [self accessibilityRoleAttribute];
       
   531     return [role isEqualToString:NSAccessibilityMenuBarRole] || [role isEqualToString:NSAccessibilityMenuRole] || [role isEqualToString:NSAccessibilityMenuItemRole];
       
   532 }
       
   533 
       
   534 - (BOOL)isSelected:(JNIEnv *)env
       
   535 {
       
   536     if (fIndex == -1) {
       
   537         return NO;
       
   538     }
       
   539 
       
   540     return isChildSelected(env, ((JavaComponentAccessibility *)[self parent])->fAccessible, fIndex, fComponent);
       
   541 }
       
   542 
       
   543 - (BOOL)isVisible:(JNIEnv *)env
       
   544 {
       
   545     if (fIndex == -1) {
       
   546         return NO;
       
   547     }
       
   548 
       
   549     return isShowing(env, [self axContextWithEnv:env], fComponent);
       
   550 }
       
   551 
       
   552 // the array of names for each role is cached in the sAttributeNamesForRoleCache
       
   553 - (NSArray *)accessibilityAttributeNames
       
   554 {
       
   555     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   556 
       
   557     @synchronized(sAttributeNamesLOCK) {
       
   558         NSString *javaRole = [self javaRole];
       
   559         NSArray *names = (NSArray *)[sAttributeNamesForRoleCache objectForKey:javaRole];
       
   560         if (names != nil) return names;
       
   561 
       
   562         names = [self initializeAttributeNamesWithEnv:env];
       
   563         if (names != nil) {
       
   564 #ifdef JAVA_AX_DEBUG
       
   565             NSLog(@"Initializing: %s for %@: %@", __FUNCTION__, javaRole, names);
       
   566 #endif
       
   567             [sAttributeNamesForRoleCache setObject:names forKey:javaRole];
       
   568             return names;
       
   569         }
       
   570     }
       
   571 
       
   572 #ifdef JAVA_AX_DEBUG
       
   573     NSLog(@"Warning in %s: could not find attribute names for role: %@", __FUNCTION__, [self javaRole]);
       
   574 #endif
       
   575 
       
   576     return nil;
       
   577 }
       
   578 
       
   579 // -- accessibility attributes --
       
   580 
       
   581 - (BOOL)accessibilityShouldUseUniqueId {
       
   582     return YES;
       
   583 }
       
   584 
       
   585 - (BOOL)accessibilitySupportsOverriddenAttributes {
       
   586     return YES;
       
   587 }
       
   588 
       
   589 
       
   590 // generic getters & setters
       
   591 // cmcnote: it would make more sense if these generic getters/setters were in JavaAccessibilityUtilities
       
   592 - (id)accessibilityAttributeValue:(NSString *)attribute
       
   593 {
       
   594     AWT_ASSERT_APPKIT_THREAD;
       
   595 
       
   596     // turns attribute "NSAccessibilityEnabledAttribute" into getter "accessibilityEnabledAttribute",
       
   597     // calls getter on self
       
   598     return JavaAccessibilityAttributeValue(self, attribute);
       
   599 }
       
   600 
       
   601 - (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute
       
   602 {
       
   603     AWT_ASSERT_APPKIT_THREAD;
       
   604 
       
   605     // turns attribute "NSAccessibilityParentAttribute" into selector "accessibilityIsParentAttributeSettable",
       
   606     // calls selector on self
       
   607     return JavaAccessibilityIsAttributeSettable(self, attribute);
       
   608 }
       
   609 
       
   610 - (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute
       
   611 {
       
   612     AWT_ASSERT_APPKIT_THREAD;
       
   613 
       
   614     if ([self accessibilityIsAttributeSettable:attribute]) {
       
   615         // turns attribute "NSAccessibilityFocusAttribute" into setter "accessibilitySetFocusAttribute",
       
   616         // calls setter on self
       
   617         JavaAccessibilitySetAttributeValue(self, attribute, value);
       
   618     }
       
   619 }
       
   620 
       
   621 
       
   622 // specific attributes, in alphabetical order a la
       
   623 // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
       
   624 
       
   625 // Elements that current element contains (NSArray)
       
   626 - (NSArray *)accessibilityChildrenAttribute
       
   627 {
       
   628     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   629     NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_VISIBLE_CHILDREN allowIgnored:NO];
       
   630 
       
   631     NSArray *value = nil;
       
   632     if ([children count] > 0) {
       
   633         value = children;
       
   634     }
       
   635 
       
   636     return value;
       
   637 }
       
   638 - (BOOL)accessibilityIsChildrenAttributeSettable
       
   639 {
       
   640     return NO;
       
   641 }
       
   642 
       
   643 - (NSUInteger)accessibilityIndexOfChild:(id)child
       
   644 {
       
   645     // Only special-casing for Lists, for now. This allows lists to be accessible, fixing radr://3856139 "JLists are broken".
       
   646     // Will probably want to special-case for Tables when we implement them (radr://3096643 "Accessibility: Table").
       
   647     // In AppKit, NSMatrixAccessibility (which uses NSAccessibilityListRole), NSTableRowAccessibility, and NSTableViewAccessibility are the
       
   648     // only ones that override the default implementation in NSAccessibility
       
   649     if (![[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityListRole]) {
       
   650         return [super accessibilityIndexOfChild:child];
       
   651     }
       
   652 
       
   653     return JNFCallStaticIntMethod([ThreadUtilities getJNIEnv], sjm_getAccessibleIndexInParent, ((JavaComponentAccessibility *)child)->fAccessible, ((JavaComponentAccessibility *)child)->fComponent);
       
   654 }
       
   655 
       
   656 // Without this optimization accessibilityChildrenAttribute is called in order to get the entire array of children.
       
   657 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount {
       
   658     if ( (maxCount == 1) && [attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
       
   659         // Children codes for ALL, SELECTED, VISIBLE are <0. If the code is >=0, we treat it as an index to a single child
       
   660         NSArray *child = [JavaComponentAccessibility childrenOfParent:self withEnv:[ThreadUtilities getJNIEnv] withChildrenCode:(NSInteger)index allowIgnored:NO];
       
   661         if ([child count] > 0) {
       
   662             return child;
       
   663         }
       
   664     }
       
   665     return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
       
   666 }
       
   667 
       
   668 // Flag indicating enabled state of element (NSNumber)
       
   669 - (NSNumber *)accessibilityEnabledAttribute
       
   670 {
       
   671     static JNF_STATIC_MEMBER_CACHE(jm_isEnabled, sjc_CAccessibility, "isEnabled", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Z");
       
   672 
       
   673     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   674     NSNumber *value = [NSNumber numberWithBool:JNFCallStaticBooleanMethod(env, jm_isEnabled, fAccessible, fComponent)]; // AWT_THREADING Safe (AWTRunLoop)
       
   675     if (value == nil) {
       
   676         NSLog(@"WARNING: %s called on component that has no accessible component: %@", __FUNCTION__, self);
       
   677     }
       
   678     return value;
       
   679 }
       
   680 
       
   681 - (BOOL)accessibilityIsEnabledAttributeSettable
       
   682 {
       
   683     return NO;
       
   684 }
       
   685 
       
   686 // Flag indicating presence of keyboard focus (NSNumber)
       
   687 - (NSNumber *)accessibilityFocusedAttribute
       
   688 {
       
   689     if ([self accessibilityIsFocusedAttributeSettable]) {
       
   690         return [NSNumber numberWithBool:[self isEqual:[NSApp accessibilityFocusedUIElement]]];
       
   691     }
       
   692     return [NSNumber numberWithBool:NO];
       
   693 }
       
   694 
       
   695 - (BOOL)accessibilityIsFocusedAttributeSettable
       
   696 {
       
   697     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   698     // According to javadoc, a component that is focusable will return true from isFocusTraversable,
       
   699     // as well as having AccessibleState.FOCUSABLE in its AccessibleStateSet.
       
   700     // We use the former heuristic; if the component focus-traversable, add a focused attribute
       
   701     // See also initializeAttributeNamesWithEnv:
       
   702     if (JNFCallStaticBooleanMethod(env, sjm_isFocusTraversable, fAccessible, fComponent)) { // AWT_THREADING Safe (AWTRunLoop)
       
   703         return YES;
       
   704     }
       
   705 
       
   706     return NO;
       
   707 }
       
   708 
       
   709 - (void)accessibilitySetFocusedAttribute:(id)value
       
   710 {
       
   711     static JNF_STATIC_MEMBER_CACHE(jm_requestFocus, sjc_CAccessibility, "requestFocus", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)V");
       
   712 
       
   713     if ([(NSNumber*)value boolValue])
       
   714     {
       
   715         JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   716         JNFCallStaticVoidMethod(env, jm_requestFocus, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
   717     }
       
   718 }
       
   719 
       
   720 // Instance description, such as a help tag string (NSString)
       
   721 - (NSString *)accessibilityHelpAttribute
       
   722 {
       
   723     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   724 
       
   725     jobject val = JNFCallStaticObjectMethod(env, sjm_getAccessibleDescription, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
   726     return JNFJavaToNSString(env, val);
       
   727 }
       
   728 
       
   729 - (BOOL)accessibilityIsHelpAttributeSettable
       
   730 {
       
   731     return NO;
       
   732 }
       
   733 
       
   734 // Element's maximum value (id)
       
   735 - (id)accessibilityMaxValueAttribute
       
   736 {
       
   737     static JNF_STATIC_MEMBER_CACHE(jm_getMaximumAccessibleValue, sjc_CAccessibility, "getMaximumAccessibleValue", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/Number;");
       
   738 
       
   739     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   740 
       
   741     jobject axValue = JNFCallStaticObjectMethod(env, jm_getMaximumAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
   742     return JNFJavaToNSNumber(env, axValue);
       
   743 }
       
   744 
       
   745 - (BOOL)accessibilityIsMaxValueAttributeSettable
       
   746 {
       
   747     return NO;
       
   748 }
       
   749 
       
   750 // Element's minimum value (id)
       
   751 - (id)accessibilityMinValueAttribute
       
   752 {
       
   753     static JNF_STATIC_MEMBER_CACHE(jm_getMinimumAccessibleValue, sjc_CAccessibility, "getMinimumAccessibleValue", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/Number;");
       
   754 
       
   755     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   756 
       
   757     jobject axValue = JNFCallStaticObjectMethod(env, jm_getMinimumAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
   758     return JNFJavaToNSNumber(env, axValue);
       
   759 }
       
   760 
       
   761 - (BOOL)accessibilityIsMinValueAttributeSettable
       
   762 {
       
   763     return NO;
       
   764 }
       
   765 
       
   766 - (id)accessibilityOrientationAttribute
       
   767 {
       
   768     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   769     jobject axContext = [self axContextWithEnv:env];
       
   770 
       
   771     // cmcnote - should batch these two calls into one that returns an array of two bools, one for vertical and one for horiz
       
   772     if (isVertical(env, axContext, fComponent)) {
       
   773         return NSAccessibilityVerticalOrientationValue;
       
   774     }
       
   775 
       
   776     if (isHorizontal(env, axContext, fComponent)) {
       
   777         return NSAccessibilityHorizontalOrientationValue;
       
   778     }
       
   779 
       
   780     return nil;
       
   781 }
       
   782 
       
   783 - (BOOL)accessibilityIsOrientationAttributeSettable
       
   784 {
       
   785     return NO;
       
   786 }
       
   787 
       
   788 // Element containing current element (id)
       
   789 - (id)accessibilityParentAttribute
       
   790 {
       
   791     return NSAccessibilityUnignoredAncestor([self parent]);
       
   792 }
       
   793 
       
   794 - (BOOL)accessibilityIsParentAttributeSettable
       
   795 {
       
   796     return NO;
       
   797 }
       
   798 
       
   799 // Screen position of element's lower-left corner in lower-left relative screen coordinates (NSValue)
       
   800 - (NSValue *)accessibilityPositionAttribute
       
   801 {
       
   802     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   803     jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
   804 
       
   805     // NSAccessibility wants the bottom left point of the object in
       
   806     // bottom left based screen coords
       
   807 
       
   808     // Get the java screen coords, and make a NSPoint of the bottom left of the AxComponent.
       
   809     NSSize size = getAxComponentSize(env, axComponent, fComponent);
       
   810     NSPoint point = getAxComponentLocationOnScreen(env, axComponent, fComponent);
       
   811 
       
   812     point.y += size.height;
       
   813 
       
   814     // Now make it into Cocoa screen coords.
       
   815     point.y = [[[[self view] window] screen] frame].size.height - point.y;
       
   816 
       
   817     return [NSValue valueWithPoint:point];
       
   818 }
       
   819 
       
   820 - (BOOL)accessibilityIsPositionAttributeSettable
       
   821 {
       
   822     // In AppKit, position is only settable for a window (NSAccessibilityWindowRole). Our windows are taken care of natively, so we don't need to deal with this here
       
   823     // We *could* make use of Java's AccessibleComponent.setLocation() method. Investigate. radr://3953869
       
   824     return NO;
       
   825 }
       
   826 
       
   827 // Element type, such as NSAccessibilityRadioButtonRole (NSString). See the role table
       
   828 // at http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
       
   829 - (NSString *)accessibilityRoleAttribute
       
   830 {
       
   831     if (fNSRole == nil) {
       
   832         NSString *javaRole = [self javaRole];
       
   833         fNSRole = [sRoles objectForKey:javaRole];
       
   834         if (fNSRole == nil) {
       
   835             // this component has assigned itself a custom AccessibleRole not in the sRoles array
       
   836             fNSRole = javaRole;
       
   837         }
       
   838         [fNSRole retain];
       
   839     }
       
   840     return fNSRole;
       
   841 }
       
   842 - (BOOL)accessibilityIsRoleAttributeSettable
       
   843 {
       
   844     return NO;
       
   845 }
       
   846 
       
   847 // Localized, user-readable description of role, such as radio button (NSString)
       
   848 - (NSString *)accessibilityRoleDescriptionAttribute
       
   849 {
       
   850     // first ask AppKit for its accessible role description for a given AXRole
       
   851     NSString *value = NSAccessibilityRoleDescription([self accessibilityRoleAttribute], nil);
       
   852 
       
   853     if (value == nil) {
       
   854         // query java if necessary
       
   855         static JNF_STATIC_MEMBER_CACHE(jm_getAccessibleRoleDisplayString, sjc_CAccessibility, "getAccessibleRoleDisplayString", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
       
   856 
       
   857         JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   858 
       
   859         jobject axRole = JNFCallStaticObjectMethod(env, jm_getAccessibleRoleDisplayString, fAccessible, fComponent);
       
   860         if(axRole != NULL) {
       
   861             value = JNFJavaToNSString(env, axRole);
       
   862         } else {
       
   863             value = @"unknown";
       
   864         }
       
   865     }
       
   866 
       
   867     return value;
       
   868 }
       
   869 
       
   870 - (BOOL)accessibilityIsRoleDescriptionAttributeSettable
       
   871 {
       
   872     return NO;
       
   873 }
       
   874 
       
   875 // Currently selected children (NSArray)
       
   876 - (NSArray *)accessibilitySelectedChildrenAttribute
       
   877 {
       
   878     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   879     NSArray *selectedChildren = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_SELECTED_CHILDREN allowIgnored:NO];
       
   880     if ([selectedChildren count] > 0) {
       
   881         return selectedChildren;
       
   882     }
       
   883 
       
   884     return nil;
       
   885 }
       
   886 
       
   887 - (BOOL)accessibilityIsSelectedChildrenAttributeSettable
       
   888 {
       
   889     return NO; // cmcnote: actually it should be. so need to write accessibilitySetSelectedChildrenAttribute also
       
   890 }
       
   891 
       
   892 // Element size (NSValue)
       
   893 - (NSValue *)accessibilitySizeAttribute {
       
   894     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   895     jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
   896     return [NSValue valueWithSize:getAxComponentSize(env, axComponent, fComponent)];
       
   897 }
       
   898 
       
   899 - (BOOL)accessibilityIsSizeAttributeSettable
       
   900 {
       
   901     // SIZE is settable in windows if [self styleMask] & NSResizableWindowMask - but windows are heavyweight so we're ok here
       
   902     // SIZE is settable in columns if [[self tableValue] allowsColumnResizing - haven't dealt with columns yet
       
   903     return NO;
       
   904 }
       
   905 
       
   906 // Element subrole type, such as NSAccessibilityTableRowSubrole (NSString). See the subrole attribute table at
       
   907 // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
       
   908 - (NSString *)accessibilitySubroleAttribute
       
   909 {
       
   910     NSString *value = nil;
       
   911     if ([[self javaRole] isEqualToString:@"passwordtext"])
       
   912     {
       
   913         value = NSAccessibilitySecureTextFieldSubrole;
       
   914     }
       
   915     /*
       
   916     // other subroles. TableRow and OutlineRow may be relevant to us
       
   917      NSAccessibilityCloseButtonSubrole // no, heavyweight window takes care of this
       
   918      NSAccessibilityMinimizeButtonSubrole // "
       
   919      NSAccessibilityOutlineRowSubrole    // maybe?
       
   920      NSAccessibilitySecureTextFieldSubrole // currently used
       
   921      NSAccessibilityTableRowSubrole        // maybe?
       
   922      NSAccessibilityToolbarButtonSubrole // maybe?
       
   923      NSAccessibilityUnknownSubrole
       
   924      NSAccessibilityZoomButtonSubrole    // no, heavyweight window takes care of this
       
   925      NSAccessibilityStandardWindowSubrole// no, heavyweight window takes care of this
       
   926      NSAccessibilityDialogSubrole        // maybe?
       
   927      NSAccessibilitySystemDialogSubrole    // no
       
   928      NSAccessibilityFloatingWindowSubrole // in 1.5 if we implement these, heavyweight will take care of them anyway
       
   929      NSAccessibilitySystemFloatingWindowSubrole
       
   930      NSAccessibilityIncrementArrowSubrole  // no
       
   931      NSAccessibilityDecrementArrowSubrole  // no
       
   932      NSAccessibilityIncrementPageSubrole   // no
       
   933      NSAccessibilityDecrementPageSubrole   // no
       
   934      NSAccessibilitySearchFieldSubrole    //no
       
   935      */
       
   936     return value;
       
   937 }
       
   938 
       
   939 - (BOOL)accessibilityIsSubroleAttributeSettable
       
   940 {
       
   941     return NO;
       
   942 }
       
   943 
       
   944 // Title of element, such as button text (NSString)
       
   945 - (NSString *)accessibilityTitleAttribute
       
   946 {
       
   947     // Return empty string for labels, since their value and tile end up being the same thing and this leads to repeated text.
       
   948     if ([[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityStaticTextRole]) {
       
   949         return @"";
       
   950     }
       
   951 
       
   952     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   953 
       
   954     jobject val = JNFCallStaticObjectMethod(env, sjm_getAccessibleName, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
   955     return JNFJavaToNSString(env, val);
       
   956 }
       
   957 
       
   958 - (BOOL)accessibilityIsTitleAttributeSettable
       
   959 {
       
   960     return NO;
       
   961 }
       
   962 
       
   963 - (NSWindow *)accessibilityTopLevelUIElementAttribute
       
   964 {
       
   965     return [self window];
       
   966 }
       
   967 
       
   968 - (BOOL)accessibilityIsTopLevelUIElementAttributeSettable
       
   969 {
       
   970     return NO;
       
   971 }
       
   972 
       
   973 // Element's value (id)
       
   974 // note that the appKit meaning of "accessibilityValue" is different from the java
       
   975 // meaning of "accessibleValue", which is specific to numerical values
       
   976 // (http://java.sun.com/j2se/1.3/docs/api/javax/accessibility/AccessibleValue.html#setCurrentAccessibleValue(java.lang.Number))
       
   977 - (id)accessibilityValueAttribute
       
   978 {
       
   979     static JNF_STATIC_MEMBER_CACHE(jm_getCurrentAccessibleValue, sjc_CAccessibility, "getCurrentAccessibleValue", "(Ljavax/accessibility/AccessibleValue;Ljava/awt/Component;)Ljava/lang/Number;");
       
   980 
       
   981     JNIEnv* env = [ThreadUtilities getJNIEnv];
       
   982 
       
   983     // ask Java for the component's accessibleValue. In java, the "accessibleValue" just means a numerical value
       
   984     // a text value is taken care of in JavaTextAccessibility
       
   985 
       
   986     // cmcnote should coalesce these calls into one java call
       
   987     jobject axValue = JNFCallStaticObjectMethod(env, sjm_getAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
   988     return JNFJavaToNSNumber(env, JNFCallStaticObjectMethod(env, jm_getCurrentAccessibleValue, axValue, fComponent)); // AWT_THREADING Safe (AWTRunLoop)
       
   989 }
       
   990 
       
   991 - (BOOL)accessibilityIsValueAttributeSettable
       
   992 {
       
   993     // according ot AppKit sources, in general the value attribute is not settable, except in the cases
       
   994     // of an NSScroller, an NSSplitView, and text that's both enabled & editable
       
   995     BOOL isSettable = NO;
       
   996     NSString *role = [self accessibilityRoleAttribute];
       
   997 
       
   998     if ([role isEqualToString:NSAccessibilityScrollBarRole] || // according to NSScrollerAccessibility
       
   999         [role isEqualToString:NSAccessibilitySplitGroupRole] ) // according to NSSplitViewAccessibility
       
  1000     {
       
  1001         isSettable = YES;
       
  1002     }
       
  1003     return isSettable;
       
  1004 }
       
  1005 
       
  1006 - (void)accessibilitySetValueAttribute:(id)value
       
  1007 {
       
  1008 #ifdef JAVA_AX_DEBUG
       
  1009     NSLog(@"Not yet implemented: %s\n", __FUNCTION__); // radr://3954018
       
  1010 #endif
       
  1011 }
       
  1012 
       
  1013 
       
  1014 // Child elements that are visible (NSArray)
       
  1015 - (NSArray *)accessibilityVisibleChildrenAttribute
       
  1016 {
       
  1017     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1018     NSArray *visibleChildren = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_VISIBLE_CHILDREN allowIgnored:NO];
       
  1019     if ([visibleChildren count] <= 0) return nil;
       
  1020     return visibleChildren;
       
  1021 }
       
  1022 
       
  1023 - (BOOL)accessibilityIsVisibleChildrenAttributeSettable
       
  1024 {
       
  1025     return NO;
       
  1026 }
       
  1027 
       
  1028 // Window containing current element (id)
       
  1029 - (id)accessibilityWindowAttribute
       
  1030 {
       
  1031     return [self window];
       
  1032 }
       
  1033 
       
  1034 - (BOOL)accessibilityIsWindowAttributeSettable
       
  1035 {
       
  1036     return NO;
       
  1037 }
       
  1038 
       
  1039 
       
  1040 // -- accessibility actions --
       
  1041 - (NSArray *)accessibilityActionNames
       
  1042 {
       
  1043     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1044     return [[self getActions:env] allKeys];
       
  1045 }
       
  1046 
       
  1047 - (NSString *)accessibilityActionDescription:(NSString *)action
       
  1048 {
       
  1049     AWT_ASSERT_APPKIT_THREAD;
       
  1050 
       
  1051     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1052     return [(id <JavaAccessibilityAction>)[[self getActions:env] objectForKey:action] getDescription];
       
  1053 }
       
  1054 
       
  1055 - (void)accessibilityPerformAction:(NSString *)action
       
  1056 {
       
  1057     AWT_ASSERT_APPKIT_THREAD;
       
  1058 
       
  1059     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1060     [(id <JavaAccessibilityAction>)[[self getActions:env] objectForKey:action] perform];
       
  1061 }
       
  1062 
       
  1063 
       
  1064 // -- misc accessibility --
       
  1065 - (BOOL)accessibilityIsIgnored
       
  1066 {
       
  1067 #ifdef JAVA_AX_NO_IGNORES
       
  1068     return NO;
       
  1069 #else
       
  1070     return [[self accessibilityRoleAttribute] isEqualToString:JavaAccessibilityIgnore];
       
  1071 #endif /* JAVA_AX_NO_IGNORES */
       
  1072 }
       
  1073 
       
  1074 - (id)accessibilityHitTest:(NSPoint)point withEnv:(JNIEnv *)env
       
  1075 {
       
  1076     static JNF_CLASS_CACHE(jc_Container, "java/awt/Container");
       
  1077     static JNF_STATIC_MEMBER_CACHE(jm_accessibilityHitTest, sjc_CAccessibility, "accessibilityHitTest", "(Ljava/awt/Container;FF)Ljavax/accessibility/Accessible;");
       
  1078 
       
  1079     // Make it into java screen coords
       
  1080     point.y = [[[[self view] window] screen] frame].size.height - point.y;
       
  1081 
       
  1082     jobject jparent = fComponent;
       
  1083 
       
  1084     id value = nil;
       
  1085     if (JNFIsInstanceOf(env, jparent, &jc_Container)) {
       
  1086         jobject jaccessible = JNFCallStaticObjectMethod(env, jm_accessibilityHitTest, jparent, (jfloat)point.x, (jfloat)point.y); // AWT_THREADING Safe (AWTRunLoop)
       
  1087         value = [JavaComponentAccessibility createWithAccessible:jaccessible withEnv:env withView:fView];
       
  1088     }
       
  1089 
       
  1090     if (value == nil) {
       
  1091         value = self;
       
  1092     }
       
  1093 
       
  1094     if ([value accessibilityIsIgnored]) {
       
  1095         value = NSAccessibilityUnignoredAncestor(value);
       
  1096     }
       
  1097 
       
  1098 #ifdef JAVA_AX_DEBUG
       
  1099     NSLog(@"%s: %@", __FUNCTION__, value);
       
  1100 #endif
       
  1101     return value;
       
  1102 }
       
  1103 
       
  1104 - (id)accessibilityFocusedUIElement
       
  1105 {
       
  1106     static JNF_STATIC_MEMBER_CACHE(jm_getFocusOwner, sjc_CAccessibility, "getFocusOwner", "(Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
       
  1107 
       
  1108     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1109     id value = nil;
       
  1110 
       
  1111     jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop)
       
  1112     if (focused != NULL) {
       
  1113         if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) {
       
  1114             value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView];
       
  1115         }
       
  1116     }
       
  1117 
       
  1118     if (value == nil) {
       
  1119         value = self;
       
  1120     }
       
  1121 #ifdef JAVA_AX_DEBUG
       
  1122     NSLog(@"%s: %@", __FUNCTION__, value);
       
  1123 #endif
       
  1124     return value;
       
  1125 }
       
  1126 
       
  1127 @end
       
  1128 
       
  1129 /*
       
  1130  * Class:     sun_lwawt_macosx_CAccessibility
       
  1131  * Method:    focusChanged
       
  1132  * Signature: ()V
       
  1133  */
       
  1134 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged
       
  1135 (JNIEnv *env, jobject jthis)
       
  1136 {
       
  1137 
       
  1138 JNF_COCOA_ENTER(env);
       
  1139     [ThreadUtilities performOnMainThread:@selector(postFocusChanged:) on:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO];
       
  1140 JNF_COCOA_EXIT(env);
       
  1141 }
       
  1142 
       
  1143 
       
  1144 
       
  1145 /*
       
  1146  * Class:     sun_lwawt_macosx_CAccessible
       
  1147  * Method:    valueChanged
       
  1148  * Signature: (I)V
       
  1149  */
       
  1150 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_valueChanged
       
  1151 (JNIEnv *env, jclass jklass, jlong element)
       
  1152 {
       
  1153 JNF_COCOA_ENTER(env);
       
  1154     [ThreadUtilities performOnMainThread:@selector(postValueChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
       
  1155 JNF_COCOA_EXIT(env);
       
  1156 }
       
  1157 
       
  1158 /*
       
  1159  * Class:     sun_lwawt_macosx_CAccessible
       
  1160  * Method:    selectionChanged
       
  1161  * Signature: (I)V
       
  1162  */
       
  1163 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged
       
  1164 (JNIEnv *env, jclass jklass, jlong element)
       
  1165 {
       
  1166 JNF_COCOA_ENTER(env);
       
  1167     [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
       
  1168 JNF_COCOA_EXIT(env);
       
  1169 }
       
  1170 
       
  1171 
       
  1172 /*
       
  1173  * Class:     sun_lwawt_macosx_CAccessible
       
  1174  * Method:    unregisterFromCocoaAXSystem
       
  1175  * Signature: (I)V
       
  1176  */
       
  1177 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSystem
       
  1178 (JNIEnv *env, jclass jklass, jlong element)
       
  1179 {
       
  1180 JNF_COCOA_ENTER(env);
       
  1181     [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
       
  1182 JNF_COCOA_EXIT(env);
       
  1183 }
       
  1184 
       
  1185 @implementation TabGroupAccessibility
       
  1186 
       
  1187 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
       
  1188 {
       
  1189     self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
       
  1190     if (self) {
       
  1191         _numTabs = -1; //flag for uninitialized numTabs
       
  1192     }
       
  1193     return self;
       
  1194 }
       
  1195 
       
  1196 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
       
  1197 {
       
  1198     NSMutableArray *names = (NSMutableArray *)[super initializeAttributeNamesWithEnv:env];
       
  1199 
       
  1200     [names addObject:NSAccessibilityTabsAttribute];
       
  1201     [names addObject:NSAccessibilityContentsAttribute];
       
  1202     [names addObject:NSAccessibilityValueAttribute];
       
  1203 
       
  1204     return names;
       
  1205 }
       
  1206 
       
  1207 - (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext
       
  1208 {
       
  1209     NSArray *tabs = [self tabControlsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];
       
  1210 
       
  1211     // Looking at the JTabbedPane sources, there is always one AccessibleSelection.
       
  1212     jobject selAccessible = getAxContextSelection(env, axContext, 0, fComponent);
       
  1213     if (selAccessible == NULL) return nil;
       
  1214 
       
  1215     // Go through the tabs and find selAccessible
       
  1216     _numTabs = [tabs count];
       
  1217     JavaComponentAccessibility *aTab;
       
  1218     NSInteger i;
       
  1219     for (i = 0; i < _numTabs; i++) {
       
  1220         aTab = (JavaComponentAccessibility *)[tabs objectAtIndex:i];
       
  1221         if ([aTab isAccessibleWithEnv:env forAccessible:selAccessible]) {
       
  1222             return aTab;
       
  1223         }
       
  1224     }
       
  1225 
       
  1226     return nil;
       
  1227 }
       
  1228 
       
  1229 - (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
       
  1230 {
       
  1231     jobjectArray jtabsAndRoles = JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, fAccessible, fComponent, whichTabs, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
       
  1232     if(jtabsAndRoles == NULL) return nil;
       
  1233 
       
  1234     jsize arrayLen = (*env)->GetArrayLength(env, jtabsAndRoles);
       
  1235     if (arrayLen == 0) return nil;
       
  1236 
       
  1237     NSMutableArray *tabs = [NSMutableArray arrayWithCapacity:(arrayLen/2)];
       
  1238 
       
  1239     // all of the tabs have the same role, so we can just find out what that is here and use it for all the tabs
       
  1240     jobject jtabJavaRole = (*env)->GetObjectArrayElement(env, jtabsAndRoles, 1); // the array entries alternate between tab/role, starting with tab. so the first role is entry 1.
       
  1241     if (jtabJavaRole == NULL) return nil;
       
  1242 
       
  1243     NSString *tabJavaRole = JNFJavaToNSString(env, JNFGetObjectField(env, jtabJavaRole, sjf_key));
       
  1244 
       
  1245     NSInteger i;
       
  1246     NSUInteger tabIndex = (whichTabs >= 0) ? whichTabs : 0; // if we're getting one particular child, make sure to set its index correctly
       
  1247     for(i = 0; i < arrayLen; i+=2) {
       
  1248         jobject jtab = (*env)->GetObjectArrayElement(env, jtabsAndRoles, i);
       
  1249         JavaComponentAccessibility *tab = [[[TabGroupControlAccessibility alloc] initWithParent:self withEnv:env withAccessible:jtab withIndex:tabIndex withTabGroup:axContext withView:[self view] withJavaRole:tabJavaRole] autorelease];
       
  1250         [tabs addObject:tab];
       
  1251         tabIndex++;
       
  1252     }
       
  1253 
       
  1254     return tabs;
       
  1255 }
       
  1256 
       
  1257 - (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
       
  1258 {
       
  1259     // Contents are the children of the selected tab.
       
  1260     id currentTab = [self currentTabWithEnv:env withAxContext:axContext];
       
  1261     if (currentTab == nil) return nil;
       
  1262 
       
  1263     NSArray *contents = [JavaComponentAccessibility childrenOfParent:currentTab withEnv:env withChildrenCode:whichTabs allowIgnored:allowIgnored];
       
  1264     if ([contents count] <= 0) return nil;
       
  1265     return contents;
       
  1266 }
       
  1267 
       
  1268 - (id) accessibilityTabsAttribute
       
  1269 {
       
  1270     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1271     jobject axContext = [self axContextWithEnv:env];
       
  1272     return [self tabControlsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];
       
  1273 }
       
  1274 
       
  1275 - (BOOL)accessibilityIsTabsAttributeSettable
       
  1276 {
       
  1277     return NO; //cmcnote: not sure.
       
  1278 }
       
  1279 
       
  1280 - (NSInteger)numTabs
       
  1281 {
       
  1282     if (_numTabs == -1) {
       
  1283         _numTabs = [[self accessibilityTabsAttribute] count];
       
  1284     }
       
  1285     return _numTabs;
       
  1286 }
       
  1287 
       
  1288 - (NSArray *) accessibilityContentsAttribute
       
  1289 {
       
  1290     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1291     jobject axContext = [self axContextWithEnv:env];
       
  1292     return [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];
       
  1293 }
       
  1294 
       
  1295 - (BOOL)accessibilityIsContentsAttributeSettable
       
  1296 {
       
  1297     return NO;
       
  1298 }
       
  1299 
       
  1300 // axValue is the currently selected tab
       
  1301 -(id) accessibilityValueAttribute
       
  1302 {
       
  1303     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1304     jobject axContext = [self axContextWithEnv:env];
       
  1305     return [self currentTabWithEnv:env withAxContext:axContext];
       
  1306 }
       
  1307 
       
  1308 - (BOOL)accessibilityIsValueAttributeSettable
       
  1309 {
       
  1310     return YES;
       
  1311 }
       
  1312 
       
  1313 - (void)accessibilitySetValueAttribute:(id)value //cmcnote: not certain this is ever actually called. investigate.
       
  1314 {
       
  1315     // set the current tab
       
  1316     NSNumber *number = (NSNumber *)value;
       
  1317     if (![number boolValue]) return;
       
  1318 
       
  1319     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1320     jobject axContext = [self axContextWithEnv:env];
       
  1321     setAxContextSelection(env, axContext, fIndex, fComponent);
       
  1322 }
       
  1323 
       
  1324 - (NSArray *)accessibilityChildrenAttribute
       
  1325 {
       
  1326     //children = AXTabs + AXContents
       
  1327     NSArray *tabs = [self accessibilityTabsAttribute];
       
  1328     NSArray *contents = [self accessibilityContentsAttribute];
       
  1329 
       
  1330     NSMutableArray *children = [NSMutableArray arrayWithCapacity:[tabs count] + [contents count]];
       
  1331     [children addObjectsFromArray:tabs];
       
  1332     [children addObjectsFromArray:contents];
       
  1333 
       
  1334     return (NSArray *)children;
       
  1335 }
       
  1336 
       
  1337 // Without this optimization accessibilityChildrenAttribute is called in order to get the entire array of children.
       
  1338 // See similar optimization in JavaComponentAccessibility. We have to extend the base implementation here, since
       
  1339 // children of tabs are AXTabs + AXContents
       
  1340 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount {
       
  1341     NSArray *result = nil;
       
  1342     if ( (maxCount == 1) && [attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
       
  1343         // Children codes for ALL, SELECTED, VISIBLE are <0. If the code is >=0, we treat it as an index to a single child
       
  1344         JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1345         jobject axContext = [self axContextWithEnv:env];
       
  1346 
       
  1347         //children = AXTabs + AXContents
       
  1348         NSArray *children = [self tabControlsWithEnv:env withTabGroupAxContext:axContext withTabCode:index allowIgnored:NO]; // first look at the tabs
       
  1349         if ([children count] > 0) {
       
  1350             result = children;
       
  1351          } else {
       
  1352             children= [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:(index-[self numTabs]) allowIgnored:NO];
       
  1353             if ([children count] > 0) {
       
  1354                 result = children;
       
  1355             }
       
  1356         }
       
  1357     } else {
       
  1358         result = [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
       
  1359     }
       
  1360     return result;
       
  1361 }
       
  1362 
       
  1363 @end
       
  1364 
       
  1365 
       
  1366 static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
       
  1367 
       
  1368 @implementation TabGroupControlAccessibility
       
  1369 
       
  1370 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole
       
  1371 {
       
  1372     self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
       
  1373     if (self) {
       
  1374         if (tabGroup != NULL) {
       
  1375             fTabGroupAxContext = JNFNewGlobalRef(env, tabGroup);
       
  1376         } else {
       
  1377             fTabGroupAxContext = NULL;
       
  1378         }
       
  1379     }
       
  1380     return self;
       
  1381 }
       
  1382 
       
  1383 - (void)dealloc
       
  1384 {
       
  1385     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
       
  1386 
       
  1387     if (fTabGroupAxContext != NULL) {
       
  1388         JNFDeleteGlobalRef(env, fTabGroupAxContext);
       
  1389         fTabGroupAxContext = NULL;
       
  1390     }
       
  1391 
       
  1392     [super dealloc];
       
  1393 }
       
  1394 
       
  1395 - (id)accessibilityValueAttribute
       
  1396 {
       
  1397     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1398     jobject axContext = [self axContextWithEnv:env];
       
  1399 
       
  1400     // Returns the current selection of the page tab list
       
  1401     return [NSNumber numberWithBool:ObjectEquals(env, axContext, getAxContextSelection(env, [self tabGroup], fIndex, fComponent), fComponent)];
       
  1402 }
       
  1403 
       
  1404 - (void)getActionsWithEnv:(JNIEnv *)env
       
  1405 {
       
  1406     TabGroupAction *action = [[TabGroupAction alloc] initWithEnv:env withTabGroup:[self tabGroup] withIndex:fIndex withComponent:fComponent];
       
  1407     [fActions setObject:action forKey:NSAccessibilityPressAction];
       
  1408     [action release];
       
  1409 }
       
  1410 
       
  1411 - (jobject)tabGroup
       
  1412 {
       
  1413     if (fTabGroupAxContext == NULL) {
       
  1414         JNIEnv* env = [ThreadUtilities getJNIEnv];
       
  1415         jobject tabGroupAxContext = [(JavaComponentAccessibility *)[self parent] axContextWithEnv:env];
       
  1416         fTabGroupAxContext = JNFNewGlobalRef(env, tabGroupAxContext);
       
  1417     }
       
  1418     return fTabGroupAxContext;
       
  1419 }
       
  1420 
       
  1421 @end
       
  1422 
       
  1423 
       
  1424 @implementation ScrollAreaAccessibility
       
  1425 
       
  1426 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
       
  1427 {
       
  1428     NSMutableArray *names = (NSMutableArray *)[super initializeAttributeNamesWithEnv:env];
       
  1429 
       
  1430     [names addObject:NSAccessibilityHorizontalScrollBarAttribute];
       
  1431     [names addObject:NSAccessibilityVerticalScrollBarAttribute];
       
  1432     [names addObject:NSAccessibilityContentsAttribute];
       
  1433 
       
  1434     return names;
       
  1435 }
       
  1436 
       
  1437 - (id)accessibilityHorizontalScrollBarAttribute
       
  1438 {
       
  1439     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1440 
       
  1441     NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
       
  1442     if ([children count] <= 0) return nil;
       
  1443 
       
  1444     // The scroll bars are in the children.
       
  1445     JavaComponentAccessibility *aElement;
       
  1446     NSEnumerator *enumerator = [children objectEnumerator];
       
  1447     while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
       
  1448         if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
       
  1449             jobject elementAxContext = [aElement axContextWithEnv:env];
       
  1450             if (isHorizontal(env, elementAxContext, fComponent)) {
       
  1451                 return aElement;
       
  1452             }
       
  1453         }
       
  1454     }
       
  1455 
       
  1456     return nil;
       
  1457 }
       
  1458 
       
  1459 - (BOOL)accessibilityIsHorizontalScrollBarAttributeSettable
       
  1460 {
       
  1461     return NO;
       
  1462 }
       
  1463 
       
  1464 - (id)accessibilityVerticalScrollBarAttribute
       
  1465 {
       
  1466     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1467 
       
  1468     NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
       
  1469     if ([children count] <= 0) return nil;
       
  1470 
       
  1471     // The scroll bars are in the children.
       
  1472     NSEnumerator *enumerator = [children objectEnumerator];
       
  1473     JavaComponentAccessibility *aElement;
       
  1474     while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
       
  1475         if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
       
  1476             jobject elementAxContext = [aElement axContextWithEnv:env];
       
  1477             if (isVertical(env, elementAxContext, fComponent)) {
       
  1478                 return aElement;
       
  1479             }
       
  1480         }
       
  1481     }
       
  1482 
       
  1483     return nil;
       
  1484 }
       
  1485 
       
  1486 - (BOOL)accessibilityIsVerticalScrollBarAttributeSettable
       
  1487 {
       
  1488     return NO;
       
  1489 }
       
  1490 
       
  1491 - (NSArray *)accessibilityContentsAttribute
       
  1492 {
       
  1493     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
  1494     NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
       
  1495 
       
  1496     if ([children count] <= 0) return nil;
       
  1497     NSArray *contents = [NSMutableArray arrayWithCapacity:[children count]];
       
  1498 
       
  1499     // The scroll bars are in the children. children less the scroll bars is the contents
       
  1500     NSEnumerator *enumerator = [children objectEnumerator];
       
  1501     JavaComponentAccessibility *aElement;
       
  1502     while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
       
  1503         if (![[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
       
  1504             // no scroll bars in contents
       
  1505             [(NSMutableArray *)contents addObject:aElement];
       
  1506         }
       
  1507     }
       
  1508 
       
  1509     return contents;
       
  1510 }
       
  1511 
       
  1512 - (BOOL)accessibilityIsContentsAttributeSettable
       
  1513 {
       
  1514     return NO;
       
  1515 }
       
  1516 
       
  1517 @end
       
  1518 
       
  1519 /*
       
  1520  * Returns Object.equals for the two items
       
  1521  * This may use LWCToolkit.invokeAndWait(); don't call while holding fLock
       
  1522  * and try to pass a component so the event happens on the correct thread.
       
  1523  */
       
  1524 static JNF_CLASS_CACHE(sjc_Object, "java/lang/Object");
       
  1525 static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component)
       
  1526 {
       
  1527     static JNF_MEMBER_CACHE(jm_equals, sjc_Object, "equals", "(Ljava/lang/Object;)Z");
       
  1528 
       
  1529     if ((a == NULL) && (b == NULL)) return YES;
       
  1530     if ((a == NULL) || (b == NULL)) return NO;
       
  1531 
       
  1532     if (pthread_main_np() != 0) {
       
  1533         // If we are on the AppKit thread
       
  1534         static JNF_CLASS_CACHE(sjc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit");
       
  1535         static JNF_STATIC_MEMBER_CACHE(jm_doEquals, sjc_LWCToolkit, "doEquals", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/awt/Component;)Z");
       
  1536         return JNFCallStaticBooleanMethod(env, jm_doEquals, a, b, component); // AWT_THREADING Safe (AWTRunLoopMode)
       
  1537     }
       
  1538 
       
  1539     return JNFCallBooleanMethod(env, a, jm_equals, b); // AWT_THREADING Safe (!appKit)
       
  1540 }