comparison dwt/accessibility/Accessible.d @ 45:d8635bb48c7c

Merge with SWT 3.5
author Jacob Carlborg <doob@me.com>
date Mon, 01 Dec 2008 17:07:00 +0100
parents 642f460a0908
children cfa563df4fdd
comparison
equal deleted inserted replaced
44:ca5e494f2bbf 45:d8635bb48c7c
1 /******************************************************************************* 1 /*******************************************************************************
2 * Copyright (c) 2000, 2005 IBM Corporation and others. 2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials 3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0 4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at 5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html 6 * http://www.eclipse.org/legal/epl-v10.html
7 * 7 *
8 * Contributors: 8 * Contributors:
9 * IBM Corporation - initial API and implementation 9 * IBM Corporation - initial API and implementation
10 * 10 *
11 * Port to the D programming language: 11 * Port to the D programming language:
12 * Jacob Carlborg <jacob.carlborg@gmail.com> 12 * Jacob Carlborg <doob@me.com>
13 *******************************************************************************/ 13 *******************************************************************************/
14 module dwt.accessibility.Accessible; 14 module dwt.accessibility.Accessible;
15 15
16 import dwt.dwthelper.utils; 16 import dwt.dwthelper.utils;
17 import java.util.Collection;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.Map;
21 import java.util.Vector;
22
23 import dwt.DWT;
17 import dwt.DWTException; 24 import dwt.DWTException;
25 import dwt.graphics.Point;
26 import dwt.graphics.Rectangle;
27 import dwt.internal.cocoa.NSArray;
28 import dwt.internal.cocoa.NSMutableArray;
29 import dwt.internal.cocoa.NSNumber;
30 import dwt.internal.cocoa.NSObject;
31 import dwt.internal.cocoa.NSPoint;
32 import dwt.internal.cocoa.NSRange;
33 import dwt.internal.cocoa.NSSize;
34 import dwt.internal.cocoa.NSString;
35 import dwt.internal.cocoa.NSValue;
36 import dwt.internal.cocoa.OS;
37 import dwt.internal.cocoa.id;
38 import dwt.widgets.Composite;
18 import dwt.widgets.Control; 39 import dwt.widgets.Control;
40 import dwt.widgets.Display;
41 import dwt.widgets.Monitor;
42 import dwt.widgets.Shell;
19 43
20 import dwt.accessibility.AccessibleListener; 44 import dwt.accessibility.AccessibleListener;
21 import dwt.accessibility.AccessibleControlListener; 45 import dwt.accessibility.AccessibleControlListener;
22 import dwt.accessibility.AccessibleTextListener; 46 import dwt.accessibility.AccessibleTextListener;
23 47
37 * @see Control#getAccessible 61 * @see Control#getAccessible
38 * @see AccessibleListener 62 * @see AccessibleListener
39 * @see AccessibleEvent 63 * @see AccessibleEvent
40 * @see AccessibleControlListener 64 * @see AccessibleControlListener
41 * @see AccessibleControlEvent 65 * @see AccessibleControlEvent
66 * @see <a href="http://www.eclipse.org/swt/snippets/#accessibility">Accessibility snippets</a>
67 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
42 * 68 *
43 * @since 2.0 69 * @since 2.0
44 */ 70 */
45 public class Accessible { 71 public class Accessible {
72
73 static NSString[] baseAttributes = {
74 OS.NSAccessibilityRoleAttribute,
75 OS.NSAccessibilityRoleDescriptionAttribute,
76 OS.NSAccessibilityHelpAttribute,
77 OS.NSAccessibilityFocusedAttribute,
78 OS.NSAccessibilityParentAttribute,
79 OS.NSAccessibilityChildrenAttribute,
80 OS.NSAccessibilityPositionAttribute,
81 OS.NSAccessibilitySizeAttribute,
82 OS.NSAccessibilityWindowAttribute,
83 OS.NSAccessibilityTopLevelUIElementAttribute
84 };
85
86 static NSString[] baseTextAttributes = {
87 OS.NSAccessibilityNumberOfCharactersAttribute,
88 OS.NSAccessibilitySelectedTextAttribute,
89 OS.NSAccessibilitySelectedTextRangeAttribute,
90 OS.NSAccessibilityInsertionPointLineNumberAttribute,
91 OS.NSAccessibilitySelectedTextRangesAttribute,
92 OS.NSAccessibilityVisibleCharacterRangeAttribute,
93 OS.NSAccessibilityValueAttribute,
94 };
95
96 static NSString[] baseParameterizedAttributes = {
97 OS.NSAccessibilityStringForRangeParameterizedAttribute,
98 OS.NSAccessibilityRangeForLineParameterizedAttribute,
99 };
100
101
102 NSMutableArray attributeNames = null;
103 NSMutableArray parameterizedAttributeNames = null;
104 NSMutableArray actionNames = null;
105
106 Vector accessibleListeners = new Vector();
107 Vector accessibleControlListeners = new Vector();
108 Vector accessibleTextListeners = new Vector ();
46 Control control; 109 Control control;
47 110
111 Map /*<Integer, SWTAccessibleDelegate>*/ children = new HashMap();
112
48 this (Control control) { 113 this (Control control) {
114
49 this.control = control; 115 this.control = control;
50 } 116 }
51 117
52 /** 118 /**
53 * Invokes platform specific functionality to allocate a new accessible object. 119 * Invokes platform specific functionality to allocate a new accessible object.
86 * 152 *
87 * @see AccessibleListener 153 * @see AccessibleListener
88 * @see #removeAccessibleListener 154 * @see #removeAccessibleListener
89 */ 155 */
90 public void addAccessibleListener (AccessibleListener listener) { 156 public void addAccessibleListener (AccessibleListener listener) {
91 } 157 checkWidget();
92 158 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
93 /** 159 accessibleListeners.addElement(listener);
94 * Removes the listener from the collection of listeners who will
95 * be notified when an accessible client asks for certain strings,
96 * such as name, description, help, or keyboard shortcut.
97 *
98 * @param listener the listener that should no longer be notified when the receiver
99 * is asked for a name, description, help, or keyboard shortcut string
100 *
101 * @exception IllegalArgumentException <ul>
102 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
103 * </ul>
104 * @exception DWTException <ul>
105 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
106 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
107 * </ul>
108 *
109 * @see AccessibleListener
110 * @see #addAccessibleListener
111 */
112 public void removeAccessibleListener (AccessibleListener listener) {
113 } 160 }
114 161
115 /** 162 /**
116 * Adds the listener to the collection of listeners who will 163 * Adds the listener to the collection of listeners who will
117 * be notified when an accessible client asks for custom control 164 * be notified when an accessible client asks for custom control
131 * </ul> 178 * </ul>
132 * 179 *
133 * @see AccessibleControlListener 180 * @see AccessibleControlListener
134 * @see #removeAccessibleControlListener 181 * @see #removeAccessibleControlListener
135 */ 182 */
136 public void addAccessibleControlListener (AccessibleControlListener listener) { 183 public void addAccessibleControlListener(AccessibleControlListener listener) {
137 } 184 checkWidget();
138 185 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
139 /** 186 accessibleControlListeners.addElement(listener);
140 * Removes the listener from the collection of listeners who will
141 * be notified when an accessible client asks for custom control
142 * specific information.
143 *
144 * @param listener the listener that should no longer be notified when the receiver
145 * is asked for custom control specific information
146 *
147 * @exception IllegalArgumentException <ul>
148 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
149 * </ul>
150 * @exception DWTException <ul>
151 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
152 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
153 * </ul>
154 *
155 * @see AccessibleControlListener
156 * @see #addAccessibleControlListener
157 */
158 public void removeAccessibleControlListener (AccessibleControlListener listener) {
159 } 187 }
160 188
161 /** 189 /**
162 * Adds the listener to the collection of listeners who will 190 * Adds the listener to the collection of listeners who will
163 * be notified when an accessible client asks for custom text control 191 * be notified when an accessible client asks for custom text control
180 * @see #removeAccessibleTextListener 208 * @see #removeAccessibleTextListener
181 * 209 *
182 * @since 3.0 210 * @since 3.0
183 */ 211 */
184 public void addAccessibleTextListener (AccessibleTextListener listener) { 212 public void addAccessibleTextListener (AccessibleTextListener listener) {
185 } 213 checkWidget ();
186 214 if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
187 /** 215 accessibleTextListeners.addElement (listener);
188 * Removes the listener from the collection of listeners who will 216 }
189 * be notified when an accessible client asks for custom text control 217
190 * specific information. 218 public id internal_accessibilityActionDescription(NSString action, int childID) {
191 * 219 // TODO No action support for now.
192 * @param listener the listener that should no longer be notified when the receiver 220 return NSString.stringWith("");
193 * is asked for custom text control specific information 221 }
194 * 222
195 * @exception IllegalArgumentException <ul> 223 public NSArray internal_accessibilityActionNames(int childID) {
196 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 224 // The supported action list depends on the role played by the control.
197 * </ul> 225 AccessibleControlEvent event = new AccessibleControlEvent(this);
198 * @exception DWTException <ul> 226 event.childID = childID;
199 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 227 event.detail = -1;
200 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 228 for (int i = 0; i < accessibleControlListeners.size(); i++) {
201 * </ul> 229 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
202 * 230 listener.getRole(event);
203 * @see AccessibleTextListener 231 }
204 * @see #addAccessibleTextListener 232
205 * 233 // No accessible listener is overriding the role of the control, so let Cocoa return the default set for the control.
206 * @since 3.0 234 if (event.detail is -1) {
207 */ 235 return null;
208 public void removeAccessibleTextListener (AccessibleTextListener listener) { 236 }
237
238 if ((childID is ACC.CHILDID_SELF) && (actionNames !is null)) {
239 return retainedAutoreleased(actionNames);
240 }
241
242 NSMutableArray returnValue = NSMutableArray.arrayWithCapacity(5);
243
244 switch (event.detail) {
245 case ACC.ROLE_PUSHBUTTON:
246 case ACC.ROLE_RADIOBUTTON:
247 case ACC.ROLE_CHECKBUTTON:
248 case ACC.ROLE_TABITEM:
249 returnValue.addObject(OS.NSAccessibilityPressAction);
250 break;
251 }
252
253 switch (event.detail) {
254 case ACC.ROLE_COMBOBOX:
255 returnValue.addObject(OS.NSAccessibilityConfirmAction);
256 break;
257 }
258
259
260 if (childID is ACC.CHILDID_SELF) {
261 actionNames = returnValue;
262 actionNames.retain();
263 return retainedAutoreleased(actionNames);
264 } else {
265 // Caller must retain if they want to hold on to it.
266 return returnValue;
267 }
268 }
269
270 public NSArray internal_accessibilityAttributeNames(int childID) {
271 // The supported attribute set depends on the role played by the control.
272 // We may need to add or remove from the base set as needed.
273 AccessibleControlEvent event = new AccessibleControlEvent(this);
274 event.childID = childID;
275 event.detail = -1;
276 for (int i = 0; i < accessibleControlListeners.size(); i++) {
277 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
278 listener.getRole(event);
279 }
280
281 // No accessible listener is overriding the role of the control, so let Cocoa
282 // return the default set for the control.
283 if (event.detail is -1)
284 return null;
285
286 if ((childID is ACC.CHILDID_SELF) && (attributeNames !is null)) {
287 return retainedAutoreleased(attributeNames);
288 }
289
290 NSMutableArray returnValue = NSMutableArray.arrayWithCapacity(baseAttributes.length);
291
292 /* Add our list of supported attributes to the array.
293 * Make sure each attribute name is not already in the array before appending.
294 */
295 for (int i = 0; i < baseAttributes.length; i++) {
296 if (!returnValue.containsObject(baseAttributes[i])) {
297 returnValue.addObject(baseAttributes[i]);
298 }
299 }
300
301 if (accessibleTextListeners.size() > 0) {
302 for (int i = 0; i < baseTextAttributes.length; i++) {
303 if (!returnValue.containsObject(baseTextAttributes[i])) {
304 returnValue.addObject(baseTextAttributes[i]);
305 }
306 }
307 }
308
309 // The following are expected to have a value (AXValue)
310 switch (event.detail) {
311 case ACC.ROLE_CHECKBUTTON:
312 case ACC.ROLE_RADIOBUTTON:
313 case ACC.ROLE_LABEL:
314 case ACC.ROLE_TABITEM:
315 case ACC.ROLE_TABFOLDER:
316 returnValue.addObject(OS.NSAccessibilityValueAttribute);
317 break;
318 }
319
320 // The following are expected to report their enabled status (AXEnabled)
321 switch (event.detail) {
322 case ACC.ROLE_CHECKBUTTON:
323 case ACC.ROLE_RADIOBUTTON:
324 case ACC.ROLE_LABEL:
325 case ACC.ROLE_TABITEM:
326 case ACC.ROLE_PUSHBUTTON:
327 case ACC.ROLE_COMBOBOX:
328 returnValue.addObject(OS.NSAccessibilityEnabledAttribute);
329 break;
330 }
331
332 // The following are expected to report a title (AXTitle)
333 switch (event.detail) {
334 case ACC.ROLE_CHECKBUTTON:
335 case ACC.ROLE_RADIOBUTTON:
336 case ACC.ROLE_PUSHBUTTON:
337 case ACC.ROLE_TABITEM:
338 returnValue.addObject(OS.NSAccessibilityTitleAttribute);
339 break;
340 }
341
342 // Accessibility verifier says these attributes must be reported for combo boxes.
343 if (event.detail is ACC.ROLE_COMBOBOX) {
344 returnValue.addObject(OS.NSAccessibilityExpandedAttribute);
345 }
346
347 // Accessibility verifier says these attributes must be reported for tab folders.
348 if (event.detail is ACC.ROLE_TABFOLDER) {
349 returnValue.addObject(OS.NSAccessibilityContentsAttribute);
350 returnValue.addObject(OS.NSAccessibilityTabsAttribute);
351 }
352
353 /*
354 * Only report back sub-roles when the DWT role maps to a sub-role.
355 */
356 if (event.detail !is -1) {
357 String osRole = roleToOs(event.detail);
358
359 if (osRole.indexOf(':') is -1)
360 returnValue.removeObject(OS.NSAccessibilitySubroleAttribute);
361 }
362
363 /*
364 * Children never return their own children, so remove that attribute.
365 */
366 if (childID !is ACC.CHILDID_SELF) {
367 returnValue.removeObject(OS.NSAccessibilityChildrenAttribute);
368 }
369
370 if (childID is ACC.CHILDID_SELF) {
371 attributeNames = returnValue;
372 attributeNames.retain();
373 return retainedAutoreleased(attributeNames);
374 } else {
375 // Caller must retain if necessary.
376 return returnValue;
377 }
378 }
379
380 public id internal_accessibilityAttributeValue(NSString attribute, int childID) {
381 if (attribute.isEqualToString(OS.NSAccessibilityRoleAttribute)) return getRoleAttribute(childID);
382 if (attribute.isEqualToString(OS.NSAccessibilitySubroleAttribute)) return getSubroleAttribute(childID);
383 if (attribute.isEqualToString(OS.NSAccessibilityRoleDescriptionAttribute)) return getRoleDescriptionAttribute(childID);
384 if (attribute.isEqualToString(OS.NSAccessibilityExpandedAttribute)) return getExpandedAttribute(childID);
385 if (attribute.isEqualToString(OS.NSAccessibilityHelpAttribute)) return getHelpAttribute(childID);
386 if (attribute.isEqualToString(OS.NSAccessibilityTitleAttribute)) return getTitleAttribute(childID);
387 if (attribute.isEqualToString(OS.NSAccessibilityValueAttribute)) return getValueAttribute(childID);
388 if (attribute.isEqualToString(OS.NSAccessibilityEnabledAttribute)) return getEnabledAttribute(childID);
389 if (attribute.isEqualToString(OS.NSAccessibilityFocusedAttribute)) return getFocusedAttribute(childID);
390 if (attribute.isEqualToString(OS.NSAccessibilityParentAttribute)) return getParentAttribute(childID);
391 if (attribute.isEqualToString(OS.NSAccessibilityChildrenAttribute)) return getChildrenAttribute(childID);
392 if (attribute.isEqualToString(OS.NSAccessibilityContentsAttribute)) return getChildrenAttribute(childID);
393 // FIXME: There's no specific API just for tabs, which won't include the buttons (if any.)
394 if (attribute.isEqualToString(OS.NSAccessibilityTabsAttribute)) return getTabsAttribute(childID);
395 if (attribute.isEqualToString(OS.NSAccessibilityWindowAttribute)) return getWindowAttribute(childID);
396 if (attribute.isEqualToString(OS.NSAccessibilityTopLevelUIElementAttribute)) return getTopLevelUIElementAttribute(childID);
397 if (attribute.isEqualToString(OS.NSAccessibilityPositionAttribute)) return getPositionAttribute(childID);
398 if (attribute.isEqualToString(OS.NSAccessibilitySizeAttribute)) return getSizeAttribute(childID);
399 if (attribute.isEqualToString(OS.NSAccessibilityDescriptionAttribute)) return getDescriptionAttribute(childID);
400 if (attribute.isEqualToString(OS.NSAccessibilityNumberOfCharactersAttribute)) return getNumberOfCharactersAttribute(childID);
401 if (attribute.isEqualToString(OS.NSAccessibilitySelectedTextAttribute)) return getSelectedTextAttribute(childID);
402 if (attribute.isEqualToString(OS.NSAccessibilitySelectedTextRangeAttribute)) return getSelectedTextRangeAttribute(childID);
403 if (attribute.isEqualToString(OS.NSAccessibilityInsertionPointLineNumberAttribute)) return getInsertionPointLineNumberAttribute(childID);
404 if (attribute.isEqualToString(OS.NSAccessibilitySelectedTextRangesAttribute)) return getSelectedTextRangesAttribute(childID);
405 if (attribute.isEqualToString(OS.NSAccessibilityVisibleCharacterRangeAttribute)) return getVisibleCharacterRangeAttribute(childID);
406
407 // If this object don't know how to get the value it's up to the control itself to return an attribute value.
408 return null;
409 }
410
411 public id internal_accessibilityAttributeValue_forParameter(NSString attribute, id parameter, int childID) {
412 if (attribute.isEqualToString(OS.NSAccessibilityStringForRangeParameterizedAttribute)) return getStringForRangeAttribute(parameter, childID);
413 if (attribute.isEqualToString(OS.NSAccessibilityRangeForLineParameterizedAttribute)) return getRangeForLineParameterizedAttribute(parameter, childID);
414 return null;
415 }
416
417 // Returns the UI Element that has the focus. You can assume that the search for the focus has already been narrowed down to the receiver.
418 // Override this method to do a deeper search with a UIElement - e.g. a NSMatrix would determine if one of its cells has the focus.
419 public id internal_accessibilityFocusedUIElement(int childID) {
420 AccessibleControlEvent event = new AccessibleControlEvent(this);
421 event.childID = ACC.CHILDID_MULTIPLE; // set to invalid value, to test if the application sets it in getFocus()
422 event.accessible = null;
423 for (int i = 0; i < accessibleControlListeners.size(); i++) {
424 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
425 listener.getFocus(event);
426 }
427
428 // The listener did not respond, so let Cocoa figure it out.
429 if (event.childID is ACC.CHILDID_MULTIPLE)
430 return null;
431
432 /* The application can optionally answer an accessible. */
433 if (event.accessible !is null) {
434 return new id(OS.NSAccessibilityUnignoredAncestor(event.accessible.control.view.id));
435 }
436
437 /* Or the application can answer a valid child ID, including CHILDID_SELF and CHILDID_NONE. */
438 if (event.childID is ACC.CHILDID_SELF || event.childID is ACC.CHILDID_NONE) {
439 return new id(OS.NSAccessibilityUnignoredAncestor(control.view.id));
440 }
441
442 return new id(OS.NSAccessibilityUnignoredAncestor(childIDToOs(event.childID).id));
443 }
444
445 // Returns the deepest descendant of the UIElement hierarchy that contains the point.
446 // You can assume the point has already been determined to lie within the receiver.
447 // Override this method to do deeper hit testing within a UIElement - e.g. a NSMatrix would test its cells. The point is bottom-left relative screen coordinates.
448 public id internal_accessibilityHitTest(NSPoint point, int childID) {
449 AccessibleControlEvent event = new AccessibleControlEvent(this);
450 event.x = (int) point.x;
451 Monitor primaryMonitor = Display.getCurrent().getPrimaryMonitor();
452 event.y = (int) (primaryMonitor.getBounds().height - point.y);
453
454 // Set an impossible value to determine if anything responded to the event.
455 event.childID = ACC.CHILDID_MULTIPLE;
456 for (int i = 0; i < accessibleControlListeners.size(); i++) {
457 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
458 listener.getChildAtPoint(event);
459 }
460
461 // The listener did not respond, so let Cocoa figure it out.
462 if (event.childID is ACC.CHILDID_MULTIPLE)
463 return null;
464
465 if (event.accessible !is null) {
466 return new id(OS.NSAccessibilityUnignoredAncestor(event.accessible.control.view.id));
467 }
468
469 if (event.childID is ACC.CHILDID_SELF || event.childID is ACC.CHILDID_NONE) {
470 return new id(OS.NSAccessibilityUnignoredAncestor(control.view.id));
471 }
472
473 return new id(OS.NSAccessibilityUnignoredAncestor(childIDToOs(event.childID).id));
474 }
475
476 public bool internal_accessibilityIsAttributeSettable(NSString attribute, int childID) {
477 return false;
478 }
479
480 // Return YES if the UIElement doesn't show up to the outside world - i.e. its parent should return the UIElement's children as its own - cutting the UIElement out. E.g. NSControls are ignored when they are single-celled.
481 public bool internal_accessibilityIsIgnored(int childID) {
482 return false;
483 }
484
485 // parameterized attribute methods
486 public NSArray internal_accessibilityParameterizedAttributeNames(int childID) {
487
488 if ((childID is ACC.CHILDID_SELF) && (parameterizedAttributeNames !is null)) {
489 return retainedAutoreleased(parameterizedAttributeNames);
490 }
491
492 NSMutableArray returnValue = NSMutableArray.arrayWithCapacity(4);
493
494 if (accessibleTextListeners.size() > 0) {
495 for (int i = 0; i < baseParameterizedAttributes.length; i++) {
496 if (!returnValue.containsObject(baseParameterizedAttributes[i])) {
497 returnValue.addObject(baseParameterizedAttributes[i]);
498 }
499 }
500
501 }
502
503 if (childID is ACC.CHILDID_SELF) {
504 parameterizedAttributeNames = returnValue;
505 parameterizedAttributeNames.retain();
506 return retainedAutoreleased(parameterizedAttributeNames);
507 } else {
508 // Caller must retain if they want to keep it.
509 return returnValue;
510 }
511 }
512
513 public void internal_accessibilityPerformAction(NSString action, int childID) {
514 // TODO Auto-generated method stub
515 // No action support for now.
209 } 516 }
210 517
211 /** 518 /**
212 * Returns the control for this Accessible object. 519 * Returns the control for this Accessible object.
213 * 520 *
214 * @return the receiver's control 521 * @return the receiver's control
215 * @since 3.0 522 * @since 3.0
216 */ 523 */
217 public Control getControl () { 524 public Control getControl() {
218 return control; 525 return control;
219 }
220
221 /**
222 * Sends a message to accessible clients that the child selection
223 * within a custom container control has changed.
224 *
225 * @exception DWTException <ul>
226 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
227 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
228 * </ul>
229 *
230 * @since 3.0
231 */
232 public void selectionChanged () {
233 }
234
235 /**
236 * Sends a message to accessible clients that the text
237 * caret has moved within a custom control.
238 *
239 * @param index the new caret index within the control
240 *
241 * @exception DWTException <ul>
242 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
243 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
244 * </ul>
245 *
246 * @since 3.0
247 */
248 public void textCaretMoved (int index) {
249 }
250
251 /**
252 * Sends a message to accessible clients that the text
253 * within a custom control has changed.
254 *
255 * @param type the type of change, one of <code>ACC.NOTIFY_TEXT_INSERT</code>
256 * or <code>ACC.NOTIFY_TEXT_DELETE</code>
257 * @param startIndex the text index within the control where the insertion or deletion begins
258 * @param length the non-negative length in characters of the insertion or deletion
259 *
260 * @exception DWTException <ul>
261 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
262 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
263 * </ul>
264 *
265 * @see ACC#TEXT_INSERT
266 * @see ACC#TEXT_DELETE
267 *
268 * @since 3.0
269 */
270 public void textChanged (int type, int startIndex, int length) {
271 }
272
273 /**
274 * Sends a message to accessible clients that the text
275 * selection has changed within a custom control.
276 *
277 * @exception DWTException <ul>
278 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
279 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
280 * </ul>
281 *
282 * @since 3.0
283 */
284 public void textSelectionChanged () {
285 }
286
287 /**
288 * Sends a message to accessible clients indicating that the focus
289 * has changed within a custom control.
290 *
291 * @param childID an identifier specifying a child of the control
292 *
293 * @exception DWTException <ul>
294 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
295 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
296 * </ul>
297 */
298 public void setFocus (int childID) {
299 } 526 }
300 527
301 /** 528 /**
302 * Invokes platform specific functionality to dispose an accessible object. 529 * Invokes platform specific functionality to dispose an accessible object.
303 * <p> 530 * <p>
306 * can be shared within the packages provided by DWT. It is not 533 * can be shared within the packages provided by DWT. It is not
307 * available on all platforms, and should never be called from 534 * available on all platforms, and should never be called from
308 * application code. 535 * application code.
309 * </p> 536 * </p>
310 */ 537 */
311 public void internal_dispose_Accessible () { 538 public void internal_dispose_Accessible() {
539 if (actionNames !is null) actionNames.release();
540 actionNames = null;
541 if (attributeNames !is null) attributeNames.release();
542 attributeNames = null;
543 if (parameterizedAttributeNames !is null) parameterizedAttributeNames.release();
544 parameterizedAttributeNames = null;
545
546 Collection delegates = children.values();
547 Iterator iter = delegates.iterator();
548 while (iter.hasNext()) {
549 SWTAccessibleDelegate childDelegate = (SWTAccessibleDelegate)iter.next();
550 childDelegate.internal_dispose_SWTAccessibleDelegate();
551 }
552
553 children.clear();
554 }
555
556 id getExpandedAttribute(int childID) {
557 // TODO: May need to expand the API so the combo box state can be reported.
558 return NSNumber.numberWithBool(false);
559 }
560
561 id getHelpAttribute (int childID) {
562 id returnValue = null;
563 AccessibleEvent event = new AccessibleEvent(this);
564 event.childID = childID;
565 for (int i = 0; i < accessibleListeners.size(); i++) {
566 AccessibleListener listener = (AccessibleListener) accessibleListeners.elementAt(i);
567 listener.getHelp(event);
568 }
569
570 if (event.result !is null) {
571 returnValue = NSString.stringWith(event.result);
572 }
573
574 return returnValue;
575 }
576
577 NSString getRoleAttribute(int childID) {
578 NSString returnValue = null;
579 AccessibleControlEvent event = new AccessibleControlEvent(this);
580 event.childID = childID;
581 event.detail = -1;
582 for (int i = 0; i < accessibleControlListeners.size(); i++) {
583 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
584 listener.getRole(event);
585 }
586 if (event.detail !is -1) {
587 String appRole = roleToOs (event.detail);
588 int index = appRole.indexOf(':');
589 if (index !is -1) appRole = appRole.substring(0, index);
590 returnValue = NSString.stringWith(appRole);
591 }
592
593 return returnValue;
594 }
595
596 id getSubroleAttribute (int childID) {
597 id returnValue = null;
598 AccessibleControlEvent event = new AccessibleControlEvent(this);
599 event.childID = childID;
600 event.detail = -1;
601 for (int i = 0; i < accessibleControlListeners.size(); i++) {
602 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
603 listener.getRole(event);
604 }
605 if (event.detail !is -1) {
606 String appRole = roleToOs (event.detail);
607 int index = appRole.indexOf(':');
608 if (index !is -1) {
609 appRole = appRole.substring(index + 1);
610 returnValue = NSString.stringWith(appRole);
611 }
612 }
613 return returnValue;
614 }
615
616 id getRoleDescriptionAttribute (int childID) {
617 id returnValue = null;
618 AccessibleControlEvent event = new AccessibleControlEvent(this);
619 event.childID = childID;
620 event.detail = -1;
621 for (int i = 0; i < accessibleControlListeners.size(); i++) {
622 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
623 listener.getRole(event);
624 }
625 if (event.detail !is -1) {
626 String appRole = roleToOs (event.detail);
627 String appSubrole = null;
628 int index = appRole.indexOf(':');
629 if (index !is -1) {
630 appSubrole = appRole.substring(index + 1);
631 appRole = appRole.substring(0, index);
632 }
633 NSString nsAppRole = NSString.stringWith(appRole);
634 NSString nsAppSubrole = null;
635
636 if (appSubrole !is null) nsAppSubrole = NSString.stringWith(appSubrole);
637 returnValue = new NSString(OS.NSAccessibilityRoleDescription (((nsAppRole !is null) ? nsAppRole.id : 0), (nsAppSubrole !is null) ? nsAppSubrole.id : 0));
638 }
639 return returnValue;
640 }
641
642 id getTitleAttribute (int childID) {
643
644 id returnValue = null;//NSString.stringWith("");
645
646 /*
647 * Feature of the Macintosh. The text of a Label is returned in its value,
648 * not its title, so ensure that the role is not Label before asking for the title.
649 */
650 AccessibleControlEvent roleEvent = new AccessibleControlEvent(this);
651 roleEvent.childID = childID;
652 roleEvent.detail = -1;
653 for (int i = 0; i < accessibleControlListeners.size(); i++) {
654 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
655 listener.getRole(roleEvent);
656 }
657 if (roleEvent.detail !is ACC.ROLE_LABEL) {
658 AccessibleEvent event = new AccessibleEvent(this);
659 event.childID = childID;
660 event.result = null;
661 for (int i = 0; i < accessibleListeners.size(); i++) {
662 AccessibleListener listener = (AccessibleListener) accessibleListeners.elementAt(i);
663 listener.getName(event);
664 }
665
666 if (event.result !is null)
667 returnValue = NSString.stringWith(event.result);
668 }
669 return returnValue;
670 }
671
672 id getValueAttribute (int childID) {
673 id returnValue = null;
674 AccessibleControlEvent event = new AccessibleControlEvent(this);
675 event.childID = childID;
676 event.detail = -1;
677 event.result = null; //TODO: could pass the OS value to the app
678 for (int i = 0; i < accessibleControlListeners.size(); i++) {
679 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
680 listener.getRole(event);
681 listener.getValue(event);
682 }
683 int role = event.detail;
684 String value = event.result;
685
686 switch (role) {
687 case ACC.ROLE_RADIOBUTTON: // 1 = on, 0 = off
688 case ACC.ROLE_CHECKBUTTON: // 1 = checked, 0 = unchecked, 2 = mixed
689 case ACC.ROLE_SCROLLBAR: // numeric value representing the position of the scroller
690 case ACC.ROLE_SLIDER: // the value associated with the position of the slider thumb
691 case ACC.ROLE_PROGRESSBAR: // the value associated with the fill level of the progress bar
692 if (value !is null) {
693 try {
694 int number = Integer.parseInt(value);
695 returnValue = NSNumber.numberWithInt(number);
696 } catch (NumberFormatException ex) {
697 if (value.equalsIgnoreCase("true")) {
698 returnValue = NSNumber.numberWithBool(true);
699 } else if (value.equalsIgnoreCase("false")) {
700 returnValue = NSNumber.numberWithBool(false);
701 }
702 }
703 } else {
704 returnValue = NSNumber.numberWithBool(false);
705 }
706 break;
707 case ACC.ROLE_TABFOLDER: // the accessibility object representing the currently selected tab item
708 case ACC.ROLE_TABITEM: // 1 = selected, 0 = not selected
709 AccessibleControlEvent ace = new AccessibleControlEvent(this);
710 ace.childID = -4;
711 for (int i = 0; i < accessibleControlListeners.size(); i++) {
712 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
713 listener.getSelection(ace);
714 }
715 if (ace.childID >= ACC.CHILDID_SELF) {
716 if (role is ACC.ROLE_TABITEM) {
717 returnValue = NSNumber.numberWithBool(ace.childID is childID);
718 } else {
719 returnValue = new id(OS.NSAccessibilityUnignoredAncestor(childIDToOs(ace.childID).id));
720 }
721 } else {
722 returnValue = NSNumber.numberWithBool(false);
723 }
724 break;
725 case ACC.ROLE_COMBOBOX: // text of the currently selected item
726 case ACC.ROLE_TEXT: // text in the text field
727 if (value !is null) returnValue = NSString.stringWith(value);
728 break;
729 case ACC.ROLE_LABEL: // text in the label
730 /* On a Mac, the 'value' of a label is the same as the 'name' of the label. */
731 AccessibleEvent e = new AccessibleEvent(this);
732 e.childID = childID;
733 e.result = null;
734 for (int i = 0; i < accessibleListeners.size(); i++) {
735 AccessibleListener listener = (AccessibleListener) accessibleListeners.elementAt(i);
736 listener.getName(e);
737 }
738 if (e.result !is null) {
739 returnValue = NSString.stringWith(e.result);
740 } else {
741 if (value !is null) returnValue = NSString.stringWith(value);
742 }
743 break;
744 }
745
746 return returnValue;
747 }
748
749 id getEnabledAttribute (int childID) {
750 AccessibleControlEvent event = new AccessibleControlEvent(this);
751 event.detail = -1;
752 for (int i = 0; i < accessibleControlListeners.size(); i++) {
753 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
754 listener.getState(event);
755 }
756
757 return NSNumber.numberWithBool(control.isEnabled());
758 }
759
760 id getFocusedAttribute (int childID) {
761 AccessibleControlEvent event = new AccessibleControlEvent(this);
762 event.childID = ACC.CHILDID_MULTIPLE; // set to invalid value, to test if the application sets it in getFocus()
763 event.accessible = null;
764 for (int i = 0; i < accessibleControlListeners.size(); i++) {
765 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
766 listener.getFocus(event);
767 }
768
769 /* The application can optionally answer an accessible. */
770 // FIXME:
771 // if (event.accessible !is null) {
772 // bool hasFocus = (event.accessible.childID is childID) && (event.accessible.control is this.control);
773 // return NSNumber.numberWithBool(hasFocus);
774 // }
775
776 /* Or the application can answer a valid child ID, including CHILDID_SELF and CHILDID_NONE. */
777 if (event.childID is ACC.CHILDID_SELF) {
778 bool hasFocus = (event.childID is childID);
779 return NSNumber.numberWithBool(hasFocus);
780 }
781 if (event.childID is ACC.CHILDID_NONE) {
782 return NSNumber.numberWithBool(false);
783 }
784 if (event.childID !is ACC.CHILDID_MULTIPLE) {
785 /* Other valid childID. */
786 return NSNumber.numberWithBool(event.childID is childID);
787 }
788
789 // Invalid childID at this point means the application did not implement getFocus, so
790 // let the default handler return the native focus.
791 bool hasFocus = (this.control.view.window().firstResponder() is control.view);
792 return NSNumber.numberWithBool(hasFocus);
793 }
794
795 id getParentAttribute (int childID) {
796 // Returning null here means 'let Cocoa figure it out.'
797 if (childID is ACC.CHILDID_SELF)
798 return null;
799 else
800 return new id(OS.NSAccessibilityUnignoredAncestor(control.view.id));
801 }
802
803 id getChildrenAttribute (int childID) {
804 id returnValue = null;
805 if (childID is ACC.CHILDID_SELF) {
806 AccessibleControlEvent event = new AccessibleControlEvent(this);
807 event.childID = childID;
808 event.detail = -1; // set to impossible value to test if app resets
809 for (int i = 0; i < accessibleControlListeners.size(); i++) {
810 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
811 listener.getChildCount(event);
812 }
813 if (event.detail > 0) {
814 for (int i = 0; i < accessibleControlListeners.size(); i++) {
815 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
816 listener.getChildren(event);
817 }
818 Object [] appChildren = event.children;
819 if (appChildren !is null && appChildren.length > 0) {
820 /* return an NSArray of NSAccessible objects. */
821 NSMutableArray childArray = NSMutableArray.arrayWithCapacity(appChildren.length);
822
823 for (int i = 0; i < appChildren.length; i++) {
824 Object child = appChildren[i];
825 if (child instanceof Integer) {
826 id accChild = childIDToOs(((Integer)child).intValue());
827 childArray.addObject(accChild);
828 } else {
829 childArray.addObject(((Accessible)child).control.view);
830 }
831 }
832
833 returnValue = new id(OS.NSAccessibilityUnignoredChildren(childArray.id));
834 }
835 }
836 } else {
837 // Lightweight children have no children of their own.
838 // Don't return null if there are no children -- always return an empty array.
839 returnValue = NSArray.array();
840 }
841
842 // Returning null here means we want the control itself to determine its children. If the accessible listener
843 // implemented getChildCount/getChildren, references to those objects would have been returned above.
844 return returnValue;
845 }
846
847 id getTabsAttribute (int childID) {
848 id returnValue = null;
849 if (childID is ACC.CHILDID_SELF) {
850 AccessibleControlEvent event = new AccessibleControlEvent(this);
851 event.childID = childID;
852 event.detail = -1; // set to impossible value to test if app resets
853 for (int i = 0; i < accessibleControlListeners.size(); i++) {
854 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
855 listener.getChildCount(event);
856 }
857 if (event.detail > 0) {
858 for (int i = 0; i < accessibleControlListeners.size(); i++) {
859 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
860 listener.getChildren(event);
861 }
862 Object [] appChildren = event.children;
863 if (appChildren !is null && appChildren.length > 0) {
864 /* return an NSArray of NSAccessible objects. */
865 NSMutableArray childArray = NSMutableArray.arrayWithCapacity(appChildren.length);
866
867 for (int i = 0; i < appChildren.length; i++) {
868 Object child = appChildren[i];
869 if (child instanceof Integer) {
870 int subChildID = ((Integer)child).intValue();
871 event.childID = subChildID;
872 event.detail = -1;
873 for (int j = 0; j < accessibleControlListeners.size(); j++) {
874 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(j);
875 listener.getRole(event);
876 }
877
878 if (event.detail is ACC.ROLE_TABITEM) {
879 id accChild = childIDToOs(((Integer)child).intValue());
880 childArray.addObject(accChild);
881 }
882 } else {
883 childArray.addObject(((Accessible)child).control.view);
884 }
885 }
886
887 returnValue = new id(OS.NSAccessibilityUnignoredChildren(childArray.id));
888 }
889 }
890 } else {
891 // Lightweight children have no children of their own.
892 // Don't return null if there are no children -- always return an empty array.
893 returnValue = NSArray.array();
894 }
895
896 // Returning null here means we want the control itself to determine its children. If the accessible listener
897 // implemented getChildCount/getChildren, references to those objects would have been returned above.
898 return returnValue;
899 }
900
901 id getWindowAttribute (int childID) {
902 return control.view.window();
903 }
904
905 id getTopLevelUIElementAttribute (int childID) {
906 return control.view.window();
907 }
908
909 id getPositionAttribute (int childID) {
910 id returnValue = null;
911 AccessibleControlEvent event = new AccessibleControlEvent(this);
912 event.childID = childID;
913 event.width = -1;
914
915 for (int i = 0; i < accessibleControlListeners.size(); i++) {
916 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
917 listener.getLocation(event);
918 }
919
920 Monitor primaryMonitor = Display.getCurrent().getPrimaryMonitor();
921
922 NSPoint osPositionAttribute = new NSPoint ();
923 if (event.width !is -1) {
924 // The point returned is the lower-left coordinate of the widget in lower-left relative screen coordinates.
925 osPositionAttribute.x = event.x;
926 osPositionAttribute.y = primaryMonitor.getBounds().height - event.y - event.height;
927 returnValue = NSValue.valueWithPoint(osPositionAttribute);
928 } else {
929 if (childID !is ACC.CHILDID_SELF) {
930 Point pt = null;
931 Rectangle location = control.getBounds();
932
933 if (control.getParent() !is null)
934 pt = control.getParent().toDisplay(location.x, location.y);
935 else
936 pt = ((Shell)control).toDisplay(location.x, location.y);
937
938 osPositionAttribute.x = pt.x;
939 osPositionAttribute.y = pt.y;
940 returnValue = NSValue.valueWithPoint(osPositionAttribute);
941 }
942 }
943
944 return returnValue;
945 }
946
947 id getSizeAttribute (int childID) {
948 id returnValue = null;
949 AccessibleControlEvent event = new AccessibleControlEvent(this);
950 event.childID = childID;
951 event.width = -1;
952
953 for (int i = 0; i < accessibleControlListeners.size(); i++) {
954 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
955 listener.getLocation(event);
956 }
957
958 NSSize controlSize = new NSSize ();
959 if (event.width !is -1) {
960 controlSize.width = event.width;
961 controlSize.height = event.height;
962 returnValue = NSValue.valueWithSize(controlSize);
963 } else {
964 if (childID !is ACC.CHILDID_SELF) {
965 controlSize.width = controlSize.height = 0;
966 returnValue = NSValue.valueWithSize(controlSize);
967 }
968 }
969
970 return returnValue;
971 }
972
973 id getDescriptionAttribute (int childID) {
974 AccessibleEvent event = new AccessibleEvent(this);
975 event.childID = childID;
976 event.result = null;
977 id returnValue = null;
978 for (int i = 0; i < accessibleListeners.size(); i++) {
979 AccessibleListener listener = (AccessibleListener) accessibleListeners.elementAt(i);
980 listener.getDescription(event);
981 }
982
983 returnValue = (event.result !is null ? NSString.stringWith(event.result) : null);
984
985 // If no description was provided, try the name.
986 if (returnValue is null) {
987 if (control instanceof Composite) returnValue = NSString.stringWith("");
988 }
989
990 return returnValue;
991 }
992
993 id getInsertionPointLineNumberAttribute (int childID) {
994 id returnValue = null;
995 AccessibleControlEvent controlEvent = new AccessibleControlEvent(this);
996 controlEvent.childID = childID;
997 controlEvent.result = null;
998 for (int i = 0; i < accessibleControlListeners.size(); i++) {
999 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
1000 listener.getValue(controlEvent);
1001 }
1002 AccessibleTextEvent textEvent = new AccessibleTextEvent(this);
1003 textEvent.childID = childID;
1004 textEvent.offset = -1;
1005 for (int i = 0; i < accessibleTextListeners.size(); i++) {
1006 AccessibleTextListener listener = (AccessibleTextListener) accessibleTextListeners.elementAt(i);
1007 listener.getCaretOffset(textEvent);
1008 }
1009 if (controlEvent.result !is null && textEvent.offset !is -1) {
1010 int lineNumber = lineNumberForOffset (controlEvent.result, textEvent.offset);
1011 returnValue = NSNumber.numberWithInt(lineNumber);
1012 }
1013 return returnValue;
1014 }
1015
1016 id getNumberOfCharactersAttribute (int childID) {
1017 id returnValue = null;
1018 AccessibleControlEvent event = new AccessibleControlEvent(this);
1019 event.childID = childID;
1020 event.result = null;
1021 for (int i = 0; i < accessibleControlListeners.size(); i++) {
1022 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
1023 listener.getValue(event);
1024 }
1025 String appValue = event.result;
1026 if (appValue !is null) {
1027 returnValue = NSNumber.numberWithInt(appValue.length());
1028 }
1029 return returnValue;
1030 }
1031
1032 id getRangeForLineParameterizedAttribute (id parameter, int childID) {
1033 id returnValue = null;
1034
1035 // The parameter is an NSNumber with the line number.
1036 NSNumber lineNumberObj = new NSNumber(parameter.id);
1037 int lineNumber = lineNumberObj.intValue();
1038 System.out.println("Line number = " + lineNumber);
1039 AccessibleControlEvent event = new AccessibleControlEvent(this);
1040 event.childID = childID;
1041 event.result = null;
1042 for (int i = 0; i < accessibleControlListeners.size(); i++) {
1043 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
1044 listener.getValue(event);
1045 }
1046 if (event.result !is null) {
1047 NSRange range = rangeForLineNumber (lineNumber, event.result);
1048 if (range.location !is -1) {
1049 returnValue = NSValue.valueWithRange(range);
1050 }
1051 }
1052 return returnValue;
1053 }
1054
1055 id getSelectedTextAttribute (int childID) {
1056 id returnValue = NSString.stringWith("");
1057 AccessibleTextEvent event = new AccessibleTextEvent(this);
1058 event.childID = childID;
1059 event.offset = -1;
1060 event.length = -1;
1061 for (int i = 0; i < accessibleTextListeners.size(); i++) {
1062 AccessibleTextListener listener = (AccessibleTextListener) accessibleTextListeners.elementAt(i);
1063 listener.getSelectionRange(event);
1064 }
1065 int offset = event.offset;
1066 int length = event.length;
1067 if (offset !is -1 && length !is -1 && length !is 0) { // TODO: do we need the && length !is 0 ?
1068 AccessibleControlEvent event2 = new AccessibleControlEvent(this);
1069 event2.childID = event.childID;
1070 event2.result = null;
1071 for (int i = 0; i < accessibleControlListeners.size(); i++) {
1072 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
1073 listener.getValue(event2);
1074 }
1075 String appValue = event2.result;
1076 if (appValue !is null) {
1077 returnValue = NSString.stringWith(appValue.substring(offset, offset + length));
1078 }
1079 }
1080 return returnValue;
1081 }
1082
1083 id getSelectedTextRangeAttribute (int childID) {
1084 id returnValue = null;
1085 AccessibleTextEvent event = new AccessibleTextEvent(this);
1086 event.childID = childID;
1087 event.offset = -1;
1088 event.length = 0;
1089 for (int i = 0; i < accessibleTextListeners.size(); i++) {
1090 AccessibleTextListener listener = (AccessibleTextListener) accessibleTextListeners.elementAt(i);
1091 listener.getSelectionRange(event);
1092 }
1093 if (event.offset !is -1) {
1094 NSRange range = new NSRange();
1095 range.location = event.offset;
1096 range.length = event.length;
1097 returnValue = NSValue.valueWithRange(range);
1098 }
1099 return returnValue;
1100 }
1101
1102 id getStringForRangeAttribute (id parameter, int childID) {
1103 id returnValue = null;
1104
1105 // Parameter is an NSRange wrapped in an NSValue.
1106 NSValue parameterObject = new NSValue(parameter.id);
1107 NSRange range = parameterObject.rangeValue();
1108 AccessibleControlEvent event = new AccessibleControlEvent(this);
1109 event.childID = childID;
1110 event.result = null;
1111 for (int i = 0; i < accessibleControlListeners.size(); i++) {
1112 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
1113 listener.getValue(event);
1114 }
1115 String appValue = event.result;
1116
1117 if (appValue !is null) {
1118 returnValue = NSString.stringWith(appValue.substring(range.location, range.location + range.length));
1119 }
1120
1121 return returnValue;
1122 }
1123
1124 id getSelectedTextRangesAttribute (int childID) {
1125 NSMutableArray returnValue = null;
1126 AccessibleTextEvent event = new AccessibleTextEvent(this);
1127 event.childID = childID;
1128 event.offset = -1;
1129 event.length = 0;
1130
1131 for (int i = 0; i < accessibleTextListeners.size(); i++) {
1132 AccessibleTextListener listener = (AccessibleTextListener) accessibleTextListeners.elementAt(i);
1133 listener.getSelectionRange(event);
1134 }
1135
1136 if (event.offset !is -1) {
1137 returnValue = NSMutableArray.arrayWithCapacity(1);
1138 NSRange range = new NSRange();
1139 range.location = event.offset;
1140 range.length = event.length;
1141 returnValue.addObject(NSValue.valueWithRange(range));
1142 }
1143
1144 return returnValue;
1145 }
1146
1147 id getVisibleCharacterRangeAttribute (int childID) {
1148 AccessibleControlEvent event = new AccessibleControlEvent(this);
1149 event.childID = childID;
1150 event.result = null;
1151 for (int i = 0; i < accessibleControlListeners.size(); i++) {
1152 AccessibleControlListener listener = (AccessibleControlListener) accessibleControlListeners.elementAt(i);
1153 listener.getValue(event);
1154 }
1155
1156 NSRange range = new NSRange();
1157
1158 if (event.result !is null) {
1159 range.location = 0;
1160 range.length = event.result.length();
1161 } else {
1162 return null;
1163 // range.location = range.length = 0;
1164 }
1165
1166 return NSValue.valueWithRange(range);
1167 }
1168
1169 int lineNumberForOffset (String text, int offset) {
1170 int lineNumber = 1;
1171 int length = text.length();
1172 for (int i = 0; i < offset; i++) {
1173 switch (text.charAt (i)) {
1174 case '\r':
1175 if (i + 1 < length) {
1176 if (text.charAt (i + 1) is '\n') ++i;
1177 }
1178 // FALL THROUGH
1179 case '\n':
1180 lineNumber++;
1181 }
1182 }
1183 return lineNumber;
1184 }
1185
1186 NSRange rangeForLineNumber (int lineNumber, String text) {
1187 NSRange range = new NSRange();
1188 range.location = -1;
1189 int line = 1;
1190 int count = 0;
1191 int length = text.length ();
1192 for (int i = 0; i < length; i++) {
1193 if (line is lineNumber) {
1194 if (count is 0) {
1195 range.location = i;
1196 }
1197 count++;
1198 }
1199 if (line > lineNumber) break;
1200 switch (text.charAt (i)) {
1201 case '\r':
1202 if (i + 1 < length && text.charAt (i + 1) is '\n') i++;
1203 // FALL THROUGH
1204 case '\n':
1205 line++;
1206 }
1207 }
1208 range.length = count;
1209 return range;
312 } 1210 }
313 1211
314 /** 1212 /**
315 * Invokes platform specific functionality to handle a window message. 1213 * Removes the listener from the collection of listeners who will
316 * <p> 1214 * be notified when an accessible client asks for certain strings,
317 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public 1215 * such as name, description, help, or keyboard shortcut.
318 * API for <code>Accessible</code>. It is marked public only so that it 1216 *
319 * can be shared within the packages provided by DWT. It is not 1217 * @param listener the listener that should no longer be notified when the receiver
320 * available on all platforms, and should never be called from 1218 * is asked for a name, description, help, or keyboard shortcut string
321 * application code. 1219 *
322 * </p> 1220 * @exception IllegalArgumentException <ul>
1221 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1222 * </ul>
1223 * @exception DWTException <ul>
1224 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1225 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1226 * </ul>
1227 *
1228 * @see AccessibleListener
1229 * @see #addAccessibleListener
323 */ 1230 */
324 public int internal_WM_GETOBJECT (int wParam, int lParam) { 1231 public void removeAccessibleListener(AccessibleListener listener) {
325 return 0; 1232 checkWidget();
326 } 1233 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1234 accessibleListeners.removeElement(listener);
1235 }
1236
1237 /**
1238 * Removes the listener from the collection of listeners who will
1239 * be notified when an accessible client asks for custom control
1240 * specific information.
1241 *
1242 * @param listener the listener that should no longer be notified when the receiver
1243 * is asked for custom control specific information
1244 *
1245 * @exception IllegalArgumentException <ul>
1246 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1247 * </ul>
1248 * @exception DWTException <ul>
1249 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1250 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1251 * </ul>
1252 *
1253 * @see AccessibleControlListener
1254 * @see #addAccessibleControlListener
1255 */
1256 public void removeAccessibleControlListener(AccessibleControlListener listener) {
1257 checkWidget();
1258 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1259 accessibleControlListeners.removeElement(listener);
1260 }
1261
1262 /**
1263 * Removes the listener from the collection of listeners who will
1264 * be notified when an accessible client asks for custom text control
1265 * specific information.
1266 *
1267 * @param listener the listener that should no longer be notified when the receiver
1268 * is asked for custom text control specific information
1269 *
1270 * @exception IllegalArgumentException <ul>
1271 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1272 * </ul>
1273 * @exception DWTException <ul>
1274 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1275 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1276 * </ul>
1277 *
1278 * @see AccessibleTextListener
1279 * @see #addAccessibleTextListener
1280 *
1281 * @since 3.0
1282 */
1283 public void removeAccessibleTextListener (AccessibleTextListener listener) {
1284 checkWidget ();
1285 if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
1286 accessibleTextListeners.removeElement (listener);
1287 }
1288
1289 static NSArray retainedAutoreleased(NSArray inObject) {
1290 id temp = inObject.retain();
1291 id temp2 = new NSObject(temp.id).autorelease();
1292 return new NSArray(temp2.id);
1293 }
1294
1295 /**
1296 * Sends a message to accessible clients that the child selection
1297 * within a custom container control has changed.
1298 *
1299 * @exception DWTException <ul>
1300 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1301 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1302 * </ul>
1303 *
1304 * @since 3.0
1305 */
1306 public void selectionChanged () {
1307 checkWidget();
1308 OS.NSAccessibilityPostNotification(control.view.id, OS.NSAccessibilitySelectedChildrenChangedNotification.id);
1309 }
1310
1311 /**
1312 * Sends a message to accessible clients indicating that the focus
1313 * has changed within a custom control.
1314 *
1315 * @param childID an identifier specifying a child of the control
1316 *
1317 * @exception DWTException <ul>
1318 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1319 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1320 * </ul>
1321 */
1322 public void setFocus(int childID) {
1323 checkWidget();
1324 OS.NSAccessibilityPostNotification(control.view.id, OS.NSAccessibilityFocusedUIElementChangedNotification.id);
1325 }
1326
1327 /**
1328 * Sends a message to accessible clients that the text
1329 * caret has moved within a custom control.
1330 *
1331 * @param index the new caret index within the control
1332 *
1333 * @exception DWTException <ul>
1334 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1335 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1336 * </ul>
1337 *
1338 * @since 3.0
1339 */
1340 public void textCaretMoved (int index) {
1341 checkWidget();
1342 OS.NSAccessibilityPostNotification(control.view.id, OS.NSAccessibilitySelectedTextChangedNotification.id);
1343 }
1344
1345 /**
1346 * Sends a message to accessible clients that the text
1347 * within a custom control has changed.
1348 *
1349 * @param type the type of change, one of <code>ACC.NOTIFY_TEXT_INSERT</code>
1350 * or <code>ACC.NOTIFY_TEXT_DELETE</code>
1351 * @param startIndex the text index within the control where the insertion or deletion begins
1352 * @param length the non-negative length in characters of the insertion or deletion
1353 *
1354 * @exception DWTException <ul>
1355 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1356 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1357 * </ul>
1358 *
1359 * @see ACC#TEXT_INSERT
1360 * @see ACC#TEXT_DELETE
1361 *
1362 * @since 3.0
1363 */
1364 public void textChanged (int type, int startIndex, int length) {
1365 checkWidget();
1366 OS.NSAccessibilityPostNotification(control.view.id, OS.NSAccessibilityValueChangedNotification.id);
1367 }
1368
1369 /**
1370 * Sends a message to accessible clients that the text
1371 * selection has changed within a custom control.
1372 *
1373 * @exception DWTException <ul>
1374 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li>
1375 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li>
1376 * </ul>
1377 *
1378 * @since 3.0
1379 */
1380 public void textSelectionChanged () {
1381 checkWidget();
1382 OS.NSAccessibilityPostNotification(control.view.id, OS.NSAccessibilitySelectedTextChangedNotification.id);
1383 }
1384
1385 id childIDToOs(int childID) {
1386 if (childID is ACC.CHILDID_SELF) {
1387 return control.view;
1388 }
1389
1390 /* Check cache for childID, if found, return corresponding osChildID. */
1391 SWTAccessibleDelegate childRef = (SWTAccessibleDelegate) children.get(new Integer(childID));
1392
1393 if (childRef is null) {
1394 childRef = new SWTAccessibleDelegate(this, childID);
1395 children.put(new Integer(childID), childRef);
1396 }
1397
1398 return childRef;
1399 }
1400
1401 NSString concatStringsAsRole(NSString str1, NSString str2) {
1402 NSString returnValue = str1;
1403 returnValue = returnValue.stringByAppendingString(NSString.stringWith(":"));
1404 returnValue = returnValue.stringByAppendingString(str2);
1405 return returnValue;
1406 }
1407
1408 String roleToOs(int role) {
1409 NSString nsReturnValue = null; //OS.NSAccessibilityUnknownRole;
1410
1411 switch (role) {
1412 case ACC.ROLE_CLIENT_AREA: nsReturnValue = OS.NSAccessibilityGroupRole; break;
1413 case ACC.ROLE_WINDOW: nsReturnValue = OS.NSAccessibilityWindowRole; break;
1414 case ACC.ROLE_MENUBAR: nsReturnValue = OS.NSAccessibilityMenuBarRole; break;
1415 case ACC.ROLE_MENU: nsReturnValue = OS.NSAccessibilityMenuRole; break;
1416 case ACC.ROLE_MENUITEM: nsReturnValue = OS.NSAccessibilityMenuItemRole; break;
1417 case ACC.ROLE_SEPARATOR: nsReturnValue = OS.NSAccessibilitySplitterRole; break;
1418 case ACC.ROLE_TOOLTIP: nsReturnValue = OS.NSAccessibilityHelpTagRole; break;
1419 case ACC.ROLE_SCROLLBAR: nsReturnValue = OS.NSAccessibilityScrollBarRole; break;
1420 case ACC.ROLE_DIALOG: nsReturnValue = concatStringsAsRole(OS.NSAccessibilityWindowRole, OS.NSAccessibilityDialogSubrole); break;
1421 case ACC.ROLE_LABEL: nsReturnValue = OS.NSAccessibilityStaticTextRole; break;
1422 case ACC.ROLE_PUSHBUTTON: nsReturnValue = OS.NSAccessibilityButtonRole; break;
1423 case ACC.ROLE_CHECKBUTTON: nsReturnValue = OS.NSAccessibilityCheckBoxRole; break;
1424 case ACC.ROLE_RADIOBUTTON: nsReturnValue = OS.NSAccessibilityRadioButtonRole; break;
1425 case ACC.ROLE_COMBOBOX: nsReturnValue = OS.NSAccessibilityComboBoxRole; break;
1426 case ACC.ROLE_TEXT: {
1427 int style = control.getStyle();
1428
1429 if ((style & DWT.MULTI) !is 0) {
1430 nsReturnValue = OS.NSAccessibilityTextAreaRole;
1431 } else {
1432 nsReturnValue = OS.NSAccessibilityTextFieldRole;
1433 }
1434
1435 break;
1436 }
1437 case ACC.ROLE_TOOLBAR: nsReturnValue = OS.NSAccessibilityToolbarRole; break;
1438 case ACC.ROLE_LIST: nsReturnValue = OS.NSAccessibilityOutlineRole; break;
1439 case ACC.ROLE_LISTITEM: nsReturnValue = OS.NSAccessibilityStaticTextRole; break;
1440 case ACC.ROLE_TABLE: nsReturnValue = OS.NSAccessibilityTableRole; break;
1441 case ACC.ROLE_TABLECELL: nsReturnValue = concatStringsAsRole(OS.NSAccessibilityRowRole, OS.NSAccessibilityTableRowSubrole); break;
1442 case ACC.ROLE_TABLECOLUMNHEADER: nsReturnValue = OS.NSAccessibilitySortButtonRole; break;
1443 case ACC.ROLE_TABLEROWHEADER: nsReturnValue = concatStringsAsRole(OS.NSAccessibilityRowRole, OS.NSAccessibilityTableRowSubrole); break;
1444 case ACC.ROLE_TREE: nsReturnValue = OS.NSAccessibilityOutlineRole; break;
1445 case ACC.ROLE_TREEITEM: nsReturnValue = concatStringsAsRole(OS.NSAccessibilityOutlineRole, OS.NSAccessibilityOutlineRowSubrole); break;
1446 case ACC.ROLE_TABFOLDER: nsReturnValue = OS.NSAccessibilityTabGroupRole; break;
1447 case ACC.ROLE_TABITEM: nsReturnValue = OS.NSAccessibilityRadioButtonRole; break;
1448 case ACC.ROLE_PROGRESSBAR: nsReturnValue = OS.NSAccessibilityProgressIndicatorRole; break;
1449 case ACC.ROLE_SLIDER: nsReturnValue = OS.NSAccessibilitySliderRole; break;
1450 case ACC.ROLE_LINK: nsReturnValue = OS.NSAccessibilityLinkRole; break;
1451 }
1452
1453 return nsReturnValue.getString();
1454 }
1455
1456 int osToRole(NSString osRole) {
1457 if (osRole is null) return 0;
1458 if (osRole.isEqualToString(OS.NSAccessibilityWindowRole)) return ACC.ROLE_WINDOW;
1459 if (osRole.isEqualToString(OS.NSAccessibilityMenuBarRole)) return ACC.ROLE_MENUBAR;
1460 if (osRole.isEqualToString(OS.NSAccessibilityMenuRole)) return ACC.ROLE_MENU;
1461 if (osRole.isEqualToString(OS.NSAccessibilityMenuItemRole)) return ACC.ROLE_MENUITEM;
1462 if (osRole.isEqualToString(OS.NSAccessibilitySplitterRole)) return ACC.ROLE_SEPARATOR;
1463 if (osRole.isEqualToString(OS.NSAccessibilityHelpTagRole)) return ACC.ROLE_TOOLTIP;
1464 if (osRole.isEqualToString(OS.NSAccessibilityScrollBarRole)) return ACC.ROLE_SCROLLBAR;
1465 if (osRole.isEqualToString(OS.NSAccessibilityScrollAreaRole)) return ACC.ROLE_LIST;
1466 if (osRole.isEqualToString(concatStringsAsRole(OS.NSAccessibilityWindowRole, OS.NSAccessibilityDialogSubrole))) return ACC.ROLE_DIALOG;
1467 if (osRole.isEqualToString(concatStringsAsRole(OS.NSAccessibilityWindowRole, OS.NSAccessibilitySystemDialogSubrole))) return ACC.ROLE_DIALOG;
1468 if (osRole.isEqualToString(OS.NSAccessibilityStaticTextRole)) return ACC.ROLE_LABEL;
1469 if (osRole.isEqualToString(OS.NSAccessibilityButtonRole)) return ACC.ROLE_PUSHBUTTON;
1470 if (osRole.isEqualToString(OS.NSAccessibilityCheckBoxRole)) return ACC.ROLE_CHECKBUTTON;
1471 if (osRole.isEqualToString(OS.NSAccessibilityRadioButtonRole)) return ACC.ROLE_RADIOBUTTON;
1472 if (osRole.isEqualToString(OS.NSAccessibilityComboBoxRole)) return ACC.ROLE_COMBOBOX;
1473 if (osRole.isEqualToString(OS.NSAccessibilityTextFieldRole)) return ACC.ROLE_TEXT;
1474 if (osRole.isEqualToString(OS.NSAccessibilityTextAreaRole)) return ACC.ROLE_TEXT;
1475 if (osRole.isEqualToString(OS.NSAccessibilityToolbarRole)) return ACC.ROLE_TOOLBAR;
1476 if (osRole.isEqualToString(OS.NSAccessibilityListRole)) return ACC.ROLE_LIST;
1477 if (osRole.isEqualToString(OS.NSAccessibilityTableRole)) return ACC.ROLE_TABLE;
1478 if (osRole.isEqualToString(OS.NSAccessibilityColumnRole)) return ACC.ROLE_TABLECOLUMNHEADER;
1479 if (osRole.isEqualToString(concatStringsAsRole(OS.NSAccessibilityButtonRole, OS.NSAccessibilitySortButtonRole))) return ACC.ROLE_TABLECOLUMNHEADER;
1480 if (osRole.isEqualToString(concatStringsAsRole(OS.NSAccessibilityRowRole, OS.NSAccessibilityTableRowSubrole))) return ACC.ROLE_TABLEROWHEADER;
1481 if (osRole.isEqualToString(OS.NSAccessibilityOutlineRole)) return ACC.ROLE_TREE;
1482 if (osRole.isEqualToString(concatStringsAsRole(OS.NSAccessibilityOutlineRole, OS.NSAccessibilityOutlineRowSubrole))) return ACC.ROLE_TREEITEM;
1483 if (osRole.isEqualToString(OS.NSAccessibilityTabGroupRole)) return ACC.ROLE_TABFOLDER;
1484 if (osRole.isEqualToString(OS.NSAccessibilityProgressIndicatorRole)) return ACC.ROLE_PROGRESSBAR;
1485 if (osRole.isEqualToString(OS.NSAccessibilitySliderRole)) return ACC.ROLE_SLIDER;
1486 if (osRole.isEqualToString(OS.NSAccessibilityLinkRole)) return ACC.ROLE_LINK;
1487 return ACC.ROLE_CLIENT_AREA;
1488 }
1489
1490 /* checkWidget was copied from Widget, and rewritten to work in this package */
1491 void checkWidget () {
1492 if (!isValidThread ()) DWT.error (DWT.ERROR_THREAD_INVALID_ACCESS);
1493 if (control.isDisposed ()) DWT.error (DWT.ERROR_WIDGET_DISPOSED);
1494 }
1495
1496 /* isValidThread was copied from Widget, and rewritten to work in this package */
1497 bool isValidThread () {
1498 return control.getDisplay ().getThread () is Thread.currentThread ();
1499 }
1500
327 } 1501 }