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 @interface TabGroupAccessibility : JavaComponentAccessibility {
79 NSInteger _numTabs;
80 }
81
82 - (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext;
83 - (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
84 - (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
85 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
86
87 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
88 - (NSArray *)accessibilityChildrenAttribute;
89 - (id) accessibilityTabsAttribute;
196 }
197
198 - (void)postValueChanged
199 {
200 AWT_ASSERT_APPKIT_THREAD;
201 NSAccessibilityPostNotification(self, NSAccessibilityValueChangedNotification);
202 }
203
204 - (void)postSelectedTextChanged
205 {
206 AWT_ASSERT_APPKIT_THREAD;
207 NSAccessibilityPostNotification(self, NSAccessibilitySelectedTextChangedNotification);
208 }
209
210 - (void)postSelectionChanged
211 {
212 AWT_ASSERT_APPKIT_THREAD;
213 NSAccessibilityPostNotification(self, NSAccessibilitySelectedChildrenChangedNotification);
214 }
215
216 - (BOOL)isEqual:(id)anObject
217 {
218 if (![anObject isKindOfClass:[self class]]) return NO;
219 JavaComponentAccessibility *accessibility = (JavaComponentAccessibility *)anObject;
220
221 JNIEnv* env = [ThreadUtilities getJNIEnv];
222 return (*env)->IsSameObject(env, accessibility->fAccessible, fAccessible);
223 }
224
225 - (BOOL)isAccessibleWithEnv:(JNIEnv *)env forAccessible:(jobject)accessible
226 {
227 return (*env)->IsSameObject(env, fAccessible, accessible);
228 }
229
230 + (void)initialize
231 {
232 if (sAttributeNamesForRoleCache == nil) {
233 sAttributeNamesLOCK = [[NSObject alloc] init];
234 sAttributeNamesForRoleCache = [[NSMutableDictionary alloc] initWithCapacity:60];
235 }
261 NSInteger i;
262 for (i = 0; i < count; i++) {
263 jstring jString = JNFNSToJavaString(env, [ignoredKeys objectAtIndex:i]);
264 (*env)->SetObjectArrayElement(env, result, i, jString);
265 (*env)->DeleteLocalRef(env, jString);
266 }
267
268 sAccessibilityClass = JNFCallStaticObjectMethod(env, jm_getAccessibility, result); // AWT_THREADING Safe (known object)
269 }
270 }
271
272 + (void)postFocusChanged:(id)message
273 {
274 AWT_ASSERT_APPKIT_THREAD;
275 NSAccessibilityPostNotification([NSApp accessibilityFocusedUIElement], NSAccessibilityFocusedUIElementChangedNotification);
276 }
277
278 + (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env {
279 if (JNFIsInstanceOf(env, jaccessible, &sjc_CAccessible)) {
280 return jaccessible;
281 }
282 else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
283 return JNFCallStaticObjectMethod(env, sjm_getCAccessible, jaccessible);
284 }
285 return NULL;
286 }
287
288 + (NSArray *)childrenOfParent:(JavaComponentAccessibility *)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored
289 {
290 if (parent->fAccessible == NULL) return nil;
291 jobjectArray jchildrenAndRoles = (jobjectArray)JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, parent->fAccessible, parent->fComponent, whichChildren, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
292 if (jchildrenAndRoles == NULL) return nil;
293
294 jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
295 NSMutableArray *children = [NSMutableArray arrayWithCapacity:arrayLen/2]; //childrenAndRoles array contains two elements (child, role) for each child
296
297 NSInteger i;
298 NSUInteger childIndex = (whichChildren >= 0) ? whichChildren : 0; // if we're getting one particular child, make sure to set its index correctly
299 for(i = 0; i < arrayLen; i+=2)
300 {
301 jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
302 jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
347 }
348
349 // otherwise, create a new instance
350 JavaComponentAccessibility *newChild = nil;
351 if ([javaRole isEqualToString:@"pagetablist"]) {
352 newChild = [TabGroupAccessibility alloc];
353 } else if ([javaRole isEqualToString:@"scrollpane"]) {
354 newChild = [ScrollAreaAccessibility alloc];
355 } else {
356 NSString *nsRole = [sRoles objectForKey:javaRole];
357 if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] || [nsRole isEqualToString:NSAccessibilityTextAreaRole] || [nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
358 newChild = [JavaTextAccessibility alloc];
359 } else {
360 newChild = [JavaComponentAccessibility alloc];
361 }
362 }
363
364 // must init freshly -alloc'd object
365 [newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance
366
367 // must hard retain pointer poked into Java object
368 [newChild retain];
369 JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
370 (*env)->DeleteLocalRef(env, jCAX);
371
372 // return autoreleased instance
373 return [newChild autorelease];
374 }
375
376 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
377 {
378 static JNF_STATIC_MEMBER_CACHE(jm_getInitialAttributeStates, sjc_CAccessibility, "getInitialAttributeStates", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[Z");
379
380 NSMutableArray *attributeNames = [NSMutableArray arrayWithCapacity:20];
381 [attributeNames retain];
382
383 // all elements respond to parent, role, role description, window, topLevelUIElement, help
384 [attributeNames addObject:NSAccessibilityParentAttribute];
385 [attributeNames addObject:NSAccessibilityRoleAttribute];
386 [attributeNames addObject:NSAccessibilityRoleDescriptionAttribute];
613 names = [self initializeAttributeNamesWithEnv:env];
614 #ifdef JAVA_AX_DEBUG
615 NSLog(@"Initializing: %s for %@: %@", __FUNCTION__, javaRole, names);
616 #endif
617 [sAttributeNamesForRoleCache setObject:names forKey:javaRole];
618 }
619 // The above set of attributes is immutable per role, but some objects, if
620 // they are the child of a list, need to add the selected and index attributes.
621 id myParent = [self accessibilityParentAttribute];
622 if ([myParent isKindOfClass:[JavaComponentAccessibility class]]) {
623 NSString *parentRole = [(JavaComponentAccessibility *)myParent javaRole];
624 if ([parentRole isEqualToString:@"list"]) {
625 NSMutableArray *moreNames =
626 [[NSMutableArray alloc] initWithCapacity: [names count] + 2];
627 [moreNames addObjectsFromArray: names];
628 [moreNames addObject:NSAccessibilitySelectedAttribute];
629 [moreNames addObject:NSAccessibilityIndexAttribute];
630 return moreNames;
631 }
632 }
633 return names;
634
635 } // end @synchronized
636
637 #ifdef JAVA_AX_DEBUG
638 NSLog(@"Warning in %s: could not find attribute names for role: %@", __FUNCTION__, [self javaRole]);
639 #endif
640
641 return nil;
642 }
643
644 // -- accessibility attributes --
645
646 - (BOOL)accessibilityShouldUseUniqueId {
647 return YES;
648 }
649
650 - (BOOL)accessibilitySupportsOverriddenAttributes {
651 return YES;
652 }
686
687 // specific attributes, in alphabetical order a la
688 // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
689
690 // Elements that current element contains (NSArray)
691 - (NSArray *)accessibilityChildrenAttribute
692 {
693 JNIEnv* env = [ThreadUtilities getJNIEnv];
694 NSArray *children = [JavaComponentAccessibility childrenOfParent:self
695 withEnv:env
696 withChildrenCode:JAVA_AX_ALL_CHILDREN
697 allowIgnored:NO];
698
699 NSArray *value = nil;
700 if ([children count] > 0) {
701 value = children;
702 }
703
704 return value;
705 }
706 - (BOOL)accessibilityIsChildrenAttributeSettable
707 {
708 return NO;
709 }
710
711 - (NSUInteger)accessibilityIndexOfChild:(id)child
712 {
713 // Only special-casing for Lists, for now. This allows lists to be accessible, fixing radr://3856139 "JLists are broken".
714 // Will probably want to special-case for Tables when we implement them (radr://3096643 "Accessibility: Table").
715 // In AppKit, NSMatrixAccessibility (which uses NSAccessibilityListRole), NSTableRowAccessibility, and NSTableViewAccessibility are the
716 // only ones that override the default implementation in NSAccessibility
717 if (![[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityListRole]) {
718 return [super accessibilityIndexOfChild:child];
719 }
720
721 jint returnValue =
722 JNFCallStaticIntMethod( [ThreadUtilities getJNIEnv],
723 sjm_getAccessibleIndexInParent,
724 ((JavaComponentAccessibility *)child)->fAccessible,
725 ((JavaComponentAccessibility *)child)->fComponent );
918 // Now make it into Cocoa screen coords.
919 point.y = [[[[self view] window] screen] frame].size.height - point.y;
920
921 return [NSValue valueWithPoint:point];
922 }
923
924 - (BOOL)accessibilityIsPositionAttributeSettable
925 {
926 // 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
927 // We *could* make use of Java's AccessibleComponent.setLocation() method. Investigate. radr://3953869
928 return NO;
929 }
930
931 // Element type, such as NSAccessibilityRadioButtonRole (NSString). See the role table
932 // at http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
933 - (NSString *)accessibilityRoleAttribute
934 {
935 if (fNSRole == nil) {
936 NSString *javaRole = [self javaRole];
937 fNSRole = [sRoles objectForKey:javaRole];
938 if (fNSRole == nil) {
939 // this component has assigned itself a custom AccessibleRole not in the sRoles array
940 fNSRole = javaRole;
941 }
942 [fNSRole retain];
943 }
944 return fNSRole;
945 }
946 - (BOOL)accessibilityIsRoleAttributeSettable
947 {
948 return NO;
949 }
950
951 // Localized, user-readable description of role, such as radio button (NSString)
952 - (NSString *)accessibilityRoleDescriptionAttribute
953 {
954 // first ask AppKit for its accessible role description for a given AXRole
955 NSString *value = NSAccessibilityRoleDescription([self accessibilityRoleAttribute], nil);
956
957 if (value == nil) {
958 // query java if necessary
959 static JNF_STATIC_MEMBER_CACHE(jm_getAccessibleRoleDisplayString, sjc_CAccessibility, "getAccessibleRoleDisplayString", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
960
961 JNIEnv* env = [ThreadUtilities getJNIEnv];
962
963 jobject axRole = JNFCallStaticObjectMethod(env, jm_getAccessibleRoleDisplayString, fAccessible, fComponent);
964 if (axRole != NULL) {
965 value = JNFJavaToNSString(env, axRole);
1025 - (NSValue *)accessibilitySizeAttribute {
1026 JNIEnv* env = [ThreadUtilities getJNIEnv];
1027 jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
1028 NSValue* size = [NSValue valueWithSize:getAxComponentSize(env, axComponent, fComponent)];
1029 (*env)->DeleteLocalRef(env, axComponent);
1030 return size;
1031 }
1032
1033 - (BOOL)accessibilityIsSizeAttributeSettable
1034 {
1035 // SIZE is settable in windows if [self styleMask] & NSResizableWindowMask - but windows are heavyweight so we're ok here
1036 // SIZE is settable in columns if [[self tableValue] allowsColumnResizing - haven't dealt with columns yet
1037 return NO;
1038 }
1039
1040 // Element subrole type, such as NSAccessibilityTableRowSubrole (NSString). See the subrole attribute table at
1041 // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
1042 - (NSString *)accessibilitySubroleAttribute
1043 {
1044 NSString *value = nil;
1045 if ([[self javaRole] isEqualToString:@"passwordtext"])
1046 {
1047 value = NSAccessibilitySecureTextFieldSubrole;
1048 }
1049 /*
1050 // other subroles. TableRow and OutlineRow may be relevant to us
1051 NSAccessibilityCloseButtonSubrole // no, heavyweight window takes care of this
1052 NSAccessibilityMinimizeButtonSubrole // "
1053 NSAccessibilityOutlineRowSubrole // maybe?
1054 NSAccessibilitySecureTextFieldSubrole // currently used
1055 NSAccessibilityTableRowSubrole // maybe?
1056 NSAccessibilityToolbarButtonSubrole // maybe?
1057 NSAccessibilityUnknownSubrole
1058 NSAccessibilityZoomButtonSubrole // no, heavyweight window takes care of this
1059 NSAccessibilityStandardWindowSubrole// no, heavyweight window takes care of this
1060 NSAccessibilityDialogSubrole // maybe?
1061 NSAccessibilitySystemDialogSubrole // no
1062 NSAccessibilityFloatingWindowSubrole // in 1.5 if we implement these, heavyweight will take care of them anyway
1063 NSAccessibilitySystemFloatingWindowSubrole
1064 NSAccessibilityIncrementArrowSubrole // no
1065 NSAccessibilityDecrementArrowSubrole // no
1066 NSAccessibilityIncrementPageSubrole // no
1102 - (NSWindow *)accessibilityTopLevelUIElementAttribute
1103 {
1104 return [self window];
1105 }
1106
1107 - (BOOL)accessibilityIsTopLevelUIElementAttributeSettable
1108 {
1109 return NO;
1110 }
1111
1112 // Element's value (id)
1113 // note that the appKit meaning of "accessibilityValue" is different from the java
1114 // meaning of "accessibleValue", which is specific to numerical values
1115 // (https://docs.oracle.com/javase/8/docs/api/javax/accessibility/AccessibleValue.html#setCurrentAccessibleValue-java.lang.Number-)
1116 - (id)accessibilityValueAttribute
1117 {
1118 static JNF_STATIC_MEMBER_CACHE(jm_getCurrentAccessibleValue, sjc_CAccessibility, "getCurrentAccessibleValue", "(Ljavax/accessibility/AccessibleValue;Ljava/awt/Component;)Ljava/lang/Number;");
1119
1120 JNIEnv* env = [ThreadUtilities getJNIEnv];
1121
1122 // ask Java for the component's accessibleValue. In java, the "accessibleValue" just means a numerical value
1123 // a text value is taken care of in JavaTextAccessibility
1124
1125 // cmcnote should coalesce these calls into one java call
1126 NSNumber *num = nil;
1127 jobject axValue = JNFCallStaticObjectMethod(env, sjm_getAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
1128 if (axValue != NULL) {
1129 jobject str = JNFCallStaticObjectMethod(env, jm_getCurrentAccessibleValue, axValue, fComponent);
1130 if (str != NULL) {
1131 num = JNFJavaToNSNumber(env, str); // AWT_THREADING Safe (AWTRunLoop)
1132 (*env)->DeleteLocalRef(env, str);
1133 }
1134 (*env)->DeleteLocalRef(env, axValue);
1135 }
1136 if (num == nil) {
1137 num = [NSNumber numberWithInt:0];
1138 }
1139 return num;
1140 }
1141
1324 withObject:nil
1325 waitUntilDone:NO];
1326 JNF_COCOA_EXIT(env);
1327 }
1328
1329 /*
1330 * Class: sun_lwawt_macosx_CAccessible
1331 * Method: selectionChanged
1332 * Signature: (I)V
1333 */
1334 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged
1335 (JNIEnv *env, jclass jklass, jlong element)
1336 {
1337 JNF_COCOA_ENTER(env);
1338 [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
1339 JNF_COCOA_EXIT(env);
1340 }
1341
1342 /*
1343 * Class: sun_lwawt_macosx_CAccessible
1344 * Method: unregisterFromCocoaAXSystem
1345 * Signature: (I)V
1346 */
1347 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSystem
1348 (JNIEnv *env, jclass jklass, jlong element)
1349 {
1350 JNF_COCOA_ENTER(env);
1351 [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
1352 JNF_COCOA_EXIT(env);
1353 }
1354
1355 @implementation TabGroupAccessibility
1356
1357 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
1358 {
1359 self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
1360 if (self) {
1361 _numTabs = -1; //flag for uninitialized numTabs
1362 }
1363 return self;
|
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 static jobject sAccessibilityClass = NULL;
70
71 // sAttributeNamesForRoleCache holds the names of the attributes to which each java
72 // AccessibleRole responds (see AccessibleRole.java).
73 // This cache is queried before attempting to access a given attribute for a particular role.
74 static NSMutableDictionary *sAttributeNamesForRoleCache = nil;
75 static NSObject *sAttributeNamesLOCK = nil;
76
77 @interface TabGroupAccessibility : JavaComponentAccessibility {
78 NSInteger _numTabs;
79 }
80
81 - (id)currentTabWithEnv:(JNIEnv *)env withAxContext:(jobject)axContext;
82 - (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
83 - (NSArray *)contentsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored;
84 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env;
85
86 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
87 - (NSArray *)accessibilityChildrenAttribute;
88 - (id) accessibilityTabsAttribute;
195 }
196
197 - (void)postValueChanged
198 {
199 AWT_ASSERT_APPKIT_THREAD;
200 NSAccessibilityPostNotification(self, NSAccessibilityValueChangedNotification);
201 }
202
203 - (void)postSelectedTextChanged
204 {
205 AWT_ASSERT_APPKIT_THREAD;
206 NSAccessibilityPostNotification(self, NSAccessibilitySelectedTextChangedNotification);
207 }
208
209 - (void)postSelectionChanged
210 {
211 AWT_ASSERT_APPKIT_THREAD;
212 NSAccessibilityPostNotification(self, NSAccessibilitySelectedChildrenChangedNotification);
213 }
214
215 - (void)postMenuOpened
216 {
217 AWT_ASSERT_APPKIT_THREAD;
218 NSAccessibilityPostNotification(self, (NSString *)kAXMenuOpenedNotification);
219 }
220
221 - (void)postMenuClosed
222 {
223 AWT_ASSERT_APPKIT_THREAD;
224 NSAccessibilityPostNotification(self, (NSString *)kAXMenuClosedNotification);
225 }
226
227 - (void)postMenuItemSelected
228 {
229 AWT_ASSERT_APPKIT_THREAD;
230 NSAccessibilityPostNotification(self, (NSString *)kAXMenuItemSelectedNotification);
231 }
232
233 - (BOOL)isEqual:(id)anObject
234 {
235 if (![anObject isKindOfClass:[self class]]) return NO;
236 JavaComponentAccessibility *accessibility = (JavaComponentAccessibility *)anObject;
237
238 JNIEnv* env = [ThreadUtilities getJNIEnv];
239 return (*env)->IsSameObject(env, accessibility->fAccessible, fAccessible);
240 }
241
242 - (BOOL)isAccessibleWithEnv:(JNIEnv *)env forAccessible:(jobject)accessible
243 {
244 return (*env)->IsSameObject(env, fAccessible, accessible);
245 }
246
247 + (void)initialize
248 {
249 if (sAttributeNamesForRoleCache == nil) {
250 sAttributeNamesLOCK = [[NSObject alloc] init];
251 sAttributeNamesForRoleCache = [[NSMutableDictionary alloc] initWithCapacity:60];
252 }
278 NSInteger i;
279 for (i = 0; i < count; i++) {
280 jstring jString = JNFNSToJavaString(env, [ignoredKeys objectAtIndex:i]);
281 (*env)->SetObjectArrayElement(env, result, i, jString);
282 (*env)->DeleteLocalRef(env, jString);
283 }
284
285 sAccessibilityClass = JNFCallStaticObjectMethod(env, jm_getAccessibility, result); // AWT_THREADING Safe (known object)
286 }
287 }
288
289 + (void)postFocusChanged:(id)message
290 {
291 AWT_ASSERT_APPKIT_THREAD;
292 NSAccessibilityPostNotification([NSApp accessibilityFocusedUIElement], NSAccessibilityFocusedUIElementChangedNotification);
293 }
294
295 + (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env {
296 if (JNFIsInstanceOf(env, jaccessible, &sjc_CAccessible)) {
297 return jaccessible;
298 } else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
299 return JNFCallStaticObjectMethod(env, sjm_getCAccessible, jaccessible);
300 }
301 return NULL;
302 }
303
304 + (NSArray *)childrenOfParent:(JavaComponentAccessibility *)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored
305 {
306 if (parent->fAccessible == NULL) return nil;
307 jobjectArray jchildrenAndRoles = (jobjectArray)JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, parent->fAccessible, parent->fComponent, whichChildren, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
308 if (jchildrenAndRoles == NULL) return nil;
309
310 jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
311 NSMutableArray *children = [NSMutableArray arrayWithCapacity:arrayLen/2]; //childrenAndRoles array contains two elements (child, role) for each child
312
313 NSInteger i;
314 NSUInteger childIndex = (whichChildren >= 0) ? whichChildren : 0; // if we're getting one particular child, make sure to set its index correctly
315 for(i = 0; i < arrayLen; i+=2)
316 {
317 jobject /* Accessible */ jchild = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i);
318 jobject /* String */ jchildJavaRole = (*env)->GetObjectArrayElement(env, jchildrenAndRoles, i+1);
363 }
364
365 // otherwise, create a new instance
366 JavaComponentAccessibility *newChild = nil;
367 if ([javaRole isEqualToString:@"pagetablist"]) {
368 newChild = [TabGroupAccessibility alloc];
369 } else if ([javaRole isEqualToString:@"scrollpane"]) {
370 newChild = [ScrollAreaAccessibility alloc];
371 } else {
372 NSString *nsRole = [sRoles objectForKey:javaRole];
373 if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] || [nsRole isEqualToString:NSAccessibilityTextAreaRole] || [nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
374 newChild = [JavaTextAccessibility alloc];
375 } else {
376 newChild = [JavaComponentAccessibility alloc];
377 }
378 }
379
380 // must init freshly -alloc'd object
381 [newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance
382
383 // If creating a JPopupMenu (not a combobox popup list) need to fire menuOpened.
384 // This is the only way to know if the menu is opening; visible state change
385 // can't be caught because the listeners are not set up in time.
386 if ( [javaRole isEqualToString:@"popupmenu"] &&
387 ![[parent javaRole] isEqualToString:@"combobox"] ) {
388 [newChild postMenuOpened];
389 }
390
391 // must hard retain pointer poked into Java object
392 [newChild retain];
393 JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
394 (*env)->DeleteLocalRef(env, jCAX);
395
396 // return autoreleased instance
397 return [newChild autorelease];
398 }
399
400 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
401 {
402 static JNF_STATIC_MEMBER_CACHE(jm_getInitialAttributeStates, sjc_CAccessibility, "getInitialAttributeStates", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[Z");
403
404 NSMutableArray *attributeNames = [NSMutableArray arrayWithCapacity:20];
405 [attributeNames retain];
406
407 // all elements respond to parent, role, role description, window, topLevelUIElement, help
408 [attributeNames addObject:NSAccessibilityParentAttribute];
409 [attributeNames addObject:NSAccessibilityRoleAttribute];
410 [attributeNames addObject:NSAccessibilityRoleDescriptionAttribute];
637 names = [self initializeAttributeNamesWithEnv:env];
638 #ifdef JAVA_AX_DEBUG
639 NSLog(@"Initializing: %s for %@: %@", __FUNCTION__, javaRole, names);
640 #endif
641 [sAttributeNamesForRoleCache setObject:names forKey:javaRole];
642 }
643 // The above set of attributes is immutable per role, but some objects, if
644 // they are the child of a list, need to add the selected and index attributes.
645 id myParent = [self accessibilityParentAttribute];
646 if ([myParent isKindOfClass:[JavaComponentAccessibility class]]) {
647 NSString *parentRole = [(JavaComponentAccessibility *)myParent javaRole];
648 if ([parentRole isEqualToString:@"list"]) {
649 NSMutableArray *moreNames =
650 [[NSMutableArray alloc] initWithCapacity: [names count] + 2];
651 [moreNames addObjectsFromArray: names];
652 [moreNames addObject:NSAccessibilitySelectedAttribute];
653 [moreNames addObject:NSAccessibilityIndexAttribute];
654 return moreNames;
655 }
656 }
657 // popupmenu's return values not selected children
658 if ( [javaRole isEqualToString:@"popupmenu"] &&
659 ![[[self parent] javaRole] isEqualToString:@"combobox"] ) {
660 NSMutableArray *moreNames =
661 [[NSMutableArray alloc] initWithCapacity: [names count] + 1];
662 [moreNames addObjectsFromArray: names];
663 [moreNames addObject:NSAccessibilityValueAttribute];
664 return moreNames;
665 }
666 return names;
667
668 } // end @synchronized
669
670 #ifdef JAVA_AX_DEBUG
671 NSLog(@"Warning in %s: could not find attribute names for role: %@", __FUNCTION__, [self javaRole]);
672 #endif
673
674 return nil;
675 }
676
677 // -- accessibility attributes --
678
679 - (BOOL)accessibilityShouldUseUniqueId {
680 return YES;
681 }
682
683 - (BOOL)accessibilitySupportsOverriddenAttributes {
684 return YES;
685 }
719
720 // specific attributes, in alphabetical order a la
721 // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
722
723 // Elements that current element contains (NSArray)
724 - (NSArray *)accessibilityChildrenAttribute
725 {
726 JNIEnv* env = [ThreadUtilities getJNIEnv];
727 NSArray *children = [JavaComponentAccessibility childrenOfParent:self
728 withEnv:env
729 withChildrenCode:JAVA_AX_ALL_CHILDREN
730 allowIgnored:NO];
731
732 NSArray *value = nil;
733 if ([children count] > 0) {
734 value = children;
735 }
736
737 return value;
738 }
739
740 - (BOOL)accessibilityIsChildrenAttributeSettable
741 {
742 return NO;
743 }
744
745 - (NSUInteger)accessibilityIndexOfChild:(id)child
746 {
747 // Only special-casing for Lists, for now. This allows lists to be accessible, fixing radr://3856139 "JLists are broken".
748 // Will probably want to special-case for Tables when we implement them (radr://3096643 "Accessibility: Table").
749 // In AppKit, NSMatrixAccessibility (which uses NSAccessibilityListRole), NSTableRowAccessibility, and NSTableViewAccessibility are the
750 // only ones that override the default implementation in NSAccessibility
751 if (![[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityListRole]) {
752 return [super accessibilityIndexOfChild:child];
753 }
754
755 jint returnValue =
756 JNFCallStaticIntMethod( [ThreadUtilities getJNIEnv],
757 sjm_getAccessibleIndexInParent,
758 ((JavaComponentAccessibility *)child)->fAccessible,
759 ((JavaComponentAccessibility *)child)->fComponent );
952 // Now make it into Cocoa screen coords.
953 point.y = [[[[self view] window] screen] frame].size.height - point.y;
954
955 return [NSValue valueWithPoint:point];
956 }
957
958 - (BOOL)accessibilityIsPositionAttributeSettable
959 {
960 // 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
961 // We *could* make use of Java's AccessibleComponent.setLocation() method. Investigate. radr://3953869
962 return NO;
963 }
964
965 // Element type, such as NSAccessibilityRadioButtonRole (NSString). See the role table
966 // at http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
967 - (NSString *)accessibilityRoleAttribute
968 {
969 if (fNSRole == nil) {
970 NSString *javaRole = [self javaRole];
971 fNSRole = [sRoles objectForKey:javaRole];
972 // The sRoles NSMutableDictionary maps popupmenu to Mac's popup button.
973 // JComboBox behavior currently relies on this. However this is not the
974 // proper mapping for a JPopupMenu so fix that.
975 if ( [javaRole isEqualToString:@"popupmenu"] &&
976 ![[[self parent] javaRole] isEqualToString:@"combobox"] ) {
977 fNSRole = NSAccessibilityMenuRole;
978 }
979 if (fNSRole == nil) {
980 // this component has assigned itself a custom AccessibleRole not in the sRoles array
981 fNSRole = javaRole;
982 }
983 [fNSRole retain];
984 }
985 return fNSRole;
986 }
987
988 - (BOOL)accessibilityIsRoleAttributeSettable
989 {
990 return NO;
991 }
992
993 // Localized, user-readable description of role, such as radio button (NSString)
994 - (NSString *)accessibilityRoleDescriptionAttribute
995 {
996 // first ask AppKit for its accessible role description for a given AXRole
997 NSString *value = NSAccessibilityRoleDescription([self accessibilityRoleAttribute], nil);
998
999 if (value == nil) {
1000 // query java if necessary
1001 static JNF_STATIC_MEMBER_CACHE(jm_getAccessibleRoleDisplayString, sjc_CAccessibility, "getAccessibleRoleDisplayString", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
1002
1003 JNIEnv* env = [ThreadUtilities getJNIEnv];
1004
1005 jobject axRole = JNFCallStaticObjectMethod(env, jm_getAccessibleRoleDisplayString, fAccessible, fComponent);
1006 if (axRole != NULL) {
1007 value = JNFJavaToNSString(env, axRole);
1067 - (NSValue *)accessibilitySizeAttribute {
1068 JNIEnv* env = [ThreadUtilities getJNIEnv];
1069 jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
1070 NSValue* size = [NSValue valueWithSize:getAxComponentSize(env, axComponent, fComponent)];
1071 (*env)->DeleteLocalRef(env, axComponent);
1072 return size;
1073 }
1074
1075 - (BOOL)accessibilityIsSizeAttributeSettable
1076 {
1077 // SIZE is settable in windows if [self styleMask] & NSResizableWindowMask - but windows are heavyweight so we're ok here
1078 // SIZE is settable in columns if [[self tableValue] allowsColumnResizing - haven't dealt with columns yet
1079 return NO;
1080 }
1081
1082 // Element subrole type, such as NSAccessibilityTableRowSubrole (NSString). See the subrole attribute table at
1083 // http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Protocols/NSAccessibility.html
1084 - (NSString *)accessibilitySubroleAttribute
1085 {
1086 NSString *value = nil;
1087 if ([[self javaRole] isEqualToString:@"passwordtext"]) {
1088 value = NSAccessibilitySecureTextFieldSubrole;
1089 }
1090 /*
1091 // other subroles. TableRow and OutlineRow may be relevant to us
1092 NSAccessibilityCloseButtonSubrole // no, heavyweight window takes care of this
1093 NSAccessibilityMinimizeButtonSubrole // "
1094 NSAccessibilityOutlineRowSubrole // maybe?
1095 NSAccessibilitySecureTextFieldSubrole // currently used
1096 NSAccessibilityTableRowSubrole // maybe?
1097 NSAccessibilityToolbarButtonSubrole // maybe?
1098 NSAccessibilityUnknownSubrole
1099 NSAccessibilityZoomButtonSubrole // no, heavyweight window takes care of this
1100 NSAccessibilityStandardWindowSubrole// no, heavyweight window takes care of this
1101 NSAccessibilityDialogSubrole // maybe?
1102 NSAccessibilitySystemDialogSubrole // no
1103 NSAccessibilityFloatingWindowSubrole // in 1.5 if we implement these, heavyweight will take care of them anyway
1104 NSAccessibilitySystemFloatingWindowSubrole
1105 NSAccessibilityIncrementArrowSubrole // no
1106 NSAccessibilityDecrementArrowSubrole // no
1107 NSAccessibilityIncrementPageSubrole // no
1143 - (NSWindow *)accessibilityTopLevelUIElementAttribute
1144 {
1145 return [self window];
1146 }
1147
1148 - (BOOL)accessibilityIsTopLevelUIElementAttributeSettable
1149 {
1150 return NO;
1151 }
1152
1153 // Element's value (id)
1154 // note that the appKit meaning of "accessibilityValue" is different from the java
1155 // meaning of "accessibleValue", which is specific to numerical values
1156 // (https://docs.oracle.com/javase/8/docs/api/javax/accessibility/AccessibleValue.html#setCurrentAccessibleValue-java.lang.Number-)
1157 - (id)accessibilityValueAttribute
1158 {
1159 static JNF_STATIC_MEMBER_CACHE(jm_getCurrentAccessibleValue, sjc_CAccessibility, "getCurrentAccessibleValue", "(Ljavax/accessibility/AccessibleValue;Ljava/awt/Component;)Ljava/lang/Number;");
1160
1161 JNIEnv* env = [ThreadUtilities getJNIEnv];
1162
1163 // Need to handle popupmenus differently.
1164 //
1165 // At least for now don't handle combo box menus.
1166 // This may change when later fixing issues which currently
1167 // exist for combo boxes, but for now the following is only
1168 // for JPopupMenus, not for combobox menus.
1169 id parent = [self parent];
1170 if ( [[self javaRole] isEqualToString:@"popupmenu"] &&
1171 ![[parent javaRole] isEqualToString:@"combobox"] ) {
1172 NSArray *children =
1173 [JavaComponentAccessibility childrenOfParent:self
1174 withEnv:env
1175 withChildrenCode:JAVA_AX_ALL_CHILDREN
1176 allowIgnored:YES];
1177 if ([children count] > 0) {
1178 // handle case of AXMenuItem
1179 // need to ask menu what is selected
1180 NSArray *selectedChildrenOfMenu =
1181 [self accessibilitySelectedChildrenAttribute];
1182 JavaComponentAccessibility *selectedMenuItem =
1183 [selectedChildrenOfMenu objectAtIndex:0];
1184 if (selectedMenuItem != nil) {
1185 jobject itemValue =
1186 JNFCallStaticObjectMethod( env,
1187 sjm_getAccessibleName,
1188 selectedMenuItem->fAccessible,
1189 selectedMenuItem->fComponent ); // AWT_THREADING Safe (AWTRunLoop)
1190 if (itemValue == NULL) {
1191 return nil;
1192 }
1193 NSString* itemString = JNFJavaToNSString(env, itemValue);
1194 (*env)->DeleteLocalRef(env, itemValue);
1195 return itemString;
1196 } else {
1197 return nil;
1198 }
1199 }
1200 }
1201
1202 // ask Java for the component's accessibleValue. In java, the "accessibleValue" just means a numerical value
1203 // a text value is taken care of in JavaTextAccessibility
1204
1205 // cmcnote should coalesce these calls into one java call
1206 NSNumber *num = nil;
1207 jobject axValue = JNFCallStaticObjectMethod(env, sjm_getAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
1208 if (axValue != NULL) {
1209 jobject str = JNFCallStaticObjectMethod(env, jm_getCurrentAccessibleValue, axValue, fComponent);
1210 if (str != NULL) {
1211 num = JNFJavaToNSNumber(env, str); // AWT_THREADING Safe (AWTRunLoop)
1212 (*env)->DeleteLocalRef(env, str);
1213 }
1214 (*env)->DeleteLocalRef(env, axValue);
1215 }
1216 if (num == nil) {
1217 num = [NSNumber numberWithInt:0];
1218 }
1219 return num;
1220 }
1221
1404 withObject:nil
1405 waitUntilDone:NO];
1406 JNF_COCOA_EXIT(env);
1407 }
1408
1409 /*
1410 * Class: sun_lwawt_macosx_CAccessible
1411 * Method: selectionChanged
1412 * Signature: (I)V
1413 */
1414 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged
1415 (JNIEnv *env, jclass jklass, jlong element)
1416 {
1417 JNF_COCOA_ENTER(env);
1418 [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
1419 JNF_COCOA_EXIT(env);
1420 }
1421
1422 /*
1423 * Class: sun_lwawt_macosx_CAccessible
1424 * Method: menuOpened
1425 * Signature: (I)V
1426 */
1427 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuOpened
1428 (JNIEnv *env, jclass jklass, jlong element)
1429 {
1430 JNF_COCOA_ENTER(env);
1431 [ThreadUtilities performOnMainThread:@selector(postMenuOpened)
1432 on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1433 withObject:nil
1434 waitUntilDone:NO];
1435 JNF_COCOA_EXIT(env);
1436 }
1437
1438 /*
1439 * Class: sun_lwawt_macosx_CAccessible
1440 * Method: menuClosed
1441 * Signature: (I)V
1442 */
1443 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuClosed
1444 (JNIEnv *env, jclass jklass, jlong element)
1445 {
1446 JNF_COCOA_ENTER(env);
1447 [ThreadUtilities performOnMainThread:@selector(postMenuClosed)
1448 on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1449 withObject:nil
1450 waitUntilDone:NO];
1451 JNF_COCOA_EXIT(env);
1452 }
1453
1454 /*
1455 * Class: sun_lwawt_macosx_CAccessible
1456 * Method: menuItemSelected
1457 * Signature: (I)V
1458 */
1459 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuItemSelected
1460 (JNIEnv *env, jclass jklass, jlong element)
1461 {
1462 JNF_COCOA_ENTER(env);
1463 [ThreadUtilities performOnMainThread:@selector(postMenuItemSelected)
1464 on:(JavaComponentAccessibility *)jlong_to_ptr(element)
1465 withObject:nil
1466 waitUntilDone:NO];
1467 JNF_COCOA_EXIT(env);
1468 }
1469
1470 /*
1471 * Class: sun_lwawt_macosx_CAccessible
1472 * Method: unregisterFromCocoaAXSystem
1473 * Signature: (I)V
1474 */
1475 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSystem
1476 (JNIEnv *env, jclass jklass, jlong element)
1477 {
1478 JNF_COCOA_ENTER(env);
1479 [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
1480 JNF_COCOA_EXIT(env);
1481 }
1482
1483 @implementation TabGroupAccessibility
1484
1485 - (id)initWithParent:(NSObject *)parent withEnv:(JNIEnv *)env withAccessible:(jobject)accessible withIndex:(jint)index withView:(NSView *)view withJavaRole:(NSString *)javaRole
1486 {
1487 self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
1488 if (self) {
1489 _numTabs = -1; //flag for uninitialized numTabs
1490 }
1491 return self;
|