changeset 6511:579fbfe34c8c

[Accessibility] Tree clean up, implement expand/collapse for windows, remove Attribute.NEXT_SIBLING, PREVIOUS_SIBLING, remove TreeCell ugly helpers, use indices on the same currency
author Felipe Heidrich <felipe.heidrich@oracle.com>
date Tue, 18 Mar 2014 16:44:34 -0700
parents 9604915644c1
children 9823085ebf0e
files modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TreeViewSkin.java modules/controls/src/main/java/javafx/scene/control/TreeCell.java modules/controls/src/main/java/javafx/scene/control/TreeTableRow.java modules/graphics/src/main/java/com/sun/glass/ui/mac/MacAccessible.java modules/graphics/src/main/java/com/sun/glass/ui/win/WinAccessible.java modules/graphics/src/main/java/javafx/scene/accessibility/Attribute.java
diffstat 6 files changed, 90 insertions(+), 124 deletions(-) [+]
line wrap: on
line diff
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TreeViewSkin.java	Tue Mar 18 14:17:08 2014 -0700
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TreeViewSkin.java	Tue Mar 18 16:44:34 2014 -0700
@@ -517,8 +517,12 @@
                 return flow.getCell(focusedIndex);
             }
             case ROW_AT_INDEX: {
+            	/* Note: Using getVisibleCell() is safer than getCell() for this case.
+            	 * getCell() frequently recycles cells for hidden items which can cause 
+            	 * next sibling traversal to infinite loop.
+            	 */
                 final int rowIndex = (Integer)parameters[0];
-                return rowIndex < 0 ? null : flow.getCell(rowIndex);
+                return rowIndex < 0 ? null : flow.getVisibleCell(rowIndex);
             }
             case SELECTED_ROWS: {
                 MultipleSelectionModel<TreeItem<T>> sm = getSkinnable().getSelectionModel();
@@ -526,11 +530,6 @@
                 List<Node> selection = new ArrayList<>(indices.size());
                 for (int i : indices) {
                     TreeCell<T> row = flow.getCell(i);
-
-                    // We should never, ever get row == null. If we do then
-                    // something is very wrong.
-                    assert row != null;
-
                     if (row != null) selection.add(row);
                 }
                 return FXCollections.observableArrayList(selection);
--- a/modules/controls/src/main/java/javafx/scene/control/TreeCell.java	Tue Mar 18 14:17:08 2014 -0700
+++ b/modules/controls/src/main/java/javafx/scene/control/TreeCell.java	Tue Mar 18 16:44:34 2014 -0700
@@ -645,34 +645,27 @@
     public Object accGetAttribute(Attribute attribute, Object... parameters) {
         TreeItem<T> treeItem = getTreeItem();
         TreeView<T> treeView = getTreeView();
-
         switch (attribute) {
             case ROLE: return Role.TREE_ITEM;
             case TREE_ITEM_PARENT: {
-                if (treeItem == null) {
-                    return null;
-                }
-                TreeItem parent = treeItem.getParent();
-                return parent == null ? treeView : getTreeCell(getVirtualFlow(), parent);
+                if (treeView == null) return null;
+                if (treeItem == null) return null;
+                TreeItem<T> parent = treeItem.getParent();
+                if (parent == null) return null;
+                int parentIndex = treeView.getRow(parent);
+                return treeView.accGetAttribute(Attribute.ROW_AT_INDEX, parentIndex);
             }
             case TREE_ITEM_COUNT: {
-                // response is relative to this tree cell
                 return treeItem == null  ? 0 : treeItem.getChildren().size();
             }
-            case TREE_ITEM_AT_INDEX: {
-                // index is relative to this tree cell
-                final int offset = (Integer)parameters[0];
-                final int p = offset + getIndex();
-                return treeItem == null                  ? null :
-                       p > treeItem.getChildren().size() ? null :
-                       getVirtualFlow().getCell(p);
-            }
-            case PREVIOUS_SIBLING: {
-                return treeItem == null ? null : getTreeCell(getVirtualFlow(), treeItem.previousSibling());
-            }
-            case NEXT_SIBLING: {
-                return treeItem == null ? null : getTreeCell(getVirtualFlow(), treeItem.nextSibling());
-            }
+            case TREE_ITEM_AT_INDEX:
+                if (treeItem == null) return null;
+                int index = (Integer)parameters[0];
+                if (index >= treeItem.getChildren().size()) return null;
+                TreeItem<T> child = treeItem.getChildren().get(index);
+                if (child == null) return null;
+                int childIndex = treeView.getRow(child);
+                return treeView.accGetAttribute(Attribute.ROW_AT_INDEX, childIndex);
             case TITLE: {
                 Object value = treeItem == null ? null : treeItem.getValue();
                 return value == null ? "" : value.toString();
@@ -682,8 +675,7 @@
             case INDEX: return getIndex();
             case SELECTED: return isSelected();
             case DISCLOSURE_LEVEL: {
-                // FIXME replace with treeView.getTreeItemLevel(treeItem) when we sync up with 8u20
-                return treeView == null ? 0 : TreeView.getNodeLevel(treeItem);
+                return treeView == null ? 0 : treeView.getTreeItemLevel(treeItem);
             }
             default: return super.accGetAttribute(attribute, parameters);
         }
@@ -720,32 +712,4 @@
             default: super.accExecuteAction(action);
         }
     }
-
-    private VirtualFlow getVirtualFlow() {
-        // FIXME Ugly hack! Clean this up once everything is understood
-        Parent p = getParent();
-        while (p != null && ! (p instanceof VirtualFlow)) {
-            p = p.getParent();
-        }
-
-        if (p == null) {
-            return null;
-        }
-
-        return (VirtualFlow) p;
-    }
-
-    private TreeCell<T> getTreeCell(VirtualFlow<TreeCell<T>> flow, TreeItem treeItem) {
-        // FIXME Ugly hack! Clean this up once everything is understood
-        if (treeItem == null) return null;
-
-        final int treeItemIndex = getTreeView().getRow(treeItem);
-        TreeCell<T> cell = null;
-
-        if (flow != null) {
-            cell = flow.getVisibleCell(treeItemIndex);
-        }
-
-        return cell;
-    }
 }
