--- old/tools/Jemmy/JemmyFX/src/org/jemmy/fx/control/TableUtils.java 2016-12-22 11:26:48.889266906 +0300 +++ new/tools/Jemmy/JemmyFX/src/org/jemmy/fx/control/TableUtils.java 2016-12-22 11:26:48.837266405 +0300 @@ -1,366 +1,366 @@ -/* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.jemmy.fx.control; - -import java.util.function.Function; -import javafx.scene.Node; -import javafx.scene.control.Control; -import javafx.scene.control.IndexedCell; -import javafx.scene.control.TableCell; -import javafx.scene.control.TreeTableCell; -import javafx.util.Callback; -import org.jemmy.Point; -import org.jemmy.Rectangle; -import org.jemmy.action.FutureAction; -import org.jemmy.control.Wrap; -import org.jemmy.env.Environment; -import org.jemmy.fx.FXClickFocus; -import org.jemmy.fx.NodeWrap; -import org.jemmy.input.AbstractScroll; -import org.jemmy.interfaces.Caret; -import org.jemmy.interfaces.Focus; -import org.jemmy.interfaces.Parent; -import org.jemmy.lookup.Lookup; - -/** - * @author Alexander Kirov - */ -public class TableUtils { - - public Focus focuser(Wrap wrap) { - final Rectangle bounds = wrap.getScreenBounds(); - return new FXClickFocus(wrap, new Point( - Math.max(bounds.getWidth() / 2, bounds.getWidth() - 3), - Math.max(bounds.getHeight() / 2, bounds.getHeight() - 3))); - } - - public static void scrollToInSingleDimension(final Wrap controlWrap, - final Class itemClass, - final Callback indexCallback, - final Integer targetControlIndex, - final Caret caret, - final boolean isVertical) { - caret.to(new Caret.Direction() { - /** - * @return < 0 to scroll toward decreasing value, > 0 - vice versa 0 - * to stop scrolling NOTE - see implementation - * KnobDragScrollerImpl.to(Direction) which is used in ScrollBarWrap - * better to return constant values (-1 || 0 || +1) to get smooth - * dragging - */ - final javafx.scene.Parent clippedContainer = getClippedContainerControl(controlWrap); - - @Override - public int to() { - Bounds visibleBounds = shown1dImpl(controlWrap, clippedContainer, indexCallback, itemClass, isVertical); - if (targetControlIndex < visibleBounds.getBegin()) { - return -1; - } else if (targetControlIndex > visibleBounds.getEnd()) { - return 1; - } else { - return 0; - } - } - - @Override - public String toString() { - return "'" + controlWrap.getControl() + "' state at index " + targetControlIndex; - } - }); - } - - public static Bounds shown1d( - final Wrap controlWrap, - final Callback indexCallback, - final Class itemClass, - final boolean isVertical) { - - return shown1dImpl(controlWrap, getClippedContainerControl(controlWrap), indexCallback, itemClass, isVertical); - } - - /** - * Extracted for optimization purpose - we don't need to find clipped - * container each time. - * - * @parameter clippedContainerWrap - precomputed wrap of clipped container. - */ - private static Bounds shown1dImpl( - final Wrap controlWrap, - final javafx.scene.Parent clippedContainer, - final Callback indexCallback, - final Class itemClass, - final boolean isVertical) { - final int[] minmax = new int[]{Integer.MAX_VALUE, -1}; - final Parent parent = controlWrap.as(Parent.class, Node.class); - parent.lookup(itemClass, cntrl -> { - boolean checkIndices; - checkIndices = NodeWrap.isInBounds(clippedContainer, cntrl, controlWrap.getEnvironment(), isVertical); - if (checkIndices) { - int index = indexCallback.call(cntrl); - if (index >= 0) { - if (index < minmax[0]) { - minmax[0] = index; - } - if (index > minmax[1]) { - minmax[1] = index; - } - } - } - - return true; - }).size(); - - return new Bounds(minmax[0], minmax[1]); - } - - /** - * checkScrolls(); must be called before this method call. - * - * @param row - * @param column - * @return - */ - static Wrap scrollTo(final Environment env, - final Wrap wrap, - AbstractScroll hScroll, - AbstractScroll vScroll, - final int row, - final int column, - final Function infoProvider, - final Class cellType) { - - final Rectangle actuallyVisibleArea = getActuallyVisibleArea(wrap); - if (vScroll != null) { - vScroll.caret().to(() -> { - int[] shown = shown(env, wrap, infoProvider, cellType, actuallyVisibleArea); - if (shown[1] > row) { - return -1; - } - if (shown[3] < row) { - return 1; - } - return 0; - }); - } - - if (hScroll != null) { - hScroll.caret().to(() -> { - int[] shown = shown(env, wrap, infoProvider, cellType, actuallyVisibleArea); - if (shown[0] > column) { - return -1; - } - if (shown[2] < column) { - return 1; - } - return 0; - }); - } - return null; - } - - /** - * Identifies which elements are shown in the TableView currently. - * - * @return {minColumn, minRow, maxColumn, maxRow} of cells that are fully - * visible in the list. - */ - public static int[] shown( - Environment env, - final Wrap wrap, - final Function infoProvider, - final Class cellType) { - - final Rectangle actuallyVisibleArea = getActuallyVisibleArea(wrap); - - return shown(env, wrap, infoProvider, cellType, actuallyVisibleArea); - } - - private static int[] shown( - Environment env, - final Wrap wrap, - final Function infoProvider, - final Class cellType, - final Rectangle actuallyVisibleArea) { - return new FutureAction<>(env, () -> { - final int[] res = new int[]{Integer.MAX_VALUE, Integer.MAX_VALUE, -1, -1}; - - final Parent parent = wrap.as(Parent.class, Node.class); - parent.lookup(cellType, control -> { - if (control.isVisible() && control.getParent().isVisible() && control.getOpacity() == 1.0) { - Rectangle bounds = NodeWrap.getScreenBounds(wrap.getEnvironment(), control); - Point cellCoord = infoProvider.apply(control); - int column = cellCoord.x; - int row = cellCoord.y; - if (actuallyVisibleArea.contains(bounds) && row >= 0 && column >= 0) { - res[0] = Math.min(res[0], column); - res[1] = Math.min(res[1], row); - res[2] = Math.max(res[2], column); - res[3] = Math.max(res[3], row); - } - } - return false; - }).size(); - - return res; - }).get(); - } - - /** - * @param controlWrap wrap of control like listView, tableView, treeView, or - * treeTableView. - * @param treeRowWrap wrap of row : treeItem, treeTableRow or tableRow, - * listItem. - * @return center of area, which is visible part of row/item. - */ - public static Point getClickPoint(Wrap controlWrap, Wrap rowWrap) { - Rectangle visibleAreaBounds = rowWrap.getScreenBounds(); - return getClickPointCommon(controlWrap, visibleAreaBounds); - } - - /** - * Method, specific for TableView and TreeTableView, which counts only - * actual cells width, without space of the last empty column. - */ - public static Point getTableRowClickPoint(Wrap controlWrap, Wrap rowWrap) { - Rectangle clickableArea = TableUtils.constructClickableArea(rowWrap); - return getClickPointCommon(controlWrap, clickableArea); - } - - /** - * Used for ListView, TreeView, TableView, TreeTableView. - * - * @param wrap of control. - * @return - */ - static Rectangle getActuallyVisibleArea(final Wrap wrap) { - final Rectangle viewArea = getContainerWrap(wrap.as(Parent.class, Node.class)).getScreenBounds(); - final Rectangle clippedContainerArea = getClippedContainerWrap(wrap.as(Parent.class, Node.class)).getScreenBounds(); - return new Rectangle(viewArea.x, viewArea.y, clippedContainerArea.width, clippedContainerArea.height); - } - - /** - * @return wrap of parent container that contains Cells - */ - static Wrap getContainerWrap(Parent parent) { - return getParentWrap(parent, VIRTIAL_FLOW_CLASS_NAME); - } - - static Wrap getClippedContainerWrap(Parent parent) { - return getParentWrap(parent, CLIPPED_CONTAINER_CLASS_NAME); - } - - static private Wrap getParentWrap(Parent parent, final String className) { - return parent.lookup(javafx.scene.Parent.class, control -> control.getClass().getName().endsWith(className)).wrap(); - } - - static private javafx.scene.Parent getClippedContainerControl(Wrap controlWrap) { - final Parent parent = controlWrap.as(Parent.class, Node.class); - final Wrap clippedContainerWrap = getClippedContainerWrap(parent); - return clippedContainerWrap.getControl(); - } - - /** - * Common algorithm - */ - private static Point getClickPointCommon(Wrap controlWrap, Rectangle clickableArea) { - Rectangle visibleAreaBounds = TableUtils.getActuallyVisibleArea(controlWrap); - Rectangle intersection = clickableArea.intersection(visibleAreaBounds); - int dx = intersection.x - clickableArea.x; - int dy = intersection.y - clickableArea.y; - return new Point(dx + intersection.width / 2, dy + intersection.height / 2); - } - - /** - * Special for TableView, and TreeTableView, as the last column contains - * empty not clickable space. - */ - private static Rectangle constructClickableArea(Wrap wrap) { - Rectangle rec = null; - final Lookup lookup = wrap.as(Parent.class, Node.class).lookup(IndexedCell.class); - for (int i = 0; i < lookup.size(); i++) { - Wrap cell = lookup.wrap(i); - if (rec == null) { - rec = cell.getScreenBounds(); - } else { - rec = rec.union(cell.getScreenBounds()); - } - } - return rec; - } - private static final String VIRTIAL_FLOW_CLASS_NAME = "VirtualFlow"; - private static final String CLIPPED_CONTAINER_CLASS_NAME = "VirtualFlow$ClippedContainer"; - - public final static class TableViewIndexInfoProvider implements Function { - - TableViewWrap theWrap; - - public TableViewIndexInfoProvider(TableViewWrap wrap) { - this.theWrap = wrap; - } - - @Override - public Point apply(TableCell t) { - return new Point(theWrap.getColumnIndex(t), theWrap.getRowIndex(t)); - } - } - - public final static class TreeTableViewIndexInfoProvider implements Function { - - TreeTableViewWrap theWrap; - - public TreeTableViewIndexInfoProvider(TreeTableViewWrap wrap) { - this.theWrap = wrap; - } - - @Override - public Point apply(TreeTableCell t) { - return new Point(theWrap.getColumnIndex(t), theWrap.getRowIndex(t)); - } - } - - public static class Bounds { - - private final int begin; - private final int end; - - public Bounds(int begin, int end) { - this.begin = begin; - this.end = end; - } - - public int getBegin() { - return begin; - } - - public int getEnd() { - return end; - } - - @Override - public String toString() { - return "Bounds : begin <" + begin + ">, end <" + end + ">."; - } - } -} +/* + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.jemmy.fx.control; + +import java.util.function.Function; +import javafx.scene.Node; +import javafx.scene.control.Control; +import javafx.scene.control.IndexedCell; +import javafx.scene.control.TableCell; +import javafx.scene.control.TreeTableCell; +import javafx.util.Callback; +import org.jemmy.Point; +import org.jemmy.Rectangle; +import org.jemmy.action.FutureAction; +import org.jemmy.control.Wrap; +import org.jemmy.env.Environment; +import org.jemmy.fx.FXClickFocus; +import org.jemmy.fx.NodeWrap; +import org.jemmy.input.AbstractScroll; +import org.jemmy.interfaces.Caret; +import org.jemmy.interfaces.Focus; +import org.jemmy.interfaces.Parent; +import org.jemmy.lookup.Lookup; + +/** + * @author Alexander Kirov + */ +public class TableUtils { + + public Focus focuser(Wrap wrap) { + final Rectangle bounds = wrap.getScreenBounds(); + return new FXClickFocus(wrap, new Point( + Math.max(bounds.getWidth() / 2, bounds.getWidth() - 3), + Math.max(bounds.getHeight() / 2, bounds.getHeight() - 3))); + } + + public static void scrollToInSingleDimension(final Wrap controlWrap, + final Class itemClass, + final Callback indexCallback, + final Integer targetControlIndex, + final Caret caret, + final boolean isVertical) { + caret.to(new Caret.Direction() { + /** + * @return < 0 to scroll toward decreasing value, > 0 - vice versa 0 + * to stop scrolling NOTE - see implementation + * KnobDragScrollerImpl.to(Direction) which is used in ScrollBarWrap + * better to return constant values (-1 || 0 || +1) to get smooth + * dragging + */ + final javafx.scene.Parent clippedContainer = getClippedContainerControl(controlWrap); + + @Override + public int to() { + Bounds visibleBounds = shown1dImpl(controlWrap, clippedContainer, indexCallback, itemClass, isVertical); + if (targetControlIndex < visibleBounds.getBegin()) { + return -1; + } else if (targetControlIndex > visibleBounds.getEnd()) { + return 1; + } else { + return 0; + } + } + + @Override + public String toString() { + return "'" + controlWrap.getControl() + "' state at index " + targetControlIndex; + } + }); + } + + public static Bounds shown1d( + final Wrap controlWrap, + final Callback indexCallback, + final Class itemClass, + final boolean isVertical) { + + return shown1dImpl(controlWrap, getClippedContainerControl(controlWrap), indexCallback, itemClass, isVertical); + } + + /** + * Extracted for optimization purpose - we don't need to find clipped + * container each time. + * + * @parameter clippedContainerWrap - precomputed wrap of clipped container. + */ + private static Bounds shown1dImpl( + final Wrap controlWrap, + final javafx.scene.Parent clippedContainer, + final Callback indexCallback, + final Class itemClass, + final boolean isVertical) { + final int[] minmax = new int[]{Integer.MAX_VALUE, -1}; + final Parent parent = controlWrap.as(Parent.class, Node.class); + parent.lookup(itemClass, cntrl -> { + boolean checkIndices; + checkIndices = NodeWrap.isInBounds(clippedContainer, cntrl, controlWrap.getEnvironment(), isVertical); + if (checkIndices) { + int index = indexCallback.call(cntrl); + if (index >= 0) { + if (index < minmax[0]) { + minmax[0] = index; + } + if (index > minmax[1]) { + minmax[1] = index; + } + } + } + + return true; + }).size(); + + return new Bounds(minmax[0], minmax[1]); + } + + /** + * checkScrolls(); must be called before this method call. + * + * @param row + * @param column + * @return + */ + static Wrap scrollTo(final Environment env, + final Wrap wrap, + AbstractScroll hScroll, + AbstractScroll vScroll, + final int row, + final int column, + final Function infoProvider, + final Class cellType) { + + final Rectangle actuallyVisibleArea = getActuallyVisibleArea(wrap); + if (vScroll != null) { + vScroll.caret().to(() -> { + int[] shown = shown(env, wrap, infoProvider, cellType, actuallyVisibleArea); + if (shown[1] > row) { + return -1; + } + if (shown[3] < row) { + return 1; + } + return 0; + }); + } + + if (hScroll != null) { + hScroll.caret().to(() -> { + int[] shown = shown(env, wrap, infoProvider, cellType, actuallyVisibleArea); + if (shown[0] > column) { + return -1; + } + if (shown[2] < column) { + return 1; + } + return 0; + }); + } + return null; + } + + /** + * Identifies which elements are shown in the TableView currently. + * + * @return {minColumn, minRow, maxColumn, maxRow} of cells that are fully + * visible in the list. + */ + public static int[] shown( + Environment env, + final Wrap wrap, + final Function infoProvider, + final Class cellType) { + + final Rectangle actuallyVisibleArea = getActuallyVisibleArea(wrap); + + return shown(env, wrap, infoProvider, cellType, actuallyVisibleArea); + } + + private static int[] shown( + Environment env, + final Wrap wrap, + final Function infoProvider, + final Class cellType, + final Rectangle actuallyVisibleArea) { + return new FutureAction<>(env, () -> { + final int[] res = new int[]{Integer.MAX_VALUE, Integer.MAX_VALUE, -1, -1}; + + final Parent parent = wrap.as(Parent.class, Node.class); + parent.lookup(cellType, control -> { + if (control.isVisible() && control.getParent().isVisible() && control.getOpacity() == 1.0) { + Rectangle bounds = NodeWrap.getScreenBounds(wrap.getEnvironment(), control); + Point cellCoord = infoProvider.apply(control); + int column = cellCoord.x; + int row = cellCoord.y; + if (actuallyVisibleArea.contains(bounds) && row >= 0 && column >= 0) { + res[0] = Math.min(res[0], column); + res[1] = Math.min(res[1], row); + res[2] = Math.max(res[2], column); + res[3] = Math.max(res[3], row); + } + } + return false; + }).size(); + + return res; + }).get(); + } + + /** + * @param controlWrap wrap of control like listView, tableView, treeView, or + * treeTableView. + * @param treeRowWrap wrap of row : treeItem, treeTableRow or tableRow, + * listItem. + * @return center of area, which is visible part of row/item. + */ + public static Point getClickPoint(Wrap controlWrap, Wrap rowWrap) { + Rectangle visibleAreaBounds = rowWrap.getScreenBounds(); + return getClickPointCommon(controlWrap, visibleAreaBounds); + } + + /** + * Method, specific for TableView and TreeTableView, which counts only + * actual cells width, without space of the last empty column. + */ + public static Point getTableRowClickPoint(Wrap controlWrap, Wrap rowWrap) { + Rectangle clickableArea = TableUtils.constructClickableArea(rowWrap); + return getClickPointCommon(controlWrap, clickableArea); + } + + /** + * Used for ListView, TreeView, TableView, TreeTableView. + * + * @param wrap of control. + * @return + */ + static Rectangle getActuallyVisibleArea(final Wrap wrap) { + final Rectangle viewArea = getContainerWrap((Parent )wrap.as(Parent.class, Node.class)).getScreenBounds(); + final Rectangle clippedContainerArea = getClippedContainerWrap((Parent )wrap.as(Parent.class, Node.class)).getScreenBounds(); + return new Rectangle(viewArea.x, viewArea.y, clippedContainerArea.width, clippedContainerArea.height); + } + + /** + * @return wrap of parent container that contains Cells + */ + static Wrap getContainerWrap(Parent parent) { + return getParentWrap(parent, VIRTIAL_FLOW_CLASS_NAME); + } + + static Wrap getClippedContainerWrap(Parent parent) { + return getParentWrap(parent, CLIPPED_CONTAINER_CLASS_NAME); + } + + static private Wrap getParentWrap(Parent parent, final String className) { + return parent.lookup(javafx.scene.Parent.class, control -> control.getClass().getName().endsWith(className)).wrap(); + } + + static private javafx.scene.Parent getClippedContainerControl(Wrap controlWrap) { + final Parent parent = controlWrap.as(Parent.class, Node.class); + final Wrap clippedContainerWrap = getClippedContainerWrap(parent); + return clippedContainerWrap.getControl(); + } + + /** + * Common algorithm + */ + private static Point getClickPointCommon(Wrap controlWrap, Rectangle clickableArea) { + Rectangle visibleAreaBounds = TableUtils.getActuallyVisibleArea(controlWrap); + Rectangle intersection = clickableArea.intersection(visibleAreaBounds); + int dx = intersection.x - clickableArea.x; + int dy = intersection.y - clickableArea.y; + return new Point(dx + intersection.width / 2, dy + intersection.height / 2); + } + + /** + * Special for TableView, and TreeTableView, as the last column contains + * empty not clickable space. + */ + private static Rectangle constructClickableArea(Wrap wrap) { + Rectangle rec = null; + final Lookup lookup = wrap.as(Parent.class, Node.class).lookup(IndexedCell.class); + for (int i = 0; i < lookup.size(); i++) { + Wrap cell = lookup.wrap(i); + if (rec == null) { + rec = cell.getScreenBounds(); + } else { + rec = rec.union(cell.getScreenBounds()); + } + } + return rec; + } + private static final String VIRTIAL_FLOW_CLASS_NAME = "VirtualFlow"; + private static final String CLIPPED_CONTAINER_CLASS_NAME = "VirtualFlow$ClippedContainer"; + + public final static class TableViewIndexInfoProvider implements Function { + + TableViewWrap theWrap; + + public TableViewIndexInfoProvider(TableViewWrap wrap) { + this.theWrap = wrap; + } + + @Override + public Point apply(TableCell t) { + return new Point(theWrap.getColumnIndex(t), theWrap.getRowIndex(t)); + } + } + + public final static class TreeTableViewIndexInfoProvider implements Function { + + TreeTableViewWrap theWrap; + + public TreeTableViewIndexInfoProvider(TreeTableViewWrap wrap) { + this.theWrap = wrap; + } + + @Override + public Point apply(TreeTableCell t) { + return new Point(theWrap.getColumnIndex(t), theWrap.getRowIndex(t)); + } + } + + public static class Bounds { + + private final int begin; + private final int end; + + public Bounds(int begin, int end) { + this.begin = begin; + this.end = end; + } + + public int getBegin() { + return begin; + } + + public int getEnd() { + return end; + } + + @Override + public String toString() { + return "Bounds : begin <" + begin + ">, end <" + end + ">."; + } + } +}