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