diff options
author | Daniel Vogelheim <dvo@openoffice.org> | 2002-03-08 16:30:18 +0000 |
---|---|---|
committer | Daniel Vogelheim <dvo@openoffice.org> | 2002-03-08 16:30:18 +0000 |
commit | 75345d9b5845e57c3f83ade2266f59fe01ac6572 (patch) | |
tree | 1c5fc8380ea0a7a9491804e7d45344f9e733a159 /toolkit/test/accessibility | |
parent | a403b7e53223c93b47a1afa0d81da155e6920873 (diff) |
Now use custom tree model in order to create data on-the-fly.
Diffstat (limited to 'toolkit/test/accessibility')
18 files changed, 1528 insertions, 468 deletions
diff --git a/toolkit/test/accessibility/AccTreeNode.java b/toolkit/test/accessibility/AccTreeNode.java new file mode 100644 index 000000000000..6c01f7672050 --- /dev/null +++ b/toolkit/test/accessibility/AccTreeNode.java @@ -0,0 +1,87 @@ + +import java.util.Vector; + +/** + * The node type for the AccessibleTreeModel. + * This implements all the child-handling based on the appropriate + * NodeHandlers. Trivial nodes can be implemented by any Object + * type. + */ +class AccTreeNode +{ + private Vector aHandlers; /// NodeHandlers for this node + private Object aDataObject; /// the actual data object + private Object aDisplayObject; /// object to be displayed + + public AccTreeNode( Object aData ) + { + this( aData, aData ); + } + + public AccTreeNode( Object aData, Object aDisplay ) + { + aHandlers = new Vector(); + aDataObject = aData; + aDisplayObject = aDisplay; + } + + public Object getDataObject() { return aDataObject; } + public Object getDisplayObject() { return aDisplayObject; } + + public void addHandler( NodeHandler aHandler ) + { + aHandlers.add( aHandler ); + } + + + /** iterate over handlers and return child sum */ + public int getChildCount() + { + int nRet = 0; + for(int i = 0; i < aHandlers.size(); i++) + { + nRet += ((NodeHandler)aHandlers.get(i)). + getChildCount( aDataObject ); + } + return nRet; + } + + /** iterate over handlers until the child is found */ + public Object getChild(int nIndex) + { + if( nIndex >= 0 ) + { + for(int i = 0; i < aHandlers.size(); i++) + { + // check if this handler has the child, and if not + // search with next handler + NodeHandler aHandler = (NodeHandler)aHandlers.get(i); + int nCount = aHandler.getChildCount( aDataObject ); + if( nCount > nIndex ) + return aHandler.getChild( aDataObject, nIndex ); + else + nIndex -= nCount; + } + } + + // nothing found? + return null; + } + + /** this node is a leaf if have no handlers, or is those + handlers show no children */ + public boolean isLeaf() + { + return (aHandlers.size() == 0) || (getChildCount() == 0); + } + + public boolean equals(Object aOther) + { + return (this == aOther) || aDataObject.equals( aOther ); + } + + public String toString() + { + return aDisplayObject.toString(); + } +} diff --git a/toolkit/test/accessibility/AccessibilityTree.java b/toolkit/test/accessibility/AccessibilityTree.java index 429160451310..ac2734fd5eaf 100755 --- a/toolkit/test/accessibility/AccessibilityTree.java +++ b/toolkit/test/accessibility/AccessibilityTree.java @@ -25,13 +25,16 @@ import javax.swing.*; import javax.swing.tree.*; import javax.swing.event.*; +// JDK 1.4. +// import java.util.regex.Pattern; +// import java.util.regex.Matcher; + /** This class is a start to collect the handling of a JTree and a DefaultTreeModel. */ public class AccessibilityTree extends JTree - implements XAccessibleEventListener { /** Create a new accessibility tree. Use the specified message display for displaying messages and the specified canvas to draw the @@ -44,396 +47,114 @@ public class AccessibilityTree maMessageDisplay = aMessageDisplay; maCanvas = aCanvas; - maRoot = new DefaultMutableTreeNode ("Accessibility Tree"); - maTreeModel = new DefaultTreeModel (maRoot); - setModel (maTreeModel); - - setEditable (true); + setModel( new AccessibilityTreeModel( "Please press Update button" ) ); maCellRenderer = new AccessibleTreeCellRenderer(); - setCellRenderer (maCellRenderer); - - MouseListener ml = new MouseAdapter() { - public void mousePressed(MouseEvent e) { - int selRow = getRowForLocation(e.getX(), e.getY()); - TreePath selPath = getPathForLocation(e.getX(), e.getY()); - if(selRow != -1) { - if (e.getClickCount() == 2) - { - System.out.println ("double click : " + selRow + " , " + selPath); - Object aObject = selPath.getLastPathComponent(); - if (TreeNode.class.isInstance (aObject)) - { - TreeNode aNode = (TreeNode)aObject; - createTree (aNode.maAccessibleObject.getAccessible(), - selPath); - expandShapes (); - } - } - } - } - }; - addMouseListener (ml); + // setCellRenderer (maCellRenderer); // allow editing of XAccessibleText interfaces - maTreeModel.addTreeModelListener( new TextUpdateListener() ); + // setEditable (true); + // maTreeModel.addTreeModelListener( new TextUpdateListener() ); } - public void createTree (XAccessible xRoot) - { - createTree (xRoot, new TreePath (maRoot)); - } - - - + /** Predicate class to determine whether a node should be expanded + * For use with expandTree method */ + abstract class Expander + { abstract public boolean expand(Object aObject); } - public void createTree (XAccessible xRoot, TreePath aPath) + /** expand all nodes */ + class AllExpander extends Expander { - TreeNode aTree = createAccessibilityTree ( - xRoot, - 0, - new java.awt.Point(0,0), - aPath); - DefaultMutableTreeNode aRoot = (DefaultMutableTreeNode)aPath.getLastPathComponent(); - aRoot.insert (aTree, aRoot.getChildCount()); - maTreeModel.reload (); + public boolean expand(Object aObject) { return true; } } - - - public DefaultMutableTreeNode getRoot () + /** expand all nodes with accessibility roles > 100 */ + class ShapeExpander extends Expander { - return maRoot; + public boolean expand(Object aObject) + { + aObject = AccessibilityTreeModel.normalize( aObject ); + XAccessibleContext xContext = + (XAccessibleContext)UnoRuntime.queryInterface( + XAccessibleContext.class, aObject ); + int nRole = ( xContext == null ) ? -1 : + xContext.getAccessibleRole(); + return (nRole >= 100); + } } - - - - protected TreeNode createAccessibilityTree ( - XAccessible xRoot, int depth, java.awt.Point aOrigin, TreePath aPath) + private TreePath expandTree( TreePath aPath, Expander aExpander ) { - TreeNode aRoot = null; - - try - { - aRoot = new TreeNode (xRoot, this); + // return first expanded object + TreePath aFirst = null; - // Register as event listener. - XAccessibleEventBroadcaster xEventBroadcaster = - (XAccessibleEventBroadcaster) UnoRuntime.queryInterface ( - XAccessibleEventBroadcaster.class, xRoot); - if (xEventBroadcaster != null) - xEventBroadcaster.addEventListener (this); + // get 'our' object + Object aObj = aPath.getLastPathComponent(); - - TreePath aNewPath = aPath.pathByAddingChild (aRoot); - - // Create the accessible object and register this tree as listener at them. - AccessibleObject aObject = new AccessibleObject (xRoot, aNewPath); - - aRoot.maAccessibleObject = aObject; - message ("creating accessibility tree at depth " + depth + ": " - + aObject.toString()); - - if (maCanvas != null) - { - if (aObject.getOrigin().x != 0 || aObject.getOrigin().y != 0) - { - maCanvas.addAccessible (aObject); - } - } - else - System.out.println ("no canvas"); - - aOrigin = aObject.getOrigin (); - - - // Iterate over accessible children, create their subtrees and - // inserert these trees into the new node. - XAccessibleContext xContext = xRoot.getAccessibleContext(); - if (xContext != null) - { - int n = xContext.getAccessibleChildCount(); - for (int i=0; i<n; i++) - { - DefaultMutableTreeNode aNode = - createAccessibilityTree (xContext.getAccessibleChild(i), - depth+1, aOrigin, aNewPath); - aRoot.insert (aNode, aRoot.getChildCount()); - } - } - } - catch (Exception e) + // expand this object, if the Expander tells us so + if( aExpander.expand( aObj ) ) { - System.out.println ("caught exception while creating accessibility tree: " + e); + expandPath (aPath); + if( aFirst == null ) + aFirst = aPath; } - return aRoot; - } - - - /** Remove this tree as event listener from all the nodes in the subtree - of the specified root. - */ - protected void removeEventListeners (DefaultMutableTreeNode aRoot) - { - java.util.Enumeration aEnumeration = aRoot.breadthFirstEnumeration(); - while (aEnumeration.hasMoreElements()) + // visit all children + if( aObj instanceof AccTreeNode ) { - Object aElement = aEnumeration.nextElement(); - if (TreeNode.class.isInstance (aElement)) + AccTreeNode aNode = (AccTreeNode)aObj; + int nLength = aNode.getChildCount(); + for( int i = 0; i < nLength; i++ ) { - TreeNode aNode = (TreeNode)aElement; - XAccessibleEventBroadcaster xEventBroadcaster = - (XAccessibleEventBroadcaster) UnoRuntime.queryInterface ( - XAccessibleEventBroadcaster.class, aNode.getContext()); - if (xEventBroadcaster != null) - xEventBroadcaster.addEventListener (this); + TreePath aRet = expandTree( + aPath.pathByAddingChild( aNode.getChild( i ) ), + aExpander ); + if( aFirst == null ) + aFirst = aRet; } } + + return aFirst; } /** Expand all nodes and their subtrees that represent shapes. Call - this method from the outside. - */ + * this method from the outside. */ public void expandShapes () { message ("Expanding shapes."); - mbFirstShapeSeen = false; - // Iterate over all nodes in the tree. - java.util.Enumeration aEnumeration = maRoot.breadthFirstEnumeration(); - while (aEnumeration.hasMoreElements()) + TreePath aFirst = expandTree( new TreePath( getModel().getRoot() ), + new ShapeExpander() ); + if( aFirst != null ) { - Object aElement = aEnumeration.nextElement(); - if (TreeNode.class.isInstance (aElement)) - { - TreeNode aNode = (TreeNode)aElement; - AccessibleObject aAccessibleObject = (AccessibleObject)aNode.maAccessibleObject; - if (aAccessibleObject != null) - // Expand every node that has one of the new OO roles. - if (aAccessibleObject.getRole() >= 100) - { - TreePath aPath = new TreePath (aNode.getPath()); - expandPath (aPath); - if ( ! mbFirstShapeSeen) - { - mbFirstShapeSeen = true; - makeVisible (aPath); - } - } - } + makeVisible (aFirst); } } - - - - public void addDocument (XAccessible xAccessible, String sURL) + /** Expand all nodes */ + public void expandAll () { - if (maTreeModel != null && maRoot != null) - { - if (sURL.length() == 0) - sURL = "<unnamed>"; - TreeNode aNode = new TreeNode ("Document: " + sURL); - aNode.maAccessibleObject = new AccessibleObject (xAccessible, - new TreePath (maRoot).pathByAddingChild(aNode)); - maRoot.insert (aNode, maRoot.getChildCount()); - } - maTreeModel.reload (); + message ("Expanding complete tree"); + expandTree( new TreePath( getModel().getRoot() ), new AllExpander() ); } - public void clear () - { - removeEventListeners (maRoot); - maRoot.removeAllChildren(); - } - - /** Search for node in tree that represents the specified accessible object. - If found return this node, else return null. - */ - public TreeNode getNodeForXAccessible (XAccessible xAccessible) - { - try - { - java.util.Enumeration aEnumeration = maRoot.depthFirstEnumeration (); - while (aEnumeration.hasMoreElements()) - { - Object aElement = aEnumeration.nextElement(); - if (TreeNode.class.isInstance (aElement)) - { - TreeNode aNode = (TreeNode)aElement; - if (aNode != null) - { - AccessibleObject aAccessibleObject = (AccessibleObject)aNode.maAccessibleObject; - if (aAccessibleObject!=null) - if (aAccessibleObject.getAccessible().equals (xAccessible)) - return aNode; - } - } - } - } - catch (Exception e) - { - System.out.println ("caught exception while getting XAccessible: " + e); - } - return null; - } - - - /** Callback for accessible notify events. - */ - public void notifyEvent (AccessibleEventObject e) + protected void message (String message) { - try - { - System.out.println ("notify Event ("+e.EventId+") : " + e); - XAccessible xSource = (XAccessible) UnoRuntime.queryInterface ( - XAccessible.class, e.Source); - switch (e.EventId) - { - case AccessibleEventId.ACCESSIBLE_CHILD_EVENT: - XAccessible aOldChild = (XAccessible)e.OldValue; - XAccessible aNewChild = (XAccessible)e.NewValue; - if (aNewChild == null) - { - System.out.println ("child event deletion of " + aOldChild); - removeNode (getNodeForXAccessible (aOldChild)); - } - else - { - System.out.println ("adding child "+ aNewChild); - addNode (getNodeForXAccessible (xSource), aNewChild); - } - break; - - case AccessibleEventId.ACCESSIBLE_VISIBLE_DATA_EVENT: - System.out.println ("xSource = " + xSource); - System.out.println ("Source = " + e.Source); - System.out.println ("old and new values =" + e.OldValue + ", " + e.NewValue); - updateNode (getNodeForXAccessible (xSource)); - break; - - default: - System.out.println (" event has unhandled id " + e.EventId); - - } - } - catch (Exception event) - { - System.out.println ("caught exception processing notifyEvent: " + event); - } + maMessageDisplay.message (message); } - public void disposing (com.sun.star.lang.EventObject e) { System.out.println ("disposing " + e); } - /** Remove the specified node and its sub-tree from the tree and the canvas. - @param aNode - The root node of the sub-tree to remove. If it is null then - nothing happens. - */ - protected void removeNode (TreeNode aRoot) - { - if (aRoot != null) - { - System.out.println (" removing node " + aRoot); - removeEventListeners (aRoot); - if (TreeNode.class.isInstance (aRoot.getParent())) - ((TreeNode)aRoot.getParent()).updateChildCount(); - aRoot.removeFromParent(); - maTreeModel.reload (); - expandShapes (); - - // Remove all nodes of the subtree from the canvas by iterating - // over an enumeration of that tree. - System.out.println ("removing object from canvas"); - java.util.Enumeration aSubtree = aRoot.depthFirstEnumeration(); - while (aSubtree.hasMoreElements()) - { - Object aNode = aSubtree.nextElement (); - if (TreeNode.class.isInstance (aNode)) - maCanvas.removeAccessible (((TreeNode)aNode).maAccessibleObject); - } - } - } - - - - - /** Add the specified node to the tree and the canvas. - @param aRoot - The root node under which to add the new child. If it is null then - nothing happens. - @param aNewChild - The new child node to add. - */ - protected void addNode (TreeNode aRoot, XAccessible aNewChild) - { - if (aRoot != null) - { - aRoot.insert ( - createAccessibilityTree ( - aNewChild, - 0, - aRoot.maAccessibleObject.getOrigin(), - new TreePath (aRoot.getPath())), - aRoot.getChildCount()); - maTreeModel.reload (); - expandShapes (); - } - } - - - /** Update the visible data of the specified node. This method is - called after resize and movement operations of objects. - */ - protected void updateNode (TreeNode aNode) - { - try - { - System.out.println ("aNode = " + aNode); - if (aNode != null) - { - maCellRenderer.clearAllChanges (); - - // Update the graphical represenation of the node. - aNode.maAccessibleObject.update (); - - // Create a new list to collect all changed nodes in. - Vector aChangedNodes = new Vector (); - if (aNode.maAccessibleObject != null) - { - aNode.updateVisibleData (aChangedNodes); - maCellRenderer.addChangedNodes (aChangedNodes, this); - } - - // Repaint the tree and the canvas. - repaint (); - maCanvas.repaint (); - } - } - catch (Exception event) - { - System.out.println ("caught exception while updating a node: " + event); - } - } - - - protected void message (String message) - { - maMessageDisplay.message (message); - } /** listen to tree model changes in order to update XAccessibleText objects @@ -446,26 +167,47 @@ public class AccessibilityTree // with an XAccessibleText child, then we call updateText int[] aIndices = e.getChildIndices(); if( (aIndices != null) && - (aIndices.length > 0) && - (aIndices[0] == 0) ) + (aIndices.length > 0) ) { - // so there is a first child, check for XAccessibleText then + // we have a parent... lets check for XAccessibleText then DefaultMutableTreeNode aParent = (DefaultMutableTreeNode) (e.getTreePath().getLastPathComponent()); DefaultMutableTreeNode aNode = (DefaultMutableTreeNode) - (aParent.getChildAt(0)); - + (aParent.getChildAt(aIndices[0])); if( aParent.getUserObject() instanceof XAccessibleText) { - // joy! Call updateText with the data + // aha! we have an xText. So we can now check for + // the various cases we support XAccessibleText xText = (XAccessibleText)aParent.getUserObject(); - updateText( xText, aNode.toString() ); -// // and update the tree (by deleting the old children) -// // (this is a work-around for the currently missing -// // notifications) -// updateNode( xText, aParent ); + if( aIndices[0] == 0 ) + { + // first child! Then we call updateText + updateText( xText, aNode.toString() ); + } + else + { +// JDK 1.4: +// // check for pattern "Selection:" +// Matcher m = Pattern.compile( +// "selection: \\[(-?[0-9]+),(-?[0-9]+)\\] \".*" ). +// matcher( aNode.toString() ); +// if( m.matches() ) +// { +// try +// { +// // aha! Selection: +// setSelection( xText, +// Integer.parseInt(m.group(1)), +// Integer.parseInt(m.group(2)) ); +// } +// catch( NumberFormatException f ) +// { +// // ignore +// } +// } + } } } } @@ -541,6 +283,18 @@ public class AccessibilityTree return bRet; } + boolean setSelection( XAccessibleText xText, int p1, int p2 ) + { + try + { + return xText.setSelection( p1, p2 ); + } + catch( com.sun.star.lang.IndexOutOfBoundsException f ) + { + return false; + } + } + // /** replace the given node with a new xText node */ // void updateNode( XAccessibleText xText, // DefaultMutableTreeNode aNode ) @@ -567,10 +321,6 @@ public class AccessibilityTree protected AccessibleTreeCellRenderer maCellRenderer; - private DefaultMutableTreeNode - maRoot; - private DefaultTreeModel - maTreeModel; private Canvas maCanvas; private boolean diff --git a/toolkit/test/accessibility/AccessibilityTreeModel.java b/toolkit/test/accessibility/AccessibilityTreeModel.java new file mode 100644 index 000000000000..9025d3557ab4 --- /dev/null +++ b/toolkit/test/accessibility/AccessibilityTreeModel.java @@ -0,0 +1,678 @@ + +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; +import javax.swing.event.TreeModelListener; +import javax.swing.event.TreeModelEvent; + +import java.util.Vector; +import java.util.HashMap; +import java.util.Enumeration; + +import drafts.com.sun.star.accessibility.*; + +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.Any; +import com.sun.star.lang.EventObject; +import com.sun.star.lang.XServiceInfo; + +public class AccessibilityTreeModel + implements TreeModel, XAccessibleEventListener +{ + public AccessibilityTreeModel( Object aRoot ) + { + // create default node (unless we have a 'proper' node) + if( ! (aRoot instanceof AccTreeNode) ) + aRoot = createDefaultNode( aRoot ); + maRoot = aRoot; + + aListeners = new Vector(); + aParents = new HashMap(); + aChildren = new HashMap(); + aNodes = new HashMap(); + aNodes.put( normalize(maRoot), maRoot ); + } + + + // + // the root node + // + + private Object maRoot; + + public Object getRoot() + { + return maRoot; + } + + + // + // child management: + // + + public int getChildCount(Object aParent) + { + return (aParent instanceof AccTreeNode) ? + ((AccTreeNode)aParent).getChildCount() : 0; + } + + 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; + } + + /** iterate over all children and look for child */ + public int getIndexOfChild(Object aParent, Object aChild) + { + aChild = normalize( aChild ); + + // compare to all children + int nChildCount = getChildCount( aParent ); + for( int i = 0; i < nChildCount; i++ ) + { + if( aChild.equals( normalize( getChild(aParent, i) ) ) ) + return i; + } + + // not found? + return -1; + } + + + public boolean isLeaf(Object aNode) + { + return (aNode instanceof AccTreeNode) ? + ((AccTreeNode)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) + { + // 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 ) + { + // 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 ); + + // store the parent's child + Vector aKids = (Vector)aChildren.get( aParent ); + if( aKids == null ) + { + // no children known... insert a new vector + aKids = new Vector(); + aChildren.put( aParent, aKids ); + } + + // 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) + { + 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 ); + + // depth-first removal of children + int nLength = (aKids == null) ? 0 : aKids.size(); + for( int i = nLength-1; i >= 0; i-- ) + { + removeNode( aKids.elementAt(i) ); + } + + // remove from parents' child vector + if( aParent != null ) + { + Vector aParentKids = (Vector)aChildren.get( aParent ); + if( aParentKids != null ) + aParentKids.remove( aNode ); + } + } + + /** 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); + } + + 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) + { + Vector aPath = new Vector(); + createPath( aNode, aPath ); + return aPath.toArray(); + } + + // + // listeners (and helper methods) + // + // We are registered with listeners as soon as objects are in the + // tree cache, and we should get removed as soon as they are out. + // + + Vector aListeners; + + public void addTreeModelListener(TreeModelListener l) + { + aListeners.add(l); + } + + public void removeTreeModelListener(TreeModelListener l) + { + aListeners.remove(l); + } + + protected void fireTreeNodesChanged(final TreeModelEvent e) + { + System.out.println("treeNodesChanges: " + e); + new Thread( new EventRunner() { + protected void fire( TreeModelListener l ) + { l.treeNodesChanged(e); } + } ).start(); + } + + protected void fireTreeNodesInserted(final TreeModelEvent e) + { + System.out.println("treeNodesInserted: " + e); + new Thread( new EventRunner() { + protected void fire( TreeModelListener l ) + { l.treeNodesInserted(e); } + } ).start(); + } + + protected void fireTreeNodesRemoved(final TreeModelEvent e) + { + System.out.println("treeNodesRemoved: " + e); + new Thread( new EventRunner() { + protected void fire( TreeModelListener l ) + { l.treeNodesRemoved(e); } + } ).start(); + } + + protected void fireTreeStructureChanged(final TreeModelEvent e) + { + System.out.println("treeStructureChanged: " + e); + new Thread( new EventRunner() { + protected void fire( TreeModelListener l ) + { l.treeStructureChanged(e); } + } ).start(); + } + + protected TreeModelEvent createEvent( Object aNode ) + { + return createEvent( aNode, null ); + } + + protected TreeModelEvent createEvent( Object aParent, Object aChild ) + { + // 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 ) } ); + } + + /** + * broadcast a tree event in a seperate Thread + * must override fire method + */ + class EventRunner implements Runnable + { + public void run() + { + for(int i = 0; i < aListeners.size(); i++) + { + fire( (TreeModelListener)aListeners.get(i) ); + } + } + + protected void fire( TreeModelListener l) { } + } + + + protected XAccessibleEventBroadcaster getBroadcaster( Object aObject ) + { + if( aObject instanceof AccTreeNode ) + aObject = ((AccTreeNode)aObject).getDataObject(); + return (XAccessibleEventBroadcaster) UnoRuntime.queryInterface ( + XAccessibleEventBroadcaster.class, aObject); + } + + protected void registerAccListener( Object aObject ) + { + // register this as listener for XAccessibleEventBroadcaster + // implementations + XAccessibleEventBroadcaster xBroadcaster = getBroadcaster( aObject ); + if (xBroadcaster != null) + { + xBroadcaster.addEventListener( this ); + } + } + + protected void removeAccListener( Object aObject ) + { + XAccessibleEventBroadcaster xBroadcaster = getBroadcaster( aObject ); + if (xBroadcaster != null) + { + xBroadcaster.removeEventListener( this ); + } + } + + + // + // tree model edit + // + public void valueForPathChanged(TreePath path, Object newValue) { } + + + // + // 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 ) + { + Object aObject = aNode.getDataObject(); + + // try each type + Enumeration aEnum = aDefaultHandlers.elements(); + while( aEnum.hasMoreElements() ) + { + HandlerPair aPair = (HandlerPair)aEnum.nextElement(); + Class aType = aPair.aType; + + // try instanceof, and a UNO query, if we have an XInterface + if( aType.isInstance( aObject ) ) + { + aNode.addHandler( aPair.aHandler ); + } + else if( XInterface.class.isAssignableFrom( aType ) ) + { + Object aQuery = UnoRuntime.queryInterface(aType, aObject); + if( aQuery != null ) + aNode.addHandler( aPair.aHandler ); + } + } + } + + /** create a node with the default handlers */ + public static AccTreeNode createDefaultNode( Object aObject ) + { + // default: aObject + aDisplay + Object aDisplay = aObject; + + // if we are accessible, we use the context + name instead + XAccessible xAccessible = + (XAccessible) UnoRuntime.queryInterface ( + XAccessible.class, aObject); + if (xAccessible != null) + { + XAccessibleContext aContext = xAccessible.getAccessibleContext(); + + // 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 ); + return aNode; + } + + + // + // XAccessibleEventListener interface + // + + private static String objectToString(Object aObject) + { + if( aObject instanceof Any ) + aObject = ((Any)aObject).getObject(); + + if( aObject instanceof XInterface ) + { + XServiceInfo xInfo = + (XServiceInfo)UnoRuntime.queryInterface( XServiceInfo.class, + aObject); + aObject = (xInfo != null) ? xInfo.getImplementationName() + : aObject.getClass().toString(); + } + + return (aObject != null) ? aObject.toString() : null; + } + + public void disposing( EventObject aEvent) + { + System.out.println("dispose: " + objectToString(aEvent.Source)); + + if( knowsNode( aEvent.Source ) ) + { + System.out.println("ERROR: Dispose for living node called! " + + "Maybe notifications don't work?"); + removeNode( aEvent.Source ); +// fireTreeStructureChanged( createEvent( getRoot() ) ); + } + + } + + static final String[] aEventNames = + { + "[UNKNOWN]", "ACTION", "ACTIVE_DESCENDANT", "CARET", "CHILD", + "DESCRIPTION", "HYPERTEXT_OFFSET", "NAME", "SELECTION", "STATE", + "TABLE_CAPTION_CHANGED", "TABLE_COLUMN_DESCRIPTION_CHANGED", + "TABLE_COLUMN_HEADER_CHANGED", "TABLE_MODEL_CHANGED", + "TABLE_ROW_DESCRIPTION_CHANGED", "TABLE_ROW_HEADER_CHANGED", + "TABLE_SUMMARY_CHANGED", "TEXT", "VALUE", "VISIBLE_DATA", + "CONTROLLED_BY_PROPERTY", "CONTROLLER_FOR_PROPERTY", + "LABEL_FOR_PROPERTY", "LABELED_BY_PROPERTY", "MEMBER_OF_PROPERTY", + "[UNKNOWN]" + }; + + public 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) + " (" + + (knowsNode(aEvent.Source) ? "known" : "unknown") + + "), " + + objectToString(aEvent.OldValue) + "->" + + objectToString(aEvent.NewValue) ); + + + switch( aEvent.EventId ) + { + case AccessibleEventId.ACCESSIBLE_CHILD_EVENT: + // fire insertion and deletion events: + if( aOld != null ) + { + TreeModelEvent aTreeEvent = createEvent( aSource, aOld ); + removeNode( aOld ); + fireTreeNodesRemoved( aTreeEvent ); + } + if( aNew != null ) + { + fireTreeNodesInserted( createEvent( aSource, aNew ) ); + } + break; + + case AccessibleEventId.ACCESSIBLE_VISIBLE_DATA_EVENT: + case AccessibleEventId.ACCESSIBLE_ACTIVE_DESCENDANT_EVENT: + case AccessibleEventId.ACCESSIBLE_ACTION_EVENT: + case AccessibleEventId.ACCESSIBLE_CARET_EVENT: + case AccessibleEventId.ACCESSIBLE_DESCRIPTION_EVENT: + case AccessibleEventId.ACCESSIBLE_HYPERTEXT_OFFSET: + case AccessibleEventId.ACCESSIBLE_NAME_EVENT: + case AccessibleEventId.ACCESSIBLE_SELECTION_EVENT: + case AccessibleEventId.ACCESSIBLE_STATE_EVENT: + case AccessibleEventId.ACCESSIBLE_TABLE_CAPTION_CHANGED: + case AccessibleEventId.ACCESSIBLE_TABLE_COLUMN_DESCRIPTION_CHANGED: + case AccessibleEventId.ACCESSIBLE_TABLE_COLUMN_HEADER_CHANGED: + case AccessibleEventId.ACCESSIBLE_TABLE_MODEL_CHANGED: + case AccessibleEventId.ACCESSIBLE_TABLE_ROW_DESCRIPTION_CHANGED: + case AccessibleEventId.ACCESSIBLE_TABLE_ROW_HEADER_CHANGED: + case AccessibleEventId.ACCESSIBLE_TABLE_SUMMARY_CHANGED: + case AccessibleEventId.ACCESSIBLE_TEXT_EVENT: + case AccessibleEventId.ACCESSIBLE_VALUE_EVENT: + case AccessibleEventId.CONTROLLED_BY_PROPERTY: + case AccessibleEventId.CONTROLLER_FOR_PROPERTY: + case AccessibleEventId.LABEL_FOR_PROPERTY: + case AccessibleEventId.LABELED_BY_PROPERTY: + case AccessibleEventId.MEMBER_OF_PROPERTY: + fireTreeNodesChanged( createEvent( aSource ) ); + updateOnCanvas( aSource ); + break; + + + + default: + break; + } + } + + + // + // canvas + // + + private Canvas maCanvas; + + public void setCanvas( Canvas aCanvas ) + { + maCanvas = aCanvas; + } + + + private XAccessibleContext getContext(Object aObject) + { + XAccessibleContext xAcc = + (XAccessibleContext)UnoRuntime.queryInterface( + XAccessibleContext.class, aObject); + return xAcc; + } + + protected void addToCanvas( Object aObject ) + { + XAccessibleContext xContext = getContext( aObject ); + if( (maCanvas != null) && (xContext != null) ) + maCanvas.addContext( xContext, + new TreePath( createPath( xContext ) ) ); + } + + protected void removeFromCanvas( Object aObject ) + { + XAccessibleContext xContext = getContext( aObject ); + if( (maCanvas != null) && (xContext != null) ) + maCanvas.removeContext( xContext ); + } + + protected void updateOnCanvas( Object aObject ) + { + XAccessibleContext xContext = getContext( aObject ); + if( (maCanvas != null) && (xContext != null) ) + maCanvas.updateContext( xContext ); + } +} + + +/** HandlerPair stores a NodeHandler and the appropriate type */ +class HandlerPair +{ + public Class aType; + public NodeHandler aHandler; + + public HandlerPair( Class aT, NodeHandler aH ) + { + aType = aT; + aHandler = aH; + } +} diff --git a/toolkit/test/accessibility/AccessibilityWorkBench.java b/toolkit/test/accessibility/AccessibilityWorkBench.java index 1884c7473fb3..2d2f07f7547c 100755 --- a/toolkit/test/accessibility/AccessibilityWorkBench.java +++ b/toolkit/test/accessibility/AccessibilityWorkBench.java @@ -203,8 +203,10 @@ public class AccessibilityWorkBench // Buttons. aConnectButton = createButton ("Connect", "connect"); aLoadButton = createButton ("Load", "load"); - aRunButton = createButton ("Run", "run"); aUpdateButton = createButton ("Update", "update"); + aShapesButton = createButton ("Shapes", "shapes"); + aExpandButton = createButton ("Expand", "expand"); + aTextButton = createButton("Text", "text"); aQuitButton = createButton ("Quit", "quit"); maMainPanel.setLayout (aLayout); @@ -237,16 +239,15 @@ public class AccessibilityWorkBench protected void initialize () { - // Clear the accessibility tree. - if (maTree != null) - maTree.clear (); - // Delete the graphical representations. if (maCanvas != null) maCanvas.clear (); - // Add entries for open documents to tree. - addOpenDocumentsToTree (); + // create new model (with new documents) + AccessibilityTreeModel aModel = + new AccessibilityTreeModel( createTreeModelRoot() ); + aModel.setCanvas( maCanvas ); + maTree.setModel( aModel ); // if (office != null && office.getDesktop() != null) // office.getDesktop().addTerminateListener (this); @@ -264,7 +265,6 @@ public class AccessibilityWorkBench } else if (e.getActionCommand().equals("quit")) { - maTree.clear(); System.exit (0); } else if (e.getActionCommand().equals("load")) @@ -276,130 +276,51 @@ public class AccessibilityWorkBench else { println ("."); - XWindow xWindow = office.getCurrentWindow (mxModel); - XAccessible xRoot = office.getAccessibleRoot (xWindow); - maTree.addDocument (xRoot, msFileName); + initialize(); } } - else if (e.getActionCommand().equals("run")) - { - run (mxModel); - } else if (e.getActionCommand().equals("update")) { initialize (); - run (mxModel); } - else + else if (e.getActionCommand().equals("shapes")) { - System.err.println("unknown command " + e.getActionCommand()); + maTree.expandShapes(); } - } - - - - - public void test (XModel xModel) - { - println ("Test:"); - try + else if (e.getActionCommand().equals("expand")) { - if (xModel == null) - { - XDrawView xView = office.getCurrentView (); - if (xView == null) - println ("no current view"); - else - xModel = office.getModel (xView); - } - info.showProperties (xModel); - - XWindow xWindow = office.getCurrentWindow (xModel); - if (xWindow != null) - { - println ("current window:"); - com.sun.star.awt.Rectangle aRectangle = xWindow.getPosSize(); - println (aRectangle.X + " " + aRectangle.Y + " " - + aRectangle.Width + " " + aRectangle.Height); - } - else - println ("Can't get window"); - - XPropertySet xSet = (XPropertySet) UnoRuntime.queryInterface ( - XPropertySet.class, xModel); - if (xSet != null) - { - com.sun.star.awt.Rectangle aRectangle = - (com.sun.star.awt.Rectangle) xSet.getPropertyValue ( - "VisibleArea"); - println (aRectangle.X + " " + aRectangle.Y + " " - + aRectangle.Width + " " + aRectangle.Height); - } - else - println ("model does not support XPropertySet"); + maTree.expandAll(); } - catch (Exception e) + else if (e.getActionCommand().equals("text")) { - System.out.println ("caught exception in test: " + e); + Canvas.bPaintText = ! Canvas.bPaintText; } - println ("Test finished."); - } - - - - - /** Get the accessibility tree for the specified model. - */ - protected void run (XModel xModel) - { - try - { - addListeners (xModel); - XWindow xWindow = office.getCurrentWindow (xModel); - XAccessible xRoot = office.getAccessibleRoot (xWindow); - if (xRoot != null) - { - println ("window is accessible"); - } - else - { - println ("window is not accessible."); - return; - } - - message ("creating accessibility tree"); - maTree.createTree (xRoot); - maTree.expandShapes (); - } - catch (Exception e) + else { - System.out.println ("caught exception in run: " + e); + System.err.println("unknown command " + e.getActionCommand()); } } - - /** Experimental. Add list of currently open (and named) documents to - the tree widget. - */ - public void addOpenDocumentsToTree () + /** Create an AccessibilityTreeModel root which contains the documents */ + private Object createTreeModelRoot() { + Vector aRoots = new Vector(); + try { XDesktop xDesktop = office.getDesktop(); if (xDesktop == null) { - println ("can't get desktop to retrieve open documents"); - return; + return "ERROR: Can't connect. (No desktop)"; } XEnumerationAccess xEA = xDesktop.getComponents(); if (xEA == null) { - println ("Can't get list of components from desktop"); - return; + return "ERROR: Can't get components"; } XEnumeration xE = xEA.createEnumeration(); while (xE.hasMoreElements()) @@ -413,10 +334,13 @@ public class AccessibilityWorkBench println (xModel.getURL()); XWindow xWindow = office.getCurrentWindow (xModel); XAccessible xRoot = office.getAccessibleRoot (xWindow); - maTree.addDocument (xRoot, xModel.getURL()); + + // create document node + aRoots.add( + AccessibilityTreeModel.createDefaultNode(xRoot) ); } else - println ("can't cast component to model"); + aRoots.add( "can't cast component to model" ); } println ("finished getting named documents"); } @@ -424,11 +348,17 @@ public class AccessibilityWorkBench { System.out.println ("caught exception while getting document names: " + e); } + + // create root node + AccTreeNode aNode = new AccTreeNode( aRoots, "Accessibility Tree" ); + AccessibilityTreeModel.addDefaultHandlers( aNode ); + return aNode; } + /** Add various listeners to the model and other Office objects. */ protected void addListeners (XModel xModel) @@ -617,5 +547,7 @@ public class AccessibilityWorkBench aQuitButton, aLoadButton, aUpdateButton, - aRunButton; + aExpandButton, + aShapesButton, + aTextButton; } diff --git a/toolkit/test/accessibility/AccessibleActionHandler.java b/toolkit/test/accessibility/AccessibleActionHandler.java new file mode 100644 index 000000000000..e0c5b6cbb56a --- /dev/null +++ b/toolkit/test/accessibility/AccessibleActionHandler.java @@ -0,0 +1,45 @@ + +import com.sun.star.uno.UnoRuntime; +import drafts.com.sun.star.accessibility.XAccessibleAction; +import com.sun.star.lang.IndexOutOfBoundsException; + +class AccessibleActionHandler extends NodeHandler +{ + protected XAccessibleAction getAction(Object aObject) + { + return (XAccessibleAction) UnoRuntime.queryInterface ( + XAccessibleAction.class, aObject); + } + + public int getChildCount(Object aObject) + { + XAccessibleAction xAction = getAction(aObject); + return (xAction == null) ? 0 : 1 + xAction.getAccessibleActionCount(); + } + + public Object getChild(Object aObject, int nIndex) + { + Object aRet = null; + + XAccessibleAction xAction = getAction(aObject); + if( xAction != null ) + { + if( nIndex == 1 ) + aRet = "Actions: " + xAction.getAccessibleActionCount(); + else + { + try + { + aRet = "Action " + (nIndex-1) + " : " + + xAction.getAccessibleActionDescription(nIndex-1); + } + catch( IndexOutOfBoundsException e ) + { + aRet = "ERROR"; + } + } + } + + return aRet; + } +} diff --git a/toolkit/test/accessibility/AccessibleComponentHandler.java b/toolkit/test/accessibility/AccessibleComponentHandler.java new file mode 100644 index 000000000000..699043ddacd9 --- /dev/null +++ b/toolkit/test/accessibility/AccessibleComponentHandler.java @@ -0,0 +1,45 @@ + +import com.sun.star.uno.UnoRuntime; +import drafts.com.sun.star.accessibility.XAccessibleComponent; + + +class AccessibleComponentHandler extends AccessibleTreeHandler +{ + private XAccessibleComponent getComponent(Object aObject) + { + return (XAccessibleComponent) UnoRuntime.queryInterface ( + XAccessibleComponent.class, aObject); + } + + public int getChildCount(Object aObject) + { + return (getComponent(aObject) == null) ? 0 : 3; + } + + public Object getChild(Object aObject, int nIndex) + { + XAccessibleComponent xComponent = getComponent(aObject); + + Object aRet = null; + if( xComponent != null ) + { + switch( nIndex ) + { + case 0: + aRet = "Location: "+ xComponent.getLocation().X + + ", " + xComponent.getLocation().Y; + break; + case 1: + aRet = "Location on Screen: "+ + xComponent.getLocationOnScreen().X + ", " + + xComponent.getLocationOnScreen().Y; + break; + case 2: + aRet = "Size: "+ xComponent.getSize().Width + ", " + + xComponent.getSize().Height; + break; + } + } + return aRet; + } +} diff --git a/toolkit/test/accessibility/AccessibleContextHandler.java b/toolkit/test/accessibility/AccessibleContextHandler.java new file mode 100644 index 000000000000..1e7ae3c0fae8 --- /dev/null +++ b/toolkit/test/accessibility/AccessibleContextHandler.java @@ -0,0 +1,39 @@ + +import drafts.com.sun.star.accessibility.XAccessibleContext; + + +class AccessibleContextHandler extends AccessibleTreeHandler +{ + public int getChildCount(Object aObject) + { + return (getContext(aObject) == null) ? 0 : 4; + } + + public Object getChild(Object aObject, int nIndex) + { + XAccessibleContext xContext = getContext(aObject); + + Object aRet = null; + if( xContext != null ) + { + switch( nIndex ) + { + case 0: + aRet = "Description: " + + xContext.getAccessibleDescription(); + break; + case 1: + aRet = "Role: " + xContext.getAccessibleRole(); + break; + case 2: + aRet = "Has parent: " + + (xContext.getAccessibleParent()!=null ? "yes" : "no"); + break; + case 3: + aRet = "Child count: " + xContext.getAccessibleChildCount(); + break; + } + } + return aRet; + } +} diff --git a/toolkit/test/accessibility/AccessibleEditableTextHandler.java b/toolkit/test/accessibility/AccessibleEditableTextHandler.java new file mode 100644 index 000000000000..918f6bb2d787 --- /dev/null +++ b/toolkit/test/accessibility/AccessibleEditableTextHandler.java @@ -0,0 +1,24 @@ + +import com.sun.star.uno.UnoRuntime; +import drafts.com.sun.star.accessibility.XAccessibleEditableText; + + +class AccessibleEditableTextHandler extends NodeHandler +{ + protected XAccessibleEditableText getEText(Object aObject) + { + return (XAccessibleEditableText) UnoRuntime.queryInterface ( + XAccessibleEditableText.class, aObject); + } + + public int getChildCount(Object aObject) + { + return (getEText(aObject) == null) ? 0 : 1; + } + + public Object getChild(Object aObject, int nIndex) + { + XAccessibleEditableText xContext = getEText(aObject); + return "XAccessibleEditableText is supported"; + } +} diff --git a/toolkit/test/accessibility/AccessibleExtendedComponentHandler.java b/toolkit/test/accessibility/AccessibleExtendedComponentHandler.java new file mode 100644 index 000000000000..17e66d8353b3 --- /dev/null +++ b/toolkit/test/accessibility/AccessibleExtendedComponentHandler.java @@ -0,0 +1,48 @@ + +import com.sun.star.uno.UnoRuntime; +import drafts.com.sun.star.accessibility.XAccessibleExtendedComponent; + + +class AccessibleExtendedComponentHandler extends AccessibleTreeHandler +{ + private XAccessibleExtendedComponent getComponent(Object aObject) + { + return (XAccessibleExtendedComponent) UnoRuntime.queryInterface ( + XAccessibleExtendedComponent.class, aObject); + } + + + public int getChildCount(Object aObject) + { + return (getComponent(aObject) == null) ? 0 : 2; + } + + public Object getChild(Object aObject, int nIndex) + { + XAccessibleExtendedComponent xEComponent = getComponent(aObject); + + Object aRet = null; + if( xEComponent != null ) + { + int nColor; + switch( nIndex ) + { + case 0: + nColor = xEComponent.getForeground(); + aRet = "Foreground color: R" + + (nColor>>16&0xff) + + "G" + (nColor>>8&0xff) + + "B" + (nColor>>0&0xff); + break; + case 1: + nColor = xEComponent.getBackground(); + aRet = "Background color: R" + + (nColor>>16&0xff) + + "G" + (nColor>>8&0xff) + + "B" + (nColor>>0&0xff); + break; + } + } + return aRet; + } +} diff --git a/toolkit/test/accessibility/AccessibleHyperlinkHandler.java b/toolkit/test/accessibility/AccessibleHyperlinkHandler.java new file mode 100644 index 000000000000..a7bd0583d101 --- /dev/null +++ b/toolkit/test/accessibility/AccessibleHyperlinkHandler.java @@ -0,0 +1,25 @@ + +import com.sun.star.uno.UnoRuntime; +import drafts.com.sun.star.accessibility.XAccessibleHyperlink; + + +class AccessibleHyperlinkHandler extends AccessibleTreeHandler +{ + protected XAccessibleHyperlink getHyperlink(Object aObject) + { + XAccessibleHyperlink xHyperlink = + (XAccessibleHyperlink) UnoRuntime.queryInterface ( + XAccessibleHyperlink.class, aObject); + return xHyperlink; + } + + public int getChildCount(Object aObject) + { + return (getHyperlink(aObject) == null) ? 0 : 1; + } + + public Object getChild(Object aObject, int nIndex) + { + return "interface XAccessibleHyperlink is supported"; + } +} diff --git a/toolkit/test/accessibility/AccessibleHypertextHandler.java b/toolkit/test/accessibility/AccessibleHypertextHandler.java new file mode 100644 index 000000000000..0e1f4ece6823 --- /dev/null +++ b/toolkit/test/accessibility/AccessibleHypertextHandler.java @@ -0,0 +1,25 @@ + +import com.sun.star.uno.UnoRuntime; +import drafts.com.sun.star.accessibility.XAccessibleHypertext; + + +class AccessibleHypertextHandler extends AccessibleTreeHandler +{ + protected XAccessibleHypertext getHypertext(Object aObject) + { + XAccessibleHypertext xHypertext = + (XAccessibleHypertext) UnoRuntime.queryInterface ( + XAccessibleHypertext.class, aObject); + return xHypertext; + } + + public int getChildCount(Object aObject) + { + return (getHypertext(aObject) == null) ? 0 : 1; + } + + public Object getChild(Object aObject, int nIndex) + { + return "interface XAccessibleHypertext is supported"; + } +} diff --git a/toolkit/test/accessibility/AccessibleImageHandler.java b/toolkit/test/accessibility/AccessibleImageHandler.java new file mode 100644 index 000000000000..260207699383 --- /dev/null +++ b/toolkit/test/accessibility/AccessibleImageHandler.java @@ -0,0 +1,25 @@ + +import com.sun.star.uno.UnoRuntime; +import drafts.com.sun.star.accessibility.XAccessibleImage; + + +class AccessibleImageHandler extends NodeHandler +{ + protected XAccessibleImage getImage(Object aObject) + { + return (XAccessibleImage) UnoRuntime.queryInterface ( + XAccessibleImage.class, aObject); + } + + public int getChildCount(Object aObject) + { + return (getImage(aObject) == null) ? 0 : 1; + } + + public Object getChild(Object aObject, int nIndex) + { + XAccessibleImage xImage = getImage(aObject); + return (xImage == null) ? "" : + "Image description: " + xImage.getAccessibleImageDescription(); + } +} diff --git a/toolkit/test/accessibility/AccessibleTableHandler.java b/toolkit/test/accessibility/AccessibleTableHandler.java new file mode 100644 index 000000000000..90d6d1b791fd --- /dev/null +++ b/toolkit/test/accessibility/AccessibleTableHandler.java @@ -0,0 +1,24 @@ + +import com.sun.star.uno.UnoRuntime; +import drafts.com.sun.star.accessibility.XAccessibleTable; + + +class AccessibleTableHandler extends NodeHandler +{ + protected XAccessibleTable getTable(Object aObject) + { + return (XAccessibleTable) UnoRuntime.queryInterface ( + XAccessibleTable.class, aObject); + } + + public int getChildCount(Object aObject) + { + return (getTable(aObject) == null) ? 0 : 1; + } + + public Object getChild(Object aObject, int nIndex) + { + XAccessibleTable xTable = getTable(aObject); + return "interface XAccessibleTable is supported"; + } +} diff --git a/toolkit/test/accessibility/AccessibleTextHandler.java b/toolkit/test/accessibility/AccessibleTextHandler.java new file mode 100644 index 000000000000..3d9c7671d45f --- /dev/null +++ b/toolkit/test/accessibility/AccessibleTextHandler.java @@ -0,0 +1,208 @@ + +import drafts.com.sun.star.accessibility.XAccessibleText; +import drafts.com.sun.star.accessibility.AccessibleTextType; + +import com.sun.star.awt.Rectangle; +import com.sun.star.awt.Point; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.lang.IndexOutOfBoundsException; + +import java.util.Vector; + +class AccessibleTextHandler extends NodeHandler +{ + private XAccessibleText getText( Object aObject ) + { + XAccessibleText xText = + (XAccessibleText) UnoRuntime.queryInterface ( + XAccessibleText.class, aObject); + return xText; + } + + public int getChildCount(Object aObject) + { + return (getText(aObject) != null) ? 11 : 0; + } + + public Object getChild(Object aObject, int nIndex) + { + Object aRet = null; + + XAccessibleText xText = getText( aObject ); + if( xText != null ) + { + switch( nIndex ) + { + case 0: + aRet = xText.getText(); + break; + case 1: + aRet = "# chars: " + xText.getCharacterCount(); + break; + case 2: + aRet = characters( xText ); + break; + case 3: + aRet = "selection: " + "[" + xText.getSelectionStart() + + "," + xText.getSelectionEnd() + "] \"" + + xText.getSelectedText() + "\""; + break; + case 4: + aRet = "getCaretPosition: " + xText.getCaretPosition(); + break; + case 5: + aRet = textAtIndexNode( xText, "Character", + AccessibleTextType.CHARACTER ); + break; + case 6: + aRet = textAtIndexNode( xText, "Word", + AccessibleTextType.WORD ); + break; + case 7: + aRet = textAtIndexNode( xText, "Sentence", + AccessibleTextType.SENTENCE ); + break; + case 8: + aRet = textAtIndexNode( xText, "Paragraph", + AccessibleTextType.PARAGRAPH ); + break; + case 9: + aRet = textAtIndexNode( xText, "Line", + AccessibleTextType.LINE ); + break; + case 10: + aRet = bounds( xText ); + break; + } + } + return aRet; + } + + /** Create a text node that lists all strings of a particular text type + */ + private Object textAtIndexNode( + XAccessibleText xText, + String sName, + short nTextType) + { + Vector aWords = new Vector(); + + // get word at all positions; + // for nicer display, compare current word to previous one and + // make a new node for every interval, not for every word + int nLength = xText.getCharacterCount(); + if( nLength > 0 ) + { + try + { + // sWord + nStart mark the current word + // make a node as soon as a new one is found; close the last + // one at the end + String sWord = xText.getTextAtIndex(0, nTextType); + int nStart = 0; + for(int i = 1; i < nLength; i++) + { + String sTmp = xText.getTextAtIndex(i, nTextType); + if( ! sTmp.equals( sWord ) ) + { + aWords.add( "[" + nStart + "," + (i-1) + "] \"" + + sWord + "\"" ); + sWord = sTmp; + nStart = i; + } + + // don't generate more than 50 children. + if( aWords.size() > 50 ) + { + sWord = "..."; + break; + } + } + aWords.add( "[" + nStart + "," + nLength + "] \"" + + sWord + "\"" ); + } + catch( IndexOutOfBoundsException e ) + { + aWords.add( e.toString() ); + } + } + + // create node, and add default handlers + AccTreeNode aNode = new AccTreeNode( aWords, sName ); + AccessibilityTreeModel.addDefaultHandlers( aNode ); + return aNode; + } + + + + /** getCharacter (display as array string) */ + private String characters(XAccessibleText xText) + { + // get count (max. 30) + int nChars = xText.getCharacterCount(); + if( nChars > 30 ) + nChars = 30; + + // build up string + StringBuffer aChars = new StringBuffer(); + try + { + aChars.append( "[" ); + for( int i = 0; i < nChars; i++) + { + aChars.append( xText.getCharacter(i) ); + aChars.append( "," ); + } + if( nChars > 0) + { + if( nChars == xText.getCharacterCount() ) + aChars.deleteCharAt( aChars.length() - 1 ); + else + aChars.append( "..." ); + } + aChars.append( "]" ); + } + catch( IndexOutOfBoundsException e ) + { + aChars.append( " ERROR " ); + } + + // return result + return "getCharacters: " + aChars; + } + + + /** iterate over characters, and translate their positions + * back and forth */ + private String bounds( XAccessibleText xText ) + { + StringBuffer aBuffer = new StringBuffer( "bounds: " ); + try + { + // iterate over characters + int nCount = xText.getCharacterCount(); + for(int i = 0; i < nCount; i++ ) + { + // get bounds for this character + Rectangle aRect = xText.getCharacterBounds( i ); + + // get the character by 'clicking' into the middle of + // the bounds + Point aMiddle = new Point(); + aMiddle.X = aRect.X + (aRect.Width / 2) - 1; + aMiddle.Y = aRect.Y + (aRect.Height / 2 ) - 1; + int nIndex = xText.getIndexAtPoint( aMiddle ); + + // get the character, or a '#' for an illegal index + if( (nIndex >= 0) && (nIndex < xText.getCharacter(i)) ) + aBuffer.append( xText.getCharacter(nIndex) ); + else + aBuffer.append( '#' ); + } + } + catch( IndexOutOfBoundsException e ) + { ; } // ignore errors + + return aBuffer.toString(); + } +} diff --git a/toolkit/test/accessibility/AccessibleTreeHandler.java b/toolkit/test/accessibility/AccessibleTreeHandler.java new file mode 100644 index 000000000000..f3e3a65ce1ca --- /dev/null +++ b/toolkit/test/accessibility/AccessibleTreeHandler.java @@ -0,0 +1,42 @@ +import drafts.com.sun.star.accessibility.XAccessibleContext; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.lang.IndexOutOfBoundsException; + + +/** + * Map the tree of accessibility objects into their + * AccessibilityTreeModel counterparts. + */ +class AccessibleTreeHandler extends NodeHandler +{ + protected XAccessibleContext getContext(Object aObject) + { + XAccessibleContext xContext = + (XAccessibleContext) UnoRuntime.queryInterface ( + XAccessibleContext.class, aObject); + return xContext; + } + + public int getChildCount(Object aObject) + { + XAccessibleContext aContext = getContext(aObject); + return (aContext == null) ? 0 : aContext.getAccessibleChildCount(); + } + + public Object getChild(Object aObject, int nIndex) + { + Object aRet = null; + XAccessibleContext aContext = getContext(aObject); + if( aContext != null ) + { + try + { + aRet = AccessibilityTreeModel. + createDefaultNode(aContext.getAccessibleChild(nIndex)); + } + catch( IndexOutOfBoundsException e ) + { } // return null + } + return aRet; + } +} diff --git a/toolkit/test/accessibility/Canvas.java b/toolkit/test/accessibility/Canvas.java index 27667fe725cb..afacc0265330 100755 --- a/toolkit/test/accessibility/Canvas.java +++ b/toolkit/test/accessibility/Canvas.java @@ -3,6 +3,7 @@ import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.tree.*; +import drafts.com.sun.star.accessibility.XAccessibleContext; /** This canvas displays accessible objects graphically. Each accessible object with graphical representation is represented by an @@ -17,10 +18,13 @@ class Canvas public final int nMaximumWidth = 1000; public final int nMaximumHeight = 1000; + public static boolean bPaintText = false; + public Canvas (MessageInterface aMessageDisplay, JTree aTree) { super (true); maObjects = new Vector (); + maContexts = new Vector (); addMouseListener (this); addMouseMotionListener (this); maBoundingBox = new Rectangle (0,0,100,100); @@ -35,18 +39,45 @@ class Canvas public void addAccessible (AccessibleObject aObject) { - maObjects.add (aObject); + if( maObjects.indexOf( aObject ) == -1 ) + { + maObjects.add (aObject); + maContexts.add (aObject.getContext()); + } maBoundingBox = maBoundingBox.union (aObject.getBBox()); } public void removeAccessible (AccessibleObject aObject) { maObjects.remove (aObject); + maContexts.remove (aObject.getContext()); + } + + + public void addContext(XAccessibleContext xContext, TreePath aPath) + { + if( maContexts.indexOf( xContext ) == -1 ) + addAccessible( new AccessibleObject( xContext, aPath ) ); + } + + public void removeContext(XAccessibleContext xContext) + { + int i = maContexts.indexOf( xContext ); + if( i != -1 ) + removeAccessible( (AccessibleObject)maObjects.elementAt( i ) ); + } + + public void updateContext(XAccessibleContext aContext) + { + int i = maContexts.indexOf( aContext ); + if( i != -1 ) + ((AccessibleObject)maObjects.elementAt( i )).update(); } public void clear () { maObjects.clear(); + maContexts.clear(); } public void paintComponent (Graphics g) @@ -160,7 +191,7 @@ class Canvas maActiveObject.select (); maMessageDisplay.message ("mouse moved to " + e.getX() + "," + e.getY() + ": " +maActiveObject.toString()); - System.out.println (maActiveObject.getPath()); + System.out.println ("path: " + maActiveObject.getPath()); if (maTree != null) { @@ -182,7 +213,8 @@ class Canvas protected AccessibleObject maActiveObject; protected Vector - maObjects; + maObjects, + maContexts; protected Rectangle maBoundingBox; protected JTree diff --git a/toolkit/test/accessibility/NodeHandler.java b/toolkit/test/accessibility/NodeHandler.java new file mode 100644 index 000000000000..5be27f67e018 --- /dev/null +++ b/toolkit/test/accessibility/NodeHandler.java @@ -0,0 +1,16 @@ +/** + * Map an arbitrary object into parts of a tree node. + */ +abstract class NodeHandler +{ + /** return the number of children this object has */ + public abstract int getChildCount(Object aObject); + + /** + * return a child object. + * You can use any object type for trivial nodes. Complex + * children have to be AccTreeNode instances. + * @see AccTreeNode + */ + public abstract Object getChild(Object aObject, int nIndex); +} diff --git a/toolkit/test/accessibility/makefile.mk b/toolkit/test/accessibility/makefile.mk index 13112d82ff14..509ccc58ff40 100644 --- a/toolkit/test/accessibility/makefile.mk +++ b/toolkit/test/accessibility/makefile.mk @@ -29,18 +29,33 @@ JAR_FILES = \ java_uno.jar JAVA_FILES = \ + AccTreeNode.java \ + AccessibilityTree.java \ + AccessibilityTreeModel.java \ AccessibilityWorkBench.java \ + AccessibleActionHandler.java \ + AccessibleComponentHandler.java \ + AccessibleContextHandler.java \ + AccessibleEditableTextHandler.java \ + AccessibleExtendedComponentHandler.java \ + AccessibleHyperlinkHandler.java \ + AccessibleHypertextHandler.java \ + AccessibleImageHandler.java \ AccessibleObject.java \ + AccessibleTableHandler.java \ + AccessibleTextHandler.java \ AccessibleTreeCellRenderer.java \ - AccessibilityTree.java \ + AccessibleTreeHandler.java \ Canvas.java \ - InformationWriter.java \ FrameActionListener.java \ + InformationWriter.java \ MessageInterface.java \ + NodeHandler.java \ OfficeConnection.java \ Print.java \ SimpleOffice.java \ - TreeNode.java + VectorHandler.java + JAVA_CLASSPATHS := \ . \ @@ -56,15 +71,15 @@ JFLAGS = -deprecation -classpath $(CLASSPATH) AccessibilityWorkBench : $(JAVA_FILES:b:+".class") + # Create a jar file of all files neccessary to build and run the work bench. dist: jar -cf AccessibilityWorkBench.jar \ $(JAVA_FILES)\ - $(JAVA_FILES:b:+".class") + *.class +# $(JAVA_FILES:b:+".class") # Example of how to run the work bench. run: $(JAVA) -classpath $(CLASSPATH) AccessibilityWorkBench -p $(PORT_NUMBER) -f $(FILE_NAME) -javap: - javap -classpath $(CLASSPATH) drafts.com.sun.star.accessibility.XAccessibleContext |