Line 0
Link Here
|
|
|
1 |
/******************************************************************************* |
2 |
* Copyright (c) 2011 IBM Corporation. |
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 implementation |
10 |
*******************************************************************************/ |
11 |
|
12 |
package org.eclipse.mat.ui.accessibility; |
13 |
|
14 |
import org.eclipse.mat.ui.MemoryAnalyserPlugin; |
15 |
import org.eclipse.swt.accessibility.ACC; |
16 |
import org.eclipse.swt.accessibility.AccessibleAdapter; |
17 |
import org.eclipse.swt.accessibility.AccessibleControlAdapter; |
18 |
import org.eclipse.swt.accessibility.AccessibleControlEvent; |
19 |
import org.eclipse.swt.accessibility.AccessibleEvent; |
20 |
import org.eclipse.swt.graphics.Image; |
21 |
import org.eclipse.swt.widgets.Composite; |
22 |
import org.eclipse.swt.widgets.Item; |
23 |
import org.eclipse.swt.widgets.Table; |
24 |
import org.eclipse.swt.widgets.TableItem; |
25 |
import org.eclipse.swt.widgets.Tree; |
26 |
import org.eclipse.swt.widgets.TreeItem; |
27 |
|
28 |
/** |
29 |
* AccessibleCompositeAdapter Accessibility utility class provides a single |
30 |
* encapsulated implementation of accessibility enhancements for Table & Tree |
31 |
* Controls within MAT. The implementation is essentially the same for both |
32 |
* types of view, adding an Accessible Listener to cause a specially constructed |
33 |
* name for each item to be passed to the accessibility client (Screen Reader). |
34 |
* |
35 |
* @author Jonathan Lawrence |
36 |
*/ |
37 |
public class AccessibleCompositeAdapter |
38 |
{ |
39 |
|
40 |
// Constants for String construction. |
41 |
private static final char space = ' '; |
42 |
|
43 |
// Public methods provide interface ensuring only Table or Tree are used. |
44 |
/** |
45 |
* @param table |
46 |
* The Table to decorate with Accessible. |
47 |
*/ |
48 |
public static void access(Table table) |
49 |
{ |
50 |
access(table, ACC.ROLE_TABLE); // Delegate to generic private method. |
51 |
} |
52 |
|
53 |
/** |
54 |
* @param tree |
55 |
* The Tree to decorate with Accessible. |
56 |
*/ |
57 |
public static void access(Tree tree) |
58 |
{ |
59 |
access(tree, ACC.ROLE_TREE); // Delegate to generic private method. |
60 |
} |
61 |
|
62 |
/** |
63 |
* @param composite |
64 |
* The Composite (Table/Tree) to add Accessibility |
65 |
* @param role |
66 |
* The ACC.ROLE constant representing the type of Composite. |
67 |
*/ |
68 |
private static void access(final Composite composite, final int role) |
69 |
{ |
70 |
// Add addAccessibleListener to override getName. |
71 |
composite.getAccessible().addAccessibleListener(new AccessibleAdapter() |
72 |
{ |
73 |
|
74 |
@Override |
75 |
public void getName(AccessibleEvent e) |
76 |
{ |
77 |
if (e.childID == ACC.CHILDID_SELF) |
78 |
{ |
79 |
// TODO - provide a suitable name for the Tree/Table. |
80 |
} |
81 |
else |
82 |
{ // Name is required for a child of the Composite. |
83 |
|
84 |
// Get the item... |
85 |
Item item = null; |
86 |
try |
87 |
{ |
88 |
// Defensive coding. For Tree Controls, JAWS 12 |
89 |
// sometimes |
90 |
// calls this method with invalid childIDs. |
91 |
int maxchild = getItemCount(composite, role); |
92 |
if (e.childID >= 0 && e.childID < maxchild) |
93 |
{ // Valid range |
94 |
// Get Item |
95 |
item = getItem(composite, role, e.childID); |
96 |
} |
97 |
// Otherwise use first selected item if any. |
98 |
else |
99 |
{ |
100 |
item = getSelection(composite, role)[0]; |
101 |
} |
102 |
} |
103 |
catch (IndexOutOfBoundsException ie) |
104 |
{ // Do nothing |
105 |
// item will be null, no name will be returned in e. |
106 |
|
107 |
} // catch() |
108 |
|
109 |
// Construct a row of readable text for the Table/TreeItem |
110 |
if (item != null) // Valid item |
111 |
{ |
112 |
int ncol = getColumnCount(composite, role); |
113 |
int[] colorder = getColumnOrder(composite, role); |
114 |
StringBuffer rowbuf = new StringBuffer(); |
115 |
Item column = null; |
116 |
Image image = null; |
117 |
for (int icol = 0; icol < ncol; icol++) // For each |
118 |
// column |
119 |
{ |
120 |
int jcol = colorder[icol]; // The index of the |
121 |
// column when created. |
122 |
image = getImage(item, role, jcol); // Get image if |
123 |
// any |
124 |
if (image != null) // Image exists in this column |
125 |
{ // Append the descriptive text for this image |
126 |
rowbuf.append(MemoryAnalyserPlugin.getDefault().getImageText(image)); |
127 |
rowbuf.append(space); |
128 |
} |
129 |
column = getColumn(composite, role, jcol); // Get |
130 |
// relevant |
131 |
// Column |
132 |
rowbuf.append(column.getText()); // Append column |
133 |
// header |
134 |
rowbuf.append(space); |
135 |
rowbuf.append(getText(item, role, jcol)); // Append |
136 |
// column |
137 |
// content |
138 |
rowbuf.append(space); |
139 |
} |
140 |
e.result = rowbuf.toString(); |
141 |
} // if() |
142 |
} // if() |
143 |
} // getName() |
144 |
|
145 |
}); |
146 |
|
147 |
// Experimentation with JAWS 12 shows that the following is also |
148 |
// required to ensure |
149 |
// that JAWS will read out the name returned for the Item. |
150 |
composite.getAccessible().addAccessibleControlListener(new AccessibleControlAdapter() |
151 |
{ |
152 |
@Override |
153 |
public void getRole(AccessibleControlEvent e) |
154 |
{ |
155 |
if (e.childID == ACC.CHILDID_SELF) |
156 |
{ |
157 |
e.detail = role; // The ACC.ROLE constant for the Control. |
158 |
} |
159 |
else |
160 |
{ |
161 |
e.detail = ACC.ROLE_TEXT; // Return TEXT for an Item. |
162 |
} // if() |
163 |
} // getRole() |
164 |
}); |
165 |
|
166 |
} |
167 |
|
168 |
// ////////////////////////////////////////////////////////////// |
169 |
// Utility methods to map inquiry methods onto the Control-type |
170 |
// specific variants for Table or Tree, as required. |
171 |
// ////////////////////////////////////////////////////////////// |
172 |
|
173 |
private static Item getColumn(Composite composite, int role, int index) |
174 |
{ |
175 |
return (role == ACC.ROLE_TABLE) ? ((Table) composite).getColumn(index) : ((Tree) composite).getColumn(index); |
176 |
} |
177 |
|
178 |
private static int getColumnCount(Composite composite, int role) |
179 |
{ |
180 |
return (role == ACC.ROLE_TABLE) ? ((Table) composite).getColumnCount() : ((Tree) composite).getColumnCount(); |
181 |
} |
182 |
|
183 |
private static int[] getColumnOrder(Composite composite, int role) |
184 |
{ |
185 |
return (role == ACC.ROLE_TABLE) ? ((Table) composite).getColumnOrder() : ((Tree) composite).getColumnOrder(); |
186 |
} |
187 |
|
188 |
private static Item getItem(Composite composite, int role, int index) |
189 |
{ |
190 |
return (role == ACC.ROLE_TABLE) ? ((Table) composite).getItem(index) : ((Tree) composite).getItem(index); |
191 |
} |
192 |
|
193 |
private static Item[] getSelection(Composite composite, int role) |
194 |
{ |
195 |
return (role == ACC.ROLE_TABLE) ? ((Table) composite).getSelection() : ((Tree) composite).getSelection(); |
196 |
} |
197 |
|
198 |
private static int getItemCount(Composite composite, int role) |
199 |
{ |
200 |
return (role == ACC.ROLE_TABLE) ? ((Table) composite).getItemCount() : ((Tree) composite).getItemCount(); |
201 |
} |
202 |
|
203 |
private static Image getImage(Item item, int role, int index) |
204 |
{ |
205 |
return (role == ACC.ROLE_TABLE) ? ((TableItem) item).getImage(index) : ((TreeItem) item).getImage(index); |
206 |
} |
207 |
|
208 |
private static String getText(Item item, int role, int index) |
209 |
{ |
210 |
return (role == ACC.ROLE_TABLE) ? ((TableItem) item).getText(index) : ((TreeItem) item).getText(index); |
211 |
} |
212 |
|
213 |
} |