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