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