1 /******************************************************************************* 2 * Copyright (c) 2000, 2008 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 * Port to the D programming language: 11 * Frank Benoit <benoit@tionex.de> 12 *******************************************************************************/ 13 module org.eclipse.swt.accessibility.Accessible; 14 15 import java.lang.all; 16 17 import org.eclipse.swt.accessibility.AccessibleListener; 18 import org.eclipse.swt.accessibility.AccessibleTextListener; 19 import org.eclipse.swt.accessibility.AccessibleControlListener; 20 import org.eclipse.swt.accessibility.AccessibleControlListener; 21 import org.eclipse.swt.accessibility.AccessibleFactory; 22 import org.eclipse.swt.accessibility.AccessibleObject; 23 import org.eclipse.swt.SWT; 24 //import org.eclipse.swt.events.*; 25 import org.eclipse.swt.internal.gtk.OS; 26 import org.eclipse.swt.widgets.Control; 27 import org.eclipse.swt.events.DisposeListener; 28 import org.eclipse.swt.events.DisposeEvent; 29 30 import java.lang.Thread; 31 import java.util.Vector; 32 33 /** 34 * Instances of this class provide a bridge between application 35 * code and assistive technology clients. Many platforms provide 36 * default accessible behavior for most widgets, and this class 37 * allows that default behavior to be overridden. Applications 38 * can get the default Accessible object for a control by sending 39 * it <code>getAccessible</code>, and then add an accessible listener 40 * to override simple items like the name and help string, or they 41 * can add an accessible control listener to override complex items. 42 * As a rule of thumb, an application would only want to use the 43 * accessible control listener to implement accessibility for a 44 * custom control. 45 * 46 * @see Control#getAccessible 47 * @see AccessibleListener 48 * @see AccessibleEvent 49 * @see AccessibleControlListener 50 * @see AccessibleControlEvent 51 * @see <a href="http://www.eclipse.org/swt/snippets/#accessibility">Accessibility snippets</a> 52 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 53 * 54 * @since 2.0 55 */ 56 public class Accessible { 57 Vector accessibleListeners; 58 Vector controlListeners; 59 Vector textListeners; 60 AccessibleObject accessibleObject; 61 Control control; 62 63 this (Control control) { 64 accessibleListeners = new Vector(); 65 controlListeners = new Vector(); 66 textListeners = new Vector(); 67 this.control = control; 68 AccessibleFactory.registerAccessible (this); 69 control.addDisposeListener (new class () DisposeListener { 70 public void widgetDisposed (DisposeEvent e) { 71 release (); 72 } 73 }); 74 } 75 76 /** 77 * Adds the listener to the collection of listeners who will 78 * be notified when an accessible client asks for certain strings, 79 * such as name, description, help, or keyboard shortcut. The 80 * listener is notified by sending it one of the messages defined 81 * in the <code>AccessibleListener</code> interface. 82 * 83 * @param listener the listener that should be notified when the receiver 84 * is asked for a name, description, help, or keyboard shortcut string 85 * 86 * @exception IllegalArgumentException <ul> 87 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 88 * </ul> 89 * @exception SWTException <ul> 90 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 91 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 92 * </ul> 93 * 94 * @see AccessibleListener 95 * @see #removeAccessibleListener 96 */ 97 public void addAccessibleListener (AccessibleListener listener) { 98 checkWidget (); 99 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 100 accessibleListeners.addElement(cast(Object)listener); 101 } 102 103 /** 104 * Adds the listener to the collection of listeners who will 105 * be notified when an accessible client asks for custom control 106 * specific information. The listener is notified by sending it 107 * one of the messages defined in the <code>AccessibleControlListener</code> 108 * interface. 109 * 110 * @param listener the listener that should be notified when the receiver 111 * is asked for custom control specific information 112 * 113 * @exception IllegalArgumentException <ul> 114 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 115 * </ul> 116 * @exception SWTException <ul> 117 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 118 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 119 * </ul> 120 * 121 * @see AccessibleControlListener 122 * @see #removeAccessibleControlListener 123 */ 124 public void addAccessibleControlListener (AccessibleControlListener listener) { 125 checkWidget (); 126 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 127 controlListeners.addElement(cast(Object)listener); 128 } 129 130 /** 131 * Adds the listener to the collection of listeners who will 132 * be notified when an accessible client asks for custom text control 133 * specific information. The listener is notified by sending it 134 * one of the messages defined in the <code>AccessibleTextListener</code> 135 * interface. 136 * 137 * @param listener the listener that should be notified when the receiver 138 * is asked for custom text control specific information 139 * 140 * @exception IllegalArgumentException <ul> 141 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 142 * </ul> 143 * @exception SWTException <ul> 144 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 145 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 146 * </ul> 147 * 148 * @see AccessibleTextListener 149 * @see #removeAccessibleTextListener 150 * 151 * @since 3.0 152 */ 153 public void addAccessibleTextListener (AccessibleTextListener listener) { 154 checkWidget (); 155 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 156 textListeners.addElement(cast(Object)listener); 157 } 158 159 /** 160 * Returns the control for this Accessible object. 161 * 162 * @return the receiver's control 163 * @since 3.0 164 */ 165 public Control getControl() { 166 return control; 167 } 168 169 /* checkWidget was copied from Widget, and rewritten to work in this package */ 170 void checkWidget () { 171 if (!isValidThread ()) SWT.error (SWT.ERROR_THREAD_INVALID_ACCESS); 172 if (control.isDisposed ()) SWT.error (SWT.ERROR_WIDGET_DISPOSED); 173 } 174 175 AccessibleListener[] getAccessibleListeners () { 176 if (accessibleListeners is null ) return null; 177 AccessibleListener[] result = new AccessibleListener [accessibleListeners.size ()]; 178 accessibleListeners.copyInto ( cast(void*[])result); 179 return result; 180 } 181 182 GtkWidget* getControlHandle () { 183 return control.handle; 184 } 185 186 AccessibleControlListener[] getControlListeners () { 187 if (controlListeners is null) return null; 188 AccessibleControlListener[] result = new AccessibleControlListener [controlListeners.size ()]; 189 controlListeners.copyInto ( cast(void*[])result); 190 return result; 191 } 192 193 AccessibleTextListener[] getTextListeners () { 194 if (textListeners is null) return null; 195 AccessibleTextListener[] result = new AccessibleTextListener [textListeners.size ()]; 196 textListeners.copyInto ( cast(void*[])result); 197 return result; 198 } 199 200 /** 201 * Invokes platform specific functionality to allocate a new accessible object. 202 * <p> 203 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public 204 * API for <code>Accessible</code>. It is marked public only so that it 205 * can be shared within the packages provided by SWT. It is not 206 * available on all platforms, and should never be called from 207 * application code. 208 * </p> 209 * 210 * @param control the control to get the accessible object for 211 * @return the platform specific accessible object 212 */ 213 public static Accessible internal_new_Accessible (Control control) { 214 return new Accessible (control); 215 } 216 217 /* isValidThread was copied from Widget, and rewritten to work in this package */ 218 bool isValidThread () { 219 return control.getDisplay ().getThread () is Thread.currentThread (); 220 } 221 222 void release () { 223 AccessibleFactory.unregisterAccessible (/*Accessible.*/this); 224 if (accessibleObject !is null) { 225 accessibleObject.release (); 226 accessibleObject = null; 227 } 228 accessibleListeners = null; 229 controlListeners = null; 230 textListeners = null; 231 } 232 /** 233 * Removes the listener from the collection of listeners who will 234 * be notified when an accessible client asks for custom control 235 * specific information. 236 * 237 * @param listener the listener that should no longer be notified when the receiver 238 * is asked for custom control specific information 239 * 240 * @exception IllegalArgumentException <ul> 241 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 242 * </ul> 243 * @exception SWTException <ul> 244 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 245 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 246 * </ul> 247 * 248 * @see AccessibleControlListener 249 * @see #addAccessibleControlListener 250 */ 251 public void removeAccessibleControlListener (AccessibleControlListener listener) { 252 checkWidget (); 253 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 254 controlListeners.removeElement( cast(Object)listener ); 255 } 256 257 /** 258 * Removes the listener from the collection of listeners who will 259 * be notified when an accessible client asks for certain strings, 260 * such as name, description, help, or keyboard shortcut. 261 * 262 * @param listener the listener that should no longer be notified when the receiver 263 * is asked for a name, description, help, or keyboard shortcut string 264 * 265 * @exception IllegalArgumentException <ul> 266 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 267 * </ul> 268 * @exception SWTException <ul> 269 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 270 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 271 * </ul> 272 * 273 * @see AccessibleListener 274 * @see #addAccessibleListener 275 */ 276 public void removeAccessibleListener (AccessibleListener listener) { 277 checkWidget (); 278 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 279 accessibleListeners.removeElement( cast(Object)listener); 280 } 281 282 /** 283 * Removes the listener from the collection of listeners who will 284 * be notified when an accessible client asks for custom text control 285 * specific information. 286 * 287 * @param listener the listener that should no longer be notified when the receiver 288 * is asked for custom text control specific information 289 * 290 * @exception IllegalArgumentException <ul> 291 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 292 * </ul> 293 * @exception SWTException <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 * @see AccessibleTextListener 299 * @see #addAccessibleTextListener 300 * 301 * @since 3.0 302 */ 303 public void removeAccessibleTextListener (AccessibleTextListener listener) { 304 checkWidget (); 305 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 306 textListeners.removeElement( cast(Object)listener ); 307 } 308 309 /** 310 * Sends a message to accessible clients that the child selection 311 * within a custom container control has changed. 312 * 313 * @exception SWTException <ul> 314 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 315 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 316 * </ul> 317 * 318 * @since 3.0 319 */ 320 public void selectionChanged () { 321 checkWidget (); 322 if (accessibleObject !is null) { 323 accessibleObject.selectionChanged (); 324 } 325 } 326 327 /** 328 * Sends a message to accessible clients indicating that the focus 329 * has changed within a custom control. 330 * 331 * @param childID an identifier specifying a child of the control 332 * 333 * @exception SWTException <ul> 334 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 335 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 336 * </ul> 337 */ 338 public void setFocus (int childID) { 339 checkWidget (); 340 if (accessibleObject !is null) { 341 accessibleObject.setFocus (childID); 342 } 343 } 344 345 /** 346 * Sends a message to accessible clients that the text 347 * caret has moved within a custom control. 348 * 349 * @param index the new caret index within the control 350 * 351 * @exception SWTException <ul> 352 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 353 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 354 * </ul> 355 * 356 * @since 3.0 357 */ 358 public void textCaretMoved (int index) { 359 checkWidget (); 360 if (accessibleObject !is null) { 361 accessibleObject.textCaretMoved (index); 362 } 363 } 364 365 /** 366 * Sends a message to accessible clients that the text 367 * within a custom control has changed. 368 * 369 * @param type the type of change, one of <code>ACC.NOTIFY_TEXT_INSERT</code> 370 * or <code>ACC.NOTIFY_TEXT_DELETE</code> 371 * @param startIndex the text index within the control where the insertion or deletion begins 372 * @param length the non-negative length in characters of the insertion or deletion 373 * 374 * @exception SWTException <ul> 375 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 376 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 377 * </ul> 378 * 379 * @see ACC#TEXT_INSERT 380 * @see ACC#TEXT_DELETE 381 * 382 * @since 3.0 383 */ 384 public void textChanged (int type, int startIndex, int length) { 385 checkWidget (); 386 if (accessibleObject !is null) { 387 accessibleObject.textChanged (type, startIndex, length); 388 } 389 } 390 391 /** 392 * Sends a message to accessible clients that the text 393 * selection has changed within a custom control. 394 * 395 * @exception SWTException <ul> 396 * <li>ERROR_WIDGET_DISPOSED - if the receiver's control has been disposed</li> 397 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver's control</li> 398 * </ul> 399 * 400 * @since 3.0 401 */ 402 public void textSelectionChanged () { 403 checkWidget (); 404 if (accessibleObject !is null) { 405 accessibleObject.textSelectionChanged (); 406 } 407 } 408 }