< prev index next >

src/java.desktop/macosx/native/libawt_lwawt/awt/JavaComponentAccessibility.m

Print this page




 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 }


 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?


 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


 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         }


 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 {


 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


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     NSWindow* hostWindow = [[self->fView window] retain];
1112     jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop)
1113     [hostWindow release];
1114     
1115     if (focused != NULL) {
1116         if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) {
1117             value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView];
1118         }

1119     }
1120 
1121     if (value == nil) {
1122         value = self;
1123     }
1124 #ifdef JAVA_AX_DEBUG
1125     NSLog(@"%s: %@", __FUNCTION__, value);
1126 #endif
1127     return value;
1128 }
1129 
1130 @end
1131 
1132 /*
1133  * Class:     sun_lwawt_macosx_CAccessibility
1134  * Method:    focusChanged
1135  * Signature: ()V
1136  */
1137 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged
1138 (JNIEnv *env, jobject jthis)


1218     // Go through the tabs and find selAccessible
1219     _numTabs = [tabs count];
1220     JavaComponentAccessibility *aTab;
1221     NSInteger i;
1222     for (i = 0; i < _numTabs; i++) {
1223         aTab = (JavaComponentAccessibility *)[tabs objectAtIndex:i];
1224         if ([aTab isAccessibleWithEnv:env forAccessible:selAccessible]) {
1225             return aTab;
1226         }
1227     }
1228 
1229     return nil;
1230 }
1231 
1232 - (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
1233 {
1234     jobjectArray jtabsAndRoles = JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, fAccessible, fComponent, whichTabs, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
1235     if(jtabsAndRoles == NULL) return nil;
1236 
1237     jsize arrayLen = (*env)->GetArrayLength(env, jtabsAndRoles);
1238     if (arrayLen == 0) return nil;
1239 


1240     NSMutableArray *tabs = [NSMutableArray arrayWithCapacity:(arrayLen/2)];
1241 
1242     // 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
1243     jobject jtabJavaRole = (*env)->GetObjectArrayElement(env, jtabsAndRoles, 1); // the array entries alternate between tab/role, starting with tab. so the first role is entry 1.
1244     if (jtabJavaRole == NULL) return nil;
1245 


1246     NSString *tabJavaRole = JNFJavaToNSString(env, JNFGetObjectField(env, jtabJavaRole, sjf_key));
1247 
1248     NSInteger i;
1249     NSUInteger tabIndex = (whichTabs >= 0) ? whichTabs : 0; // if we're getting one particular child, make sure to set its index correctly
1250     for(i = 0; i < arrayLen; i+=2) {
1251         jobject jtab = (*env)->GetObjectArrayElement(env, jtabsAndRoles, i);
1252         JavaComponentAccessibility *tab = [[[TabGroupControlAccessibility alloc] initWithParent:self withEnv:env withAccessible:jtab withIndex:tabIndex withTabGroup:axContext withView:[self view] withJavaRole:tabJavaRole] autorelease];
1253         [tabs addObject:tab];
1254         tabIndex++;
1255     }
1256 
1257     return tabs;
1258 }
1259 
1260 - (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
1261 {
1262     // Contents are the children of the selected tab.
1263     id currentTab = [self currentTabWithEnv:env withAxContext:axContext];
1264     if (currentTab == nil) return nil;
1265 
1266     NSArray *contents = [JavaComponentAccessibility childrenOfParent:currentTab withEnv:env withChildrenCode:whichTabs allowIgnored:allowIgnored];
1267     if ([contents count] <= 0) return nil;
1268     return contents;
1269 }
1270 
1271 - (id) accessibilityTabsAttribute
1272 {
1273     JNIEnv *env = [ThreadUtilities getJNIEnv];
1274     jobject axContext = [self axContextWithEnv:env];
1275     return [self tabControlsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];


1276 }
1277 
1278 - (BOOL)accessibilityIsTabsAttributeSettable
1279 {
1280     return NO; //cmcnote: not sure.
1281 }
1282 
1283 - (NSInteger)numTabs
1284 {
1285     if (_numTabs == -1) {
1286         _numTabs = [[self accessibilityTabsAttribute] count];
1287     }
1288     return _numTabs;
1289 }
1290 
1291 - (NSArray *) accessibilityContentsAttribute
1292 {
1293     JNIEnv *env = [ThreadUtilities getJNIEnv];
1294     jobject axContext = [self axContextWithEnv:env];
1295     return [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];


1296 }
1297 
1298 - (BOOL)accessibilityIsContentsAttributeSettable
1299 {
1300     return NO;
1301 }
1302 
1303 // axValue is the currently selected tab
1304 -(id) accessibilityValueAttribute
1305 {
1306     JNIEnv *env = [ThreadUtilities getJNIEnv];
1307     jobject axContext = [self axContextWithEnv:env];
1308     return [self currentTabWithEnv:env withAxContext:axContext];


1309 }
1310 
1311 - (BOOL)accessibilityIsValueAttributeSettable
1312 {
1313     return YES;
1314 }
1315 
1316 - (void)accessibilitySetValueAttribute:(id)value //cmcnote: not certain this is ever actually called. investigate.
1317 {
1318     // set the current tab
1319     NSNumber *number = (NSNumber *)value;
1320     if (![number boolValue]) return;
1321 
1322     JNIEnv *env = [ThreadUtilities getJNIEnv];
1323     jobject axContext = [self axContextWithEnv:env];
1324     setAxContextSelection(env, axContext, fIndex, fComponent);

1325 }
1326 
1327 - (NSArray *)accessibilityChildrenAttribute
1328 {
1329     //children = AXTabs + AXContents
1330     NSArray *tabs = [self accessibilityTabsAttribute];
1331     NSArray *contents = [self accessibilityContentsAttribute];
1332 
1333     NSMutableArray *children = [NSMutableArray arrayWithCapacity:[tabs count] + [contents count]];
1334     [children addObjectsFromArray:tabs];
1335     [children addObjectsFromArray:contents];
1336 
1337     return (NSArray *)children;
1338 }
1339 
1340 // Without this optimization accessibilityChildrenAttribute is called in order to get the entire array of children.
1341 // See similar optimization in JavaComponentAccessibility. We have to extend the base implementation here, since
1342 // children of tabs are AXTabs + AXContents
1343 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount {
1344     NSArray *result = nil;
1345     if ( (maxCount == 1) && [attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
1346         // Children codes for ALL, SELECTED, VISIBLE are <0. If the code is >=0, we treat it as an index to a single child
1347         JNIEnv *env = [ThreadUtilities getJNIEnv];
1348         jobject axContext = [self axContextWithEnv:env];
1349 
1350         //children = AXTabs + AXContents
1351         NSArray *children = [self tabControlsWithEnv:env withTabGroupAxContext:axContext withTabCode:index allowIgnored:NO]; // first look at the tabs
1352         if ([children count] > 0) {
1353             result = children;
1354          } else {
1355             children= [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:(index-[self numTabs]) allowIgnored:NO];
1356             if ([children count] > 0) {
1357                 result = children;
1358             }
1359         }

1360     } else {
1361         result = [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
1362     }
1363     return result;
1364 }
1365 
1366 @end
1367 
1368 
1369 static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
1370 
1371 @implementation TabGroupControlAccessibility
1372 
1373 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole
1374 {
1375     self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
1376     if (self) {
1377         if (tabGroup != NULL) {
1378             fTabGroupAxContext = JNFNewGlobalRef(env, tabGroup);
1379         } else {


1384 }
1385 
1386 - (void)dealloc
1387 {
1388     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
1389 
1390     if (fTabGroupAxContext != NULL) {
1391         JNFDeleteGlobalRef(env, fTabGroupAxContext);
1392         fTabGroupAxContext = NULL;
1393     }
1394 
1395     [super dealloc];
1396 }
1397 
1398 - (id)accessibilityValueAttribute
1399 {
1400     JNIEnv *env = [ThreadUtilities getJNIEnv];
1401     jobject axContext = [self axContextWithEnv:env];
1402 
1403     // Returns the current selection of the page tab list
1404     return [NSNumber numberWithBool:ObjectEquals(env, axContext, getAxContextSelection(env, [self tabGroup], fIndex, fComponent), fComponent)];


1405 }
1406 
1407 - (void)getActionsWithEnv:(JNIEnv *)env
1408 {
1409     TabGroupAction *action = [[TabGroupAction alloc] initWithEnv:env withTabGroup:[self tabGroup] withIndex:fIndex withComponent:fComponent];
1410     [fActions setObject:action forKey:NSAccessibilityPressAction];
1411     [action release];
1412 }
1413 
1414 - (jobject)tabGroup
1415 {
1416     if (fTabGroupAxContext == NULL) {
1417         JNIEnv* env = [ThreadUtilities getJNIEnv];
1418         jobject tabGroupAxContext = [(JavaComponentAccessibility *)[self parent] axContextWithEnv:env];
1419         fTabGroupAxContext = JNFNewGlobalRef(env, tabGroupAxContext);

1420     }
1421     return fTabGroupAxContext;
1422 }
1423 
1424 @end
1425 
1426 
1427 @implementation ScrollAreaAccessibility
1428 
1429 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
1430 {
1431     NSMutableArray *names = (NSMutableArray *)[super initializeAttributeNamesWithEnv:env];
1432 
1433     [names addObject:NSAccessibilityHorizontalScrollBarAttribute];
1434     [names addObject:NSAccessibilityVerticalScrollBarAttribute];
1435     [names addObject:NSAccessibilityContentsAttribute];
1436 
1437     return names;
1438 }
1439 
1440 - (id)accessibilityHorizontalScrollBarAttribute
1441 {
1442     JNIEnv *env = [ThreadUtilities getJNIEnv];
1443 
1444     NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
1445     if ([children count] <= 0) return nil;
1446 
1447     // The scroll bars are in the children.
1448     JavaComponentAccessibility *aElement;
1449     NSEnumerator *enumerator = [children objectEnumerator];
1450     while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
1451         if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
1452             jobject elementAxContext = [aElement axContextWithEnv:env];
1453             if (isHorizontal(env, elementAxContext, fComponent)) {

1454                 return aElement;
1455             }

1456         }
1457     }
1458 
1459     return nil;
1460 }
1461 
1462 - (BOOL)accessibilityIsHorizontalScrollBarAttributeSettable
1463 {
1464     return NO;
1465 }
1466 
1467 - (id)accessibilityVerticalScrollBarAttribute
1468 {
1469     JNIEnv *env = [ThreadUtilities getJNIEnv];
1470 
1471     NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
1472     if ([children count] <= 0) return nil;
1473 
1474     // The scroll bars are in the children.
1475     NSEnumerator *enumerator = [children objectEnumerator];
1476     JavaComponentAccessibility *aElement;
1477     while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
1478         if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
1479             jobject elementAxContext = [aElement axContextWithEnv:env];
1480             if (isVertical(env, elementAxContext, fComponent)) {

1481                 return aElement;
1482             }

1483         }
1484     }
1485 
1486     return nil;
1487 }
1488 
1489 - (BOOL)accessibilityIsVerticalScrollBarAttributeSettable
1490 {
1491     return NO;
1492 }
1493 
1494 - (NSArray *)accessibilityContentsAttribute
1495 {
1496     JNIEnv *env = [ThreadUtilities getJNIEnv];
1497     NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
1498 
1499     if ([children count] <= 0) return nil;
1500     NSArray *contents = [NSMutableArray arrayWithCapacity:[children count]];
1501 
1502     // The scroll bars are in the children. children less the scroll bars is the contents




 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         
 142         jobject jcomponent = [(AWTView *)fView awtComponent:env];
 143         fComponent = JNFNewGlobalRef(env, jcomponent);
 144         (*env)->DeleteLocalRef(env, jcomponent);
 145 
 146         fIndex = index;
 147 
 148         fActions = nil;
 149         fActionsLOCK = [[NSObject alloc] init];
 150     }
 151     return self;
 152 }
 153 
 154 - (void)unregisterFromCocoaAXSystem
 155 {
 156     AWT_ASSERT_APPKIT_THREAD;
 157     static dispatch_once_t initialize_unregisterUniqueId_once;
 158     static void (*unregisterUniqueId)(id);
 159     dispatch_once(&initialize_unregisterUniqueId_once, ^{
 160         void *jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL);
 161         unregisterUniqueId = dlsym(jrsFwk, "JRSAccessibilityUnregisterUniqueIdForUIElement");
 162     });
 163     if (unregisterUniqueId) unregisterUniqueId(self);
 164 }


 273 + (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env {
 274     if (JNFIsInstanceOf(env, jaccessible, &sjc_CAccessible)) {
 275         return jaccessible;
 276     }
 277     else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
 278         return JNFCallStaticObjectMethod(env, sjm_getCAccessible, jaccessible);
 279     }
 280     return NULL;
 281 }
 282 
 283 + (NSArray *)childrenOfParent:(JavaComponentAccessibility *)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored
 284 {
 285     jobjectArray jchildrenAndRoles = JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, parent->fAccessible, parent->fComponent, whichChildren, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
 286     if (jchildrenAndRoles == NULL) return nil;
 287     
 288     jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
 289     NSMutableArray *children = [NSMutableArray arrayWithCapacity:arrayLen/2]; //childrenAndRoles array contains two elements (child, role) for each child
 290 
 291     NSInteger i;
 292     NSUInteger childIndex = (whichChildren >= 0) ? whichChildren : 0; // if we're getting one particular child, make sure to set its index correctly
 293     
 294     for(i = 0; i < arrayLen; i+=2)
 295     {
 296         jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
 297         jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
 298 
 299         NSString *childJavaRole = nil;
 300         if (jchildJavaRole != NULL) {
 301             childJavaRole = JNFJavaToNSString(env, JNFGetObjectField(env, jchildJavaRole, sjf_key));
 302         }
 303 
 304         JavaComponentAccessibility *child = [self createWithParent:parent accessible:jchild role:childJavaRole index:childIndex withEnv:env withView:parent->fView];
 305         
 306         (*env)->DeleteLocalRef(env, jchild);
 307         (*env)->DeleteLocalRef(env, jchildJavaRole);
 308         
 309         [children addObject:child];
 310         childIndex++;
 311     }
 312     (*env)->DeleteLocalRef(env, jchildrenAndRoles);
 313     
 314     return children;
 315 }
 316 
 317 + (JavaComponentAccessibility *)createWithAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env withView:(NSView *)view
 318 {
 319     jobject jcomponent = [(AWTView *)view awtComponent:env];
 320     jint index = JNFCallStaticIntMethod(env, sjm_getAccessibleIndexInParent, jaccessible, jcomponent);
 321     NSString *javaRole = getJavaRole(env, jaccessible, jcomponent);
 322     (*env)->DeleteLocalRef(env, jcomponent);
 323 
 324     return [self createWithAccessible:jaccessible role:javaRole index:index withEnv:env withView:view];
 325 }
 326 
 327 + (JavaComponentAccessibility *) createWithAccessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
 328 {
 329     return [self createWithParent:nil accessible:jaccessible role:javaRole index:index withEnv:env withView:view];
 330 }
 331 
 332 + (JavaComponentAccessibility *) createWithParent:(JavaComponentAccessibility *)parent accessible:(jobject)jaccessible role:(NSString *)javaRole index:(jint)index withEnv:(JNIEnv *)env withView:(NSView *)view
 333 {
 334     // try to fetch the jCAX from Java, and return autoreleased
 335     jobject jCAX = [JavaComponentAccessibility getCAccessible:jaccessible withEnv:env];
 336     if (jCAX == NULL) return nil;
 337     JavaComponentAccessibility *value = (JavaComponentAccessibility *) jlong_to_ptr(JNFGetLongField(env, jCAX, jf_ptr));
 338     if (value != nil) {
 339         (*env)->DeleteLocalRef(env, jCAX);
 340         return [[value retain] autorelease];
 341     }
 342 
 343     // otherwise, create a new instance
 344     JavaComponentAccessibility *newChild = nil;
 345     if ([javaRole isEqualToString:@"pagetablist"]) {
 346         newChild = [TabGroupAccessibility alloc];
 347     } else if ([javaRole isEqualToString:@"scrollpane"]) {
 348         newChild = [ScrollAreaAccessibility alloc];
 349     } else {
 350         NSString *nsRole = [sRoles objectForKey:javaRole];
 351         if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] || [nsRole isEqualToString:NSAccessibilityTextAreaRole] || [nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
 352             newChild = [JavaTextAccessibility alloc];
 353         } else {
 354             newChild = [JavaComponentAccessibility alloc];
 355         }
 356     }
 357 
 358     // must init freshly -alloc'd object
 359     [newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance
 360 
 361     // must hard retain pointer poked into Java object
 362     [newChild retain];
 363     JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
 364     (*env)->DeleteLocalRef(env, jCAX);
 365 
 366     // return autoreleased instance
 367     return [newChild autorelease];
 368 }
 369 
 370 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
 371 {
 372     static JNF_STATIC_MEMBER_CACHE(jm_getInitialAttributeStates, sjc_CAccessibility, "getInitialAttributeStates", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[Z");
 373 
 374     NSMutableArray *attributeNames = [NSMutableArray arrayWithCapacity:10];
 375     [attributeNames retain];
 376 
 377     // all elements respond to parent, role, role description, window, topLevelUIElement, help
 378     [attributeNames addObject:NSAccessibilityParentAttribute];
 379     [attributeNames addObject:NSAccessibilityRoleAttribute];
 380     [attributeNames addObject:NSAccessibilityRoleDescriptionAttribute];
 381     [attributeNames addObject:NSAccessibilityHelpAttribute];
 382 
 383     // cmcnote: AXMenu usually doesn't respond to window / topLevelUIElement. But menus within a Java app's window
 384     // probably should. Should we use some role other than AXMenu / AXMenuBar for Java menus?


 493 }
 494 
 495 - (jobject)axContextWithEnv:(JNIEnv *)env
 496 {
 497     return getAxContext(env, fAccessible, fComponent);
 498 }
 499 
 500 - (id)parent
 501 {
 502     static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleParent, sjc_CAccessibility, "getAccessibleParent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
 503 
 504     if(fParent == nil) {
 505         JNIEnv* env = [ThreadUtilities getJNIEnv];
 506 
 507         jobject jparent = JNFCallStaticObjectMethod(env, sjm_getAccessibleParent, fAccessible, fComponent);
 508 
 509         if (jparent == NULL) {
 510             fParent = fView;
 511         } else {
 512             fParent = [JavaComponentAccessibility createWithAccessible:jparent withEnv:env withView:fView];
 513             (*env)->DeleteLocalRef(env, jparent);
 514             if (fParent == nil) {
 515                 fParent = fView;
 516             }
 517         }
 518         [fParent retain];
 519     }
 520     return fParent;
 521 }
 522 
 523 - (NSView *)view
 524 {
 525     return fView;
 526 }
 527 
 528 - (NSWindow *)window
 529 {
 530     return [[self view] window];
 531 }
 532 
 533 - (NSString *)javaRole


 544 {
 545     id role = [self accessibilityRoleAttribute];
 546     return [role isEqualToString:NSAccessibilityMenuBarRole] || [role isEqualToString:NSAccessibilityMenuRole] || [role isEqualToString:NSAccessibilityMenuItemRole];
 547 }
 548 
 549 - (BOOL)isSelected:(JNIEnv *)env
 550 {
 551     if (fIndex == -1) {
 552         return NO;
 553     }
 554 
 555     return isChildSelected(env, ((JavaComponentAccessibility *)[self parent])->fAccessible, fIndex, fComponent);
 556 }
 557 
 558 - (BOOL)isVisible:(JNIEnv *)env
 559 {
 560     if (fIndex == -1) {
 561         return NO;
 562     }
 563 
 564     jobject axContext = [self axContextWithEnv:env];
 565     BOOL showing = isShowing(env, axContext, fComponent);
 566     (*env)->DeleteLocalRef(env, axContext);
 567     return showing;
 568 }
 569 
 570 // the array of names for each role is cached in the sAttributeNamesForRoleCache
 571 - (NSArray *)accessibilityAttributeNames
 572 {
 573     JNIEnv* env = [ThreadUtilities getJNIEnv];
 574 
 575     @synchronized(sAttributeNamesLOCK) {
 576         NSString *javaRole = [self javaRole];
 577         NSArray *names = (NSArray *)[sAttributeNamesForRoleCache objectForKey:javaRole];
 578         if (names != nil) return names;
 579 
 580         names = [self initializeAttributeNamesWithEnv:env];
 581         if (names != nil) {
 582 #ifdef JAVA_AX_DEBUG
 583             NSLog(@"Initializing: %s for %@: %@", __FUNCTION__, javaRole, names);
 584 #endif
 585             [sAttributeNamesForRoleCache setObject:names forKey:javaRole];
 586             return names;
 587         }


 771     static JNF_STATIC_MEMBER_CACHE(jm_getMinimumAccessibleValue, sjc_CAccessibility, "getMinimumAccessibleValue", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/Number;");
 772 
 773     JNIEnv* env = [ThreadUtilities getJNIEnv];
 774 
 775     jobject axValue = JNFCallStaticObjectMethod(env, jm_getMinimumAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 776     return JNFJavaToNSNumber(env, axValue);
 777 }
 778 
 779 - (BOOL)accessibilityIsMinValueAttributeSettable
 780 {
 781     return NO;
 782 }
 783 
 784 - (id)accessibilityOrientationAttribute
 785 {
 786     JNIEnv* env = [ThreadUtilities getJNIEnv];
 787     jobject axContext = [self axContextWithEnv:env];
 788 
 789     // cmcnote - should batch these two calls into one that returns an array of two bools, one for vertical and one for horiz
 790     if (isVertical(env, axContext, fComponent)) {
 791         (*env)->DeleteLocalRef(env, axContext);
 792         return NSAccessibilityVerticalOrientationValue;
 793     }
 794 
 795     if (isHorizontal(env, axContext, fComponent)) {
 796         (*env)->DeleteLocalRef(env, axContext);
 797         return NSAccessibilityHorizontalOrientationValue;
 798     }
 799 
 800     (*env)->DeleteLocalRef(env, axContext);
 801     return nil;
 802 }
 803 
 804 - (BOOL)accessibilityIsOrientationAttributeSettable
 805 {
 806     return NO;
 807 }
 808 
 809 // Element containing current element (id)
 810 - (id)accessibilityParentAttribute
 811 {
 812     return NSAccessibilityUnignoredAncestor([self parent]);
 813 }
 814 
 815 - (BOOL)accessibilityIsParentAttributeSettable
 816 {
 817     return NO;
 818 }
 819 
 820 // Screen position of element's lower-left corner in lower-left relative screen coordinates (NSValue)
 821 - (NSValue *)accessibilityPositionAttribute
 822 {
 823     JNIEnv* env = [ThreadUtilities getJNIEnv];
 824     jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 825 
 826     // NSAccessibility wants the bottom left point of the object in
 827     // bottom left based screen coords
 828 
 829     // Get the java screen coords, and make a NSPoint of the bottom left of the AxComponent.
 830     NSSize size = getAxComponentSize(env, axComponent, fComponent);
 831     NSPoint point = getAxComponentLocationOnScreen(env, axComponent, fComponent);
 832     (*env)->DeleteLocalRef(env, axComponent);
 833 
 834     point.y += size.height;
 835 
 836     // Now make it into Cocoa screen coords.
 837     point.y = [[[[self view] window] screen] frame].size.height - point.y;
 838 
 839     return [NSValue valueWithPoint:point];
 840 }
 841 
 842 - (BOOL)accessibilityIsPositionAttributeSettable
 843 {
 844     // 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
 845     // We *could* make use of Java's AccessibleComponent.setLocation() method. Investigate. radr://3953869
 846     return NO;
 847 }
 848 
 849 // Element type, such as NSAccessibilityRadioButtonRole (NSString). See the role table
 850 // at http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
 851 - (NSString *)accessibilityRoleAttribute
 852 {


 898 - (NSArray *)accessibilitySelectedChildrenAttribute
 899 {
 900     JNIEnv* env = [ThreadUtilities getJNIEnv];
 901     NSArray *selectedChildren = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_SELECTED_CHILDREN allowIgnored:NO];
 902     if ([selectedChildren count] > 0) {
 903         return selectedChildren;
 904     }
 905 
 906     return nil;
 907 }
 908 
 909 - (BOOL)accessibilityIsSelectedChildrenAttributeSettable
 910 {
 911     return NO; // cmcnote: actually it should be. so need to write accessibilitySetSelectedChildrenAttribute also
 912 }
 913 
 914 // Element size (NSValue)
 915 - (NSValue *)accessibilitySizeAttribute {
 916     JNIEnv* env = [ThreadUtilities getJNIEnv];
 917     jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 918     NSValue* size = [NSValue valueWithSize:getAxComponentSize(env, axComponent, fComponent)];
 919     (*env)->DeleteLocalRef(env, axComponent);
 920     return size;
 921 }
 922 
 923 - (BOOL)accessibilityIsSizeAttributeSettable
 924 {
 925     // SIZE is settable in windows if [self styleMask] & NSResizableWindowMask - but windows are heavyweight so we're ok here
 926     // SIZE is settable in columns if [[self tableValue] allowsColumnResizing - haven't dealt with columns yet
 927     return NO;
 928 }
 929 
 930 // Element subrole type, such as NSAccessibilityTableRowSubrole (NSString). See the subrole attribute table at
 931 // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
 932 - (NSString *)accessibilitySubroleAttribute
 933 {
 934     NSString *value = nil;
 935     if ([[self javaRole] isEqualToString:@"passwordtext"])
 936     {
 937         value = NSAccessibilitySecureTextFieldSubrole;
 938     }
 939     /*
 940     // other subroles. TableRow and OutlineRow may be relevant to us


1092     return NO;
1093 #else
1094     return [[self accessibilityRoleAttribute] isEqualToString:JavaAccessibilityIgnore];
1095 #endif /* JAVA_AX_NO_IGNORES */
1096 }
1097 
1098 - (id)accessibilityHitTest:(NSPoint)point withEnv:(JNIEnv *)env
1099 {
1100     static JNF_CLASS_CACHE(jc_Container, "java/awt/Container");
1101     static JNF_STATIC_MEMBER_CACHE(jm_accessibilityHitTest, sjc_CAccessibility, "accessibilityHitTest", "(Ljava/awt/Container;FF)Ljavax/accessibility/Accessible;");
1102 
1103     // Make it into java screen coords
1104     point.y = [[[[self view] window] screen] frame].size.height - point.y;
1105 
1106     jobject jparent = fComponent;
1107 
1108     id value = nil;
1109     if (JNFIsInstanceOf(env, jparent, &jc_Container)) {
1110         jobject jaccessible = JNFCallStaticObjectMethod(env, jm_accessibilityHitTest, jparent, (jfloat)point.x, (jfloat)point.y); // AWT_THREADING Safe (AWTRunLoop)
1111         value = [JavaComponentAccessibility createWithAccessible:jaccessible withEnv:env withView:fView];
1112         (*env)->DeleteLocalRef(env, jaccessible);
1113     }
1114 
1115     if (value == nil) {
1116         value = self;
1117     }
1118 
1119     if ([value accessibilityIsIgnored]) {
1120         value = NSAccessibilityUnignoredAncestor(value);
1121     }
1122 
1123 #ifdef JAVA_AX_DEBUG
1124     NSLog(@"%s: %@", __FUNCTION__, value);
1125 #endif
1126     return value;
1127 }
1128 
1129 - (id)accessibilityFocusedUIElement
1130 {
1131     static JNF_STATIC_MEMBER_CACHE(jm_getFocusOwner, sjc_CAccessibility, "getFocusOwner", "(Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
1132 
1133     JNIEnv *env = [ThreadUtilities getJNIEnv];
1134     id value = nil;
1135 
1136     NSWindow* hostWindow = [[self->fView window] retain];
1137     jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop)
1138     [hostWindow release];
1139     
1140     if (focused != NULL) {
1141         if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) {
1142             value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView];
1143         }
1144         (*env)->DeleteLocalRef(env, focused);
1145     }
1146 
1147     if (value == nil) {
1148         value = self;
1149     }
1150 #ifdef JAVA_AX_DEBUG
1151     NSLog(@"%s: %@", __FUNCTION__, value);
1152 #endif
1153     return value;
1154 }
1155 
1156 @end
1157 
1158 /*
1159  * Class:     sun_lwawt_macosx_CAccessibility
1160  * Method:    focusChanged
1161  * Signature: ()V
1162  */
1163 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged
1164 (JNIEnv *env, jobject jthis)


1244     // Go through the tabs and find selAccessible
1245     _numTabs = [tabs count];
1246     JavaComponentAccessibility *aTab;
1247     NSInteger i;
1248     for (i = 0; i < _numTabs; i++) {
1249         aTab = (JavaComponentAccessibility *)[tabs objectAtIndex:i];
1250         if ([aTab isAccessibleWithEnv:env forAccessible:selAccessible]) {
1251             return aTab;
1252         }
1253     }
1254 
1255     return nil;
1256 }
1257 
1258 - (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
1259 {
1260     jobjectArray jtabsAndRoles = JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, fAccessible, fComponent, whichTabs, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
1261     if(jtabsAndRoles == NULL) return nil;
1262 
1263     jsize arrayLen = (*env)->GetArrayLength(env, jtabsAndRoles);
1264     if (arrayLen == 0) {
1265         (*env)->DeleteLocalRef(env, jtabsAndRoles);
1266         return nil;
1267     }
1268     NSMutableArray *tabs = [NSMutableArray arrayWithCapacity:(arrayLen/2)];
1269 
1270     // 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
1271     jobject jtabJavaRole = (*env)->GetObjectArrayElement(env, jtabsAndRoles, 1); // the array entries alternate between tab/role, starting with tab. so the first role is entry 1.
1272     if (jtabJavaRole == NULL) {
1273         (*env)->DeleteLocalRef(env, jtabsAndRoles);
1274         return nil;
1275     }
1276     NSString *tabJavaRole = JNFJavaToNSString(env, JNFGetObjectField(env, jtabJavaRole, sjf_key));
1277 
1278     NSInteger i;
1279     NSUInteger tabIndex = (whichTabs >= 0) ? whichTabs : 0; // if we're getting one particular child, make sure to set its index correctly
1280     for(i = 0; i < arrayLen; i+=2) {
1281         jobject jtab = (*env)->GetObjectArrayElement(env, jtabsAndRoles, i);
1282         JavaComponentAccessibility *tab = [[[TabGroupControlAccessibility alloc] initWithParent:self withEnv:env withAccessible:jtab withIndex:tabIndex withTabGroup:axContext withView:[self view] withJavaRole:tabJavaRole] autorelease];
1283         [tabs addObject:tab];
1284         tabIndex++;
1285     }
1286     (*env)->DeleteLocalRef(env, jtabsAndRoles);
1287     return tabs;
1288 }
1289 
1290 - (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
1291 {
1292     // Contents are the children of the selected tab.
1293     id currentTab = [self currentTabWithEnv:env withAxContext:axContext];
1294     if (currentTab == nil) return nil;
1295 
1296     NSArray *contents = [JavaComponentAccessibility childrenOfParent:currentTab withEnv:env withChildrenCode:whichTabs allowIgnored:allowIgnored];
1297     if ([contents count] <= 0) return nil;
1298     return contents;
1299 }
1300 
1301 - (id) accessibilityTabsAttribute
1302 {
1303     JNIEnv *env = [ThreadUtilities getJNIEnv];
1304     jobject axContext = [self axContextWithEnv:env];
1305     id tabs = [self tabControlsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];
1306     (*env)->DeleteLocalRef(env, axContext);
1307     return tabs;
1308 }
1309 
1310 - (BOOL)accessibilityIsTabsAttributeSettable
1311 {
1312     return NO; //cmcnote: not sure.
1313 }
1314 
1315 - (NSInteger)numTabs
1316 {
1317     if (_numTabs == -1) {
1318         _numTabs = [[self accessibilityTabsAttribute] count];
1319     }
1320     return _numTabs;
1321 }
1322 
1323 - (NSArray *) accessibilityContentsAttribute
1324 {
1325     JNIEnv *env = [ThreadUtilities getJNIEnv];
1326     jobject axContext = [self axContextWithEnv:env];
1327     NSArray* cont = [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];
1328     (*env)->DeleteLocalRef(env, axContext);
1329     return cont;
1330 }
1331 
1332 - (BOOL)accessibilityIsContentsAttributeSettable
1333 {
1334     return NO;
1335 }
1336 
1337 // axValue is the currently selected tab
1338 -(id) accessibilityValueAttribute
1339 {
1340     JNIEnv *env = [ThreadUtilities getJNIEnv];
1341     jobject axContext = [self axContextWithEnv:env];
1342     id val = [self currentTabWithEnv:env withAxContext:axContext];
1343     (*env)->DeleteLocalRef(env, axContext);
1344     return val;
1345 }
1346 
1347 - (BOOL)accessibilityIsValueAttributeSettable
1348 {
1349     return YES;
1350 }
1351 
1352 - (void)accessibilitySetValueAttribute:(id)value //cmcnote: not certain this is ever actually called. investigate.
1353 {
1354     // set the current tab
1355     NSNumber *number = (NSNumber *)value;
1356     if (![number boolValue]) return;
1357 
1358     JNIEnv *env = [ThreadUtilities getJNIEnv];
1359     jobject axContext = [self axContextWithEnv:env];
1360     setAxContextSelection(env, axContext, fIndex, fComponent);
1361     (*env)->DeleteLocalRef(env, axContext);
1362 }
1363 
1364 - (NSArray *)accessibilityChildrenAttribute
1365 {
1366     //children = AXTabs + AXContents
1367     NSArray *tabs = [self accessibilityTabsAttribute];
1368     NSArray *contents = [self accessibilityContentsAttribute];
1369 
1370     NSMutableArray *children = [NSMutableArray arrayWithCapacity:[tabs count] + [contents count]];
1371     [children addObjectsFromArray:tabs];
1372     [children addObjectsFromArray:contents];
1373 
1374     return (NSArray *)children;
1375 }
1376 
1377 // Without this optimization accessibilityChildrenAttribute is called in order to get the entire array of children.
1378 // See similar optimization in JavaComponentAccessibility. We have to extend the base implementation here, since
1379 // children of tabs are AXTabs + AXContents
1380 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount {
1381     NSArray *result = nil;
1382     if ( (maxCount == 1) && [attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
1383         // Children codes for ALL, SELECTED, VISIBLE are <0. If the code is >=0, we treat it as an index to a single child
1384         JNIEnv *env = [ThreadUtilities getJNIEnv];
1385         jobject axContext = [self axContextWithEnv:env];
1386 
1387         //children = AXTabs + AXContents
1388         NSArray *children = [self tabControlsWithEnv:env withTabGroupAxContext:axContext withTabCode:index allowIgnored:NO]; // first look at the tabs
1389         if ([children count] > 0) {
1390             result = children;
1391         } else {
1392             children= [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:(index-[self numTabs]) allowIgnored:NO];
1393             if ([children count] > 0) {
1394                 result = children;
1395             }
1396         }
1397         (*env)->DeleteLocalRef(env, axContext);
1398     } else {
1399         result = [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
1400     }
1401     return result;
1402 }
1403 
1404 @end
1405 
1406 
1407 static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
1408 
1409 @implementation TabGroupControlAccessibility
1410 
1411 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withTabGroup:(jobject)tabGroup withView:(NSView *)view withJavaRole:(NSString *)javaRole
1412 {
1413     self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
1414     if (self) {
1415         if (tabGroup != NULL) {
1416             fTabGroupAxContext = JNFNewGlobalRef(env, tabGroup);
1417         } else {


1422 }
1423 
1424 - (void)dealloc
1425 {
1426     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
1427 
1428     if (fTabGroupAxContext != NULL) {
1429         JNFDeleteGlobalRef(env, fTabGroupAxContext);
1430         fTabGroupAxContext = NULL;
1431     }
1432 
1433     [super dealloc];
1434 }
1435 
1436 - (id)accessibilityValueAttribute
1437 {
1438     JNIEnv *env = [ThreadUtilities getJNIEnv];
1439     jobject axContext = [self axContextWithEnv:env];
1440 
1441     // Returns the current selection of the page tab list
1442     id val = [NSNumber numberWithBool:ObjectEquals(env, axContext, getAxContextSelection(env, [self tabGroup], fIndex, fComponent), fComponent)];
1443     (*env)->DeleteLocalRef(env, axContext);
1444     return val;
1445 }
1446 
1447 - (void)getActionsWithEnv:(JNIEnv *)env
1448 {
1449     TabGroupAction *action = [[TabGroupAction alloc] initWithEnv:env withTabGroup:[self tabGroup] withIndex:fIndex withComponent:fComponent];
1450     [fActions setObject:action forKey:NSAccessibilityPressAction];
1451     [action release];
1452 }
1453 
1454 - (jobject)tabGroup
1455 {
1456     if (fTabGroupAxContext == NULL) {
1457         JNIEnv* env = [ThreadUtilities getJNIEnv];
1458         jobject tabGroupAxContext = [(JavaComponentAccessibility *)[self parent] axContextWithEnv:env];
1459         fTabGroupAxContext = JNFNewGlobalRef(env, tabGroupAxContext);
1460         (*env)->DeleteLocalRef(env, tabGroupAxContext);
1461     }
1462     return fTabGroupAxContext;
1463 }
1464 
1465 @end
1466 
1467 
1468 @implementation ScrollAreaAccessibility
1469 
1470 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
1471 {
1472     NSMutableArray *names = (NSMutableArray *)[super initializeAttributeNamesWithEnv:env];
1473 
1474     [names addObject:NSAccessibilityHorizontalScrollBarAttribute];
1475     [names addObject:NSAccessibilityVerticalScrollBarAttribute];
1476     [names addObject:NSAccessibilityContentsAttribute];
1477 
1478     return names;
1479 }
1480 
1481 - (id)accessibilityHorizontalScrollBarAttribute
1482 {
1483     JNIEnv *env = [ThreadUtilities getJNIEnv];
1484 
1485     NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
1486     if ([children count] <= 0) return nil;
1487 
1488     // The scroll bars are in the children.
1489     JavaComponentAccessibility *aElement;
1490     NSEnumerator *enumerator = [children objectEnumerator];
1491     while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
1492         if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
1493             jobject elementAxContext = [aElement axContextWithEnv:env];
1494             if (isHorizontal(env, elementAxContext, fComponent)) {
1495                 (*env)->DeleteLocalRef(env, elementAxContext);
1496                 return aElement;
1497             }
1498             (*env)->DeleteLocalRef(env, elementAxContext);
1499         }
1500     }
1501 
1502     return nil;
1503 }
1504 
1505 - (BOOL)accessibilityIsHorizontalScrollBarAttributeSettable
1506 {
1507     return NO;
1508 }
1509 
1510 - (id)accessibilityVerticalScrollBarAttribute
1511 {
1512     JNIEnv *env = [ThreadUtilities getJNIEnv];
1513 
1514     NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
1515     if ([children count] <= 0) return nil;
1516 
1517     // The scroll bars are in the children.
1518     NSEnumerator *enumerator = [children objectEnumerator];
1519     JavaComponentAccessibility *aElement;
1520     while ((aElement = (JavaComponentAccessibility *)[enumerator nextObject])) {
1521         if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
1522             jobject elementAxContext = [aElement axContextWithEnv:env];
1523             if (isVertical(env, elementAxContext, fComponent)) {
1524                 (*env)->DeleteLocalRef(env, elementAxContext);
1525                 return aElement;
1526             }
1527             (*env)->DeleteLocalRef(env, elementAxContext);
1528         }
1529     }
1530 
1531     return nil;
1532 }
1533 
1534 - (BOOL)accessibilityIsVerticalScrollBarAttributeSettable
1535 {
1536     return NO;
1537 }
1538 
1539 - (NSArray *)accessibilityContentsAttribute
1540 {
1541     JNIEnv *env = [ThreadUtilities getJNIEnv];
1542     NSArray *children = [JavaComponentAccessibility childrenOfParent:self withEnv:env withChildrenCode:JAVA_AX_ALL_CHILDREN allowIgnored:YES];
1543 
1544     if ([children count] <= 0) return nil;
1545     NSArray *contents = [NSMutableArray arrayWithCapacity:[children count]];
1546 
1547     // The scroll bars are in the children. children less the scroll bars is the contents


< prev index next >