# HG changeset patch # User jgiles # Date 1395348607 -46800 # Fri Mar 21 09:50:07 2014 +1300 # Node ID fa0866379c4060e62c210bcf2032e71c0a0c2a60 # Parent 6e5b35c6cfb5b9f22eaf5659362b8ce7b040f639 RT-36266: [Accessibility] Implement scrolling diff --git a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ListViewSkin.java b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ListViewSkin.java --- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ListViewSkin.java +++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ListViewSkin.java @@ -531,6 +531,8 @@ } return FXCollections.observableArrayList(selection); } + case VERTICAL_SCROLLBAR: return flow.getVbar(); + case HORIZONTAL_SCROLLBAR: return flow.getHbar(); default: return super.accGetAttribute(attribute, parameters); } } diff --git a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TableViewSkinBase.java b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TableViewSkinBase.java --- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TableViewSkinBase.java +++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TableViewSkinBase.java @@ -981,6 +981,8 @@ * look for column headers */ return getTableHeaderRow(); } + case VERTICAL_SCROLLBAR: return flow.getVbar(); + case HORIZONTAL_SCROLLBAR: return flow.getHbar(); default: return super.accGetAttribute(attribute, parameters); } } diff --git a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TreeViewSkin.java b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TreeViewSkin.java --- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TreeViewSkin.java +++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TreeViewSkin.java @@ -534,6 +534,8 @@ } return FXCollections.observableArrayList(selection); } + case VERTICAL_SCROLLBAR: return flow.getVbar(); + case HORIZONTAL_SCROLLBAR: return flow.getHbar(); 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,44 @@ private static final PseudoClass PSEUDO_CLASS_HORIZONTAL = PseudoClass.getPseudoClass("horizontal"); + + + /*************************************************************************** + * * + * Accessibility handling * + * * + **************************************************************************/ + + /** @treatAsPrivate */ + @Override public Object accGetAttribute(Attribute attribute, Object... parameters) { + switch (attribute) { + case ROLE: return Role.LIST_VIEW; + case ROW_COUNT: return getItems().size(); + case MULTIPLE_SELECTION: { + MultipleSelectionModel sm = getSelectionModel(); + return sm != null && sm.getSelectionMode() == SelectionMode.MULTIPLE; + } + case ROW_AT_INDEX: //Skin + case SELECTED_ROWS: //Skin + case VERTICAL_SCROLLBAR: //Skin + case HORIZONTAL_SCROLLBAR: // Skin + default: return super.accGetAttribute(attribute, parameters); + } + } + + /** @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 * @@ -1493,20 +1532,4 @@ } } } - - /** @treatAsPrivate */ - @Override - public Object accGetAttribute(Attribute attribute, Object... parameters) { - switch (attribute) { - case ROLE: return Role.LIST_VIEW; - case ROW_COUNT: return getItems().size(); - case MULTIPLE_SELECTION: { - MultipleSelectionModel sm = getSelectionModel(); - return sm != null && sm.getSelectionMode() == SelectionMode.MULTIPLE; - } - case ROW_AT_INDEX: //Skin - case SELECTED_ROWS: //Skin - default: return super.accGetAttribute(attribute, parameters); - } - } } 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; /** @@ -347,6 +347,14 @@ setValue(Utils.clamp(getMin(), getValue() - getUnitIncrement(), getMax())); } + private void blockIncrement() { + adjustValue(getValue() + getBlockIncrement()); + } + + private void blockDecrement() { + adjustValue(getValue() - getBlockIncrement()); + } + /** {@inheritDoc} */ @Override protected Skin createDefaultSkin() { return new ScrollBarSkin(this); @@ -474,6 +482,14 @@ return Boolean.FALSE; } + + + /*************************************************************************** + * * + * Accessibility handling * + * * + **************************************************************************/ + /** @treatAsPrivate */ @Override public Object accGetAttribute(Attribute attribute, Object... parameters) { switch (attribute) { @@ -491,6 +507,8 @@ switch (action) { case INCREMENT: increment(); break; case DECREMENT: decrement(); break; + case BLOCK_INCREMENT: blockIncrement(); break; + case BLOCK_DECREMENT: blockDecrement(); 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,62 @@ public List> getControlCssMetaData() { return getClassCssMetaData(); } - + + + + /*************************************************************************** + * * + * Accessibility handling * + * * + **************************************************************************/ + + /** @treatAsPrivate */ + @Override public Object accGetAttribute(Attribute attribute, Object... parameters) { + switch (attribute) { + case ROLE: return Role.TABLE_VIEW; + case COLUMN_COUNT: return getVisibleLeafColumns().size(); + case ROW_COUNT: return getItems().size(); + case SELECTED_CELLS: { + // TableViewSkin returns TableRows back to TableView. + // TableRowSkin returns TableCells back to TableRow. + ObservableList> rows = (ObservableList>)super.accGetAttribute(attribute, parameters); + List selection = new ArrayList<>(); + for (TableRow row : rows) { + ObservableList cells = (ObservableList)row.accGetAttribute(attribute, parameters); + if (cells != null) selection.addAll(cells); + } + return FXCollections.observableArrayList(selection); + } + case FOCUS_ITEM: + case CELL_AT_ROWCOLUMN: { + TableRow row = (TableRow)super.accGetAttribute(attribute, parameters); + return row != null ? row.accGetAttribute(attribute, parameters) : null; + } + case MULTIPLE_SELECTION: { + MultipleSelectionModel sm = getSelectionModel(); + return sm != null && sm.getSelectionMode() == SelectionMode.MULTIPLE; + } + case COLUMN_AT_INDEX: //Skin + case COLUMN_INDEX: //Skin + case HEADER: //Skin + case VERTICAL_SCROLLBAR: //Skin + case HORIZONTAL_SCROLLBAR: // Skin + default: return super.accGetAttribute(attribute, parameters); + } + } + + /** @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); + } + } + /*************************************************************************** @@ -2989,38 +3045,4 @@ return tableView.getVisibleLeafColumn(newColumnIndex); } } - - /** @treatAsPrivate */ - @Override - public Object accGetAttribute(Attribute attribute, Object... parameters) { - switch (attribute) { - case ROLE: return Role.TABLE_VIEW; - case COLUMN_COUNT: return getVisibleLeafColumns().size(); - case ROW_COUNT: return getItems().size(); - case SELECTED_CELLS: { - // TableViewSkin returns TableRows back to TableView. - // TableRowSkin returns TableCells back to TableRow. - ObservableList> rows = (ObservableList>)super.accGetAttribute(attribute, parameters); - List selection = new ArrayList<>(); - for (TableRow row : rows) { - ObservableList cells = (ObservableList)row.accGetAttribute(attribute, parameters); - if (cells != null) selection.addAll(cells); - } - return FXCollections.observableArrayList(selection); - } - case FOCUS_ITEM: - case CELL_AT_ROWCOLUMN: { - TableRow row = (TableRow)super.accGetAttribute(attribute, parameters); - return row != null ? row.accGetAttribute(attribute, parameters) : null; - } - case MULTIPLE_SELECTION: { - MultipleSelectionModel sm = getSelectionModel(); - return sm != null && sm.getSelectionMode() == SelectionMode.MULTIPLE; - } - case COLUMN_AT_INDEX: //Skin - case COLUMN_INDEX: //Skin - case HEADER: //Skin - default: return super.accGetAttribute(attribute, 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,74 @@ return new TreeTableViewSkin(this); } - + + + /*************************************************************************** + * * + * Accessibility handling * + * * + **************************************************************************/ + + /** @treatAsPrivate */ + @Override public Object accGetAttribute(Attribute attribute, Object... parameters) { + switch (attribute) { + case ROLE: return Role.TREE_TABLE_VIEW; + + case TREE_ITEM_COUNT: + case ROW_COUNT: return getExpandedItemCount(); + + // --- TableView-specific attributes + case COLUMN_COUNT: return getVisibleLeafColumns().size(); + /* + * TreeTableViewSkin returns TreeTableRows back to TreeTableView. + * TreeTableRowSkin returns TreeTableCells back to TreeTableRow. + */ + case SELECTED_CELLS: { + ObservableList> rows = (ObservableList>)super.accGetAttribute(attribute, parameters); + List selection = new ArrayList<>(); + for (TreeTableRow row : rows) { + ObservableList cells = (ObservableList)row.accGetAttribute(attribute, parameters); + if (cells != null) selection.addAll(cells); + } + return FXCollections.observableArrayList(selection); + } + case FOCUS_ITEM: + case CELL_AT_ROWCOLUMN: { + TreeTableRow row = (TreeTableRow)super.accGetAttribute(attribute, parameters); + return row != null ? row.accGetAttribute(attribute, parameters) : null; + } + case MULTIPLE_SELECTION: { + MultipleSelectionModel sm = getSelectionModel(); + return sm != null && sm.getSelectionMode() == SelectionMode.MULTIPLE; + } + case COLUMN_INDEX: //Skin + case HEADER: //Skin + + // --- TreeView-specific attributes + case ROW_AT_INDEX: //Skin + case SELECTED_ROWS: //Skin + case TREE_ITEM_AT_INDEX: //Skin + + case VERTICAL_SCROLLBAR: //Skin + case HORIZONTAL_SCROLLBAR: // Skin + + default: return super.accGetAttribute(attribute, parameters); + } + } + + /** @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); + } + } + + /*************************************************************************** * * @@ -3274,49 +3342,4 @@ return treeTableView.getVisibleLeafColumn(newColumnIndex); } } - - /** @treatAsPrivate */ - @Override - public Object accGetAttribute(Attribute attribute, Object... parameters) { - switch (attribute) { - case ROLE: return Role.TREE_TABLE_VIEW; - - case TREE_ITEM_COUNT: - case ROW_COUNT: return getExpandedItemCount(); - - // --- TableView-specific attributes - case COLUMN_COUNT: return getVisibleLeafColumns().size(); - /* - * TreeTableViewSkin returns TreeTableRows back to TreeTableView. - * TreeTableRowSkin returns TreeTableCells back to TreeTableRow. - */ - case SELECTED_CELLS: { - ObservableList> rows = (ObservableList>)super.accGetAttribute(attribute, parameters); - List selection = new ArrayList<>(); - for (TreeTableRow row : rows) { - ObservableList cells = (ObservableList)row.accGetAttribute(attribute, parameters); - if (cells != null) selection.addAll(cells); - } - return FXCollections.observableArrayList(selection); - } - case FOCUS_ITEM: - case CELL_AT_ROWCOLUMN: { - TreeTableRow row = (TreeTableRow)super.accGetAttribute(attribute, parameters); - return row != null ? row.accGetAttribute(attribute, parameters) : null; - } - case MULTIPLE_SELECTION: { - MultipleSelectionModel sm = getSelectionModel(); - return sm != null && sm.getSelectionMode() == SelectionMode.MULTIPLE; - } - case COLUMN_INDEX: //Skin - case HEADER: //Skin - - // --- TreeView-specific attributes - case ROW_AT_INDEX: //Skin - case SELECTED_ROWS: //Skin - case TREE_ITEM_AT_INDEX: //Skin - - default: return super.accGetAttribute(attribute, 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,43 @@ /*************************************************************************** * * + * Accessibility handling * + * * + **************************************************************************/ + + /** @treatAsPrivate */ + @Override public Object accGetAttribute(Attribute attribute, Object... parameters) { + switch (attribute) { + case ROLE: return Role.TREE_VIEW; + case MULTIPLE_SELECTION: { + MultipleSelectionModel sm = getSelectionModel(); + return sm != null && sm.getSelectionMode() == SelectionMode.MULTIPLE; + } + case ROW_COUNT: return getExpandedItemCount(); + case ROW_AT_INDEX: //Skin + case SELECTED_ROWS: //Skin + case VERTICAL_SCROLLBAR: //Skin + case HORIZONTAL_SCROLLBAR: // Skin + default: return super.accGetAttribute(attribute, parameters); + } + } + + /** @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 * * * **************************************************************************/ @@ -1532,20 +1571,4 @@ super.focus(index); } } - - /** @treatAsPrivate */ - @Override - public Object accGetAttribute(Attribute attribute, Object... parameters) { - switch (attribute) { - case ROLE: return Role.TREE_VIEW; - case MULTIPLE_SELECTION: { - MultipleSelectionModel sm = getSelectionModel(); - return sm != null && sm.getSelectionMode() == SelectionMode.MULTIPLE; - } - case ROW_COUNT: return getExpandedItemCount(); - case ROW_AT_INDEX: //Skin - case SELECTED_ROWS: //Skin - default: return super.accGetAttribute(attribute, parameters); - } - } } 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 @@ -112,6 +112,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 */ @@ -124,6 +125,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; @@ -163,7 +165,7 @@ private static final int SupportedTextSelection_Multiple = 2; /* ExpandCollapseState */ - private static final int ExpandCollapseState_Collapsed = 0; + private static final int ExpandCollapseState_Collapsed = 0; private static final int ExpandCollapseState_Expanded = 1; private static final int ExpandCollapseState_PartiallyExpanded = 2; private static final int ExpandCollapseState_LeafNode = 3; @@ -175,6 +177,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; @@ -192,8 +197,8 @@ /* Releases the GlassAccessible and deletes the GlobalRef */ private native void _destroyGlassAccessible(long accessible); - private native static long UiaRaiseAutomationEvent(long pProvider, int id); - private native static long UiaRaiseAutomationPropertyChangedEvent(long pProvider, int id, WinVariant oldV, WinVariant newV); + private native static long UiaRaiseAutomationEvent(long pProvider, int id); + private native static long UiaRaiseAutomationPropertyChangedEvent(long pProvider, int id, WinVariant oldV, WinVariant newV); private WinAccessible(Accessible accessible) { super(accessible); @@ -339,7 +344,7 @@ break; } case EXPANDED: { - Boolean expanded = (Boolean)getAttribute(EXPANDED); + Boolean expanded = (Boolean)getAttribute(EXPANDED); if (expanded != null) { WinVariant vo = new WinVariant(); vo.vt = WinVariant.VT_I4; @@ -371,22 +376,48 @@ } 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 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: @@ -416,6 +447,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; } @@ -430,11 +462,13 @@ boolean impl = false; switch (role) { case HYPERLINK: - case BUTTON: + case BUTTON: + case INCREMENT_BUTTON: + case DECREMENT_BUTTON: impl = patternId == UIA_InvokePatternId; break; case PAGE: - case TAB_ITEM: + case TAB_ITEM: impl = patternId == UIA_SelectionItemPatternId; break; case PAGINATION: @@ -448,34 +482,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 @@ -499,7 +540,7 @@ case RADIO_BUTTON: impl = patternId == UIA_SelectionItemPatternId; break; - case CHECKBOX: + case CHECKBOX: impl = patternId == UIA_TogglePatternId; break; case TOGGLE_BUTTON: @@ -722,7 +763,7 @@ case NavigateDirection_Parent: { /* Return null for the top level node */ if (getView() != null) return 0L; - + if (treeCell) { node = (Node)getAttribute(TREE_ITEM_PARENT); if (node == null) { @@ -1039,6 +1080,8 @@ case RADIO_BUTTON: case BUTTON: case TOGGLE_BUTTON: + case INCREMENT_BUTTON: + case DECREMENT_BUTTON: executeAction(Action.FIRE); break; default: @@ -1063,22 +1106,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); } /***********************************************/ @@ -1342,39 +1371,188 @@ /***********************************************/ void Scroll(int horizontalAmount, int verticalAmount) { if (isDisposed()) return; + + /* dealing with vertical scroll first */ + if (get_VerticallyScrollable()) { + Node vsb = (Node) getAttribute(VERTICAL_SCROLLBAR); + Accessible vsbAccessible = vsb.getAccessible(); + switch (verticalAmount) { + case ScrollAmount_LargeIncrement: vsbAccessible.executeAction(Action.BLOCK_INCREMENT); break; + case ScrollAmount_SmallIncrement: vsbAccessible.executeAction(Action.INCREMENT); break; + case ScrollAmount_LargeDecrement: vsbAccessible.executeAction(Action.BLOCK_DECREMENT); break; + case ScrollAmount_SmallDecrement: vsbAccessible.executeAction(Action.DECREMENT); break; + default: break; + } + } + + /* now dealing with horizontal scroll */ + if (get_HorizontallyScrollable()) { + Node hsb = (Node) getAttribute(HORIZONTAL_SCROLLBAR); + Accessible hsbAccessible = hsb.getAccessible(); + switch (horizontalAmount) { + case ScrollAmount_LargeIncrement: hsbAccessible.executeAction(Action.BLOCK_INCREMENT); break; + case ScrollAmount_SmallIncrement: hsbAccessible.executeAction(Action.INCREMENT); break; + case ScrollAmount_LargeDecrement: hsbAccessible.executeAction(Action.BLOCK_DECREMENT); break; + case ScrollAmount_SmallDecrement: hsbAccessible.executeAction(Action.DECREMENT); break; + default: break; + } + } } void SetScrollPercent(double horizontalPercent, double verticalPercent) { if (isDisposed()) return; + + /* dealing with vertical scroll first */ + if (verticalPercent != UIA_ScrollPatternNoScroll && get_VerticallyScrollable()) { + Node vsb = (Node) getAttribute(VERTICAL_SCROLLBAR); + Double min = (Double)vsb.getAccessible().getAttribute(MIN_VALUE); + Double max = (Double)vsb.getAccessible().getAttribute(MAX_VALUE); + if (min != null && max != null) { + vsb.getAccessible().executeAction(Action.SET_VALUE, (max-min)*(verticalPercent/100)+min); + } + } + + /* now dealing with horizontal scroll */ + if (horizontalPercent != UIA_ScrollPatternNoScroll && get_HorizontallyScrollable()) { + Node hsb = (Node) getAttribute(HORIZONTAL_SCROLLBAR); + Double min = (Double)hsb.getAccessible().getAttribute(MIN_VALUE); + Double max = (Double)hsb.getAccessible().getAttribute(MAX_VALUE); + if (min != null && max != null) { + hsb.getAccessible().executeAction(Action.SET_VALUE, (max-min)*(horizontalPercent/100)+min); + } + } } boolean get_HorizontallyScrollable() { if (isDisposed()) return false; - return false; + + Node hsb = (Node) getAttribute(HORIZONTAL_SCROLLBAR); + if(hsb == null) return false; + + Boolean visible = (Boolean)hsb.getAccessible().getAttribute(VISIBLE); + return Boolean.TRUE.equals(visible); } double get_HorizontalScrollPercent() { if (isDisposed()) return 0; + + if (! get_HorizontallyScrollable()) { + return UIA_ScrollPatternNoScroll; + } + + Node hsb = (Node) getAttribute(HORIZONTAL_SCROLLBAR); + if (hsb != null) { + /* Windows expects a percentage between 0 and 100 */ + Accessible hsba = hsb.getAccessible(); + Double value = (Double)hsba.getAttribute(VALUE); + if (value == null) return 0; + Double max = (Double)hsba.getAttribute(MAX_VALUE); + if (max == null) return 0; + Double min = (Double)hsba.getAttribute(MIN_VALUE); + if (min == null) return 0; + return (100 * (value - min)) / (max - min); + } + return 0; } double get_HorizontalViewSize() { if (isDisposed()) return 0; - return 0; + if (!get_HorizontallyScrollable()) return 100; /* MSDN spec */ + Node content = (Node) getAttribute(CONTENTS); + if (content == null) return 100; + Bounds contentBounds = (Bounds) content.getAccessible().getAttribute(BOUNDS); + if (contentBounds == null) return 0; + Bounds scrollPaneBounds = (Bounds)getAttribute(BOUNDS); + if (scrollPaneBounds == null) return 0; + return scrollPaneBounds.getWidth() / contentBounds.getWidth() * 100; } boolean get_VerticallyScrollable() { if (isDisposed()) return false; - return false; + + Node vsb = (Node) getAttribute(VERTICAL_SCROLLBAR); + if(vsb == null) return false; + + Boolean visible = (Boolean)vsb.getAccessible().getAttribute(VISIBLE); + return Boolean.TRUE.equals(visible); } double get_VerticalScrollPercent() { if (isDisposed()) return 0; + + if (! get_VerticallyScrollable()) { + return UIA_ScrollPatternNoScroll; + } + + Node vsb = (Node) getAttribute(Attribute.VERTICAL_SCROLLBAR); + if (vsb != null) { + /* Windows expects a percentage between 0 and 100 */ + Accessible vsba = vsb.getAccessible(); + Double value = (Double)vsba.getAttribute(VALUE); + if (value == null) return 0; + Double max = (Double)vsba.getAttribute(MAX_VALUE); + if (max == null) return 0; + Double min = (Double)vsba.getAttribute(MIN_VALUE); + if (min == null) return 0; + return (100 * (value - min)) / (max - min); + } + return 0; } 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: + case TREE_VIEW: + case TREE_TABLE_VIEW: + itemCount = (Integer) getAttribute(ROW_COUNT); + break; + default: break; + } + + /* + * 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 == null ? 0 : itemCount * 24; + } + + return contentHeight == 0 ? 0 : scrollPaneHeight / contentHeight * 100; + } + + /***********************************************/ + /* 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,14 +38,34 @@ */ ADD_TO_SELECTION, + /** + * Decrements the node (if it support BLOCK_DECREMENT) by its larger block decrement + * value. A smaller decrement can be performed by using {@link #DECREMENT}. + */ + BLOCK_DECREMENT, + + /** + * Increments the node (if it support BLOCK_INCREMENT) by its larger block increment + * value. A smaller increment can be performed by using {@link #INCREMENT}. + */ + BLOCK_INCREMENT, + COLLAPSE, + /** + * Decrements the node (if it support DECREMENT) by its smaller unit decrement + * value. A larger decrement can be performed by using {@link #BLOCK_DECREMENT}. + */ DECREMENT, EXPAND, FIRE, + /** + * Increments the node (if it support INCREMENT) by its smaller unit increment + * value. A larger increment can be performed by using {@link #BLOCK_INCREMENT}. + */ INCREMENT, /** @@ -60,6 +80,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 @@ -101,8 +101,9 @@ /** * ListView - * Attributes: ROW_AT_INDEX, ROW_COUNT, SELECTED_ROWS, MULTIPLE_SELECTION - * Actions: (none) + * Attributes: ROW_AT_INDEX, ROW_COUNT, SELECTED_ROWS, MULTIPLE_SELECTION, + * VERTICAL_SCROLLBAR, HORIZONTAL_SCROLLBAR + * Actions: SCROLL_TO_INDEX */ LIST_VIEW, @@ -200,7 +201,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, @@ -248,9 +249,10 @@ /** * Table View - * Attributes: ROW_COUNT, COLUMN_COUNT, SELECTED_CELLS, CELL_AT_ROWCOLUMN, MULTIPLE_SELECTION + * Attributes: ROW_COUNT, COLUMN_COUNT, SELECTED_CELLS, CELL_AT_ROWCOLUMN, MULTIPLE_SELECTION, + * VERTICAL_SCROLLBAR, HORIZONTAL_SCROLLBAR * Attributes for header support: COLUMN_AT_INDEX, HEADER - * Actions: (none) + * Actions: SCROLL_TO_INDEX */ TABLE_VIEW, @@ -301,17 +303,19 @@ /** * Table View - * Attributes: TREE_ITEM_COUNT, TREE_ITEM_AT_INDEX, COLUMN_COUNT, + * Attributes: ROW_COUNT, TREE_ITEM_AT_INDEX, COLUMN_COUNT, * SELECTED_CELLS, CELL_AT_ROWCOLUMN, MULTIPLE_SELECTION, + * VERTICAL_SCROLLBAR, HORIZONTAL_SCROLLBAR * 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) + * Attributes: ROW_COUNT, TREE_ITEM_AT_INDEX, SELECTED_ROWS, MULTIPLE_SELECTION, + * VERTICAL_SCROLLBAR, HORIZONTAL_SCROLLBAR + * 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; @@ -307,6 +309,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; @@ -930,6 +934,17 @@ return S_OK; } + /***********************************************/ +/* IScrollItemProvider */ +/***********************************************/ +IFACEMETHODIMP GlassAccessible::ScrollIntoView() +{ + JNIEnv* env = GetEnv(); + env->CallVoidMethod(m_jAccessible, mid_ScrollIntoView); + CheckAndClearException(env); + return S_OK; +} + /***********************************************/ /* JNI */ /***********************************************/ @@ -1107,6 +1122,10 @@ if (env->ExceptionCheck()) return; mid_get_VerticalViewSize = env->GetMethodID(jClass, "get_VerticalViewSize", "()D"); if (env->ExceptionCheck()) return; + + /* IScrollItemProvider */ + mid_ScrollIntoView = env->GetMethodID(jClass, "ScrollIntoView", "()V"); + if (env->ExceptionCheck()) return; /* Variant */ jclass jVariantClass = env->FindClass("com/sun/glass/ui/win/WinVariant"); 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: