0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.swt.accessibility;
0011:
0012: import java.util.Vector;
0013: import org.eclipse.swt.*;
0014: import org.eclipse.swt.widgets.Control;
0015: import org.eclipse.swt.internal.carbon.*;
0016:
0017: /**
0018: * Instances of this class provide a bridge between application
0019: * code and assistive technology clients. Many platforms provide
0020: * default accessible behavior for most widgets, and this class
0021: * allows that default behavior to be overridden. Applications
0022: * can get the default Accessible object for a control by sending
0023: * it <code>getAccessible</code>, and then add an accessible listener
0024: * to override simple items like the name and help string, or they
0025: * can add an accessible control listener to override complex items.
0026: * As a rule of thumb, an application would only want to use the
0027: * accessible control listener to implement accessibility for a
0028: * custom control.
0029: *
0030: * @see Control#getAccessible
0031: * @see AccessibleListener
0032: * @see AccessibleEvent
0033: * @see AccessibleControlListener
0034: * @see AccessibleControlEvent
0035: *
0036: * @since 2.0
0037: */
0038: public class Accessible {
0039: static final String[] requiredAttributes = { OS.kAXRoleAttribute,
0040: OS.kAXSubroleAttribute, OS.kAXRoleDescriptionAttribute,
0041: OS.kAXHelpAttribute, OS.kAXTitleAttribute,
0042: OS.kAXValueAttribute, OS.kAXEnabledAttribute,
0043: OS.kAXFocusedAttribute, OS.kAXParentAttribute,
0044: OS.kAXChildrenAttribute, OS.kAXSelectedChildrenAttribute,
0045: OS.kAXVisibleChildrenAttribute, OS.kAXWindowAttribute,
0046: OS.kAXTopLevelUIElementAttribute, OS.kAXPositionAttribute,
0047: OS.kAXSizeAttribute, OS.kAXDescriptionAttribute, };
0048: static final String[] textAttributes = {
0049: OS.kAXNumberOfCharactersAttribute,
0050: OS.kAXSelectedTextAttribute,
0051: OS.kAXSelectedTextRangeAttribute,
0052: OS.kAXInsertionPointLineNumberAttribute, };
0053:
0054: Vector accessibleListeners = new Vector();
0055: Vector accessibleControlListeners = new Vector();
0056: Vector accessibleTextListeners = new Vector();
0057: Control control;
0058: int axuielementref = 0;
0059: int[] osChildIDCache = new int[0];
0060:
0061: Accessible(Control control) {
0062: this .control = control;
0063: axuielementref = OS.AXUIElementCreateWithHIObjectAndIdentifier(
0064: control.handle, 0);
0065: OS.HIObjectSetAccessibilityIgnored(control.handle, false);
0066: }
0067:
0068: /**
0069: * Invokes platform specific functionality to allocate a new accessible object.
0070: * <p>
0071: * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
0072: * API for <code>Accessible</code>. It is marked public only so that it
0073: * can be shared within the packages provided by SWT. It is not
0074: * available on all platforms, and should never be called from
0075: * application code.
0076: * </p>
0077: *
0078: * @param control the control to get the accessible object for
0079: * @return the platform specific accessible object
0080: */
0081: public static Accessible internal_new_Accessible(Control control) {
0082: return new Accessible(control);
0083: }
0084:
0085: /**
0086: * Adds the listener to the collection of listeners who will
0087: * be notified when an accessible client asks for certain strings,
0088: * such as name, description, help, or keyboard shortcut. The
0089: * listener is notified by sending it one of the messages defined
0090: * in the <code>AccessibleListener</code> interface.
0091: *
0092: * @param listener the listener that should be notified when the receiver
0093: * is asked for a name, description, help, or keyboard shortcut string
0094: *
0095: * @exception IllegalArgumentException <ul>
0096: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
0097: * </ul>
0098: * @exception SWTException <ul>
0099: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
0100: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
0101: * </ul>
0102: *
0103: * @see AccessibleListener
0104: * @see #removeAccessibleListener
0105: */
0106: public void addAccessibleListener(AccessibleListener listener) {
0107: checkWidget();
0108: if (listener == null)
0109: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0110: accessibleListeners.addElement(listener);
0111: }
0112:
0113: /**
0114: * Adds the listener to the collection of listeners who will
0115: * be notified when an accessible client asks for custom control
0116: * specific information. The listener is notified by sending it
0117: * one of the messages defined in the <code>AccessibleControlListener</code>
0118: * interface.
0119: *
0120: * @param listener the listener that should be notified when the receiver
0121: * is asked for custom control specific information
0122: *
0123: * @exception IllegalArgumentException <ul>
0124: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
0125: * </ul>
0126: * @exception SWTException <ul>
0127: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
0128: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
0129: * </ul>
0130: *
0131: * @see AccessibleControlListener
0132: * @see #removeAccessibleControlListener
0133: */
0134: public void addAccessibleControlListener(
0135: AccessibleControlListener listener) {
0136: checkWidget();
0137: if (listener == null)
0138: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0139: accessibleControlListeners.addElement(listener);
0140: }
0141:
0142: /**
0143: * Adds the listener to the collection of listeners who will
0144: * be notified when an accessible client asks for custom text control
0145: * specific information. The listener is notified by sending it
0146: * one of the messages defined in the <code>AccessibleTextListener</code>
0147: * interface.
0148: *
0149: * @param listener the listener that should be notified when the receiver
0150: * is asked for custom text control specific information
0151: *
0152: * @exception IllegalArgumentException <ul>
0153: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
0154: * </ul>
0155: * @exception SWTException <ul>
0156: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
0157: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
0158: * </ul>
0159: *
0160: * @see AccessibleTextListener
0161: * @see #removeAccessibleTextListener
0162: *
0163: * @since 3.0
0164: */
0165: public void addAccessibleTextListener(
0166: AccessibleTextListener listener) {
0167: checkWidget();
0168: if (listener == null)
0169: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0170: accessibleTextListeners.addElement(listener);
0171: }
0172:
0173: /**
0174: * Returns the control for this Accessible object.
0175: *
0176: * @return the receiver's control
0177: * @since 3.0
0178: */
0179: public Control getControl() {
0180: return control;
0181: }
0182:
0183: /**
0184: * Invokes platform specific functionality to dispose an accessible object.
0185: * <p>
0186: * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
0187: * API for <code>Accessible</code>. It is marked public only so that it
0188: * can be shared within the packages provided by SWT. It is not
0189: * available on all platforms, and should never be called from
0190: * application code.
0191: * </p>
0192: */
0193: public void internal_dispose_Accessible() {
0194: if (axuielementref != 0) {
0195: OS.CFRelease(axuielementref);
0196: axuielementref = 0;
0197: for (int index = 1; index < osChildIDCache.length; index += 2) {
0198: OS.CFRelease(osChildIDCache[index]);
0199: }
0200: osChildIDCache = new int[0];
0201: }
0202: }
0203:
0204: /**
0205: * Invokes platform specific functionality to handle a window message.
0206: * <p>
0207: * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
0208: * API for <code>Accessible</code>. It is marked public only so that it
0209: * can be shared within the packages provided by SWT. It is not
0210: * available on all platforms, and should never be called from
0211: * application code.
0212: * </p>
0213: */
0214: public int internal_kEventAccessibleGetChildAtPoint(
0215: int nextHandler, int theEvent, int userData) {
0216: if (axuielementref != 0) {
0217: int childID = getChildIDFromEvent(theEvent);
0218: CGPoint pt = new CGPoint();
0219: OS.GetEventParameter(theEvent, OS.kEventParamMouseLocation,
0220: OS.typeHIPoint, null, CGPoint.sizeof, null, pt);
0221: AccessibleControlEvent event = new AccessibleControlEvent(
0222: this );
0223: event.x = (int) pt.x;
0224: event.y = (int) pt.y;
0225: event.childID = ACC.CHILDID_SELF;
0226: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0227: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0228: .elementAt(i);
0229: listener.getChildAtPoint(event);
0230: }
0231: if (event.accessible != null) {
0232: OS.SetEventParameter(theEvent,
0233: OS.kEventParamAccessibleChild,
0234: OS.typeCFTypeRef, 4,
0235: new int[] { event.accessible.axuielementref });
0236: return OS.noErr;
0237: }
0238: if (event.childID == ACC.CHILDID_SELF
0239: || event.childID == ACC.CHILDID_NONE
0240: || event.childID == childID) {
0241: /*
0242: * From the Carbon doc for kEventAccessibleGetChildAtPoint: "If there is no child at the given point,
0243: * you should still return noErr, but leave the parameter empty (do not call SetEventParameter)."
0244: */
0245: return OS.noErr;
0246: }
0247: OS.SetEventParameter(theEvent,
0248: OS.kEventParamAccessibleChild, OS.typeCFTypeRef, 4,
0249: new int[] { childIDToOs(event.childID) });
0250: return OS.noErr;
0251: }
0252: return OS.eventNotHandledErr;
0253: }
0254:
0255: /**
0256: * Invokes platform specific functionality to handle a window message.
0257: * <p>
0258: * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
0259: * API for <code>Accessible</code>. It is marked public only so that it
0260: * can be shared within the packages provided by SWT. It is not
0261: * available on all platforms, and should never be called from
0262: * application code.
0263: * </p>
0264: */
0265: public int internal_kEventAccessibleGetFocusedChild(
0266: int nextHandler, int theEvent, int userData) {
0267: if (axuielementref != 0) {
0268: int childID = getChildIDFromEvent(theEvent);
0269: if (childID != ACC.CHILDID_SELF) {
0270: /* From the Carbon doc for kEventAccessibleGetFocusedChild: "Only return immediate children;
0271: * do not return grandchildren of yourself."
0272: */
0273: return OS.noErr;
0274: }
0275: AccessibleControlEvent event = new AccessibleControlEvent(
0276: this );
0277: event.childID = ACC.CHILDID_MULTIPLE; // set to invalid value, to test if the application sets it in getFocus()
0278: event.accessible = null;
0279: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0280: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0281: .elementAt(i);
0282: listener.getFocus(event);
0283: }
0284:
0285: /* The application can optionally answer an accessible. */
0286: if (event.accessible != null) {
0287: OS.SetEventParameter(theEvent,
0288: OS.kEventParamAccessibleChild,
0289: OS.typeCFTypeRef, 4,
0290: new int[] { event.accessible.axuielementref });
0291: return OS.noErr;
0292: }
0293:
0294: /* Or the application can answer a valid child ID, including CHILDID_SELF and CHILDID_NONE. */
0295: if (event.childID == ACC.CHILDID_SELF) {
0296: OS.SetEventParameter(theEvent,
0297: OS.kEventParamAccessibleChild,
0298: OS.typeCFTypeRef, 4,
0299: new int[] { axuielementref });
0300: return OS.noErr;
0301: }
0302: if (event.childID == ACC.CHILDID_NONE) {
0303: /*
0304: * From the Carbon doc for kEventAccessibleGetFocusedChild: "If there is no child in the
0305: * focus chain, your handler should leave the kEventParamAccessibleChild parameter empty
0306: * and return noErr."
0307: */
0308: return OS.noErr;
0309: }
0310: if (event.childID != ACC.CHILDID_MULTIPLE) {
0311: /* Other valid childID. */
0312: OS.SetEventParameter(theEvent,
0313: OS.kEventParamAccessibleChild,
0314: OS.typeCFTypeRef, 4,
0315: new int[] { childIDToOs(event.childID) });
0316: return OS.noErr;
0317: }
0318:
0319: /* Invalid childID means the application did not implement getFocus, so return the native focus. */
0320: if (control.isFocusControl()) {
0321: OS.SetEventParameter(theEvent,
0322: OS.kEventParamAccessibleChild,
0323: OS.typeCFTypeRef, 4,
0324: new int[] { axuielementref });
0325: return OS.noErr;
0326: }
0327: }
0328: return OS.noErr;
0329: }
0330:
0331: /**
0332: * Invokes platform specific functionality to handle a window message.
0333: * <p>
0334: * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
0335: * API for <code>Accessible</code>. It is marked public only so that it
0336: * can be shared within the packages provided by SWT. It is not
0337: * available on all platforms, and should never be called from
0338: * application code.
0339: * </p>
0340: */
0341: public int internal_kEventAccessibleGetNamedAttribute(
0342: int nextHandler, int theEvent, int userData) {
0343: if (axuielementref != 0) {
0344: int[] stringRef = new int[1];
0345: OS.GetEventParameter(theEvent,
0346: OS.kEventParamAccessibleAttributeName,
0347: OS.typeCFStringRef, null, 4, null, stringRef);
0348: int length = OS.CFStringGetLength(stringRef[0]);
0349: char[] buffer = new char[length];
0350: CFRange range = new CFRange();
0351: range.length = length;
0352: OS.CFStringGetCharacters(stringRef[0], range, buffer);
0353: String attributeName = new String(buffer);
0354: if (attributeName.equals(OS.kAXRoleAttribute))
0355: return getRoleAttribute(nextHandler, theEvent, userData);
0356: if (attributeName.equals(OS.kAXSubroleAttribute))
0357: return getSubroleAttribute(nextHandler, theEvent,
0358: userData);
0359: if (attributeName.equals(OS.kAXRoleDescriptionAttribute))
0360: return getRoleDescriptionAttribute(nextHandler,
0361: theEvent, userData);
0362: if (attributeName.equals(OS.kAXHelpAttribute))
0363: return getHelpAttribute(nextHandler, theEvent, userData);
0364: if (attributeName.equals(OS.kAXTitleAttribute))
0365: return getTitleAttribute(nextHandler, theEvent,
0366: userData);
0367: if (attributeName.equals(OS.kAXValueAttribute))
0368: return getValueAttribute(nextHandler, theEvent,
0369: userData);
0370: if (attributeName.equals(OS.kAXEnabledAttribute))
0371: return getEnabledAttribute(nextHandler, theEvent,
0372: userData);
0373: if (attributeName.equals(OS.kAXFocusedAttribute))
0374: return getFocusedAttribute(nextHandler, theEvent,
0375: userData);
0376: //if (attributeName.equals(OS.kAXFocusedUIElementAttribute)) return getFocusedAttribute(nextHandler, theEvent, userData);
0377: //if (attributeName.equals(OS.kAXFocusedWindowAttribute)) return getFocusedAttribute(nextHandler, theEvent, userData);
0378: if (attributeName.equals(OS.kAXParentAttribute))
0379: return getParentAttribute(nextHandler, theEvent,
0380: userData);
0381: if (attributeName.equals(OS.kAXChildrenAttribute))
0382: return getChildrenAttribute(nextHandler, theEvent,
0383: userData);
0384: if (attributeName.equals(OS.kAXSelectedChildrenAttribute))
0385: return getSelectedChildrenAttribute(nextHandler,
0386: theEvent, userData);
0387: if (attributeName.equals(OS.kAXVisibleChildrenAttribute))
0388: return getVisibleChildrenAttribute(nextHandler,
0389: theEvent, userData);
0390: if (attributeName.equals(OS.kAXWindowAttribute))
0391: return getWindowAttribute(nextHandler, theEvent,
0392: userData);
0393: if (attributeName.equals(OS.kAXTopLevelUIElementAttribute))
0394: return getTopLevelUIElementAttribute(nextHandler,
0395: theEvent, userData);
0396: if (attributeName.equals(OS.kAXPositionAttribute))
0397: return getPositionAttribute(nextHandler, theEvent,
0398: userData);
0399: if (attributeName.equals(OS.kAXSizeAttribute))
0400: return getSizeAttribute(nextHandler, theEvent, userData);
0401: if (attributeName.equals(OS.kAXDescriptionAttribute))
0402: return getDescriptionAttribute(nextHandler, theEvent,
0403: userData);
0404: if (attributeName.equals(OS.kAXNumberOfCharactersAttribute))
0405: return getNumberOfCharactersAttribute(nextHandler,
0406: theEvent, userData);
0407: if (attributeName.equals(OS.kAXSelectedTextAttribute))
0408: return getSelectedTextAttribute(nextHandler, theEvent,
0409: userData);
0410: if (attributeName.equals(OS.kAXSelectedTextRangeAttribute))
0411: return getSelectedTextRangeAttribute(nextHandler,
0412: theEvent, userData);
0413: if (attributeName
0414: .equals(OS.kAXInsertionPointLineNumberAttribute))
0415: return getInsertionPointLineNumberAttribute(
0416: nextHandler, theEvent, userData);
0417: return getAttribute(nextHandler, theEvent, userData);
0418: }
0419: return OS.eventNotHandledErr;
0420: }
0421:
0422: public int internal_kEventAccessibleGetAllAttributeNames(
0423: int nextHandler, int theEvent, int userData) {
0424: if (axuielementref != 0) {
0425: int[] arrayRef = new int[1];
0426: OS.GetEventParameter(theEvent,
0427: OS.kEventParamAccessibleAttributeNames,
0428: OS.typeCFMutableArrayRef, null, 4, null, arrayRef);
0429: int stringArrayRef = arrayRef[0];
0430: // TODO make sure each attribute name is not a dup before appending?
0431: // int length = OS.CFArrayGetCount(stringArrayRef);
0432: // String [] osAllAttributes = new String [length];
0433: // for (int i = 0; i < length; i++) {
0434: // int stringRef = OS.CFArrayGetValueAtIndex(stringArrayRef, i);
0435: // osAllAttributes[i] = stringRefToString (stringRef);
0436: // }
0437: /* Add our list of supported attributes to the array. */
0438: for (int i = 0; i < requiredAttributes.length; i++) {
0439: int stringRef = stringToStringRef(requiredAttributes[i]);
0440: OS.CFArrayAppendValue(stringArrayRef, stringRef);
0441: OS.CFRelease(stringRef);
0442: }
0443: if (accessibleTextListeners.size() > 0) {
0444: for (int i = 0; i < textAttributes.length; i++) {
0445: int stringRef = stringToStringRef(textAttributes[i]);
0446: OS.CFArrayAppendValue(stringArrayRef, stringRef);
0447: OS.CFRelease(stringRef);
0448: }
0449: }
0450: return OS.noErr;
0451: }
0452: return OS.eventNotHandledErr;
0453: }
0454:
0455: int getAttribute(int nextHandler, int theEvent, int userData) {
0456: int code = OS.CallNextEventHandler(nextHandler, theEvent);
0457: if (code == OS.eventNotHandledErr) {
0458: /* If the childID was created by the application, delegate to the accessible for the control. */
0459: OS.SetEventParameter(theEvent,
0460: OS.kEventParamAccessibleObject, OS.typeCFTypeRef,
0461: 4, new int[] { axuielementref });
0462: code = OS.CallNextEventHandler(nextHandler, theEvent);
0463: }
0464: return code;
0465: }
0466:
0467: int getHelpAttribute(int nextHandler, int theEvent, int userData) {
0468: int code = OS.CallNextEventHandler(nextHandler, theEvent);
0469: String osHelpAttribute = null;
0470: int[] stringRef = new int[1];
0471: if (code == OS.noErr) {
0472: OS.GetEventParameter(theEvent,
0473: OS.kEventParamAccessibleAttributeValue,
0474: OS.typeCFStringRef, null, 4, null, stringRef);
0475: osHelpAttribute = stringRefToString(stringRef[0]);
0476: }
0477: AccessibleEvent event = new AccessibleEvent(this );
0478: event.childID = getChildIDFromEvent(theEvent);
0479: event.result = osHelpAttribute;
0480: for (int i = 0; i < accessibleListeners.size(); i++) {
0481: AccessibleListener listener = (AccessibleListener) accessibleListeners
0482: .elementAt(i);
0483: listener.getHelp(event);
0484: }
0485: if (event.result != null) {
0486: stringRef[0] = stringToStringRef(event.result);
0487: if (stringRef[0] != 0) {
0488: OS.SetEventParameter(theEvent,
0489: OS.kEventParamAccessibleAttributeValue,
0490: OS.typeCFStringRef, 4, stringRef);
0491: OS.CFRelease(stringRef[0]);
0492: return OS.noErr;
0493: }
0494: }
0495: return code;
0496: }
0497:
0498: int getRoleAttribute(int nextHandler, int theEvent, int userData) {
0499: AccessibleControlEvent event = new AccessibleControlEvent(this );
0500: event.childID = getChildIDFromEvent(theEvent);
0501: event.detail = -1;
0502: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0503: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0504: .elementAt(i);
0505: listener.getRole(event);
0506: }
0507: if (event.detail != -1) {
0508: String appRole = roleToOs(event.detail);
0509: int index = appRole.indexOf(':');
0510: if (index != -1)
0511: appRole = appRole.substring(0, index);
0512: int stringRef = stringToStringRef(appRole);
0513: if (stringRef != 0) {
0514: OS.SetEventParameter(theEvent,
0515: OS.kEventParamAccessibleAttributeValue,
0516: OS.typeCFStringRef, 4, new int[] { stringRef });
0517: OS.CFRelease(stringRef);
0518: return OS.noErr;
0519: }
0520: }
0521: return OS.CallNextEventHandler(nextHandler, theEvent);
0522: }
0523:
0524: int getSubroleAttribute(int nextHandler, int theEvent, int userData) {
0525: AccessibleControlEvent event = new AccessibleControlEvent(this );
0526: event.childID = getChildIDFromEvent(theEvent);
0527: event.detail = -1;
0528: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0529: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0530: .elementAt(i);
0531: listener.getRole(event);
0532: }
0533: if (event.detail != -1) {
0534: String appRole = roleToOs(event.detail);
0535: int index = appRole.indexOf(':');
0536: if (index != -1) {
0537: appRole = appRole.substring(index + 1);
0538: int stringRef = stringToStringRef(appRole);
0539: if (stringRef != 0) {
0540: OS.SetEventParameter(theEvent,
0541: OS.kEventParamAccessibleAttributeValue,
0542: OS.typeCFStringRef, 4,
0543: new int[] { stringRef });
0544: OS.CFRelease(stringRef);
0545: }
0546: }
0547: return OS.noErr;
0548: }
0549: return OS.CallNextEventHandler(nextHandler, theEvent);
0550: }
0551:
0552: int getRoleDescriptionAttribute(int nextHandler, int theEvent,
0553: int userData) {
0554: AccessibleControlEvent event = new AccessibleControlEvent(this );
0555: event.childID = getChildIDFromEvent(theEvent);
0556: event.detail = -1;
0557: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0558: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0559: .elementAt(i);
0560: listener.getRole(event);
0561: }
0562: if (event.detail != -1) {
0563: String appRole = roleToOs(event.detail);
0564: String appSubrole = null;
0565: int index = appRole.indexOf(':');
0566: if (index != -1) {
0567: appSubrole = appRole.substring(index + 1);
0568: appRole = appRole.substring(0, index);
0569: }
0570: int stringRef1 = stringToStringRef(appRole);
0571: if (stringRef1 != 0) {
0572: int stringRef2 = 0;
0573: if (appSubrole != null)
0574: stringRef2 = stringToStringRef(appSubrole);
0575: int stringRef3 = OS.HICopyAccessibilityRoleDescription(
0576: stringRef1, stringRef2);
0577: OS.CFRelease(stringRef1);
0578: if (stringRef2 != 0)
0579: OS.CFRelease(stringRef2);
0580: if (stringRef3 != 0) {
0581: OS.SetEventParameter(theEvent,
0582: OS.kEventParamAccessibleAttributeValue,
0583: OS.typeCFStringRef, 4,
0584: new int[] { stringRef3 });
0585: OS.CFRelease(stringRef3);
0586: return OS.noErr;
0587: }
0588: }
0589: }
0590: return OS.CallNextEventHandler(nextHandler, theEvent);
0591: }
0592:
0593: int getTitleAttribute(int nextHandler, int theEvent, int userData) {
0594: int code = OS.CallNextEventHandler(nextHandler, theEvent);
0595: String osTitleAttribute = null;
0596: int[] stringRef = new int[1];
0597: if (code == OS.noErr) {
0598: int status = OS.GetEventParameter(theEvent,
0599: OS.kEventParamAccessibleAttributeValue,
0600: OS.typeCFStringRef, null, 4, null, stringRef);
0601: if (status == OS.noErr) {
0602: osTitleAttribute = stringRefToString(stringRef[0]);
0603: }
0604: }
0605: AccessibleEvent event = new AccessibleEvent(this );
0606: event.childID = getChildIDFromEvent(theEvent);
0607: event.result = osTitleAttribute;
0608: for (int i = 0; i < accessibleListeners.size(); i++) {
0609: AccessibleListener listener = (AccessibleListener) accessibleListeners
0610: .elementAt(i);
0611: listener.getName(event);
0612: }
0613: if (event.result != null) {
0614: stringRef[0] = stringToStringRef(event.result);
0615: if (stringRef[0] != 0) {
0616: OS.SetEventParameter(theEvent,
0617: OS.kEventParamAccessibleAttributeValue,
0618: OS.typeCFStringRef, 4, stringRef);
0619: OS.CFRelease(stringRef[0]);
0620: return OS.noErr;
0621: }
0622: }
0623: //return OS.CallNextEventHandler (nextHandler, theEvent);
0624: return code;
0625: }
0626:
0627: int getValueAttribute(int nextHandler, int theEvent, int userData) {
0628: int code = OS.CallNextEventHandler(nextHandler, theEvent);
0629: int childID = getChildIDFromEvent(theEvent);
0630: AccessibleControlEvent event = new AccessibleControlEvent(this );
0631: event.childID = childID;
0632: event.detail = -1;
0633: event.result = null;
0634: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0635: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0636: .elementAt(i);
0637: listener.getRole(event);
0638: listener.getValue(event);
0639: }
0640: int role = event.detail;
0641: String value = event.result;
0642: if (value != null || role == ACC.ROLE_LABEL) {
0643: int stringRef = 0;
0644: switch (role) {
0645: case ACC.ROLE_RADIOBUTTON: // 1 = on, 0 = off
0646: case ACC.ROLE_CHECKBUTTON: // 1 = checked, 0 = unchecked, 2 = mixed
0647: case ACC.ROLE_SCROLLBAR: // numeric value representing the position of the scroller
0648: case ACC.ROLE_TABITEM: // 1 = selected, 0 = not selected
0649: case ACC.ROLE_SLIDER: // the value associated with the position of the slider thumb
0650: case ACC.ROLE_PROGRESSBAR: // the value associated with the fill level of the progress bar
0651: try {
0652: int number = Integer.parseInt(value);
0653: OS.SetEventParameter(theEvent,
0654: OS.kEventParamAccessibleAttributeValue,
0655: OS.typeSInt32, 4, new int[] { number });
0656: return OS.noErr;
0657: } catch (NumberFormatException ex) {
0658: if (value.equalsIgnoreCase("true")) {
0659: OS.SetEventParameter(theEvent,
0660: OS.kEventParamAccessibleAttributeValue,
0661: OS.typeBoolean, 4,
0662: new boolean[] { true });
0663: return OS.noErr;
0664: }
0665: if (value.equalsIgnoreCase("false")) {
0666: OS.SetEventParameter(theEvent,
0667: OS.kEventParamAccessibleAttributeValue,
0668: OS.typeBoolean, 4,
0669: new boolean[] { false });
0670: return OS.noErr;
0671: }
0672: }
0673: break;
0674: case ACC.ROLE_TABFOLDER: // the accessibility object representing the currently selected tab item
0675: //break;
0676: case ACC.ROLE_COMBOBOX: // text of the currently selected item
0677: case ACC.ROLE_TEXT: // text in the text field
0678: stringRef = stringToStringRef(value);
0679: break;
0680: case ACC.ROLE_LABEL: // text in the label
0681: /* On a Mac, the 'value' of a label is the same as the 'name' of the label. */
0682: AccessibleEvent e = new AccessibleEvent(this );
0683: e.childID = childID;
0684: e.result = null;
0685: for (int i = 0; i < accessibleListeners.size(); i++) {
0686: AccessibleListener listener = (AccessibleListener) accessibleListeners
0687: .elementAt(i);
0688: listener.getName(e);
0689: }
0690: if (e.result != null) {
0691: stringRef = stringToStringRef(e.result);
0692: } else {
0693: if (value != null)
0694: stringRef = stringToStringRef(value);
0695: }
0696: break;
0697: }
0698: if (stringRef != 0) {
0699: OS.SetEventParameter(theEvent,
0700: OS.kEventParamAccessibleAttributeValue,
0701: OS.typeCFStringRef, 4, new int[] { stringRef });
0702: OS.CFRelease(stringRef);
0703: return OS.noErr;
0704: }
0705: }
0706: return code;
0707: }
0708:
0709: int getEnabledAttribute(int nextHandler, int theEvent, int userData) {
0710: return getAttribute(nextHandler, theEvent, userData);
0711: }
0712:
0713: int getFocusedAttribute(int nextHandler, int theEvent, int userData) {
0714: int[] osChildID = new int[1];
0715: OS.GetEventParameter(theEvent, OS.kEventParamAccessibleObject,
0716: OS.typeCFTypeRef, null, 4, null, osChildID);
0717: AccessibleControlEvent event = new AccessibleControlEvent(this );
0718: event.childID = ACC.CHILDID_MULTIPLE; // set to invalid value, to test if the application sets it in getFocus()
0719: event.accessible = null;
0720: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0721: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0722: .elementAt(i);
0723: listener.getFocus(event);
0724: }
0725:
0726: /* The application can optionally answer an accessible. */
0727: if (event.accessible != null) {
0728: boolean hasFocus = OS.CFEqual(
0729: event.accessible.axuielementref, osChildID[0]);
0730: OS.SetEventParameter(theEvent,
0731: OS.kEventParamAccessibleAttributeValue,
0732: OS.typeBoolean, 4, new boolean[] { hasFocus });
0733: return OS.noErr;
0734: }
0735:
0736: /* Or the application can answer a valid child ID, including CHILDID_SELF and CHILDID_NONE. */
0737: if (event.childID == ACC.CHILDID_SELF) {
0738: boolean hasFocus = OS.CFEqual(axuielementref, osChildID[0]);
0739: OS.SetEventParameter(theEvent,
0740: OS.kEventParamAccessibleAttributeValue,
0741: OS.typeBoolean, 4, new boolean[] { hasFocus });
0742: return OS.noErr;
0743: }
0744: if (event.childID == ACC.CHILDID_NONE) {
0745: OS.SetEventParameter(theEvent,
0746: OS.kEventParamAccessibleAttributeValue,
0747: OS.typeBoolean, 4, new boolean[] { false });
0748: return OS.noErr;
0749: }
0750: if (event.childID != ACC.CHILDID_MULTIPLE) {
0751: /* Other valid childID. */
0752: int childID = osToChildID(osChildID[0]);
0753: OS.SetEventParameter(theEvent,
0754: OS.kEventParamAccessibleAttributeValue,
0755: OS.typeBoolean, 4,
0756: new boolean[] { event.childID == childID });
0757: return OS.noErr;
0758: }
0759:
0760: /* Invalid childID means the application did not implement getFocus, so return the native focus. */
0761: if (OS.CFEqual(axuielementref, osChildID[0])) {
0762: boolean hasFocus = control.isFocusControl();
0763: OS.SetEventParameter(theEvent,
0764: OS.kEventParamAccessibleAttributeValue,
0765: OS.typeBoolean, 4, new boolean[] { hasFocus });
0766: return OS.noErr;
0767: }
0768: return OS.CallNextEventHandler(nextHandler, theEvent);
0769: }
0770:
0771: int getParentAttribute(int nextHandler, int theEvent, int userData) {
0772: int code = OS.CallNextEventHandler(nextHandler, theEvent);
0773: if (code == OS.eventNotHandledErr) {
0774: /* If the childID was created by the application, the parent is the accessible for the control. */
0775: // TODO: typeCFTypeRef?... should be AXUIElementRef
0776: OS.SetEventParameter(theEvent,
0777: OS.kEventParamAccessibleAttributeValue,
0778: OS.typeCFTypeRef, 4, new int[] { axuielementref });
0779: return OS.noErr;
0780: }
0781: return code;
0782: }
0783:
0784: int getChildrenAttribute(int nextHandler, int theEvent, int userData) {
0785: int childID = getChildIDFromEvent(theEvent);
0786: if (childID == ACC.CHILDID_SELF) {
0787: AccessibleControlEvent event = new AccessibleControlEvent(
0788: this );
0789: event.childID = childID;
0790: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0791: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0792: .elementAt(i);
0793: listener.getChildren(event);
0794: }
0795: Object[] appChildren = event.children;
0796: if (appChildren != null && appChildren.length > 0) {
0797: /* return a CFArrayRef of AXUIElementRefs */
0798: int children = OS.CFArrayCreateMutable(
0799: OS.kCFAllocatorDefault, 0, 0);
0800: if (children != 0) {
0801: for (int i = 0; i < appChildren.length; i++) {
0802: Object child = appChildren[i];
0803: if (child instanceof Integer) {
0804: OS.CFArrayAppendValue(children,
0805: childIDToOs(((Integer) child)
0806: .intValue()));
0807: } else {
0808: OS
0809: .CFArrayAppendValue(
0810: children,
0811: ((Accessible) child).axuielementref);
0812: }
0813: }
0814: OS.SetEventParameter(theEvent,
0815: OS.kEventParamAccessibleAttributeValue,
0816: OS.typeCFMutableArrayRef, 4,
0817: new int[] { children });
0818: OS.CFRelease(children);
0819: return OS.noErr;
0820: }
0821: }
0822: }
0823: return OS.CallNextEventHandler(nextHandler, theEvent);
0824: }
0825:
0826: int getSelectedChildrenAttribute(int nextHandler, int theEvent,
0827: int userData) {
0828: return getAttribute(nextHandler, theEvent, userData);
0829: }
0830:
0831: int getVisibleChildrenAttribute(int nextHandler, int theEvent,
0832: int userData) {
0833: return getAttribute(nextHandler, theEvent, userData);
0834: }
0835:
0836: int getWindowAttribute(int nextHandler, int theEvent, int userData) {
0837: return getAttribute(nextHandler, theEvent, userData);
0838: }
0839:
0840: int getTopLevelUIElementAttribute(int nextHandler, int theEvent,
0841: int userData) {
0842: return getAttribute(nextHandler, theEvent, userData);
0843: }
0844:
0845: int getPositionAttribute(int nextHandler, int theEvent, int userData) {
0846: int code = OS.CallNextEventHandler(nextHandler, theEvent);
0847: CGPoint osPositionAttribute = new CGPoint();
0848: if (code == OS.noErr) {
0849: OS.GetEventParameter(theEvent, OS.kEventParamMouseLocation,
0850: OS.typeHIPoint, null, CGPoint.sizeof, null,
0851: osPositionAttribute);
0852: }
0853: AccessibleControlEvent event = new AccessibleControlEvent(this );
0854: event.childID = getChildIDFromEvent(theEvent);
0855: event.x = (int) osPositionAttribute.x;
0856: event.y = (int) osPositionAttribute.y;
0857: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0858: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0859: .elementAt(i);
0860: listener.getLocation(event);
0861: }
0862: osPositionAttribute.x = event.x;
0863: osPositionAttribute.y = event.y;
0864: OS.SetEventParameter(theEvent,
0865: OS.kEventParamAccessibleAttributeValue, OS.typeHIPoint,
0866: CGPoint.sizeof, osPositionAttribute);
0867: return OS.noErr;
0868: }
0869:
0870: int getSizeAttribute(int nextHandler, int theEvent, int userData) {
0871: int code = OS.CallNextEventHandler(nextHandler, theEvent);
0872: CGPoint osSizeAttribute = new CGPoint();
0873: if (code == OS.noErr) {
0874: OS.GetEventParameter(theEvent, OS.kEventParamMouseLocation,
0875: OS.typeHISize, null, CGPoint.sizeof, null,
0876: osSizeAttribute);
0877: }
0878: AccessibleControlEvent event = new AccessibleControlEvent(this );
0879: event.childID = getChildIDFromEvent(theEvent);
0880: event.width = (int) osSizeAttribute.x;
0881: event.height = (int) osSizeAttribute.y;
0882: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0883: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0884: .elementAt(i);
0885: listener.getLocation(event);
0886: }
0887: osSizeAttribute.x = event.width;
0888: osSizeAttribute.y = event.height;
0889: OS.SetEventParameter(theEvent,
0890: OS.kEventParamAccessibleAttributeValue, OS.typeHISize,
0891: CGPoint.sizeof, osSizeAttribute);
0892: return OS.noErr;
0893: }
0894:
0895: int getDescriptionAttribute(int nextHandler, int theEvent,
0896: int userData) {
0897: return getAttribute(nextHandler, theEvent, userData);
0898: }
0899:
0900: int getNumberOfCharactersAttribute(int nextHandler, int theEvent,
0901: int userData) {
0902: AccessibleControlEvent event = new AccessibleControlEvent(this );
0903: event.childID = getChildIDFromEvent(theEvent);
0904: event.result = null;
0905: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0906: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0907: .elementAt(i);
0908: listener.getValue(event);
0909: }
0910: String appValue = event.result;
0911: if (appValue != null) {
0912: OS.SetEventParameter(theEvent,
0913: OS.kEventParamAccessibleAttributeValue,
0914: OS.typeSInt32, 4, new int[] { appValue.length() });
0915: return OS.noErr;
0916: }
0917: return OS.CallNextEventHandler(nextHandler, theEvent);
0918: }
0919:
0920: int getSelectedTextAttribute(int nextHandler, int theEvent,
0921: int userData) {
0922: AccessibleTextEvent event = new AccessibleTextEvent(this );
0923: event.childID = getChildIDFromEvent(theEvent);
0924: event.offset = -1;
0925: event.length = -1;
0926: for (int i = 0; i < accessibleTextListeners.size(); i++) {
0927: AccessibleTextListener listener = (AccessibleTextListener) accessibleTextListeners
0928: .elementAt(i);
0929: listener.getSelectionRange(event);
0930: }
0931: int offset = event.offset;
0932: int length = event.length;
0933: if (offset != -1 && length != -1 && length != 0) { // TODO: do we need the && length != 0 ?
0934: AccessibleControlEvent event2 = new AccessibleControlEvent(
0935: this );
0936: event2.childID = event.childID;
0937: event2.result = null;
0938: for (int i = 0; i < accessibleControlListeners.size(); i++) {
0939: AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners
0940: .elementAt(i);
0941: listener.getValue(event2);
0942: }
0943: String appValue = event2.result;
0944: if (appValue != null) {
0945: int stringRef = stringToStringRef(appValue.substring(
0946: offset, offset + length));
0947: if (stringRef != 0) {
0948: OS.SetEventParameter(theEvent,
0949: OS.kEventParamAccessibleAttributeValue,
0950: OS.typeCFStringRef, 4,
0951: new int[] { stringRef });
0952: OS.CFRelease(stringRef);
0953: return OS.noErr;
0954: }
0955: }
0956: }
0957: return OS.CallNextEventHandler(nextHandler, theEvent);
0958: }
0959:
0960: int getSelectedTextRangeAttribute(int nextHandler, int theEvent,
0961: int userData) {
0962: AccessibleTextEvent event = new AccessibleTextEvent(this );
0963: event.childID = getChildIDFromEvent(theEvent);
0964: event.offset = -1;
0965: event.length = -1;
0966: for (int i = 0; i < accessibleTextListeners.size(); i++) {
0967: AccessibleTextListener listener = (AccessibleTextListener) accessibleTextListeners
0968: .elementAt(i);
0969: listener.getSelectionRange(event);
0970: }
0971: if (event.offset != -1) {
0972: CFRange range = new CFRange();
0973: range.location = event.offset;
0974: range.length = event.length;
0975: int valueRef = OS.AXValueCreate(OS.kAXValueCFRangeType,
0976: range);
0977: OS.SetEventParameter(theEvent,
0978: OS.kEventParamAccessibleAttributeValue,
0979: OS.typeCFTypeRef, 4, new int[] { valueRef });
0980: OS.CFRelease(valueRef);
0981: return OS.noErr;
0982: }
0983: return OS.CallNextEventHandler(nextHandler, theEvent);
0984: }
0985:
0986: int getInsertionPointLineNumberAttribute(int nextHandler,
0987: int theEvent, int userData) {
0988: AccessibleTextEvent event = new AccessibleTextEvent(this );
0989: event.childID = getChildIDFromEvent(theEvent);
0990: event.offset = -1;
0991: for (int i = 0; i < accessibleTextListeners.size(); i++) {
0992: AccessibleTextListener listener = (AccessibleTextListener) accessibleTextListeners
0993: .elementAt(i);
0994: listener.getCaretOffset(event);
0995: }
0996: if (event.offset != -1) {
0997: OS.SetEventParameter(theEvent,
0998: OS.kEventParamAccessibleAttributeValue,
0999: OS.typeSInt32, 4, new int[] { event.offset });
1000: return OS.noErr;
1001: }
1002: return OS.CallNextEventHandler(nextHandler, theEvent);
1003: }
1004:
1005: /**
1006: * Removes the listener from the collection of listeners who will
1007: * be notified when an accessible client asks for certain strings,
1008: * such as name, description, help, or keyboard shortcut.
1009: *
1010: * @param listener the listener that should no longer be notified when the receiver
1011: * is asked for a name, description, help, or keyboard shortcut string
1012: *
1013: * @exception IllegalArgumentException <ul>
1014: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1015: * </ul>
1016: * @exception SWTException <ul>
1017: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1018: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1019: * </ul>
1020: *
1021: * @see AccessibleListener
1022: * @see #addAccessibleListener
1023: */
1024: public void removeAccessibleListener(AccessibleListener listener) {
1025: checkWidget();
1026: if (listener == null)
1027: SWT.error(SWT.ERROR_NULL_ARGUMENT);
1028: accessibleListeners.removeElement(listener);
1029: }
1030:
1031: /**
1032: * Removes the listener from the collection of listeners who will
1033: * be notified when an accessible client asks for custom control
1034: * specific information.
1035: *
1036: * @param listener the listener that should no longer be notified when the receiver
1037: * is asked for custom control specific information
1038: *
1039: * @exception IllegalArgumentException <ul>
1040: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1041: * </ul>
1042: * @exception SWTException <ul>
1043: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1044: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1045: * </ul>
1046: *
1047: * @see AccessibleControlListener
1048: * @see #addAccessibleControlListener
1049: */
1050: public void removeAccessibleControlListener(
1051: AccessibleControlListener listener) {
1052: checkWidget();
1053: if (listener == null)
1054: SWT.error(SWT.ERROR_NULL_ARGUMENT);
1055: accessibleControlListeners.removeElement(listener);
1056: }
1057:
1058: /**
1059: * Removes the listener from the collection of listeners who will
1060: * be notified when an accessible client asks for custom text control
1061: * specific information.
1062: *
1063: * @param listener the listener that should no longer be notified when the receiver
1064: * is asked for custom text control specific information
1065: *
1066: * @exception IllegalArgumentException <ul>
1067: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1068: * </ul>
1069: * @exception SWTException <ul>
1070: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1071: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1072: * </ul>
1073: *
1074: * @see AccessibleTextListener
1075: * @see #addAccessibleTextListener
1076: *
1077: * @since 3.0
1078: */
1079: public void removeAccessibleTextListener(
1080: AccessibleTextListener listener) {
1081: checkWidget();
1082: if (listener == null)
1083: SWT.error(SWT.ERROR_NULL_ARGUMENT);
1084: accessibleTextListeners.removeElement(listener);
1085: }
1086:
1087: /**
1088: * Sends a message to accessible clients that the child selection
1089: * within a custom container control has changed.
1090: *
1091: * @exception SWTException <ul>
1092: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1093: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1094: * </ul>
1095: *
1096: * @since 3.0
1097: */
1098: public void selectionChanged() {
1099: checkWidget();
1100: int stringRef = stringToStringRef(OS.kAXSelectedChildrenChangedNotification);
1101: OS.AXNotificationHIObjectNotify(stringRef, control.handle, 0);
1102: OS.CFRelease(stringRef);
1103: }
1104:
1105: /**
1106: * Sends a message to accessible clients indicating that the focus
1107: * has changed within a custom control.
1108: *
1109: * @param childID an identifier specifying a child of the control
1110: *
1111: * @exception SWTException <ul>
1112: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1113: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1114: * </ul>
1115: */
1116: public void setFocus(int childID) {
1117: checkWidget();
1118: childIDToOs(childID); // Make sure the childID is cached
1119: int stringRef = stringToStringRef(OS.kAXFocusedUIElementChangedNotification);
1120: OS.AXNotificationHIObjectNotify(stringRef, control.handle, 0);
1121: OS.CFRelease(stringRef);
1122: }
1123:
1124: /**
1125: * Sends a message to accessible clients that the text
1126: * caret has moved within a custom control.
1127: *
1128: * @param index the new caret index within the control
1129: *
1130: * @exception SWTException <ul>
1131: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1132: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1133: * </ul>
1134: *
1135: * @since 3.0
1136: */
1137: public void textCaretMoved(int index) {
1138: checkWidget();
1139: // TODO: Look at this in more depth
1140: int stringRef = stringToStringRef(OS.kAXValueChangedNotification);
1141: OS.AXNotificationHIObjectNotify(stringRef, control.handle, 0);
1142: OS.CFRelease(stringRef);
1143: }
1144:
1145: /**
1146: * Sends a message to accessible clients that the text
1147: * within a custom control has changed.
1148: *
1149: * @param type the type of change, one of <code>ACC.NOTIFY_TEXT_INSERT</code>
1150: * or <code>ACC.NOTIFY_TEXT_DELETE</code>
1151: * @param startIndex the text index within the control where the insertion or deletion begins
1152: * @param length the non-negative length in characters of the insertion or deletion
1153: *
1154: * @exception SWTException <ul>
1155: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1156: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1157: * </ul>
1158: *
1159: * @see ACC#TEXT_INSERT
1160: * @see ACC#TEXT_DELETE
1161: *
1162: * @since 3.0
1163: */
1164: public void textChanged(int type, int startIndex, int length) {
1165: checkWidget();
1166: // TODO: Look at this in more depth
1167: int stringRef = stringToStringRef(OS.kAXValueChangedNotification);
1168: OS.AXNotificationHIObjectNotify(stringRef, control.handle, 0);
1169: OS.CFRelease(stringRef);
1170: }
1171:
1172: /**
1173: * Sends a message to accessible clients that the text
1174: * selection has changed within a custom control.
1175: *
1176: * @exception SWTException <ul>
1177: * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1178: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1179: * </ul>
1180: *
1181: * @since 3.0
1182: */
1183: public void textSelectionChanged() {
1184: checkWidget();
1185: int stringRef = stringToStringRef(OS.kAXSelectedChildrenChangedNotification);
1186: OS.AXNotificationHIObjectNotify(stringRef, control.handle, 0);
1187: OS.CFRelease(stringRef);
1188: }
1189:
1190: int getChildIDFromEvent(int theEvent) {
1191: int[] ref = new int[1];
1192: OS.GetEventParameter(theEvent, OS.kEventParamAccessibleObject,
1193: OS.typeCFTypeRef, null, 4, null, ref);
1194: return osToChildID(ref[0]);
1195: }
1196:
1197: int childIDToOs(int childID) {
1198: if (childID == ACC.CHILDID_SELF) {
1199: return axuielementref;
1200: }
1201: /* Check cache for childID, if found, return corresponding osChildID. */
1202: int index;
1203: for (index = 0; index < osChildIDCache.length; index += 2) {
1204: if (childID == osChildIDCache[index]) {
1205: return osChildIDCache[index + 1];
1206: }
1207: }
1208: /* If childID not in cache, create osChildID, grow cache by 2,
1209: * add childID/osChildID to cache, and return new osChildID. */
1210: int osChildID = OS.AXUIElementCreateWithHIObjectAndIdentifier(
1211: control.handle, childID + 1);
1212: int[] newCache = new int[osChildIDCache.length + 2];
1213: System.arraycopy(osChildIDCache, 0, newCache, 0,
1214: osChildIDCache.length);
1215: osChildIDCache = newCache;
1216: osChildIDCache[index] = childID;
1217: osChildIDCache[index + 1] = osChildID;
1218: return osChildID;
1219: }
1220:
1221: int osToChildID(int osChildID) {
1222: if (OS.CFEqual(osChildID, axuielementref)) {
1223: return ACC.CHILDID_SELF;
1224: }
1225:
1226: /* osChildID is an AXUIElementRef containing the control handle and a long identifier. */
1227: long[] childID = new long[1];
1228: OS.AXUIElementGetIdentifier(osChildID, childID);
1229: if (childID[0] == 0) {
1230: return ACC.CHILDID_SELF;
1231: }
1232: return (int) childID[0] - 1;
1233: }
1234:
1235: int stateToOs(int state) {
1236: // int osState = 0;
1237: // if ((state & ACC.STATE_SELECTED) != 0) osState |= OS.;
1238: // return osState;
1239: return state;
1240: }
1241:
1242: int osToState(int osState) {
1243: // int state = ACC.STATE_NORMAL;
1244: // if ((osState & OS.) != 0) state |= ACC.STATE_SELECTED;
1245: // return state;
1246: return osState;
1247: }
1248:
1249: String roleToOs(int role) {
1250: switch (role) {
1251: case ACC.ROLE_CLIENT_AREA:
1252: return OS.kAXWindowRole;
1253: case ACC.ROLE_WINDOW:
1254: return OS.kAXWindowRole;
1255: case ACC.ROLE_MENUBAR:
1256: return OS.kAXMenuBarRole;
1257: case ACC.ROLE_MENU:
1258: return OS.kAXMenuRole;
1259: case ACC.ROLE_MENUITEM:
1260: return OS.kAXMenuItemRole;
1261: case ACC.ROLE_SEPARATOR:
1262: return OS.kAXSplitterRole;
1263: case ACC.ROLE_TOOLTIP:
1264: return OS.kAXHelpTagRole;
1265: case ACC.ROLE_SCROLLBAR:
1266: return OS.kAXScrollBarRole;
1267: case ACC.ROLE_DIALOG:
1268: return OS.kAXWindowRole + ':' + OS.kAXDialogSubrole;
1269: case ACC.ROLE_LABEL:
1270: return OS.kAXStaticTextRole;
1271: case ACC.ROLE_PUSHBUTTON:
1272: return OS.kAXButtonRole;
1273: case ACC.ROLE_CHECKBUTTON:
1274: return OS.kAXCheckBoxRole;
1275: case ACC.ROLE_RADIOBUTTON:
1276: return OS.kAXRadioButtonRole;
1277: case ACC.ROLE_COMBOBOX:
1278: return OS.kAXComboBoxRole;
1279: case ACC.ROLE_TEXT:
1280: return OS.kAXTextFieldRole;
1281: case ACC.ROLE_TOOLBAR:
1282: return OS.kAXToolbarRole;
1283: case ACC.ROLE_LIST:
1284: return OS.kAXOutlineRole;
1285: case ACC.ROLE_LISTITEM:
1286: return OS.kAXStaticTextRole;
1287: case ACC.ROLE_TABLE:
1288: return OS.kAXTableRole;
1289: case ACC.ROLE_TABLECELL:
1290: return OS.kAXRowRole + ':' + OS.kAXTableRowSubrole;
1291: case ACC.ROLE_TABLECOLUMNHEADER:
1292: return OS.kAXButtonRole + ':' + OS.kAXSortButtonSubrole;
1293: case ACC.ROLE_TABLEROWHEADER:
1294: return OS.kAXRowRole + ':' + OS.kAXTableRowSubrole;
1295: case ACC.ROLE_TREE:
1296: return OS.kAXOutlineRole;
1297: case ACC.ROLE_TREEITEM:
1298: return OS.kAXOutlineRole + ':' + OS.kAXOutlineRowSubrole;
1299: case ACC.ROLE_TABFOLDER:
1300: return OS.kAXTabGroupRole;
1301: case ACC.ROLE_TABITEM:
1302: return OS.kAXRadioButtonRole;
1303: case ACC.ROLE_PROGRESSBAR:
1304: return OS.kAXProgressIndicatorRole;
1305: case ACC.ROLE_SLIDER:
1306: return OS.kAXSliderRole;
1307: case ACC.ROLE_LINK:
1308: return OS.kAXLinkRole;
1309: }
1310: return OS.kAXUnknownRole;
1311: }
1312:
1313: int osToRole(String osRole) {
1314: if (osRole == null)
1315: return 0;
1316: if (osRole.equals(OS.kAXWindowRole))
1317: return ACC.ROLE_WINDOW;
1318: if (osRole.equals(OS.kAXMenuBarRole))
1319: return ACC.ROLE_MENUBAR;
1320: if (osRole.equals(OS.kAXMenuRole))
1321: return ACC.ROLE_MENU;
1322: if (osRole.equals(OS.kAXMenuItemRole))
1323: return ACC.ROLE_MENUITEM;
1324: if (osRole.equals(OS.kAXSplitterRole))
1325: return ACC.ROLE_SEPARATOR;
1326: if (osRole.equals(OS.kAXHelpTagRole))
1327: return ACC.ROLE_TOOLTIP;
1328: if (osRole.equals(OS.kAXScrollBarRole))
1329: return ACC.ROLE_SCROLLBAR;
1330: if (osRole.equals(OS.kAXScrollAreaRole))
1331: return ACC.ROLE_LIST;
1332: if (osRole.equals(OS.kAXWindowRole + ':' + OS.kAXDialogSubrole))
1333: return ACC.ROLE_DIALOG;
1334: if (osRole.equals(OS.kAXWindowRole + ':'
1335: + OS.kAXSystemDialogSubrole))
1336: return ACC.ROLE_DIALOG;
1337: if (osRole.equals(OS.kAXStaticTextRole))
1338: return ACC.ROLE_LABEL;
1339: if (osRole.equals(OS.kAXButtonRole))
1340: return ACC.ROLE_PUSHBUTTON;
1341: if (osRole.equals(OS.kAXCheckBoxRole))
1342: return ACC.ROLE_CHECKBUTTON;
1343: if (osRole.equals(OS.kAXRadioButtonRole))
1344: return ACC.ROLE_RADIOBUTTON;
1345: if (osRole.equals(OS.kAXComboBoxRole))
1346: return ACC.ROLE_COMBOBOX;
1347: if (osRole.equals(OS.kAXTextFieldRole))
1348: return ACC.ROLE_TEXT;
1349: if (osRole.equals(OS.kAXTextAreaRole))
1350: return ACC.ROLE_TEXT;
1351: if (osRole.equals(OS.kAXToolbarRole))
1352: return ACC.ROLE_TOOLBAR;
1353: if (osRole.equals(OS.kAXListRole))
1354: return ACC.ROLE_LIST;
1355: if (osRole.equals(OS.kAXTableRole))
1356: return ACC.ROLE_TABLE;
1357: if (osRole.equals(OS.kAXColumnRole))
1358: return ACC.ROLE_TABLECOLUMNHEADER;
1359: if (osRole.equals(OS.kAXButtonRole + ':'
1360: + OS.kAXSortButtonSubrole))
1361: return ACC.ROLE_TABLECOLUMNHEADER;
1362: if (osRole.equals(OS.kAXRowRole + ':' + OS.kAXTableRowSubrole))
1363: return ACC.ROLE_TABLEROWHEADER;
1364: if (osRole.equals(OS.kAXOutlineRole))
1365: return ACC.ROLE_TREE;
1366: if (osRole.equals(OS.kAXOutlineRole + ':'
1367: + OS.kAXOutlineRowSubrole))
1368: return ACC.ROLE_TREEITEM;
1369: if (osRole.equals(OS.kAXTabGroupRole))
1370: return ACC.ROLE_TABFOLDER;
1371: if (osRole.equals(OS.kAXProgressIndicatorRole))
1372: return ACC.ROLE_PROGRESSBAR;
1373: if (osRole.equals(OS.kAXSliderRole))
1374: return ACC.ROLE_SLIDER;
1375: if (osRole.equals(OS.kAXLinkRole))
1376: return ACC.ROLE_LINK;
1377: return ACC.ROLE_CLIENT_AREA;
1378: }
1379:
1380: /* Return a CFStringRef representing the given java String.
1381: * Note that the caller is responsible for calling OS.CFRelease
1382: * when they are done with the stringRef.
1383: */
1384: int stringToStringRef(String string) {
1385: char[] buffer = new char[string.length()];
1386: string.getChars(0, buffer.length, buffer, 0);
1387: return OS.CFStringCreateWithCharacters(OS.kCFAllocatorDefault,
1388: buffer, buffer.length);
1389: }
1390:
1391: /* Return a Java String representing the given CFStringRef.
1392: * Note that this method does not call OS.CFRelease(stringRef).
1393: */
1394: String stringRefToString(int stringRef) {
1395: int length = OS.CFStringGetLength(stringRef);
1396: char[] buffer = new char[length];
1397: CFRange range = new CFRange();
1398: range.length = length;
1399: OS.CFStringGetCharacters(stringRef, range, buffer);
1400: return new String(buffer);
1401: }
1402:
1403: /* checkWidget was copied from Widget, and rewritten to work in this package */
1404: void checkWidget() {
1405: if (!isValidThread())
1406: SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS);
1407: if (control.isDisposed())
1408: SWT.error(SWT.ERROR_WIDGET_DISPOSED);
1409: }
1410:
1411: /* isValidThread was copied from Widget, and rewritten to work in this package */
1412: boolean isValidThread() {
1413: return control.getDisplay().getThread() == Thread
1414: .currentThread();
1415: }
1416: }
|