1 import com.sun.star.accessibility.*;
2 import com.sun.star.lang.XServiceInfo;
3 import com.sun.star.lang.IndexOutOfBoundsException;
4 import com.sun.star.uno.UnoRuntime;
5 
6 import java.util.Vector;
7 import java.awt.*;
8 import java.awt.event.*;
9 import javax.swing.*;
10 import javax.swing.tree.*;
11 import javax.swing.event.*;
12 
13 
14 
15 /** This is the tree component that is responsible for displaying the
16     contents of the tree model on the screen.
17 */
18 public class AccessibilityTree
19     implements TreeExpansionListener, TreeWillExpandListener
20 {
21     /** Create a new accessibility tree.  Use the specified message display
22         for displaying messages and the specified canvas to draw the
23         graphical representations of accessible objects on.
24     */
25     public AccessibilityTree ()
26     {
27         maTree = new JTree ();
28 
29         AccessibilityTreeModel aModel =
30             new AccessibilityTreeModel (
31                 new StringNode ("Please press Update button", null));
32         maTree.setModel (aModel);
33 
34         maCellRenderer = new AccessibleTreeCellRenderer();
35         //        setCellRenderer (maCellRenderer);
36 
37         // allow editing of XAccessibleText interfaces
38         //        setEditable (true);
39         //        maTreeModel.addTreeModelListener( new TextUpdateListener() );
40 
41         maTree.addMouseListener (new MouseListener (this));
42 
43         // Listen to expansions and collapses to change the mouse cursor.
44         mnExpandLevel = 0;
45         maTree.addTreeWillExpandListener (this);
46         maTree.addTreeExpansionListener (this);
47     }
48 
49     public JTree getComponent ()
50     {
51         return maTree;
52     }
53 
54     // Change cursor during expansions to show the user that this is a
55     // lengthy operation.
56     public void treeWillExpand (TreeExpansionEvent e)
57     {
58         if (mnExpandLevel == 0)
59         {
60             maTree.setCursor (new Cursor (Cursor.WAIT_CURSOR));
61         }
62         mnExpandLevel += 1;
63     }
64     public void treeWillCollapse (TreeExpansionEvent e)
65     {
66         if (mnExpandLevel == 0)
67         {
68             maTree.setCursor (new Cursor (Cursor.WAIT_CURSOR));
69         }
70         mnExpandLevel += 1;
71     }
72     public void treeExpanded (TreeExpansionEvent e)
73     {
74         mnExpandLevel -= 1;
75         if (mnExpandLevel == 0)
76         {
77             maTree.setCursor (new Cursor (Cursor.DEFAULT_CURSOR));
78         }
79     }
80     public void treeCollapsed (TreeExpansionEvent e)
81     {
82         mnExpandLevel -= 1;
83         if (mnExpandLevel == 0)
84         {
85             maTree.setCursor (new Cursor (Cursor.DEFAULT_CURSOR));
86         }
87     }
88 
89 
90 
91     public void SetCanvas (Canvas aCanvas)
92     {
93         maCanvas = aCanvas;
94         ((AccessibilityTreeModel)maTree.getModel()).setCanvas (maCanvas);
95     }
96 
97     /** Expand the nodes in the subtree rooted in aNode according to the the
98         specified expander.  The tree is locked during the expansion.
99     */
100     protected void expandTree (AccessibleTreeNode aNode, Expander aExpander)
101     {
102         if (mnExpandLevel == 0)
103         {
104             maTree.setEnabled (false);
105         }
106         mnExpandLevel += 1;
107 
108         ((AccessibilityTreeModel)maTree.getModel()).lock ();
109 
110         try
111         {
112             expandTree (new TreePath (aNode.createPath()), aExpander);
113         }
114         catch (Exception e)
115         {
116             // Ignore
117         }
118 
119         mnExpandLevel -= 1;
120         if (mnExpandLevel == 0)
121         {
122             maTree.setEnabled (true);
123             ((AccessibilityTreeModel)maTree.getModel()).unlock (aNode);
124         }
125     }
126 
127     private TreePath expandTree( TreePath aPath, Expander aExpander )
128     {
129         // return first expanded object
130         TreePath aFirst = null;
131 
132         //        System.out.print ("e");
133 
134         try
135         {
136             // get 'our' object
137             Object aObj = aPath.getLastPathComponent();
138 
139             // expand this object, if the Expander tells us so
140             if( aExpander.expand( aObj ) )
141             {
142                 maTree.expandPath (aPath);
143                 if( aFirst == null )
144                     aFirst = aPath;
145             }
146 
147             // visit all children
148             if (aObj instanceof AccessibleTreeNode)
149             {
150                 AccessibleTreeNode aNode = (AccessibleTreeNode)aObj;
151                 int nLength = aNode.getChildCount();
152                 for( int i = 0; i < nLength; i++ )
153                 {
154                     TreePath aRet = expandTree(
155                         aPath.pathByAddingChild( aNode.getChild( i ) ),
156                         aExpander );
157                     if( aFirst == null )
158                         aFirst = aRet;
159                 }
160             }
161         }
162         catch (Exception e)
163         {
164             System.out.println ("caught exception while expanding tree path "
165                 + aPath + ": " + e);
166             e.printStackTrace ();
167         }
168 
169         return aFirst;
170     }
171 
172 
173     /** Expand all nodes and their subtrees that represent shapes.  Call
174      *  this method from the outside. */
175     public void expandShapes ()
176     {
177         expandShapes ((AccessibleTreeNode)maTree.getModel().getRoot());
178     }
179     public void expandShapes (AccessibleTreeNode aNode)
180     {
181         expandTree (aNode, new ShapeExpander());
182     }
183 
184     /** Expand all nodes */
185     public void expandAll ()
186     {
187         expandAll ((AccessibleTreeNode)maTree.getModel().getRoot());
188     }
189     public void expandAll (AccessibleTreeNode aNode)
190     {
191         expandTree (aNode, new AllExpander());
192     }
193 
194 
195 
196     public void disposing (com.sun.star.lang.EventObject e)
197     {
198         System.out.println ("disposing " + e);
199     }
200 
201     /*
202     public Dimension getPreferredSize ()
203     {
204         Dimension aPreferredSize = super.getPreferredSize();
205         Dimension aMinimumSize = super.getMinimumSize();
206         if (aPreferredSize.width < aMinimumSize.width)
207             aPreferredSize.width = aMinimumSize.width;
208         return aPreferredSize;
209     }
210     */
211 
212     class MouseListener extends MouseAdapter
213     {
214         public MouseListener (AccessibilityTree aTree)
215         {
216             maTree=aTree;
217         }
218         public void mousePressed(MouseEvent e) { popupTrigger(e); }
219         public void mouseClicked(MouseEvent e) { popupTrigger(e); }
220         public void mouseEntered(MouseEvent e) { popupTrigger(e); }
221         public void mouseExited(MouseEvent e) { popupTrigger(e); }
222         public void mouseReleased(MouseEvent e) { popupTrigger(e); }
223 
224         public boolean popupTrigger( MouseEvent e )
225         {
226             boolean bIsPopup = e.isPopupTrigger();
227             if( bIsPopup )
228             {
229                 int selRow = maTree.getComponent().getRowForLocation(e.getX(), e.getY());
230                 if (selRow != -1)
231                 {
232                     TreePath aPath = maTree.getComponent().getPathForLocation(e.getX(), e.getY());
233 
234                     // check for actions
235                     Object aObject = aPath.getLastPathComponent();
236                     JPopupMenu aMenu = new JPopupMenu();
237                     if( aObject instanceof AccTreeNode )
238                     {
239                         AccTreeNode aNode = (AccTreeNode)aObject;
240 
241                         Vector aActions = new Vector();
242                         aMenu.add (new AccessibilityTree.ShapeExpandAction(maTree, aNode));
243                         aMenu.add (new AccessibilityTree.SubtreeExpandAction(maTree, aNode));
244 
245                         aNode.getActions(aActions);
246                         for( int i = 0; i < aActions.size(); i++ )
247                         {
248                             aMenu.add( new NodeAction(
249                                            aActions.elementAt(i).toString(),
250                                            aNode, i ) );
251                         }
252                     }
253                     else if (aObject instanceof AccessibleTreeNode)
254                     {
255                         AccessibleTreeNode aNode = (AccessibleTreeNode)aObject;
256                         String[] aActionNames = aNode.getActions();
257                         int nCount=aActionNames.length;
258                         if (nCount > 0)
259                         {
260                             for (int i=0; i<nCount; i++)
261                                 aMenu.add( new NodeAction(
262                                     aActionNames[i],
263                                     aNode,
264                                     i));
265                         }
266                         else
267                             aMenu = null;
268                     }
269                     if (aMenu != null)
270                         aMenu.show (maTree.getComponent(),
271                             e.getX(), e.getY());
272                 }
273             }
274 
275             return bIsPopup;
276         }
277 
278         private AccessibilityTree maTree;
279     }
280 
281     class NodeAction extends AbstractAction
282     {
283         private int mnIndex;
284         private AccessibleTreeNode maNode;
285 
286         public NodeAction( String aName, AccessibleTreeNode aNode, int nIndex )
287         {
288             super( aName );
289             maNode = aNode;
290             mnIndex = nIndex;
291         }
292 
293         public void actionPerformed(ActionEvent e)
294         {
295             maNode.performAction(mnIndex);
296         }
297     }
298 
299     // This action expands all shapes in the subtree rooted in the specified node.
300     class ShapeExpandAction extends AbstractAction
301     {
302         private AccessibilityTree maTree;
303         private AccTreeNode maNode;
304         public ShapeExpandAction (AccessibilityTree aTree, AccTreeNode aNode)
305         {
306             super ("Expand Shapes");
307             maTree = aTree;
308             maNode = aNode;
309         }
310         public void actionPerformed (ActionEvent e)
311         {
312             maTree.expandShapes (maNode);
313         }
314     }
315 
316     // This action expands all nodes in the subtree rooted in the specified node.
317     class SubtreeExpandAction extends AbstractAction
318     {
319         private AccessibilityTree maTree;
320         private AccTreeNode maNode;
321         public SubtreeExpandAction (AccessibilityTree aTree, AccTreeNode aNode)
322         {
323             super ("Expand Subtree");
324             maTree = aTree;
325             maNode = aNode;
326         }
327         public void actionPerformed (ActionEvent e)
328         {
329             maTree.expandAll (maNode);
330         }
331     }
332 
333     /** Predicate class to determine whether a node should be expanded
334      * For use with expandTree method */
335     abstract class Expander
336     {
337         abstract public boolean expand (Object aObject);
338     }
339 
340     /** expand all nodes */
341     class AllExpander extends Expander
342     {
343         public boolean expand(Object aObject) { return true; }
344     }
345 
346     /** expand all nodes with accessibility roles > 100 */
347     class ShapeExpander extends Expander
348     {
349         public boolean expand (Object aObject)
350         {
351             if (aObject instanceof AccTreeNode)
352             {
353                 AccTreeNode aNode = (AccTreeNode)aObject;
354                 XAccessibleContext xContext = aNode.getContext();
355                 if (xContext != null)
356                     if (xContext.getAccessibleRole() >= 100)
357                         return true;
358             }
359             return false;
360         }
361     }
362 
363 
364 
365     protected AccessibleTreeCellRenderer
366         maCellRenderer;
367 
368 
369     private JTree
370         maTree;
371     private Canvas
372         maCanvas;
373     private boolean
374         mbFirstShapeSeen;
375     private int
376         mnExpandLevel;
377 }
378