diff --git a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/VirtualFlow.java b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/VirtualFlow.java --- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/VirtualFlow.java +++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/VirtualFlow.java @@ -44,6 +44,8 @@ import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.Scene; +import javafx.scene.accessibility.Attribute; +import javafx.scene.accessibility.Role; import javafx.scene.control.Cell; import javafx.scene.control.IndexedCell; import javafx.scene.control.ScrollBar; @@ -2712,4 +2714,22 @@ tempVisibility = true; requestLayout(); } + + // This is currently only used by WinAccessible to more easily look up the + // vertical and horizontal scrollbars. With a little more code in WinAccesible + // it would be possible to not have VirtualFlow in the accessibility + // hierarchy, if desireable (it really depends on whether it is detrimental + // on platforms other than Windows - if it isn't I'd be inclined to leave it + // in). + /** @treatAsPrivate */ + @Override + public Object accGetAttribute(Attribute attribute, Object... parameters) { + switch (attribute) { + case ROLE: return Role.SCROLL_PANE; + case CONTENTS: return clipView; + case VERTICAL_SCROLLBAR: return vbar; + case HORIZONTAL_SCROLLBAR: return hbar; + default: return super.accGetAttribute(attribute, parameters); + } + } } diff --git a/modules/controls/src/main/java/javafx/scene/control/ListView.java b/modules/controls/src/main/java/javafx/scene/control/ListView.java --- a/modules/controls/src/main/java/javafx/scene/control/ListView.java +++ b/modules/controls/src/main/java/javafx/scene/control/ListView.java @@ -50,6 +50,7 @@ import javafx.event.EventHandler; import javafx.event.EventType; import javafx.geometry.Orientation; +import javafx.scene.accessibility.Action; import javafx.scene.accessibility.Attribute; import javafx.scene.accessibility.Role; import javafx.scene.layout.Region; @@ -1036,6 +1037,27 @@ private static final PseudoClass PSEUDO_CLASS_HORIZONTAL = PseudoClass.getPseudoClass("horizontal"); + + + /*************************************************************************** + * * + * Accessibility handling * + * * + **************************************************************************/ + + /** @treatAsPrivate */ + @Override public void accExecuteAction(Action action, Object... parameters) { + switch (action) { + case SCROLL_TO_INDEX: { + int index = (int) parameters[0]; + scrollTo(index); + break; + } + default: super.accExecuteAction(action, parameters); + } + } + + /*************************************************************************** * * * Support Interfaces * diff --git a/modules/controls/src/main/java/javafx/scene/control/ScrollBar.java b/modules/controls/src/main/java/javafx/scene/control/ScrollBar.java --- a/modules/controls/src/main/java/javafx/scene/control/ScrollBar.java +++ b/modules/controls/src/main/java/javafx/scene/control/ScrollBar.java @@ -25,27 +25,27 @@ package javafx.scene.control; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import com.sun.javafx.Utils; +import com.sun.javafx.css.converters.EnumConverter; +import com.sun.javafx.css.converters.SizeConverter; +import com.sun.javafx.scene.control.skin.ScrollBarSkin; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleDoubleProperty; +import javafx.css.CssMetaData; +import javafx.css.PseudoClass; +import javafx.css.Styleable; +import javafx.css.StyleableDoubleProperty; +import javafx.css.StyleableObjectProperty; +import javafx.css.StyleableProperty; import javafx.geometry.Orientation; import javafx.scene.accessibility.Action; import javafx.scene.accessibility.Attribute; import javafx.scene.accessibility.Role; -import com.sun.javafx.Utils; -import javafx.css.CssMetaData; -import javafx.css.PseudoClass; -import javafx.css.StyleableDoubleProperty; -import javafx.css.StyleableObjectProperty; -import com.sun.javafx.css.converters.EnumConverter; -import com.sun.javafx.css.converters.SizeConverter; -import com.sun.javafx.scene.control.skin.ScrollBarSkin; -import javafx.css.Styleable; -import javafx.css.StyleableProperty; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** @@ -474,6 +474,14 @@ return Boolean.FALSE; } + + + /*************************************************************************** + * * + * Accessibility handling * + * * + **************************************************************************/ + /** @treatAsPrivate */ @Override public Object accGetAttribute(Attribute attribute, Object... parameters) { switch (attribute) { @@ -491,6 +499,14 @@ switch (action) { case INCREMENT: increment(); break; case DECREMENT: decrement(); break; + case BLOCK_INCREMENT: { + adjustValue(getValue() + 0.1); + break; + } + case BLOCK_DECREMENT: { + adjustValue(getValue() - 0.1); + break; + } case SET_VALUE: { Double value = (Double) parameters[0]; if (value != null) setValue(value); diff --git a/modules/controls/src/main/java/javafx/scene/control/TableView.java b/modules/controls/src/main/java/javafx/scene/control/TableView.java --- a/modules/controls/src/main/java/javafx/scene/control/TableView.java +++ b/modules/controls/src/main/java/javafx/scene/control/TableView.java @@ -61,6 +61,7 @@ import javafx.event.EventHandler; import javafx.event.EventType; import javafx.scene.Node; +import javafx.scene.accessibility.Action; import javafx.scene.accessibility.Attribute; import javafx.scene.accessibility.Role; import javafx.scene.layout.Region; @@ -1591,7 +1592,27 @@ public List> getControlCssMetaData() { return getClassCssMetaData(); } - + + + + /*************************************************************************** + * * + * Accessibility handling * + * * + **************************************************************************/ + + /** @treatAsPrivate */ + @Override public void accExecuteAction(Action action, Object... parameters) { + switch (action) { + case SCROLL_TO_INDEX: { + int index = (int) parameters[0]; + scrollTo(index); + break; + } + default: super.accExecuteAction(action, parameters); + } + } + /*************************************************************************** diff --git a/modules/controls/src/main/java/javafx/scene/control/TreeTableView.java b/modules/controls/src/main/java/javafx/scene/control/TreeTableView.java --- a/modules/controls/src/main/java/javafx/scene/control/TreeTableView.java +++ b/modules/controls/src/main/java/javafx/scene/control/TreeTableView.java @@ -76,6 +76,7 @@ import javafx.event.EventHandler; import javafx.event.EventType; import javafx.scene.Node; +import javafx.scene.accessibility.Action; import javafx.scene.accessibility.Attribute; import javafx.scene.accessibility.Role; import javafx.scene.layout.GridPane; @@ -1858,7 +1859,27 @@ return new TreeTableViewSkin(this); } - + + + /*************************************************************************** + * * + * Accessibility handling * + * * + **************************************************************************/ + + /** @treatAsPrivate */ + @Override public void accExecuteAction(Action action, Object... parameters) { + switch (action) { + case SCROLL_TO_INDEX: { + int index = (int) parameters[0]; + scrollTo(index); + break; + } + default: super.accExecuteAction(action, parameters); + } + } + + /*************************************************************************** * * diff --git a/modules/controls/src/main/java/javafx/scene/control/TreeView.java b/modules/controls/src/main/java/javafx/scene/control/TreeView.java --- a/modules/controls/src/main/java/javafx/scene/control/TreeView.java +++ b/modules/controls/src/main/java/javafx/scene/control/TreeView.java @@ -25,17 +25,23 @@ package javafx.scene.control; -import java.lang.ref.SoftReference; -import java.util.*; - +import com.sun.javafx.css.converters.SizeConverter; +import com.sun.javafx.scene.control.skin.TreeViewSkin; +import javafx.application.Platform; +import javafx.beans.DefaultProperty; import javafx.beans.property.BooleanProperty; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectPropertyBase; +import javafx.beans.property.ReadOnlyIntegerProperty; +import javafx.beans.property.ReadOnlyIntegerWrapper; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; +import javafx.beans.value.WeakChangeListener; import javafx.css.CssMetaData; import javafx.css.Styleable; import javafx.css.StyleableDoubleProperty; @@ -43,25 +49,21 @@ import javafx.event.Event; import javafx.event.EventHandler; import javafx.event.EventType; +import javafx.event.WeakEventHandler; +import javafx.scene.accessibility.Action; import javafx.scene.accessibility.Attribute; import javafx.scene.accessibility.Role; import javafx.scene.control.TreeItem.TreeModificationEvent; import javafx.scene.layout.Region; import javafx.util.Callback; -import javafx.event.WeakEventHandler; -import com.sun.javafx.css.converters.SizeConverter; -import com.sun.javafx.scene.control.skin.TreeViewSkin; +import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; - -import javafx.application.Platform; -import javafx.beans.DefaultProperty; -import javafx.beans.property.ReadOnlyIntegerProperty; -import javafx.beans.property.ReadOnlyIntegerWrapper; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.ReadOnlyObjectWrapper; -import javafx.beans.value.WeakChangeListener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * The TreeView control provides a view on to a tree root (of type @@ -1089,6 +1091,26 @@ /*************************************************************************** * * + * Accessibility handling * + * * + **************************************************************************/ + + /** @treatAsPrivate */ + @Override public void accExecuteAction(Action action, Object... parameters) { + switch (action) { + case SCROLL_TO_INDEX: { + int index = (int) parameters[0]; + scrollTo(index); + break; + } + default: super.accExecuteAction(action, parameters); + } + } + + + + /*************************************************************************** + * * * Support Interfaces * * * **************************************************************************/ diff --git a/modules/graphics/src/main/java/com/sun/glass/ui/win/WinAccessible.java b/modules/graphics/src/main/java/com/sun/glass/ui/win/WinAccessible.java --- a/modules/graphics/src/main/java/com/sun/glass/ui/win/WinAccessible.java +++ b/modules/graphics/src/main/java/com/sun/glass/ui/win/WinAccessible.java @@ -25,18 +25,18 @@ package com.sun.glass.ui.win; +import com.sun.glass.ui.PlatformAccessible; +import com.sun.glass.ui.View; import javafx.collections.ObservableList; import javafx.geometry.Bounds; import javafx.geometry.Point2D; import javafx.scene.Node; -import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.accessibility.Accessible; import javafx.scene.accessibility.Action; import javafx.scene.accessibility.Attribute; import javafx.scene.accessibility.Role; -import com.sun.glass.ui.PlatformAccessible; -import com.sun.glass.ui.View; + import static javafx.scene.accessibility.Attribute.*; /* @@ -113,6 +113,7 @@ private static final int UIA_TextPatternId = 10014; private static final int UIA_TogglePatternId = 10015; private static final int UIA_TransformPatternId = 10016; + private static final int UIA_ScrollItemPatternId = 10017; private static final int UIA_ItemContainerPatternId = 10019; /* UIA_ControlTypeIds */ @@ -125,6 +126,7 @@ private static final int UIA_ListControlTypeId = 50008; private static final int UIA_ProgressBarControlTypeId = 50012; private static final int UIA_RadioButtonControlTypeId = 50013; + private static final int UIA_ScrollBarControlTypeId = 50014; private static final int UIA_SliderControlTypeId = 50015; private static final int UIA_TabControlTypeId = 50018; private static final int UIA_TabItemControlTypeId = 50019; @@ -176,6 +178,9 @@ private static final int ScrollAmount_LargeIncrement = 3; private static final int ScrollAmount_SmallIncrement = 4; + /* Scroll */ + private static final int UIA_ScrollPatternNoScroll = -1; + /* Other constants */ private static final int UiaAppendRuntimeId = 3; @@ -372,22 +377,83 @@ } private long getContainer(Role targetRole) { + Node node = getContainerNode(targetRole); + return node == null ? 0 : getAccessible(node); + } + + private Node getContainerNode(Role targetRole) { Node node = (Node)getAttribute(PARENT); while (node != null) { Accessible acc = node.getAccessible(); Role role = (Role)acc.getAttribute(ROLE); - if (role == targetRole) return getAccessible(node); + if (role == targetRole) return node; node = (Node)acc.getAttribute(PARENT); } - return 0; - } + return null; + } + + private Node getContainerNode() { + if (isDisposed()) return null; + Role role = (Role) getAttribute(ROLE); + if (role != null) { + switch(role) { + case TABLE_ROW: + case TABLE_CELL: return getContainerNode(Role.TABLE_VIEW); + case LIST_ITEM: return getContainerNode(Role.LIST_VIEW); + case TAB_ITEM: return getContainerNode(Role.TAB_PANE); + case PAGE: return getContainerNode(Role.PAGINATION); + case TREE_ITEM: return getContainerNode(Role.TREE_VIEW); + case TREE_TABLE_ITEM: return getContainerNode(Role.TREE_TABLE_VIEW); + case TREE_TABLE_CELL: return getContainerNode(Role.TREE_TABLE_VIEW); + default: + } + } + return null; + } + + private Node getChildNode(Role targetRole) { + return getChildNode(null, targetRole); + } + + private Node getChildNode(Node startNode, Role targetRole) { + if (startNode != null) { + Role role = (Role) startNode.accGetAttribute(ROLE); + if (role == targetRole) { + return startNode; + } + } + + ObservableList children = (ObservableList) + (startNode == null ? getAttribute(CHILDREN) : startNode.accGetAttribute(CHILDREN)); + + int size = children != null ? children.size() : 0; + + for (int i = 0; i < size; i++) { + Node n = children.get(i); + Role role = (Role) n.accGetAttribute(ROLE); + if (role == null) continue; + if (role == targetRole) { + return n; + } + } + for (int i = 0; i < size; i++) { + Node n = children.get(i); + Node childNode = getChildNode(n, targetRole); + if (childNode != null) { + return childNode; + } + } + return null; + } private int getControlType() { Role role = (Role)getAttribute(ROLE); if (role == null) return UIA_GroupControlTypeId; switch (role) { - case BUTTON: return UIA_ButtonControlTypeId; - case TOGGLE_BUTTON: return UIA_ButtonControlTypeId; + case BUTTON: + case TOGGLE_BUTTON: + case INCREMENT_BUTTON: + case DECREMENT_BUTTON: return UIA_ButtonControlTypeId; case PAGINATION: case TAB_PANE: return UIA_TabControlTypeId; case PAGE: @@ -417,6 +483,7 @@ case ACCORDION: case TITLED_PANE: case SCROLL_PANE: return UIA_PaneControlTypeId; + case SCROLL_BAR: return UIA_ScrollBarControlTypeId; case THUMB: return UIA_ThumbControlTypeId; default: return 0; } @@ -431,7 +498,9 @@ boolean impl = false; switch (role) { case HYPERLINK: - case BUTTON: + case BUTTON: + case INCREMENT_BUTTON: + case DECREMENT_BUTTON: impl = patternId == UIA_InvokePatternId; break; case PAGE: @@ -449,34 +518,41 @@ case TABLE_VIEW: impl = patternId == UIA_SelectionPatternId || patternId == UIA_GridPatternId || - patternId == UIA_TablePatternId; + patternId == UIA_TablePatternId || + patternId == UIA_ScrollPatternId; break; case TREE_VIEW: - impl = patternId == UIA_SelectionPatternId; + impl = patternId == UIA_SelectionPatternId || + patternId == UIA_ScrollPatternId; break; case LIST_VIEW: impl = patternId == UIA_SelectionPatternId || - patternId == UIA_GridPatternId; + patternId == UIA_GridPatternId || + patternId == UIA_ScrollPatternId; break; case TREE_TABLE_CELL: case TABLE_CELL: impl = patternId == UIA_SelectionItemPatternId || patternId == UIA_GridItemPatternId || - patternId == UIA_TableItemPatternId; + patternId == UIA_TableItemPatternId || + patternId == UIA_ScrollItemPatternId; break; case LIST_ITEM: impl = patternId == UIA_SelectionItemPatternId || - patternId == UIA_GridItemPatternId; + patternId == UIA_GridItemPatternId || + patternId == UIA_ScrollItemPatternId; break; case TREE_ITEM: impl = patternId == UIA_SelectionItemPatternId || - patternId == UIA_ExpandCollapsePatternId; + patternId == UIA_ExpandCollapsePatternId || + patternId == UIA_ScrollItemPatternId; break; case TREE_TABLE_ITEM: impl = patternId == UIA_SelectionItemPatternId || patternId == UIA_ExpandCollapsePatternId || patternId == UIA_GridItemPatternId || - patternId == UIA_TableItemPatternId; + patternId == UIA_TableItemPatternId || + patternId == UIA_ScrollItemPatternId; break; /* MSDN doc is confusing if text elements should implement @@ -1028,6 +1104,8 @@ case RADIO_BUTTON: case BUTTON: case TOGGLE_BUTTON: + case INCREMENT_BUTTON: + case DECREMENT_BUTTON: executeAction(Action.FIRE); break; default: @@ -1052,22 +1130,8 @@ } long get_SelectionContainer() { - if (isDisposed()) return 0; - Role role = (Role) getAttribute(ROLE); - if (role != null) { - switch(role) { - case TABLE_ROW: - case TABLE_CELL: return getContainer(Role.TABLE_VIEW); - case LIST_ITEM: return getContainer(Role.LIST_VIEW); - case TAB_ITEM: return getContainer(Role.TAB_PANE); - case PAGE: return getContainer(Role.PAGINATION); - case TREE_ITEM: return getContainer(Role.TREE_VIEW); - case TREE_TABLE_ITEM: return getContainer(Role.TREE_TABLE_VIEW); - case TREE_TABLE_CELL: return getContainer(Role.TREE_TABLE_VIEW); - default: - } - } - return 0; + Node node = getContainerNode(); + return node == null ? 0 : getAccessible(node); } /***********************************************/ @@ -1331,39 +1395,204 @@ /***********************************************/ void Scroll(int horizontalAmount, int verticalAmount) { if (isDisposed()) return; + + // dealing with vertical scroll first + if (get_VerticallyScrollable()) { + Node vsb = getScrollPaneAttribute(VERTICAL_SCROLLBAR); + switch (verticalAmount) { + case ScrollAmount_LargeIncrement: vsb.getAccessible().executeAction(Action.BLOCK_INCREMENT); break; + case ScrollAmount_SmallIncrement: vsb.getAccessible().executeAction(Action.INCREMENT); break; + case ScrollAmount_LargeDecrement: vsb.getAccessible().executeAction(Action.BLOCK_DECREMENT); break; + case ScrollAmount_SmallDecrement: vsb.getAccessible().executeAction(Action.DECREMENT); break; + } + } + + // now dealing with horizontal scroll + if (get_HorizontallyScrollable()) { + Node hsb = getScrollPaneAttribute(HORIZONTAL_SCROLLBAR); + switch (horizontalAmount) { + case ScrollAmount_LargeIncrement: hsb.getAccessible().executeAction(Action.BLOCK_INCREMENT); break; + case ScrollAmount_SmallIncrement: hsb.getAccessible().executeAction(Action.INCREMENT); break; + case ScrollAmount_LargeDecrement: hsb.getAccessible().executeAction(Action.BLOCK_DECREMENT); break; + case ScrollAmount_SmallDecrement: hsb.getAccessible().executeAction(Action.DECREMENT); break; + } + } } + // Sets the horizontal and vertical scroll position as a percentage of the + // total content area within the control. void SetScrollPercent(double horizontalPercent, double verticalPercent) { if (isDisposed()) return; + + // dealing with vertical scroll first + if (verticalPercent != UIA_ScrollPatternNoScroll && get_VerticallyScrollable()) { + Node vsb = getScrollPaneAttribute(VERTICAL_SCROLLBAR); + Double max = (Double)vsb.getAccessible().getAttribute(MAX_VALUE); + if (max != null) { + vsb.getAccessible().executeAction(Action.SET_VALUE, max * verticalPercent / 100); + } + } + + // now dealing with horizontal scroll + if (horizontalPercent != UIA_ScrollPatternNoScroll && get_HorizontallyScrollable()) { + Node hsb = getScrollPaneAttribute(HORIZONTAL_SCROLLBAR); + Double max = (Double)hsb.getAccessible().getAttribute(MAX_VALUE); + if (max != null) { + hsb.getAccessible().executeAction(Action.SET_VALUE, max * horizontalPercent / 100); + } + } } boolean get_HorizontallyScrollable() { if (isDisposed()) return false; - return false; + + Node hsb = (Node) getScrollPaneAttribute(HORIZONTAL_SCROLLBAR); + if(hsb == null) return false; + + Boolean visible = (Boolean)hsb.getAccessible().getAttribute(VISIBLE); + return Boolean.TRUE.equals(visible); } + // The horizontal scroll position, expressed as a percentage of the total + // content area within the UI Automation element. double get_HorizontalScrollPercent() { if (isDisposed()) return 0; + + if (! get_HorizontallyScrollable()) { + return UIA_ScrollPatternNoScroll; + } + + Node hsb = (Node) getScrollPaneAttribute(HORIZONTAL_SCROLLBAR); + if (hsb != null) { + // Windows expects a percentage between 0 and 100 + Double value = (Double)hsb.getAccessible().getAttribute(VALUE); + Double max = (Double)hsb.getAccessible().getAttribute(MAX_VALUE); + return value == null || max == null ? 0 : value / max * 100; + } + return 0; } + // The horizontal size of the viewable region, expressed as a percentage of + // the total content area within the control. double get_HorizontalViewSize() { if (isDisposed()) return 0; + + if (! get_HorizontallyScrollable()) return 100; + + Bounds scrollPaneBounds = (Bounds)getAttribute(BOUNDS); + Node content = (Node) getAttribute(CONTENTS); + + if (scrollPaneBounds != null && content != null) { + Bounds contentBounds = (Bounds) content.getAccessible().getAttribute(BOUNDS); + + if (contentBounds != null) { + final double scrollPaneWidth = scrollPaneBounds.getWidth(); + final double contentWidth = contentBounds.getHeight(); + + return scrollPaneWidth / contentWidth * 100; + } + } + return 0; } boolean get_VerticallyScrollable() { if (isDisposed()) return false; - return false; + + Node vsb = (Node) getScrollPaneAttribute(VERTICAL_SCROLLBAR); + if(vsb == null) return false; + + Boolean visible = (Boolean)vsb.getAccessible().getAttribute(VISIBLE); + return Boolean.TRUE.equals(visible); } + // The vertical scroll position, expressed as a percentage of the total + // content area within the UI Automation element. double get_VerticalScrollPercent() { if (isDisposed()) return 0; + + if (! get_VerticallyScrollable()) { + return UIA_ScrollPatternNoScroll; + } + + Node vsb = (Node) getScrollPaneAttribute(Attribute.VERTICAL_SCROLLBAR); + if (vsb != null) { + // Windows expects a percentage between 0 and 100 + Double value = (Double)vsb.getAccessible().getAttribute(VALUE); + Double max = (Double)vsb.getAccessible().getAttribute(MAX_VALUE); + return value == null || max == null ? 0 : value / max * 100; + } + return 0; } + // The vertical size of the viewable region, expressed as a percentage of + // the total content area within the control. double get_VerticalViewSize() { if (isDisposed()) return 0; - return 0; + if (!get_VerticallyScrollable()) return 100; + + double contentHeight = 0; + + Bounds scrollPaneBounds = (Bounds) getAttribute(BOUNDS); + if (scrollPaneBounds == null) return 0; + final double scrollPaneHeight = scrollPaneBounds.getHeight(); + + Role role = (Role) getAttribute(ROLE); + if (role == Role.SCROLL_PANE) { + Node content = (Node) getAttribute(CONTENTS); + if (content != null) { + Bounds contentBounds = (Bounds) content.getAccessible().getAttribute(BOUNDS); + contentHeight = contentBounds == null ? 0 : contentBounds.getHeight(); + } + } else { + Integer itemCount = 0; + + switch (role) { + case LIST_VIEW: + case TABLE_VIEW: + itemCount = (Integer) getAttribute(ROW_COUNT); + break; + case TREE_VIEW: + case TREE_TABLE_VIEW: + itemCount = (Integer) getAttribute(TREE_ITEM_COUNT); + break; + } + + // we do a quick calculation to approximate the height of the + // content area by assuming a fixed height multiplied by the number + // of items. The default height we use is 24px, which is the default + // height as specified in com.sun.javafx.scene.control.skin.CellSkinBase. + contentHeight = itemCount * 24; + } + + return contentHeight == 0 ? 0 : scrollPaneHeight / contentHeight * 100; + } + + private Node getScrollPaneAttribute(Attribute attribute) { + Role role = (Role) getAttribute(ROLE); + if (role == Role.SCROLL_PANE) { + return (Node) getAttribute(attribute); + } + Node scrollPane = getChildNode(Role.SCROLL_PANE); + if (scrollPane != null) { + return (Node) scrollPane.accGetAttribute(attribute); + } + + return null; + } + + /***********************************************/ + /* IScrollItemProvider */ + /***********************************************/ + void ScrollIntoView() { + if (isDisposed()) return; + + final Integer cellIndex = (Integer) getAttribute(INDEX); + final Node container = getContainerNode(); + if (cellIndex != null && container != null) { + container.getAccessible().executeAction(Action.SCROLL_TO_INDEX, cellIndex); + } } } diff --git a/modules/graphics/src/main/java/javafx/scene/accessibility/Action.java b/modules/graphics/src/main/java/javafx/scene/accessibility/Action.java --- a/modules/graphics/src/main/java/javafx/scene/accessibility/Action.java +++ b/modules/graphics/src/main/java/javafx/scene/accessibility/Action.java @@ -38,6 +38,10 @@ */ ADD_TO_SELECTION, + BLOCK_DECREMENT, + + BLOCK_INCREMENT, + COLLAPSE, DECREMENT, @@ -60,6 +64,13 @@ REMOVE_FROM_SELECTION, /** + * Requests that the given integer index is shown, if possible, by the + * container (e.g. ListView). + * Parameter: Integer + */ + SCROLL_TO_INDEX, + + /** * Selects the node, clearing out all other selection in the container. */ SELECT, diff --git a/modules/graphics/src/main/java/javafx/scene/accessibility/Role.java b/modules/graphics/src/main/java/javafx/scene/accessibility/Role.java --- a/modules/graphics/src/main/java/javafx/scene/accessibility/Role.java +++ b/modules/graphics/src/main/java/javafx/scene/accessibility/Role.java @@ -102,7 +102,7 @@ /** * ListView * Attributes: ROW_AT_INDEX, ROW_COUNT, SELECTED_ROWS, MULTIPLE_SELECTION - * Actions: (none) + * Actions: SCROLL_TO_INDEX */ LIST_VIEW, @@ -200,7 +200,7 @@ /** * ScrollBar * Attributes: VALUE, MAX_VALUE, MIN_VALUE, ORIENTATION - * Actions: INCREMENT, DECREMENT, SET_VALUE + * Actions: BLOCK_INCREMENT, INCREMENT, DECREMENT, BLOCK_DECREMENT, SET_VALUE */ SCROLL_BAR, @@ -250,7 +250,7 @@ * Table View * Attributes: ROW_COUNT, COLUMN_COUNT, SELECTED_CELLS, CELL_AT_ROWCOLUMN, MULTIPLE_SELECTION * Attributes for header support: COLUMN_AT_INDEX, HEADER - * Actions: (none) + * Actions: SCROLL_TO_INDEX */ TABLE_VIEW, @@ -304,14 +304,14 @@ * Attributes: TREE_ITEM_COUNT, TREE_ITEM_AT_INDEX, COLUMN_COUNT, * SELECTED_CELLS, CELL_AT_ROWCOLUMN, MULTIPLE_SELECTION, * Attributes for header support: COLUMN_AT_INDEX, HEADER - * Actions: (none) + * Actions: SCROLL_TO_INDEX */ TREE_TABLE_VIEW, /** * TreeView * Attributes: TREE_ITEM_COUNT, TREE_ITEM_AT_INDEX, SELECTED_ROWS, MULTIPLE_SELECTION - * Actions: (none) + * Actions: SCROLL_TO_INDEX */ TREE_VIEW, } diff --git a/modules/graphics/src/main/native-glass/win/GlassAccessible.cpp b/modules/graphics/src/main/native-glass/win/GlassAccessible.cpp --- a/modules/graphics/src/main/native-glass/win/GlassAccessible.cpp +++ b/modules/graphics/src/main/native-glass/win/GlassAccessible.cpp @@ -112,6 +112,8 @@ static jmethodID mid_get_VerticalScrollPercent; static jmethodID mid_get_VerticalViewSize; +static jmethodID mid_ScrollIntoView; + /* Variant Field IDs */ static jfieldID fid_vt; static jfieldID fid_iVal; @@ -302,6 +304,8 @@ *ppInterface = static_cast(this); } else if (riid == __uuidof(IScrollProvider)) { *ppInterface = static_cast(this); + } else if (riid == __uuidof(IScrollItemProvider)) { + *ppInterface = static_cast(this); } else { *ppInterface = NULL; return E_NOINTERFACE; @@ -921,6 +925,17 @@ return S_OK; } + /***********************************************/ +/* IScrollItemProvider */ +/***********************************************/ +IFACEMETHODIMP GlassAccessible::ScrollIntoView() +{ + JNIEnv* env = GetEnv(); + env->CallVoidMethod(m_jAccessible, mid_ScrollIntoView); + CheckAndClearException(env); + return S_OK; +} + /***********************************************/ /* JNI */ /***********************************************/ @@ -1033,6 +1048,9 @@ mid_get_VerticalScrollPercent = env->GetMethodID(jClass, "get_VerticalScrollPercent", "()D"); mid_get_VerticalViewSize = env->GetMethodID(jClass, "get_VerticalViewSize", "()D"); + /* IScrollItemProvider */ + mid_ScrollIntoView = env->GetMethodID(jClass, "ScrollIntoView", "()V"); + /* Variant */ jclass jVariantClass = env->FindClass("com/sun/glass/ui/win/WinVariant"); fid_vt = env->GetFieldID(jVariantClass, "vt", "S"); diff --git a/modules/graphics/src/main/native-glass/win/GlassAccessible.h b/modules/graphics/src/main/native-glass/win/GlassAccessible.h --- a/modules/graphics/src/main/native-glass/win/GlassAccessible.h +++ b/modules/graphics/src/main/native-glass/win/GlassAccessible.h @@ -44,7 +44,8 @@ public IToggleProvider, public IExpandCollapseProvider, public ITransformProvider, - public IScrollProvider + public IScrollProvider, + public IScrollItemProvider { public: @@ -158,6 +159,9 @@ IFACEMETHODIMP get_VerticalScrollPercent(double *pRetVal); IFACEMETHODIMP get_VerticalViewSize(double *pRetVal); + // IScrollItemProvider + IFACEMETHODIMP ScrollIntoView(); + static void copyVariant(JNIEnv *env, jobject jVariant, VARIANT* pRetVal); private: