diff options
author | Andre Fischer <af@openoffice.org> | 2002-04-02 13:06:32 +0000 |
---|---|---|
committer | Andre Fischer <af@openoffice.org> | 2002-04-02 13:06:32 +0000 |
commit | 847ceddeaddff411adf27c06e3131e818ac50154 (patch) | |
tree | 72f265bffbc023dc51d52497eabf584fb2ebe34e /toolkit/test/accessibility/AccessibilityTreeModel.java | |
parent | 76a820f393a9d87ed920efe3ef8e3ea6d92000af (diff) |
Performance improvements: Handler have become non-static members of tree nodes and cache data to prevent UNO queries. Increased type safety by introduction of tree node hierarchy.
Diffstat (limited to 'toolkit/test/accessibility/AccessibilityTreeModel.java')
-rw-r--r-- | toolkit/test/accessibility/AccessibilityTreeModel.java | 636 |
1 files changed, 324 insertions, 312 deletions
diff --git a/toolkit/test/accessibility/AccessibilityTreeModel.java b/toolkit/test/accessibility/AccessibilityTreeModel.java index ab933df174df..f005df4c8e9b 100644 --- a/toolkit/test/accessibility/AccessibilityTreeModel.java +++ b/toolkit/test/accessibility/AccessibilityTreeModel.java @@ -20,18 +20,45 @@ import com.sun.star.lang.XServiceInfo; public class AccessibilityTreeModel implements TreeModel, XAccessibleEventListener { - public AccessibilityTreeModel( Object aRoot ) + // Map to translate from accessible object to corresponding tree node. + protected HashMap maXAccessibleToNode; + + // Making both of these static is clearly a hack. + protected static MessageInterface maMessageArea; + protected static Print maPrinter; + protected static boolean mbVerbose = true; + + // If the lock count is higher then zero, then no events are processed. + private int mnLockCount; + + // The list of TreeModelListener objects. + private Vector maTMListeners; + + // default handlers, Vector<HandlerPair> + private static Vector aDefaultHandlers; + private static NodeHandler maContextHandler = new AccessibleContextHandler(); + private static NodeHandler maTextHandler = new AccessibleTextHandler(); + private static NodeHandler maEditableTextHandler = new AccessibleEditableTextHandler(); + private static NodeHandler maComponentHandler = new AccessibleComponentHandler(); + private static NodeHandler maExtendedComponentHandler = new AccessibleExtendedComponentHandler(); + private static NodeHandler maActionHandler = new AccessibleActionHandler(); + private static NodeHandler maImageHandler = new AccessibleImageHandler(); + private static NodeHandler maTableHandler = new AccessibleTableHandler(); + private static NodeHandler maHypertextHandler = new AccessibleHypertextHandler(); + private static NodeHandler maHyperlinkHandler = new AccessibleHyperlinkHandler(); + private static NodeHandler maTreeHandler = new AccessibleTreeHandler(); + + public AccessibilityTreeModel (Object aRoot, MessageInterface aMessageArea, Print aPrinter) { // create default node (unless we have a 'proper' node) - if( ! (aRoot instanceof AccTreeNode) ) - aRoot = createDefaultNode( aRoot ); + if( ! (aRoot instanceof AccessibleTreeNode) ) + aRoot = new StringNode ("Root", null); maRoot = aRoot; + maMessageArea = aMessageArea; + maPrinter = aPrinter; - aListeners = new Vector(); - aParents = new HashMap(); - aChildren = new HashMap(); - aNodes = new HashMap(); - aNodes.put( normalize(maRoot), maRoot ); + maTMListeners = new Vector(); + maXAccessibleToNode = new HashMap (); // syncronous or asyncronous event delivery? (i.e. same thread // or in s seperate event delivery thread) @@ -39,6 +66,29 @@ public class AccessibilityTreeModel xListener = new QueuedListener(); // asyncronous event delivery } + /** Lock the tree. While the tree is locked, events from the outside are + not processed. Lock the tree when you change its internal structure. + */ + public void lock () + { + mnLockCount += 1; + } + + /** Unlock the tree. After unlocking the tree as many times as locking + it, a treeStructureChange event is sent to the event listeners. + @param aNodeHint + If not null and treeStructureChange events are thrown then this + node is used as root of the modified subtree. + */ + public void unlock (AccessibleTreeNode aNodeHint) + { + mnLockCount -= 1; + if (mnLockCount == 0) + { + if (aNodeHint instanceof AccTreeNode) + fireTreeStructureChanged (createEvent (((AccTreeNode)aNodeHint).getAccessible())); + } + } // // the root node @@ -58,198 +108,150 @@ public class AccessibilityTreeModel public int getChildCount(Object aParent) { - return (aParent instanceof AccTreeNode) ? - ((AccTreeNode)aParent).getChildCount() : 0; + return (aParent instanceof AccessibleTreeNode) ? + ((AccessibleTreeNode)aParent).getChildCount() : 0; } - public Object getChild(Object aParent, int nIndex) + public Object getChild (Object aParent, int nIndex) { - Object aRet = (aParent instanceof AccTreeNode) ? - ((AccTreeNode)aParent).getChild(nIndex) : null; - setNode( aParent, nIndex, aRet ); // update tree cache - return aRet; + Object aChild = null; + try + { + if (aParent instanceof AccessibleTreeNode) + aChild = getChild ((AccessibleTreeNode)aParent, nIndex); + else + System.out.println ("getChild called for unknown parent node"); + } + catch (com.sun.star.lang.IndexOutOfBoundsException e) + { + aChild = ("no child " + nIndex + " from " + aParent + ": " + e); + } + return aChild; + } + + /** Delegate the request to the parent and then register listeners at + the child and add the child to the canvas. + */ + public synchronized AccessibleTreeNode getChild (AccessibleTreeNode aParent, int nIndex) + throws com.sun.star.lang.IndexOutOfBoundsException + { + AccessibleTreeNode aChild = null; + if (aParent != null) + aChild = aParent.getChild(nIndex); + registerAccListener (aChild); + + // Keep translation table up-to-date. + if (aChild != null) + if (aChild instanceof AccTreeNode) + { + maXAccessibleToNode.put (((AccTreeNode)aChild).getAccessible(), aChild); + addToCanvas ((AccTreeNode)aChild); + } + if (aChild == null) + System.out.println ("getChild: child not found"); + return aChild; } /** iterate over all children and look for child */ - public int getIndexOfChild(Object aParent, Object aChild) + public int getIndexOfChild (Object aParent, Object aChild) { - aChild = normalize( aChild ); + int nIndex = -1; + try + { + if ((aParent instanceof AccessibleTreeNode) && (aChild instanceof AccessibleTreeNode)) + { + AccessibleTreeNode aParentNode = (AccessibleTreeNode) aParent; + AccessibleTreeNode aChildNode = (AccessibleTreeNode) aChild; - // compare to all children - int nChildCount = getChildCount( aParent ); - for( int i = 0; i < nChildCount; i++ ) + int nChildCount = aParentNode.getChildCount(); + for( int i = 0; i < nChildCount; i++ ) + { + if (aChildNode.equals (aParentNode.getChild (i))) + { + nIndex = i; + break; + } + } + } + } + catch (com.sun.star.lang.IndexOutOfBoundsException e) { - if( aChild.equals( normalize( getChild(aParent, i) ) ) ) - return i; + // Return -1 by falling through. } // not found? - return -1; + return nIndex; } - public boolean isLeaf(Object aNode) + public boolean isLeaf (Object aNode) { - return (aNode instanceof AccTreeNode) ? - ((AccTreeNode)aNode).isLeaf() : true; + return (aNode instanceof AccessibleTreeNode) ? + ((AccessibleTreeNode)aNode).isLeaf() : true; } - // - // tree cache and child cache - // - - /** store parents of an object in the tree; HashMap<Object> */ - private HashMap aParents; - - /** store a vector with the children in each tree; - * HashMap<Vector<Object>> */ - private HashMap aChildren; - /** store a mapping of 'normalized' nodes to nodes in the tree */ - private HashMap aNodes; - - - /** normalize an object reference: - * 0) for an Any, get the containing Object - * 1) for AccTreeNode, get the data object - * 2) for XAccessible, get the accessible object - * 3) cast all UNO objects to XInterface - */ - static protected Object normalize(Object aObject) + /** Remove a node (and all children) from the tree model. + */ + protected synchronized void removeNode (AccessibleTreeNode aNode) { - // 0) for an Any, get the containing Object - if( aObject instanceof Any ) - aObject = ((Any)aObject).getObject(); - - // 1) for AccTreeNode, get the data object - if( aObject instanceof AccTreeNode ) - aObject = ((AccTreeNode)aObject).getDataObject(); - - if( aObject instanceof XInterface ) + try { - // 2) for XAccessible, get the accessible object - XAccessible xAcc = (XAccessible)UnoRuntime.queryInterface( - XAccessible.class, aObject); - if( xAcc != null ) - aObject = xAcc.getAccessibleContext(); - - // 3) cast all UNO objects to XInterface - aObject = (XInterface)UnoRuntime.queryInterface( XInterface.class, - aObject); - } - return aObject; - } - - /** add a parent/child int the node cache */ - protected void setNode(Object aOParent, int nIndex, Object aOChild) - { - Object aParent = normalize(aOParent); - Object aChild = normalize(aOChild); - - // store nodes - aNodes.put( aParent, aOParent ); - aNodes.put( aChild, aOChild ); - - // store the child's parent - aParents.put( aChild, aParent ); + if( aNode == null ) + return; + removeAccListener (aNode); + removeFromCanvas (aNode); + if (aNode instanceof AccTreeNode) + maXAccessibleToNode.remove (((AccTreeNode)aNode).getAccessible()); + AccessibleTreeNode aParent = aNode.getParent(); + if (aParent != null) + { + int nIndex = aParent.indexOf(aNode); + aParent.removeChild (nIndex); + } - // store the parent's child - Vector aKids = (Vector)aChildren.get( aParent ); - if( aKids == null ) + // depth-first removal of children + while (aNode.getChildCount() > 0) + removeNode (aNode.getChild (0)); + } + catch (com.sun.star.lang.IndexOutOfBoundsException e) { - // no children known... insert a new vector - aKids = new Vector(); - aChildren.put( aParent, aKids ); + // Ignore. } - - // make sure we have enough room - if( aKids.size() <= nIndex ) - aKids.setSize( nIndex + 1 ); // alternative: use child count - - // add child at appropriate positions; remove old listeners, - // get new ones - removeAccListener( aKids.elementAt( nIndex ) ); - aKids.setElementAt( aChild, nIndex ); - registerAccListener( aKids.elementAt( nIndex ) ); - - // update canvas - addToCanvas( aChild ); } - /** remove a node (and all children) from the node cache */ - protected void removeNode(Object aNode) + protected synchronized boolean addNode (AccTreeNode aParentNode, XAccessible xNewChild) { - if( aNode == null ) - return; - - aNode = normalize( aNode ); - removeAccListener( aNode ); - - // get parent + kids (before this information is deleted) - Vector aKids = (Vector)aChildren.get( aNode ); - Object aParent = aParents.get( aNode ); - - // remove information about this node - removeFromCanvas( aNode ); // update canvas - aParents.remove( aNode ); - aChildren.remove( aNode ); - aNodes.remove( aNode ); + boolean bRet = false; - // depth-first removal of children - int nLength = (aKids == null) ? 0 : aKids.size(); - for( int i = nLength-1; i >= 0; i-- ) + AccessibleTreeNode aChildNode = (AccessibleTreeNode)maXAccessibleToNode.get (xNewChild); + if (aChildNode == null) { - removeNode( aKids.elementAt(i) ); - } - - // remove from parents' child vector - if( aParent != null ) - { - Vector aParentKids = (Vector)aChildren.get( aParent ); - if( aParentKids != null ) - aParentKids.remove( aNode ); + AccTreeNode aChild = (AccTreeNode)((AccTreeNode)aParentNode).addAccessibleChild (xNewChild); + TreePath aPath = new TreePath (createPath (aChild)); + if (aChild != null) + { + registerAccListener (aChild); + maXAccessibleToNode.put (aChild.getAccessible(), aChild); + addToCanvas (aChild); + } + bRet = true; } - } + else + System.out.println ("node already present"); - /** determine whether this node is in the node cache */ - protected boolean knowsNode(Object aNode) - { - // we never 'know' null; we 'know' a node if it has a parent - return (aNode != null) && (aNodes.get(normalize(aNode)) != null); + return bRet; } - protected Object getNode(Object aObject) - { - return aNodes.get( normalize(aObject) ); - } - - /** recursively traverse aParents, and add nodes to path in - * post-order fashion. This causes the root to be the first - * element, just as demanded by TreeModelEvent. - * @see javax.swing.event.TreeModelEvent#TreeModelEvent - */ - private void createPath(Object aNode, Vector aPath) - { - aNode = normalize(aNode); - Object aParent = aParents.get(aNode); - if( aParent != null ) - createPath( aParent, aPath ); - Object aPathElem = aNodes.get(aNode); - if( aPathElem != null ) - aPath.add( aPathElem ); - else - System.out.println("Unknown node in path! (" + aNode + - ", pos. " + aPath.size() + ")"); - } /** create path to node, suitable for TreeModelEvent constructor * @see javax.swing.event.TreeModelEvent#TreeModelEvent */ - protected Object[] createPath(Object aNode) + protected Object[] createPath (AccessibleTreeNode aNode) { Vector aPath = new Vector(); - createPath( aNode, aPath ); + aNode.createPath (aPath); return aPath.toArray(); } @@ -260,93 +262,88 @@ public class AccessibilityTreeModel // tree cache, and we should get removed as soon as they are out. // - Vector aListeners; - public void addTreeModelListener(TreeModelListener l) { - aListeners.add(l); + maTMListeners.add(l); } public void removeTreeModelListener(TreeModelListener l) { - aListeners.remove(l); + maTMListeners.remove(l); } protected void fireTreeNodesChanged(TreeModelEvent e) { System.out.println("treeNodesChanges: " + e); - for(int i = 0; i < aListeners.size(); i++) + for(int i = 0; i < maTMListeners.size(); i++) { - ((TreeModelListener)aListeners.get(i)).treeNodesChanged(e); + ((TreeModelListener)maTMListeners.get(i)).treeNodesChanged(e); } } protected void fireTreeNodesInserted(final TreeModelEvent e) { System.out.println("treeNodesInserted: " + e); - for(int i = 0; i < aListeners.size(); i++) + for(int i = 0; i < maTMListeners.size(); i++) { - ((TreeModelListener)aListeners.get(i)).treeNodesInserted(e); + ((TreeModelListener)maTMListeners.get(i)).treeNodesInserted(e); } } protected void fireTreeNodesRemoved(final TreeModelEvent e) { System.out.println("treeNodesRemoved: " + e); - for(int i = 0; i < aListeners.size(); i++) + for(int i = 0; i < maTMListeners.size(); i++) { - ((TreeModelListener)aListeners.get(i)).treeNodesRemoved(e); + ((TreeModelListener)maTMListeners.get(i)).treeNodesRemoved(e); } } - protected void fireTreeStructureChanged(final TreeModelEvent e) + protected synchronized void fireTreeStructureChanged(final TreeModelEvent e) { System.out.println("treeStructureChanged: " + e); - for(int i = 0; i < aListeners.size(); i++) + for(int i = 0; i < maTMListeners.size(); i++) { - ((TreeModelListener)aListeners.get(i)).treeStructureChanged(e); + ((TreeModelListener)maTMListeners.get(i)).treeStructureChanged(e); } } - protected TreeModelEvent createEvent( Object aNode ) + protected TreeModelEvent createEvent (XAccessible xParent) { - return createEvent( aNode, null ); + return createEvent (xParent, null ); } - protected TreeModelEvent createEvent( Object aParent, Object aChild ) + /** Create a TreeModelEvent object that informs listeners that one child + has been removed from or inserted into its parent. + */ + protected TreeModelEvent createEvent (XAccessible xParent, XAccessible xChild) { // get parent node and create the tree path - Object aParentNode = getNode( aParent ); - Object[] aPath = createPath( aParentNode ); - - // if we already know the node (e.g. when deleting a node), - // use the position from the node cache. Else (e.g. when - // inserting a node), call getIndexOfChild to look for it. - int nIndex =-1; - if( aChild != null ) - { - if( knowsNode( aChild ) ) - { - Vector aKids = (Vector)aChildren.get( aParent ); - if( aKids != null ) - { - nIndex = aKids.indexOf( getNode( aChild ) ); - } - } - else - nIndex = getIndexOfChild( aParentNode, aChild ); - } - - - // If we have a position, broadcast the position, otherwise - // create a 'position-less' event without the child info. - return ( nIndex == -1 ) - ? new TreeModelEvent( this, aPath ) - : new TreeModelEvent( this, aPath, - new int[] { nIndex }, - new Object[] { getNode( aChild ) } ); + AccessibleTreeNode aParentNode = (AccessibleTreeNode)maXAccessibleToNode.get (xParent); + Object[] aPathToParent = createPath (aParentNode); + + AccessibleTreeNode aChildNode = null; + if (xChild != null) + aChildNode = (AccessibleTreeNode)maXAccessibleToNode.get (xChild); + int nIndexInParent = -1; + if (xChild != null) + nIndexInParent = aParentNode.indexOf (aChildNode); + + System.out.println (aParentNode + " " + aChildNode); + + if (nIndexInParent == -1) + // This event may be passed only to treeStructureChanged of the listeners. + return new TreeModelEvent (this, + aPathToParent); + else + // General purpose event for removing or inserting known nodes. + return new TreeModelEvent (this, + aPathToParent, + new int[] {nIndexInParent}, + new Object[] {aChildNode} ); } + /** * broadcast a tree event in a seperate Thread * must override fire method @@ -355,9 +352,9 @@ public class AccessibilityTreeModel { public void run() { - for(int i = 0; i < aListeners.size(); i++) + for(int i = 0; i < maTMListeners.size(); i++) { - fire( (TreeModelListener)aListeners.get(i) ); + fire( (TreeModelListener)maTMListeners.get(i) ); } } @@ -375,7 +372,7 @@ public class AccessibilityTreeModel protected XAccessibleEventBroadcaster getBroadcaster( Object aObject ) { if( aObject instanceof AccTreeNode ) - aObject = ((AccTreeNode)aObject).getDataObject(); + aObject = ((AccTreeNode)aObject).getContext(); return (XAccessibleEventBroadcaster) UnoRuntime.queryInterface ( XAccessibleEventBroadcaster.class, aObject); } @@ -411,105 +408,78 @@ public class AccessibilityTreeModel // static methods + members for creating default nodes // - // default handlers, Vector<HandlerPair> - private static Vector aDefaultHandlers; - - // initialize default handlers - static - { - aDefaultHandlers = new Vector(); - aDefaultHandlers.add( - new HandlerPair( Vector.class, - new VectorHandler() ) ); - - aDefaultHandlers.add( - new HandlerPair( XAccessibleContext.class, - new AccessibleContextHandler() ) ); - aDefaultHandlers.add( - new HandlerPair( XAccessibleContext.class, - new AccessibleTreeHandler() ) ); - aDefaultHandlers.add( - new HandlerPair( XAccessibleText.class, - new AccessibleTextHandler() ) ); - aDefaultHandlers.add( - new HandlerPair( XAccessibleComponent.class, - new AccessibleComponentHandler() ) ); - aDefaultHandlers.add( - new HandlerPair( XAccessibleExtendedComponent.class, - new AccessibleExtendedComponentHandler() ) ); - aDefaultHandlers.add( - new HandlerPair( XAccessibleAction.class, - new AccessibleActionHandler() ) ); - aDefaultHandlers.add( - new HandlerPair( XAccessibleImage.class, - new AccessibleImageHandler() ) ); - aDefaultHandlers.add( - new HandlerPair( XAccessibleTable.class, - new AccessibleTableHandler() ) ); - aDefaultHandlers.add( - new HandlerPair( XAccessibleEditableText.class, - new AccessibleEditableTextHandler() ) ); - aDefaultHandlers.add( - new HandlerPair( XAccessibleHypertext.class, - new AccessibleHypertextHandler() ) ); - aDefaultHandlers.add( - new HandlerPair( XAccessibleHyperlink.class, - new AccessibleHyperlinkHandler() ) ); - - // ... ADD NEW DEFAULT HANDLERS HERE ... - - } - /** add default handlers based on the supported interfaces */ - public static void addDefaultHandlers( AccTreeNode aNode ) + public static void addDefaultHandlers (AccTreeNode aNode, XAccessibleContext xContext) { - Object aObject = aNode.getDataObject(); - - // try each type - Enumeration aEnum = aDefaultHandlers.elements(); - while( aEnum.hasMoreElements() ) + if (false) { - HandlerPair aPair = (HandlerPair)aEnum.nextElement(); - Class aType = aPair.aType; + // Slow but complete version: try each handler type separately. + aNode.addHandler (maContextHandler.createHandler (xContext)); + aNode.addHandler (maTextHandler.createHandler (xContext)); + aNode.addHandler (maEditableTextHandler.createHandler (xContext)); + aNode.addHandler (maComponentHandler.createHandler (xContext)); + aNode.addHandler (maExtendedComponentHandler.createHandler (xContext)); + aNode.addHandler (maActionHandler.createHandler (xContext)); + aNode.addHandler (maImageHandler.createHandler (xContext)); + aNode.addHandler (maTableHandler.createHandler (xContext)); + aNode.addHandler (maHypertextHandler.createHandler (xContext)); + aNode.addHandler (maHyperlinkHandler.createHandler (xContext)); + aNode.addHandler (maTreeHandler.createHandler (xContext)); + } + else + { + // Exploit dependencies between interfaces. + NodeHandler aHandler; + aNode.addHandler (maContextHandler.createHandler (xContext)); - // try instanceof, and a UNO query, if we have an XInterface - if( aType.isInstance( aObject ) ) + aHandler = maTextHandler.createHandler (xContext); + if (aHandler != null) { - aNode.addHandler( aPair.aHandler ); + aNode.addHandler (aHandler); + aNode.addHandler (maEditableTextHandler.createHandler (xContext)); + aNode.addHandler (maHypertextHandler.createHandler (xContext)); + aNode.addHandler (maHyperlinkHandler.createHandler (xContext)); } - else if( XInterface.class.isAssignableFrom( aType ) ) + aHandler = maComponentHandler.createHandler (xContext); + if (aHandler != null) { - Object aQuery = UnoRuntime.queryInterface(aType, aObject); - if( aQuery != null ) - aNode.addHandler( aPair.aHandler ); + aNode.addHandler (aHandler); + aNode.addHandler (maExtendedComponentHandler.createHandler (xContext)); } + aNode.addHandler (maActionHandler.createHandler (xContext)); + aNode.addHandler (maImageHandler.createHandler (xContext)); + aNode.addHandler (maTableHandler.createHandler (xContext)); + aNode.addHandler (maTreeHandler.createHandler (xContext)); } } /** create a node with the default handlers */ - public static AccTreeNode createDefaultNode( Object aObject ) + public static AccTreeNode createDefaultNode (XAccessible xAccessible, AccessibleTreeNode aParent) { // default: aObject + aDisplay - Object aDisplay = aObject; + String sDisplay; // if we are accessible, we use the context + name instead - XAccessible xAccessible = - (XAccessible) UnoRuntime.queryInterface ( - XAccessible.class, aObject); + XAccessibleContext xContext = null; if (xAccessible != null) - { - XAccessibleContext aContext = xAccessible.getAccessibleContext(); + xContext = xAccessible.getAccessibleContext(); + if (xContext != null) + sDisplay = xContext.getAccessibleName(); + else + sDisplay = new String ("not accessible"); - // for accessibles, use context + name! - aObject = aContext; - aDisplay = aContext.getAccessibleName(); - } // create node, and add default handlers - AccTreeNode aNode = new AccTreeNode( aObject, aDisplay ); - AccessibilityTreeModel.addDefaultHandlers( aNode ); + AccTreeNode aNode = new AccTreeNode (xContext, sDisplay, aParent); + AccessibilityTreeModel.addDefaultHandlers (aNode, xContext); + + if (mbVerbose) + maPrinter.print (". "); + + if (aNode == null) + System.out.println ("createDefaultNode == null"); return aNode; } @@ -537,7 +507,7 @@ public class AccessibilityTreeModel public void disposing( EventObject aEvent) { - System.out.println("dispose: " + objectToString(aEvent.Source)); + /* System.out.println("dispose: " + objectToString(aEvent.Source)); if( knowsNode( aEvent.Source ) ) { @@ -546,7 +516,7 @@ public class AccessibilityTreeModel removeNode( aEvent.Source ); // fireTreeStructureChanged( createEvent( getRoot() ) ); } - + */ } static final String[] aEventNames = @@ -562,39 +532,74 @@ public class AccessibilityTreeModel "[UNKNOWN]" }; - public void notifyEvent( AccessibleEventObject aEvent ) + /** This method is called from accessible objects that broadcast + modifications of themselves or from their children. The event is + processed only, except printing some messages, if the tree is not + locked. It should be locked during changes to its internal + structure like expanding nodes. + */ + public synchronized void notifyEvent( AccessibleEventObject aEvent ) { int nId = aEvent.EventId; if( (nId < 0) || (nId >= aEventNames.length) ) nId = 0; - Object aSource = normalize( aEvent.Source ); - Object aOld = normalize( aEvent.OldValue ); - Object aNew = normalize( aEvent.NewValue ); + System.out.println( "notify: " + aEvent.EventId + " " + + aEventNames[nId] + ": " + + objectToString(aEvent.Source) + " " + + objectToString(aEvent.OldValue) + "->" + + objectToString(aEvent.NewValue) ); - System.out.println( "notify: " + aEvent.EventId + " " + - aEventNames[nId] + ": " + - objectToString(aEvent.Source) + " (" + - (knowsNode(aEvent.Source) ? "known" : "unknown") + - "), " + - objectToString(aEvent.OldValue) + "->" + - objectToString(aEvent.NewValue) ); + if (mnLockCount > 0) + { + System.out.println ("ignoring event because tree is locked"); + return; + } + XAccessible xSource = (XAccessible)UnoRuntime.queryInterface( + XAccessible.class,aEvent.Source); switch( aEvent.EventId ) { case AccessibleEventId.ACCESSIBLE_CHILD_EVENT: // fire insertion and deletion events: - if( aOld != null ) + if (aEvent.OldValue != null) { - TreeModelEvent aTreeEvent = createEvent( aSource, aOld ); - removeNode( aOld ); - fireTreeNodesRemoved( aTreeEvent ); + XAccessible xOld = (XAccessible)UnoRuntime.queryInterface( + XAccessible.class,aEvent.OldValue); + // Create event before removing the node to get the old + // index of the node. + TreeModelEvent aRemoveEvent = createEvent (xSource, xOld); + removeNode ((AccessibleTreeNode)maXAccessibleToNode.get (xOld)); + fireTreeNodesRemoved (aRemoveEvent); } - if( aNew != null ) + // Insertion and removal of children should be mutually + // exclusive. But then there is this 'should' ... + if (aEvent.NewValue != null) { - fireTreeNodesInserted( createEvent( aSource, aNew ) ); + XAccessible xNew = (XAccessible)UnoRuntime.queryInterface( + XAccessible.class,aEvent.NewValue); + // Create event after inserting it so that its new index + // in the parent can be determined. + AccessibleTreeNode aParentNode = (AccessibleTreeNode)maXAccessibleToNode.get (xSource); + if (aParentNode instanceof AccTreeNode) + { + if (addNode ((AccTreeNode)aParentNode, xNew)) + { + ((AccTreeNode)aParentNode).update (); + updateOnCanvas (xSource); + + // A call to fireTreeNodesInserted for xNew + // should be sufficient but at least the + // StringNode object that contains the number of + // children also changes and we do not know its + // index relative to its parent. Therefore the + // more expensive fireTreeStructureChanged is + // necessary. + fireTreeStructureChanged (createEvent (xSource)); + } + } } break; case AccessibleEventId.ACCESSIBLE_TABLE_MODEL_CHANGED: @@ -628,8 +633,13 @@ public class AccessibilityTreeModel case AccessibleEventId.LABEL_FOR_PROPERTY: case AccessibleEventId.LABELED_BY_PROPERTY: case AccessibleEventId.MEMBER_OF_PROPERTY: - fireTreeNodesChanged( createEvent( aSource ) ); - updateOnCanvas( aSource ); + // fireTreeNodesChanged (createEvent + // (xSource)); + // Some child(s) of xSource have changed. We do not know + // which so all we can do is send a structure change event + // to all listeners. + fireTreeStructureChanged (createEvent (xSource)); + updateOnCanvas (xSource); break; @@ -660,13 +670,15 @@ public class AccessibilityTreeModel return xAcc; } - protected void addToCanvas( Object aObject ) + protected void addToCanvas (AccTreeNode aNode) { - XAccessibleContext xContext = getContext( aObject ); - if( (maCanvas != null) && (xContext != null) ) - maCanvas.addContext( xContext, - new TreePath( createPath( xContext ) ) ); - } + return; + /* XAccessibleContext xContext = aNode.getContext(); + if ((maCanvas != null) && (xContext != null)) + maCanvas.addContext ( + xContext, + new TreePath (createPath (aNode))); + */ } protected void removeFromCanvas( Object aObject ) { |