--- a/modules/controls/src/main/java/javafx/scene/control/TreeTableRow.java	Tue Mar 18 14:17:08 2014 -0700
+++ b/modules/controls/src/main/java/javafx/scene/control/TreeTableRow.java	Tue Mar 18 16:44:34 2014 -0700
@@ -555,12 +555,6 @@
                        p > treeItem.getChildren().size() ? null :
                        getVirtualFlow().getCell(p);
             }
-            case PREVIOUS_SIBLING: {
-                return treeItem == null ? null : getTreeTableRow(getVirtualFlow(), treeItem.previousSibling());
-            }
-            case NEXT_SIBLING: {
-                return treeItem == null ? null : getTreeTableRow(getVirtualFlow(), treeItem.nextSibling());
-            }
             case TITLE: {
                 Object value = treeItem == null ? null : treeItem.getValue();
                 return value == null ? "" : value.toString();
--- a/modules/graphics/src/main/java/com/sun/glass/ui/mac/MacAccessible.java	Tue Mar 18 14:17:08 2014 -0700
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/mac/MacAccessible.java	Tue Mar 18 16:44:34 2014 -0700
@@ -1016,10 +1016,6 @@
                 break;
             }
             case NSAccessibilityDisclosedByRowAttribute:
-                Integer level = (Integer)getAttribute(DISCLOSURE_LEVEL);
-                if (level != null && level == 0) return null;
-                result = getAccessible((Node)result);
-                break;
             case NSAccessibilityOverflowButtonAttribute:
             case NSAccessibilityTitleUIElementAttribute:
             case NSAccessibilityHeaderAttribute:
--- a/modules/graphics/src/main/java/com/sun/glass/ui/win/WinAccessible.java	Tue Mar 18 14:17:08 2014 -0700
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/win/WinAccessible.java	Tue Mar 18 16:44:34 2014 -0700
@@ -93,6 +93,7 @@
     private static final int UIA_FrameworkIdPropertyId           = 30024;
     private static final int UIA_ValueValuePropertyId            = 30045;
     private static final int UIA_RangeValueValuePropertyId       = 30047;
+    private static final int UIA_ExpandCollapseExpandCollapseStatePropertyId = 30070;
     private static final int UIA_ToggleToggleStatePropertyId     = 30086;
     private static final int UIA_AriaRolePropertyId              = 30101;
     private static final int UIA_ProviderDescriptionPropertyId   = 30107;
@@ -338,6 +339,19 @@
                 }
                 break;
             }
