1*b1cdbd2cSJim Jagielski /************************************************************** 2*b1cdbd2cSJim Jagielski * 3*b1cdbd2cSJim Jagielski * Licensed to the Apache Software Foundation (ASF) under one 4*b1cdbd2cSJim Jagielski * or more contributor license agreements. See the NOTICE file 5*b1cdbd2cSJim Jagielski * distributed with this work for additional information 6*b1cdbd2cSJim Jagielski * regarding copyright ownership. The ASF licenses this file 7*b1cdbd2cSJim Jagielski * to you under the Apache License, Version 2.0 (the 8*b1cdbd2cSJim Jagielski * "License"); you may not use this file except in compliance 9*b1cdbd2cSJim Jagielski * with the License. You may obtain a copy of the License at 10*b1cdbd2cSJim Jagielski * 11*b1cdbd2cSJim Jagielski * http://www.apache.org/licenses/LICENSE-2.0 12*b1cdbd2cSJim Jagielski * 13*b1cdbd2cSJim Jagielski * Unless required by applicable law or agreed to in writing, 14*b1cdbd2cSJim Jagielski * software distributed under the License is distributed on an 15*b1cdbd2cSJim Jagielski * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*b1cdbd2cSJim Jagielski * KIND, either express or implied. See the License for the 17*b1cdbd2cSJim Jagielski * specific language governing permissions and limitations 18*b1cdbd2cSJim Jagielski * under the License. 19*b1cdbd2cSJim Jagielski * 20*b1cdbd2cSJim Jagielski *************************************************************/ 21*b1cdbd2cSJim Jagielski 22*b1cdbd2cSJim Jagielski import javax.swing.event.TreeModelEvent; 23*b1cdbd2cSJim Jagielski import javax.swing.event.TreeModelListener; 24*b1cdbd2cSJim Jagielski import javax.swing.tree.TreePath; 25*b1cdbd2cSJim Jagielski 26*b1cdbd2cSJim Jagielski 27*b1cdbd2cSJim Jagielski import java.util.Vector; 28*b1cdbd2cSJim Jagielski import java.util.HashMap; 29*b1cdbd2cSJim Jagielski import java.util.Enumeration; 30*b1cdbd2cSJim Jagielski 31*b1cdbd2cSJim Jagielski import com.sun.star.accessibility.*; 32*b1cdbd2cSJim Jagielski 33*b1cdbd2cSJim Jagielski import com.sun.star.uno.UnoRuntime; 34*b1cdbd2cSJim Jagielski import com.sun.star.uno.XInterface; 35*b1cdbd2cSJim Jagielski import com.sun.star.uno.Any; 36*b1cdbd2cSJim Jagielski import com.sun.star.lang.EventObject; 37*b1cdbd2cSJim Jagielski import com.sun.star.lang.XServiceInfo; 38*b1cdbd2cSJim Jagielski import com.sun.star.lang.XServiceName; 39*b1cdbd2cSJim Jagielski 40*b1cdbd2cSJim Jagielski public class AccessibilityTreeModel 41*b1cdbd2cSJim Jagielski extends AccessibilityTreeModelBase 42*b1cdbd2cSJim Jagielski { 43*b1cdbd2cSJim Jagielski public boolean mbVerbose = false; 44*b1cdbd2cSJim Jagielski AccessibilityTreeModel(AccessibleTreeNode aRoot)45*b1cdbd2cSJim Jagielski public AccessibilityTreeModel (AccessibleTreeNode aRoot) 46*b1cdbd2cSJim Jagielski { 47*b1cdbd2cSJim Jagielski // create default node (unless we have a 'proper' node) 48*b1cdbd2cSJim Jagielski if( ! (aRoot instanceof AccessibleTreeNode) ) 49*b1cdbd2cSJim Jagielski aRoot = new StringNode ("Root", null); 50*b1cdbd2cSJim Jagielski setRoot (aRoot); 51*b1cdbd2cSJim Jagielski 52*b1cdbd2cSJim Jagielski maNodeMap = new NodeMap(); 53*b1cdbd2cSJim Jagielski 54*b1cdbd2cSJim Jagielski maEventListener = new EventListener (this); 55*b1cdbd2cSJim Jagielski mxListener = new QueuedListener (maEventListener); 56*b1cdbd2cSJim Jagielski } 57*b1cdbd2cSJim Jagielski clear()58*b1cdbd2cSJim Jagielski public void clear () 59*b1cdbd2cSJim Jagielski { 60*b1cdbd2cSJim Jagielski maNodeMap.Clear(); 61*b1cdbd2cSJim Jagielski } 62*b1cdbd2cSJim Jagielski 63*b1cdbd2cSJim Jagielski /** Lock the tree. While the tree is locked, events from the outside are 64*b1cdbd2cSJim Jagielski not processed. Lock the tree when you change its internal structure. 65*b1cdbd2cSJim Jagielski */ lock()66*b1cdbd2cSJim Jagielski public void lock () 67*b1cdbd2cSJim Jagielski { 68*b1cdbd2cSJim Jagielski mnLockCount += 1; 69*b1cdbd2cSJim Jagielski } 70*b1cdbd2cSJim Jagielski 71*b1cdbd2cSJim Jagielski /** Unlock the tree. After unlocking the tree as many times as locking 72*b1cdbd2cSJim Jagielski it, a treeStructureChange event is sent to the event listeners. 73*b1cdbd2cSJim Jagielski @param aNodeHint 74*b1cdbd2cSJim Jagielski If not null and treeStructureChange events are thrown then this 75*b1cdbd2cSJim Jagielski node is used as root of the modified subtree. 76*b1cdbd2cSJim Jagielski */ unlock(AccessibleTreeNode aNodeHint)77*b1cdbd2cSJim Jagielski public void unlock (AccessibleTreeNode aNodeHint) 78*b1cdbd2cSJim Jagielski { 79*b1cdbd2cSJim Jagielski mnLockCount -= 1; 80*b1cdbd2cSJim Jagielski if (mnLockCount == 0) 81*b1cdbd2cSJim Jagielski fireTreeStructureChanged ( 82*b1cdbd2cSJim Jagielski new TreeModelEvent (this, 83*b1cdbd2cSJim Jagielski new TreePath (aNodeHint.createPath()))); 84*b1cdbd2cSJim Jagielski } 85*b1cdbd2cSJim Jagielski 86*b1cdbd2cSJim Jagielski 87*b1cdbd2cSJim Jagielski 88*b1cdbd2cSJim Jagielski 89*b1cdbd2cSJim Jagielski /** Inform all listeners (especially the renderer) of a change of the 90*b1cdbd2cSJim Jagielski tree's structure. 91*b1cdbd2cSJim Jagielski @param aNode This node specifies the sub tree in which all changes 92*b1cdbd2cSJim Jagielski take place. 93*b1cdbd2cSJim Jagielski */ FireTreeStructureChanged(AccessibleTreeNode aNode)94*b1cdbd2cSJim Jagielski public void FireTreeStructureChanged (AccessibleTreeNode aNode) 95*b1cdbd2cSJim Jagielski { 96*b1cdbd2cSJim Jagielski } 97*b1cdbd2cSJim Jagielski 98*b1cdbd2cSJim Jagielski 99*b1cdbd2cSJim Jagielski 100*b1cdbd2cSJim Jagielski 101*b1cdbd2cSJim Jagielski setRoot(AccessibleTreeNode aRoot)102*b1cdbd2cSJim Jagielski public synchronized void setRoot (AccessibleTreeNode aRoot) 103*b1cdbd2cSJim Jagielski { 104*b1cdbd2cSJim Jagielski if (getRoot() == null) 105*b1cdbd2cSJim Jagielski super.setRoot (aRoot); 106*b1cdbd2cSJim Jagielski else 107*b1cdbd2cSJim Jagielski { 108*b1cdbd2cSJim Jagielski lock (); 109*b1cdbd2cSJim Jagielski maNodeMap.ForEach (new NodeMapCallback () { 110*b1cdbd2cSJim Jagielski public void Apply (AccTreeNode aNode) 111*b1cdbd2cSJim Jagielski { 112*b1cdbd2cSJim Jagielski if (maCanvas != null) 113*b1cdbd2cSJim Jagielski maCanvas.removeNode (aNode); 114*b1cdbd2cSJim Jagielski removeAccListener ((AccTreeNode)aNode); 115*b1cdbd2cSJim Jagielski } 116*b1cdbd2cSJim Jagielski }); 117*b1cdbd2cSJim Jagielski maNodeMap.Clear (); 118*b1cdbd2cSJim Jagielski 119*b1cdbd2cSJim Jagielski setRoot (aRoot); 120*b1cdbd2cSJim Jagielski unlock (aRoot); 121*b1cdbd2cSJim Jagielski } 122*b1cdbd2cSJim Jagielski } 123*b1cdbd2cSJim Jagielski 124*b1cdbd2cSJim Jagielski 125*b1cdbd2cSJim Jagielski // 126*b1cdbd2cSJim Jagielski // child management: 127*b1cdbd2cSJim Jagielski // 128*b1cdbd2cSJim Jagielski 129*b1cdbd2cSJim Jagielski 130*b1cdbd2cSJim Jagielski 131*b1cdbd2cSJim Jagielski /** Delegate the request to the parent and then register listeners at 132*b1cdbd2cSJim Jagielski the child and add the child to the canvas. 133*b1cdbd2cSJim Jagielski */ getChild(Object aParent, int nIndex)134*b1cdbd2cSJim Jagielski public Object getChild (Object aParent, int nIndex) 135*b1cdbd2cSJim Jagielski { 136*b1cdbd2cSJim Jagielski AccessibleTreeNode aChild = (AccessibleTreeNode)super.getChild (aParent, nIndex); 137*b1cdbd2cSJim Jagielski 138*b1cdbd2cSJim Jagielski if (aChild == null) 139*b1cdbd2cSJim Jagielski System.out.println ("getChild: child not found"); 140*b1cdbd2cSJim Jagielski else 141*b1cdbd2cSJim Jagielski // Keep translation table up-to-date. 142*b1cdbd2cSJim Jagielski addNode (aChild); 143*b1cdbd2cSJim Jagielski 144*b1cdbd2cSJim Jagielski return aChild; 145*b1cdbd2cSJim Jagielski } 146*b1cdbd2cSJim Jagielski getChildNoCreate(Object aParent, int nIndex)147*b1cdbd2cSJim Jagielski public Object getChildNoCreate (Object aParent, int nIndex) 148*b1cdbd2cSJim Jagielski { 149*b1cdbd2cSJim Jagielski AccessibleTreeNode aChild = (AccessibleTreeNode)super.getChildNoCreate (aParent, nIndex); 150*b1cdbd2cSJim Jagielski 151*b1cdbd2cSJim Jagielski return aChild; 152*b1cdbd2cSJim Jagielski } 153*b1cdbd2cSJim Jagielski 154*b1cdbd2cSJim Jagielski 155*b1cdbd2cSJim Jagielski 156*b1cdbd2cSJim Jagielski 157*b1cdbd2cSJim Jagielski /** Remove a node (and all children) from the tree model. 158*b1cdbd2cSJim Jagielski */ removeChild(AccessibleTreeNode aNode)159*b1cdbd2cSJim Jagielski protected boolean removeChild (AccessibleTreeNode aNode) 160*b1cdbd2cSJim Jagielski { 161*b1cdbd2cSJim Jagielski try 162*b1cdbd2cSJim Jagielski { 163*b1cdbd2cSJim Jagielski if( aNode == null ) 164*b1cdbd2cSJim Jagielski { 165*b1cdbd2cSJim Jagielski System.out.println ("can't remove null node"); 166*b1cdbd2cSJim Jagielski return false; 167*b1cdbd2cSJim Jagielski } 168*b1cdbd2cSJim Jagielski else 169*b1cdbd2cSJim Jagielski { 170*b1cdbd2cSJim Jagielski // depth-first removal of children 171*b1cdbd2cSJim Jagielski while (aNode.getChildCount() > 0) 172*b1cdbd2cSJim Jagielski if ( ! removeChild (aNode.getChildNoCreate (0))) 173*b1cdbd2cSJim Jagielski break; 174*b1cdbd2cSJim Jagielski 175*b1cdbd2cSJim Jagielski // Remove node from its parent. 176*b1cdbd2cSJim Jagielski AccessibleTreeNode aParent = aNode.getParent(); 177*b1cdbd2cSJim Jagielski if (aParent != null) 178*b1cdbd2cSJim Jagielski { 179*b1cdbd2cSJim Jagielski int nIndex = aParent.indexOf(aNode); 180*b1cdbd2cSJim Jagielski aParent.removeChild (nIndex); 181*b1cdbd2cSJim Jagielski } 182*b1cdbd2cSJim Jagielski 183*b1cdbd2cSJim Jagielski maNodeMap.RemoveNode (aNode); 184*b1cdbd2cSJim Jagielski } 185*b1cdbd2cSJim Jagielski } 186*b1cdbd2cSJim Jagielski catch (Exception e) 187*b1cdbd2cSJim Jagielski { 188*b1cdbd2cSJim Jagielski System.out.println ("caught exception while removing child " 189*b1cdbd2cSJim Jagielski + aNode + " : " + e); 190*b1cdbd2cSJim Jagielski e.printStackTrace (); 191*b1cdbd2cSJim Jagielski return false; 192*b1cdbd2cSJim Jagielski } 193*b1cdbd2cSJim Jagielski return true; 194*b1cdbd2cSJim Jagielski } 195*b1cdbd2cSJim Jagielski removeNode(XAccessibleContext xNode)196*b1cdbd2cSJim Jagielski public void removeNode (XAccessibleContext xNode) 197*b1cdbd2cSJim Jagielski { 198*b1cdbd2cSJim Jagielski if (xNode != null) 199*b1cdbd2cSJim Jagielski { 200*b1cdbd2cSJim Jagielski AccessibleTreeNode aNode = maNodeMap.GetNode (xNode); 201*b1cdbd2cSJim Jagielski AccessibleTreeNode aRootNode = (AccessibleTreeNode)getRoot(); 202*b1cdbd2cSJim Jagielski TreeModelEvent aEvent = createEvent (aRootNode, aNode); 203*b1cdbd2cSJim Jagielski removeChild (aNode); 204*b1cdbd2cSJim Jagielski if (mbVerbose) 205*b1cdbd2cSJim Jagielski System.out.println (aNode); 206*b1cdbd2cSJim Jagielski fireTreeNodesRemoved (aEvent); 207*b1cdbd2cSJim Jagielski maCanvas.repaint (); 208*b1cdbd2cSJim Jagielski } 209*b1cdbd2cSJim Jagielski } 210*b1cdbd2cSJim Jagielski 211*b1cdbd2cSJim Jagielski 212*b1cdbd2cSJim Jagielski /** Add add a new child to a parent. 213*b1cdbd2cSJim Jagielski @return 214*b1cdbd2cSJim Jagielski Returns the new or existing representation of the specified 215*b1cdbd2cSJim Jagielski accessible object. 216*b1cdbd2cSJim Jagielski */ addChild(AccTreeNode aParentNode, XAccessible xNewChild)217*b1cdbd2cSJim Jagielski protected AccessibleTreeNode addChild (AccTreeNode aParentNode, XAccessible xNewChild) 218*b1cdbd2cSJim Jagielski { 219*b1cdbd2cSJim Jagielski AccessibleTreeNode aChildNode = null; 220*b1cdbd2cSJim Jagielski try 221*b1cdbd2cSJim Jagielski { 222*b1cdbd2cSJim Jagielski boolean bRet = false; 223*b1cdbd2cSJim Jagielski 224*b1cdbd2cSJim Jagielski // First make sure that the accessible object does not already have 225*b1cdbd2cSJim Jagielski // a representation. 226*b1cdbd2cSJim Jagielski aChildNode = maNodeMap.GetNode(xNewChild); 227*b1cdbd2cSJim Jagielski if (aChildNode == null) 228*b1cdbd2cSJim Jagielski aChildNode = aParentNode.addAccessibleChild (xNewChild); 229*b1cdbd2cSJim Jagielski else 230*b1cdbd2cSJim Jagielski System.out.println ("node already present"); 231*b1cdbd2cSJim Jagielski } 232*b1cdbd2cSJim Jagielski catch (Exception e) 233*b1cdbd2cSJim Jagielski { 234*b1cdbd2cSJim Jagielski System.out.println ("caught exception while adding child " 235*b1cdbd2cSJim Jagielski + xNewChild + " to parent " + aParentNode + ": " + e); 236*b1cdbd2cSJim Jagielski e.printStackTrace (); 237*b1cdbd2cSJim Jagielski } 238*b1cdbd2cSJim Jagielski return aChildNode; 239*b1cdbd2cSJim Jagielski } 240*b1cdbd2cSJim Jagielski addChild(XAccessibleContext xParent, XAccessible xChild)241*b1cdbd2cSJim Jagielski public void addChild (XAccessibleContext xParent, XAccessible xChild) 242*b1cdbd2cSJim Jagielski { 243*b1cdbd2cSJim Jagielski AccessibleTreeNode aParentNode = maNodeMap.GetNode (xParent); 244*b1cdbd2cSJim Jagielski if (aParentNode instanceof AccTreeNode) 245*b1cdbd2cSJim Jagielski { 246*b1cdbd2cSJim Jagielski AccessibleTreeNode aChild = addChild ((AccTreeNode)aParentNode, xChild); 247*b1cdbd2cSJim Jagielski if (addNode (aChild)) 248*b1cdbd2cSJim Jagielski { 249*b1cdbd2cSJim Jagielski if (maCanvas != null) 250*b1cdbd2cSJim Jagielski maCanvas.updateNode ((AccTreeNode)aParentNode); 251*b1cdbd2cSJim Jagielski 252*b1cdbd2cSJim Jagielski // A call to fireTreeNodesInserted for xNew 253*b1cdbd2cSJim Jagielski // should be sufficient but at least the 254*b1cdbd2cSJim Jagielski // StringNode object that contains the number of 255*b1cdbd2cSJim Jagielski // children also changes and we do not know its 256*b1cdbd2cSJim Jagielski // index relative to its parent. Therefore the 257*b1cdbd2cSJim Jagielski // more expensive fireTreeStructureChanged is 258*b1cdbd2cSJim Jagielski // necessary. 259*b1cdbd2cSJim Jagielski fireTreeNodesInserted (createEvent (xParent, xChild)); 260*b1cdbd2cSJim Jagielski updateNode (xParent, AccessibleTreeHandler.class); 261*b1cdbd2cSJim Jagielski } 262*b1cdbd2cSJim Jagielski maCanvas.repaint (); 263*b1cdbd2cSJim Jagielski } 264*b1cdbd2cSJim Jagielski } 265*b1cdbd2cSJim Jagielski 266*b1cdbd2cSJim Jagielski 267*b1cdbd2cSJim Jagielski /** Add the child node to the internal tree structure. 268*b1cdbd2cSJim Jagielski @param aNode 269*b1cdbd2cSJim Jagielski The node to insert into the internal tree structure. 270*b1cdbd2cSJim Jagielski */ addNode(AccessibleTreeNode aNode)271*b1cdbd2cSJim Jagielski protected boolean addNode (AccessibleTreeNode aNode) 272*b1cdbd2cSJim Jagielski { 273*b1cdbd2cSJim Jagielski boolean bRet = false; 274*b1cdbd2cSJim Jagielski try 275*b1cdbd2cSJim Jagielski { 276*b1cdbd2cSJim Jagielski if ( ! maNodeMap.ValueIsMember (aNode)) 277*b1cdbd2cSJim Jagielski { 278*b1cdbd2cSJim Jagielski if (aNode instanceof AccTreeNode) 279*b1cdbd2cSJim Jagielski { 280*b1cdbd2cSJim Jagielski AccTreeNode aChild = (AccTreeNode)aNode; 281*b1cdbd2cSJim Jagielski XAccessibleContext xChild = aChild.getContext(); 282*b1cdbd2cSJim Jagielski registerAccListener (aChild); 283*b1cdbd2cSJim Jagielski if (maCanvas != null) 284*b1cdbd2cSJim Jagielski maCanvas.addNode (aChild); 285*b1cdbd2cSJim Jagielski maNodeMap.InsertNode (xChild, aChild); 286*b1cdbd2cSJim Jagielski } 287*b1cdbd2cSJim Jagielski bRet = true; 288*b1cdbd2cSJim Jagielski } 289*b1cdbd2cSJim Jagielski 290*b1cdbd2cSJim Jagielski } 291*b1cdbd2cSJim Jagielski catch (Exception e) 292*b1cdbd2cSJim Jagielski { 293*b1cdbd2cSJim Jagielski System.out.println ("caught exception while adding node " 294*b1cdbd2cSJim Jagielski + aNode + ": " + e); 295*b1cdbd2cSJim Jagielski e.printStackTrace (); 296*b1cdbd2cSJim Jagielski } 297*b1cdbd2cSJim Jagielski return bRet; 298*b1cdbd2cSJim Jagielski } 299*b1cdbd2cSJim Jagielski 300*b1cdbd2cSJim Jagielski 301*b1cdbd2cSJim Jagielski 302*b1cdbd2cSJim Jagielski 303*b1cdbd2cSJim Jagielski /** create path to node, suitable for TreeModelEvent constructor 304*b1cdbd2cSJim Jagielski * @see javax.swing.event.TreeModelEvent#TreeModelEvent 305*b1cdbd2cSJim Jagielski */ createPath(AccessibleTreeNode aNode)306*b1cdbd2cSJim Jagielski protected Object[] createPath (AccessibleTreeNode aNode) 307*b1cdbd2cSJim Jagielski { 308*b1cdbd2cSJim Jagielski Vector aPath = new Vector(); 309*b1cdbd2cSJim Jagielski aNode.createPath (aPath); 310*b1cdbd2cSJim Jagielski return aPath.toArray(); 311*b1cdbd2cSJim Jagielski } 312*b1cdbd2cSJim Jagielski 313*b1cdbd2cSJim Jagielski // 314*b1cdbd2cSJim Jagielski // listeners (and helper methods) 315*b1cdbd2cSJim Jagielski // 316*b1cdbd2cSJim Jagielski // We are registered with listeners as soon as objects are in the 317*b1cdbd2cSJim Jagielski // tree cache, and we should get removed as soon as they are out. 318*b1cdbd2cSJim Jagielski // 319*b1cdbd2cSJim Jagielski fireTreeNodesChanged(TreeModelEvent e)320*b1cdbd2cSJim Jagielski protected void fireTreeNodesChanged(TreeModelEvent e) 321*b1cdbd2cSJim Jagielski { 322*b1cdbd2cSJim Jagielski for(int i = 0; i < maTMListeners.size(); i++) 323*b1cdbd2cSJim Jagielski { 324*b1cdbd2cSJim Jagielski ((TreeModelListener)maTMListeners.get(i)).treeNodesChanged(e); 325*b1cdbd2cSJim Jagielski } 326*b1cdbd2cSJim Jagielski } 327*b1cdbd2cSJim Jagielski fireTreeNodesInserted(final TreeModelEvent e)328*b1cdbd2cSJim Jagielski protected void fireTreeNodesInserted(final TreeModelEvent e) 329*b1cdbd2cSJim Jagielski { 330*b1cdbd2cSJim Jagielski for(int i = 0; i < maTMListeners.size(); i++) 331*b1cdbd2cSJim Jagielski { 332*b1cdbd2cSJim Jagielski ((TreeModelListener)maTMListeners.get(i)).treeNodesInserted(e); 333*b1cdbd2cSJim Jagielski } 334*b1cdbd2cSJim Jagielski } 335*b1cdbd2cSJim Jagielski fireTreeNodesRemoved(final TreeModelEvent e)336*b1cdbd2cSJim Jagielski protected void fireTreeNodesRemoved(final TreeModelEvent e) 337*b1cdbd2cSJim Jagielski { 338*b1cdbd2cSJim Jagielski for(int i = 0; i < maTMListeners.size(); i++) 339*b1cdbd2cSJim Jagielski { 340*b1cdbd2cSJim Jagielski ((TreeModelListener)maTMListeners.get(i)).treeNodesRemoved(e); 341*b1cdbd2cSJim Jagielski } 342*b1cdbd2cSJim Jagielski } 343*b1cdbd2cSJim Jagielski fireTreeStructureChanged(final TreeModelEvent e)344*b1cdbd2cSJim Jagielski protected void fireTreeStructureChanged(final TreeModelEvent e) 345*b1cdbd2cSJim Jagielski { 346*b1cdbd2cSJim Jagielski for(int i = 0; i < maTMListeners.size(); i++) 347*b1cdbd2cSJim Jagielski { 348*b1cdbd2cSJim Jagielski ((TreeModelListener)maTMListeners.get(i)).treeStructureChanged(e); 349*b1cdbd2cSJim Jagielski } 350*b1cdbd2cSJim Jagielski } 351*b1cdbd2cSJim Jagielski createEvent(XAccessibleContext xParent)352*b1cdbd2cSJim Jagielski protected TreeModelEvent createEvent (XAccessibleContext xParent) 353*b1cdbd2cSJim Jagielski { 354*b1cdbd2cSJim Jagielski AccessibleTreeNode aParentNode = maNodeMap.GetNode (xParent); 355*b1cdbd2cSJim Jagielski return new TreeModelEvent (this, createPath (aParentNode)); 356*b1cdbd2cSJim Jagielski } 357*b1cdbd2cSJim Jagielski 358*b1cdbd2cSJim Jagielski /** Create a TreeModelEvent object that informs listeners that one child 359*b1cdbd2cSJim Jagielski has been removed from or inserted into its parent. 360*b1cdbd2cSJim Jagielski */ createEvent(XAccessibleContext xParent, XAccessible xChild)361*b1cdbd2cSJim Jagielski public TreeModelEvent createEvent (XAccessibleContext xParent, XAccessible xChild) 362*b1cdbd2cSJim Jagielski { 363*b1cdbd2cSJim Jagielski AccessibleTreeNode aParentNode = maNodeMap.GetNode (xParent); 364*b1cdbd2cSJim Jagielski return createEvent (aParentNode, xParent); 365*b1cdbd2cSJim Jagielski } 366*b1cdbd2cSJim Jagielski createEvent(AccessibleTreeNode aParentNode, XAccessibleContext xChild)367*b1cdbd2cSJim Jagielski public TreeModelEvent createEvent (AccessibleTreeNode aParentNode, XAccessibleContext xChild) 368*b1cdbd2cSJim Jagielski { 369*b1cdbd2cSJim Jagielski AccessibleTreeNode aChildNode = null; 370*b1cdbd2cSJim Jagielski if (xChild != null) 371*b1cdbd2cSJim Jagielski aChildNode = maNodeMap.GetNode (xChild); 372*b1cdbd2cSJim Jagielski return createEvent (aParentNode, aChildNode); 373*b1cdbd2cSJim Jagielski } 374*b1cdbd2cSJim Jagielski 375*b1cdbd2cSJim Jagielski 376*b1cdbd2cSJim Jagielski createEvent( AccessibleTreeNode aParentNode, AccessibleTreeNode aChildNode)377*b1cdbd2cSJim Jagielski protected TreeModelEvent createEvent ( 378*b1cdbd2cSJim Jagielski AccessibleTreeNode aParentNode, 379*b1cdbd2cSJim Jagielski AccessibleTreeNode aChildNode) 380*b1cdbd2cSJim Jagielski { 381*b1cdbd2cSJim Jagielski Object[] aPathToParent = createPath (aParentNode); 382*b1cdbd2cSJim Jagielski 383*b1cdbd2cSJim Jagielski int nIndexInParent = -1; 384*b1cdbd2cSJim Jagielski if (aChildNode != null) 385*b1cdbd2cSJim Jagielski nIndexInParent = aParentNode.indexOf (aChildNode); 386*b1cdbd2cSJim Jagielski if (mbVerbose) 387*b1cdbd2cSJim Jagielski System.out.println (aChildNode + " " + nIndexInParent); 388*b1cdbd2cSJim Jagielski 389*b1cdbd2cSJim Jagielski if (nIndexInParent == -1) 390*b1cdbd2cSJim Jagielski // This event may be passed only to treeStructureChanged of the listeners. 391*b1cdbd2cSJim Jagielski return new TreeModelEvent (this, 392*b1cdbd2cSJim Jagielski aPathToParent); 393*b1cdbd2cSJim Jagielski else 394*b1cdbd2cSJim Jagielski // General purpose event for removing or inserting known nodes. 395*b1cdbd2cSJim Jagielski return new TreeModelEvent (this, 396*b1cdbd2cSJim Jagielski aPathToParent, 397*b1cdbd2cSJim Jagielski new int[] {nIndexInParent}, 398*b1cdbd2cSJim Jagielski new Object[] {aChildNode} ); 399*b1cdbd2cSJim Jagielski } 400*b1cdbd2cSJim Jagielski 401*b1cdbd2cSJim Jagielski 402*b1cdbd2cSJim Jagielski 403*b1cdbd2cSJim Jagielski 404*b1cdbd2cSJim Jagielski /** Create a TreeModelEvent that indicates changes at those children of 405*b1cdbd2cSJim Jagielski the specified node with the specified indices. 406*b1cdbd2cSJim Jagielski */ createChangeEvent(AccTreeNode aNode, Vector aChildIndices)407*b1cdbd2cSJim Jagielski protected TreeModelEvent createChangeEvent (AccTreeNode aNode, Vector aChildIndices) 408*b1cdbd2cSJim Jagielski { 409*b1cdbd2cSJim Jagielski // Build a list of child objects that are indicated by the given indices. 410*b1cdbd2cSJim Jagielski int nCount = aChildIndices.size(); 411*b1cdbd2cSJim Jagielski Object aChildObjects[] = new Object[nCount]; 412*b1cdbd2cSJim Jagielski int nChildIndices[] = new int[nCount]; 413*b1cdbd2cSJim Jagielski for (int i=0; i<nCount; i++) 414*b1cdbd2cSJim Jagielski { 415*b1cdbd2cSJim Jagielski int nIndex = ((Integer)aChildIndices.elementAt(i)).intValue(); 416*b1cdbd2cSJim Jagielski aChildObjects[i] = aNode.getChild (nIndex); 417*b1cdbd2cSJim Jagielski nChildIndices[i] = nIndex; 418*b1cdbd2cSJim Jagielski } 419*b1cdbd2cSJim Jagielski 420*b1cdbd2cSJim Jagielski return new TreeModelEvent (this, 421*b1cdbd2cSJim Jagielski createPath(aNode), 422*b1cdbd2cSJim Jagielski nChildIndices, 423*b1cdbd2cSJim Jagielski aChildObjects); 424*b1cdbd2cSJim Jagielski } 425*b1cdbd2cSJim Jagielski 426*b1cdbd2cSJim Jagielski 427*b1cdbd2cSJim Jagielski 428*b1cdbd2cSJim Jagielski /** 429*b1cdbd2cSJim Jagielski * broadcast a tree event in a seperate Thread 430*b1cdbd2cSJim Jagielski * must override fire method 431*b1cdbd2cSJim Jagielski */ 432*b1cdbd2cSJim Jagielski class EventRunner implements Runnable 433*b1cdbd2cSJim Jagielski { run()434*b1cdbd2cSJim Jagielski public void run() 435*b1cdbd2cSJim Jagielski { 436*b1cdbd2cSJim Jagielski for(int i = 0; i < maTMListeners.size(); i++) 437*b1cdbd2cSJim Jagielski { 438*b1cdbd2cSJim Jagielski fire( (TreeModelListener)maTMListeners.get(i) ); 439*b1cdbd2cSJim Jagielski } 440*b1cdbd2cSJim Jagielski } 441*b1cdbd2cSJim Jagielski fire( TreeModelListener l)442*b1cdbd2cSJim Jagielski protected void fire( TreeModelListener l) { } 443*b1cdbd2cSJim Jagielski } 444*b1cdbd2cSJim Jagielski 445*b1cdbd2cSJim Jagielski 446*b1cdbd2cSJim Jagielski getBroadcaster(Object aObject)447*b1cdbd2cSJim Jagielski protected XAccessibleEventBroadcaster getBroadcaster (Object aObject) 448*b1cdbd2cSJim Jagielski { 449*b1cdbd2cSJim Jagielski if (aObject instanceof AccTreeNode) 450*b1cdbd2cSJim Jagielski return (XAccessibleEventBroadcaster) UnoRuntime.queryInterface ( 451*b1cdbd2cSJim Jagielski XAccessibleEventBroadcaster.class, ((AccTreeNode)aObject).getContext()); 452*b1cdbd2cSJim Jagielski else 453*b1cdbd2cSJim Jagielski return null; 454*b1cdbd2cSJim Jagielski } 455*b1cdbd2cSJim Jagielski registerAccListener( Object aObject )456*b1cdbd2cSJim Jagielski protected void registerAccListener( Object aObject ) 457*b1cdbd2cSJim Jagielski { 458*b1cdbd2cSJim Jagielski // register this as listener for XAccessibleEventBroadcaster 459*b1cdbd2cSJim Jagielski // implementations 460*b1cdbd2cSJim Jagielski XAccessibleEventBroadcaster xBroadcaster = getBroadcaster( aObject ); 461*b1cdbd2cSJim Jagielski if (xBroadcaster != null) 462*b1cdbd2cSJim Jagielski { 463*b1cdbd2cSJim Jagielski xBroadcaster.addEventListener( mxListener ); 464*b1cdbd2cSJim Jagielski } 465*b1cdbd2cSJim Jagielski } 466*b1cdbd2cSJim Jagielski removeAccListener( Object aObject )467*b1cdbd2cSJim Jagielski protected void removeAccListener( Object aObject ) 468*b1cdbd2cSJim Jagielski { 469*b1cdbd2cSJim Jagielski XAccessibleEventBroadcaster xBroadcaster = getBroadcaster( aObject ); 470*b1cdbd2cSJim Jagielski if (xBroadcaster != null) 471*b1cdbd2cSJim Jagielski { 472*b1cdbd2cSJim Jagielski xBroadcaster.removeEventListener( mxListener ); 473*b1cdbd2cSJim Jagielski } 474*b1cdbd2cSJim Jagielski } 475*b1cdbd2cSJim Jagielski 476*b1cdbd2cSJim Jagielski 477*b1cdbd2cSJim Jagielski setCanvas(Canvas aCanvas)478*b1cdbd2cSJim Jagielski public void setCanvas (Canvas aCanvas) 479*b1cdbd2cSJim Jagielski { 480*b1cdbd2cSJim Jagielski maCanvas = aCanvas; 481*b1cdbd2cSJim Jagielski } 482*b1cdbd2cSJim Jagielski getCanvas()483*b1cdbd2cSJim Jagielski public Canvas getCanvas () 484*b1cdbd2cSJim Jagielski { 485*b1cdbd2cSJim Jagielski return maCanvas; 486*b1cdbd2cSJim Jagielski } 487*b1cdbd2cSJim Jagielski updateNode(XAccessibleContext xSource, java.lang.Class class1)488*b1cdbd2cSJim Jagielski public void updateNode (XAccessibleContext xSource, java.lang.Class class1) 489*b1cdbd2cSJim Jagielski { 490*b1cdbd2cSJim Jagielski updateNode (xSource, class1,null); 491*b1cdbd2cSJim Jagielski } 492*b1cdbd2cSJim Jagielski 493*b1cdbd2cSJim Jagielski /** Get a list of children of the node associated with xSource that are 494*b1cdbd2cSJim Jagielski affected by the given handlers. Fire events that these children may 495*b1cdbd2cSJim Jagielski have changed in the tree view. Update the canvas representation of 496*b1cdbd2cSJim Jagielski xSource. 497*b1cdbd2cSJim Jagielski */ updateNode(XAccessibleContext xSource, java.lang.Class class1, java.lang.Class class2)498*b1cdbd2cSJim Jagielski public AccTreeNode updateNode (XAccessibleContext xSource, 499*b1cdbd2cSJim Jagielski java.lang.Class class1, java.lang.Class class2) 500*b1cdbd2cSJim Jagielski { 501*b1cdbd2cSJim Jagielski AccessibleTreeNode aTreeNode = maNodeMap.GetNode (xSource); 502*b1cdbd2cSJim Jagielski AccTreeNode aNode = null; 503*b1cdbd2cSJim Jagielski if (mbVerbose) 504*b1cdbd2cSJim Jagielski System.out.println ("updating node " + xSource + " " + aTreeNode); 505*b1cdbd2cSJim Jagielski if (aTreeNode instanceof AccTreeNode) 506*b1cdbd2cSJim Jagielski { 507*b1cdbd2cSJim Jagielski aNode = (AccTreeNode) aTreeNode; 508*b1cdbd2cSJim Jagielski // Get list of affected children. 509*b1cdbd2cSJim Jagielski Vector aChildIndices = (aNode).updateChildren ( 510*b1cdbd2cSJim Jagielski class1, class2); 511*b1cdbd2cSJim Jagielski // Fire events that these children may have changed. 512*b1cdbd2cSJim Jagielski fireTreeNodesChanged ( 513*b1cdbd2cSJim Jagielski createChangeEvent (aNode, aChildIndices)); 514*b1cdbd2cSJim Jagielski } 515*b1cdbd2cSJim Jagielski return aNode; 516*b1cdbd2cSJim Jagielski } 517*b1cdbd2cSJim Jagielski 518*b1cdbd2cSJim Jagielski /** The listener to be registered with the accessible objects. 519*b1cdbd2cSJim Jagielski * Could be set to 'this' for same-thread event delivery, or to an 520*b1cdbd2cSJim Jagielski * instance of QueuedListener for multi-threaded delivery. May 521*b1cdbd2cSJim Jagielski * not be changed, since this would trip the 522*b1cdbd2cSJim Jagielski * register/removeAccListener logic. */ 523*b1cdbd2cSJim Jagielski private final XAccessibleEventListener mxListener; 524*b1cdbd2cSJim Jagielski 525*b1cdbd2cSJim Jagielski // Map to translate from accessible object to corresponding tree node. 526*b1cdbd2cSJim Jagielski private NodeMap maNodeMap; 527*b1cdbd2cSJim Jagielski 528*b1cdbd2cSJim Jagielski // If the lock count is higher then zero, then no events are processed. 529*b1cdbd2cSJim Jagielski private int mnLockCount; 530*b1cdbd2cSJim Jagielski 531*b1cdbd2cSJim Jagielski private Canvas maCanvas; 532*b1cdbd2cSJim Jagielski 533*b1cdbd2cSJim Jagielski private EventListener maEventListener; 534*b1cdbd2cSJim Jagielski } 535