+            case EXPANDED: {
+                Boolean expanded = (Boolean)getAttribute(EXPANDED); 
+                if (expanded != null) {
+                    WinVariant vo = new WinVariant();
+                    vo.vt = WinVariant.VT_I4;
+                    vo.lVal = expanded ? ExpandCollapseState_Collapsed : ExpandCollapseState_Expanded;
+                    WinVariant vn = new WinVariant();
+                    vn.vt = WinVariant.VT_I4;
+                    vn.lVal = expanded ? ExpandCollapseState_Expanded : ExpandCollapseState_Collapsed;
+                    UiaRaiseAutomationPropertyChangedEvent(peer, UIA_ExpandCollapseExpandCollapseStatePropertyId, vo, vn);
+                }
+                break;
+            }
             default:
                 UiaRaiseAutomationEvent(peer, UIA_AutomationPropertyChangedEventId);
         }
@@ -689,53 +703,72 @@
 
     long Navigate(int direction) {
         if (isDisposed()) return 0;
-        Accessible acc = null;
+        Role role = (Role)getAttribute(ROLE);
+        /* special case for the tree item hierarchy, as expected by Windows */
+        boolean treeCell = role == Role.TREE_ITEM || role == Role.TREE_TABLE_ITEM;
+        Node node = null;
         switch (direction) {
             case NavigateDirection_Parent: {
                 /* Return null for the top level node */
                 if (getView() != null) return 0L;
     
-                /* special case for the tree item hierarchy, as expected by Windows */
-                Parent parent = (Parent)getAttribute(TREE_ITEM_PARENT);
-    
-                if (parent == null) {
-                    parent = (Parent)getAttribute(PARENT);
-                }
-                if (parent != null) {
-                    acc = parent.getAccessible();
+                if (treeCell) {
+                    node = (Node)getAttribute(TREE_ITEM_PARENT);
+                    if (node == null) {
+                        /* root tree item case*/
+                        if (role == Role.TREE_ITEM) {
+                            return getContainer(Role.TREE_VIEW);
+                        } else {
+                            return getContainer(Role.TREE_TABLE_VIEW);
+                        }
+                    }
                 } else {
-                    Scene scene = (Scene)getAttribute(SCENE);
-                    if (scene != null) {
-                        acc = scene.getAccessible();
+                    node = (Node)getAttribute(PARENT);
+                    if (node == null) {
+                        /* scene root node case */
+                        Scene scene = (Scene)getAttribute(SCENE);
+                        if (scene != null) {
+                            Accessible acc = scene.getAccessible();
+                            WinAccessible winAcc = (WinAccessible)acc.impl_getDelegate();
+                            return winAcc.getNativeAccessible();
+                        }
                     }
                 }
                 break;
             }
             case NavigateDirection_NextSibling:
             case NavigateDirection_PreviousSibling: {
-                Role role = (Role)getAttribute(ROLE);
-                if (role == Role.TREE_ITEM || role == Role.TREE_TABLE_ITEM) {
-                    Node n = null;
-                    if (direction == NavigateDirection_PreviousSibling) {
-                        n = (Node) getAttribute(PREVIOUS_SIBLING);
-                    } else if (direction == NavigateDirection_NextSibling) {
-                        n = (Node) getAttribute(NEXT_SIBLING);
-                    }
-                    acc = n != null ? n.getAccessible() : null;
-                } else {
-                    Parent parent = (Parent)getAttribute(PARENT);
-                    if (parent != null) {
-                        //Note: parent == null -> root node (which has not siblings)
-                        Accessible parentAccessible = parent.getAccessible();
+                Node parent = (Node)getAttribute(treeCell ? TREE_ITEM_PARENT : PARENT);
+                /* When the parent is NULL is indicates either the root node for the scene
+                 * or the root tree item in a tree view. Either way, there is no siblings. 
+                 */
+                if (parent != null) {
+                    Accessible parentAccessible = parent.getAccessible();
+                    if (treeCell) {
+                        Integer result = (Integer)parentAccessible.getAttribute(TREE_ITEM_COUNT);
+                        int count = result != null ? result : 0;
+                        for (int i = 0; i < count; i++) {
+                            Node item = (Node)parentAccessible.getAttribute(Attribute.TREE_ITEM_AT_INDEX, i);
+                            if (getAccessible(item) == peer) {
+                                if (direction == NavigateDirection_NextSibling && i + 1 < count) {
+                                    node = (Node)parentAccessible.getAttribute(TREE_ITEM_AT_INDEX, i + 1);
+                                }
+                                if (direction == NavigateDirection_PreviousSibling && i > 0) {
+                                    node = (Node)parentAccessible.getAttribute(TREE_ITEM_AT_INDEX, i - 1);
+                                }
+                                break;
+                            }
+                        }
+                    } else {
                         ObservableList<Node> children = (ObservableList<Node>)parentAccessible.getAttribute(CHILDREN);
                         int size = children != null ? children.size() : 0;
                         for (int i = 0; i < size; i++) {
                             if (getAccessible(children.get(i)) == peer) {
                                 if (direction == NavigateDirection_NextSibling && i + 1 < size) {
-                                    acc = children.get(i + 1).getAccessible();
+                                   node = children.get(i + 1);
                                 }
                                 if (direction == NavigateDirection_PreviousSibling && i > 0) {
-                                    acc = children.get(i - 1).getAccessible();
+                                   node = children.get(i - 1);
                                 }
                                 break;
                             }
@@ -746,41 +779,33 @@
             }
             case NavigateDirection_FirstChild:
             case NavigateDirection_LastChild: {
-                Role role = (Role)getAttribute(ROLE);
                 if (role == Role.TREE_VIEW || role == Role.TREE_TABLE_VIEW) {
                     /* The TreeView only returns the root node as child */
-                    Node n = (Node)getAttribute(ROW_AT_INDEX, 0);
-                    acc = n != null ? n.getAccessible() : null;
-                } else if (role == Role.TREE_ITEM || role == Role.TREE_TABLE_ITEM) {
-                    int rowCount = (int) getAttribute(TREE_ITEM_COUNT);
-                    Node n = null;
-                    if (rowCount > 0) {
+                    node = (Node)getAttribute(ROW_AT_INDEX, 0);
+                } else if (treeCell) {
+                    Integer count = (Integer)getAttribute(TREE_ITEM_COUNT);
+                    if (count != null && count > 0) {
                         if (direction == NavigateDirection_FirstChild) {
-                            n = (Node) getAttribute(TREE_ITEM_AT_INDEX, 1);
+                            node = (Node)getAttribute(TREE_ITEM_AT_INDEX, 0);
                         } else if (direction == NavigateDirection_LastChild) {
-                            n = (Node) getAttribute(TREE_ITEM_AT_INDEX, rowCount - 1);
+                            node = (Node)getAttribute(TREE_ITEM_AT_INDEX, count - 1);
                         }
                     }
-                    acc = n != null ? n.getAccessible() : null;
                 } else {
                     ObservableList<Node> children = (ObservableList<Node>)getAttribute(CHILDREN);
                     int size = children != null ? children.size() : 0;
                     if (size > 0) {
                         if (direction == NavigateDirection_FirstChild) {
-                            acc = children.get(0).getAccessible();
+                            node = children.get(0);
                         } else {
-                            acc = children.get(size - 1).getAccessible();
+                            node = children.get(size - 1);
                         }
                     }
                 }
                 break;
             }
         }
-        if (acc != null) {
-            WinAccessible winAcc = (WinAccessible)acc.impl_getDelegate();
-            return winAcc.getNativeAccessible();
-        }
-        return 0l;
+        return getAccessible(node);
     }
 
     void SetFocus() {
--- a/modules/graphics/src/main/java/javafx/scene/accessibility/Attribute.java	Tue Mar 18 14:17:08 2014 -0700
+++ b/modules/graphics/src/main/java/javafx/scene/accessibility/Attribute.java	Tue Mar 18 16:44:34 2014 -0700
@@ -192,12 +192,6 @@
     NODE_AT_POINT("NodeAtPoint", Node.class),
 
     /**
-     * Used exclusively in relation to TreeView / TreeTableView, to return
-     * siblings of a given TreeItem.
-     */
-    NEXT_SIBLING("NextSibling", Node.class),
-
-    /**
      * Returns the orientation of a node
      * Type: Orientation
      */
@@ -222,12 +216,6 @@
     PARENT("Parent", Parent.class),
 
     /**
-     * Used exclusively in relation to TreeView / TreeTableView, to return
-     * siblings of a given TreeItem.
-     */
-    PREVIOUS_SIBLING("PreviousSibling", Node.class),
-
-    /**
      * Returns the role for the Node.
      * Type: Role
      */