/*******************************************************************************
* Copyright (c) 2014 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.rc.javafx.tester.util;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import org.apache.commons.lang.ObjectUtils;
import org.eclipse.jubula.rc.common.adaptable.AdapterFactoryRegistry;
import org.eclipse.jubula.rc.common.driver.ClickOptions;
import org.eclipse.jubula.rc.common.driver.DragAndDropHelper;
import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer;
import org.eclipse.jubula.rc.common.driver.IRobot;
import org.eclipse.jubula.rc.common.exception.RobotException;
import org.eclipse.jubula.rc.common.exception.StepExecutionException;
import org.eclipse.jubula.rc.common.implclasses.table.Cell;
import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeTableOperationContext;
import org.eclipse.jubula.rc.common.logger.AutServerLogger;
import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IComponent;
import org.eclipse.jubula.rc.common.tester.adapter.interfaces.ITextComponent;
import org.eclipse.jubula.rc.common.util.IndexConverter;
import org.eclipse.jubula.rc.common.util.MatchUtil;
import org.eclipse.jubula.rc.common.util.SelectionUtil;
import org.eclipse.jubula.rc.javafx.driver.EventThreadQueuerJavaFXImpl;
import org.eclipse.jubula.tools.internal.constants.TestDataConstants;
import org.eclipse.jubula.tools.internal.objects.event.EventFactory;
import org.eclipse.jubula.tools.internal.objects.event.TestErrorEvent;
import org.eclipse.jubula.tools.internal.utils.StringParsing;
import com.sun.javafx.scene.control.skin.TableColumnHeader;
import com.sun.javafx.scene.control.skin.TableHeaderRow;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTablePosition;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.layout.Pane;
/**
* This context holds the tree and supports access to the Robot. It also
* implements some general operations on the tree inside a TreeTableView.
*
* @author BREDEX GmbH
*/
public class TreeTableOperationContext
extends AbstractTreeTableOperationContext<TreeTableView<?>, Object> {
/** The AUT Server logger. */
private static AutServerLogger log = new AutServerLogger(
TreeTableOperationContext.class);
/**
* Workaround to support nested Columns without modifying classes which would
* affect other toolkits
**/
private List<TreeTableColumn<?, ?>> m_columns =
new ArrayList<TreeTableColumn<?, ?>>();
/**
* Creates a new instance.
*
* @param queuer
* the queuer
* @param robot
* the Robot
* @param treeTable
* the treeTable
* @param column
* the column
*/
public TreeTableOperationContext(IEventThreadQueuer queuer, IRobot robot,
TreeTableView<?> treeTable, int column) {
super(queuer, robot, treeTable, column);
if (treeTable.getRoot() == null) {
throw new StepExecutionException(
"Tree Table is empty.", //$NON-NLS-1$
EventFactory.createActionError(TestErrorEvent.NOT_FOUND));
}
}
/**
* Creates a new instance.
*
* @param queuer
* the queuer
* @param robot
* the Robot
* @param treeTable
* the treeTable
*/
public TreeTableOperationContext(IEventThreadQueuer queuer, IRobot robot,
TreeTableView<?> treeTable) {
super(queuer, robot, treeTable);
if (treeTable.getRoot() == null) {
throw new StepExecutionException(
"Tree Table is empty.", //$NON-NLS-1$
EventFactory.createActionError(TestErrorEvent.NOT_FOUND));
}
}
@Override
public int getNumberOfColumns() {
return getTreeTable().getVisibleLeafColumns().size();
}
@Override
protected String convertValueToText(final Object node, final int row)
throws StepExecutionException {
String result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"convertValueToText", new Callable<String>() { //$NON-NLS-1$
@Override
public String call() throws Exception {
if (node instanceof TreeItem) {
TreeItem<?> item = (TreeItem<?>) node;
if (item != null) {
Object val = item.getValue();
if (val != null) {
return val.toString();
}
}
}
return node.toString();
}
});
return result;
}
@Override
public Collection<String> getNodeTextList(final Object node) {
List<String> res = new ArrayList<String>();
int rowNotUsed = 0;
String valText = convertValueToText(node, rowNotUsed);
if (valText != null) {
res.add(valText);
}
String rendText = getRenderedText(node);
if (rendText != null) {
res.add(rendText);
}
return res;
}
@Override
public String getRenderedText(final Object node)
throws StepExecutionException {
int indexOfTreeColumn = getIndexOfTreeColumn();
return getTextFromNode(node, indexOfTreeColumn);
}
/**
* @return the index of the column containing the tree
*/
private int getIndexOfTreeColumn() {
ObservableList<?> columns = getTree().getColumns();
TreeTableColumn<?, ?> treeColumn = getTree().getTreeColumn();
int indexOfColumnContainingTree = 0;
if (columns.contains(treeColumn)) {
indexOfColumnContainingTree = columns.indexOf(treeColumn);
}
return indexOfColumnContainingTree;
}
@Override
public String getRenderedTextOfColumn(final Object node)
throws StepExecutionException {
return getTextFromNode(node, getColumn());
}
/**
* Gets the rendered text of a TreeTableCell
*
* @param node
* this can be a cell or a tree item
* @param col
* if node is a tree item this parameter is used to find the cell
* to get the rendered text from
* @return the rendered text
*/
private String getTextFromNode(final Object node, final int col) {
if (node instanceof TreeItem<?>) {
scrollNodeToVisible(node);
}
String result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getRenderedText", new Callable<String>() { //$NON-NLS-1$
@Override
public String call() throws Exception {
if (node instanceof TreeTableCell) {
TreeTableCell<?, ?> cell =
(TreeTableCell<?, ?>) node;
return getRenderedCellText(cell);
} else if (node instanceof TreeItem) {
TreeItem<?> item = (TreeItem<?>) node;
TreeTableView<?> treeTable = getTree();
List<TreeTableCell> cells = NodeTraverseHelper
.getInstancesOf(treeTable,
TreeTableCell.class);
for (TreeTableCell<?, ?> cell : cells) {
// Nullchecks because of the virtual flow cells
// are created which might not be associated
// with a row or an item
TreeTableRow<?> ttRow = cell.getTreeTableRow();
if (ttRow == null) {
continue;
}
TreeItem<?> checkItem = ttRow.getTreeItem();
if (checkItem == null) {
continue;
}
if (item != null && checkItem.equals(item)
&& treeTable.getVisibleLeafColumns()
.indexOf(cell.getTableColumn())
== col) {
return getRenderedCellText(cell);
}
}
}
return null;
}
});
return result;
}
/**
* gets the rendered text of the cell or from components within the cell
* @param cell the cell
* @return String containing the text or null if no text was found
*/
private String getRenderedCellText(TreeTableCell<?, ?> cell) {
IComponent adapter = (IComponent)
AdapterFactoryRegistry.getInstance()
.getAdapter(IComponent.class, cell);
if (adapter != null
&& adapter instanceof ITextComponent) {
return ((ITextComponent) adapter).getText();
}
return null;
}
@Override
public boolean isVisible(final Object node) {
boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait("isVisible", //$NON-NLS-1$
new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
TreeItem<?> item = (TreeItem<?>) node;
return item.isExpanded() && getTree().isVisible();
}
});
return result;
}
@Override
public Rectangle getVisibleRowBounds(final Rectangle rowBounds) {
Rectangle result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getVisibleRowBounds", new Callable<Rectangle>() { //$NON-NLS-1$
@Override
public Rectangle call() throws Exception {
TreeTableView<?> tree = getTree();
// Update the layout coordinates otherwise
// we would get old position values
tree.layout();
Rectangle visibleTreeBounds = new Rectangle(0, 0,
Rounding.round(tree.getWidth()), Rounding
.round(tree.getHeight()));
return rowBounds.intersection(visibleTreeBounds);
}
});
return result;
}
@Override
public void scrollNodeToVisible(final Object node) {
EventThreadQueuerJavaFXImpl.invokeAndWait("scrollNodeToVisible", //$NON-NLS-1$
new Callable<Void>() {
@Override
public Void call() throws Exception {
int index = ((TreeTableView) getTree())
.getRow((TreeItem<?>) node);
TreeTableView<?> trt = getTree();
trt.scrollTo(index);
if (getColumn() >= trt.getColumns().size()) {
// We want to scroll to a leaf column but the tree
// table only considers the top column for scrolling
// via index
trt.scrollToColumnIndex(
trt.getColumns().size() - 1);
} else {
trt.scrollToColumnIndex(getColumn());
}
// Update the layout coordinates otherwise
// we would get old position values
trt.layout();
return null;
}
});
}
@Override
public void clickNode(final Object node, final ClickOptions clickOps) {
scrollNodeToVisible(node);
Rectangle rowBounds = getNodeBounds(node);
Rectangle visibleRowBounds = getVisibleRowBounds(rowBounds);
getRobot().click(getTree(), visibleRowBounds, clickOps);
}
@Override
public void expandNode(final Object node) {
scrollNodeToVisible(node);
boolean expanded = EventThreadQueuerJavaFXImpl.invokeAndWait(
"expandNodeCheckIfExpanded", //$NON-NLS-1$
new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
TreeItem<?> item = (TreeItem<?>) node;
return item.isExpanded();
}
});
if (expanded) {
return;
}
// If this is called during drag mode the target is not visible
if (DragAndDropHelper.getInstance().isDragMode()) {
throw new StepExecutionException("Drop target not visible", //$NON-NLS-1$
EventFactory.createActionError(TestErrorEvent.NOT_VISIBLE));
}
Object result = EventThreadQueuerJavaFXImpl.invokeAndWait("expandNode", //$NON-NLS-1$
new Callable<Object>() {
@Override
public Object call() throws Exception {
TreeItem<?> item = (TreeItem<?>) node;
TreeTableView<?> treeTable = getTree();
List<TreeTableCell> cells = NodeTraverseHelper
.getInstancesOf(treeTable, TreeTableCell.class);
for (TreeTableCell<?, ?> treeTableCell : cells) {
// Nullchecks because of the virtual flow cells
// are created which might not be associated
// with a row or an item
TreeTableRow<?> ttRow = treeTableCell
.getTreeTableRow();
if (ttRow == null) {
continue;
}
TreeItem<?> checkItem = ttRow.getTreeItem();
if (checkItem == null) {
continue;
}
if (item != null && checkItem.equals(item)
&& !item.isExpanded()) {
return treeTableCell.getTreeTableRow()
.getDisclosureNode();
}
}
return null;
}
});
if (result != null) {
getRobot().click(result, null,
ClickOptions.create().setClickCount(1).setMouseButton(1));
}
EventThreadQueuerJavaFXImpl.invokeAndWait("expandNodeCheckIfExpanded", //$NON-NLS-1$
new Callable<Void>() {
@Override
public Void call() throws Exception {
TreeItem<?> item = (TreeItem<?>) node;
if (!getTree().isDisabled() && !item.isExpanded()) {
log.warn("Expand node fallback used for: " //$NON-NLS-1$
+ item.getValue());
item.setExpanded(true);
}
return null;
}
});
}
@Override
public void collapseNode(final Object node) {
scrollNodeToVisible(node);
Object result = EventThreadQueuerJavaFXImpl.invokeAndWait("collapseNode", //$NON-NLS-1$
new Callable<Object>() {
@Override
public Object call() throws Exception {
TreeItem<?> item = (TreeItem<?>) node;
TreeTableView<?> treeTable = getTree();
List<TreeTableCell> cells = NodeTraverseHelper
.getInstancesOf(treeTable, TreeTableCell.class);
for (TreeTableCell<?, ?> treeTableCell : cells) {
// Nullchecks because of the virtual flow cells
// are created which might not be associated
// with a row or an item
TreeTableRow<?> ttRow = treeTableCell
.getTreeTableRow();
if (ttRow == null) {
continue;
}
TreeItem<?> checkItem = ttRow.getTreeItem();
if (checkItem == null) {
continue;
}
if (item != null
&& checkItem.equals(item)
&& item.isExpanded()) {
return treeTableCell.getTreeTableRow()
.getDisclosureNode();
}
}
return null;
}
});
if (result != null) {
getRobot().click(result, null,
ClickOptions.create().setClickCount(1).setMouseButton(1));
}
EventThreadQueuerJavaFXImpl.invokeAndWait("collapseNodeCheckIfExpanded", //$NON-NLS-1$
new Callable<Void>() {
@Override
public Void call() throws Exception {
TreeItem<?> item = (TreeItem<?>) node;
if (!getTree().isDisabled() && item.isExpanded()) {
log.warn("Expand node fallback used for: " //$NON-NLS-1$
+ item.getValue());
item.setExpanded(true);
}
return null;
}
});
}
@Override
public Object getSelectedNode() {
TreeItem<?> result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getSelectedNode", new Callable<TreeItem<?>>() { //$NON-NLS-1$
@Override
public TreeItem<?> call() throws Exception {
return getTree().getSelectionModel().getSelectedItem();
}
});
if (result != null) {
SelectionUtil.validateSelection(new Object[] { result });
} else {
SelectionUtil.validateSelection(new Object[] {});
}
return result;
}
@Override
public Object[] getSelectedNodes() {
Object[] result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getSelectedNodes", new Callable<Object[]>() { //$NON-NLS-1$
@Override
public Object[] call() throws Exception {
return getTree().getSelectionModel().getSelectedItems()
.toArray();
}
});
SelectionUtil.validateSelection(result);
return result;
}
@Override
public Object[] getRootNodes() {
Object[] result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getRootNodes", new Callable<Object[]>() { //$NON-NLS-1$
@Override
public Object[] call() throws Exception {
TreeTableView<?> tree = getTree();
// If the root is visible, just return that.
if (tree.showRootProperty().getValue()) {
return new Object[] { tree.getRoot() };
}
// If the root is not visible, return all direct
// children of the
// non-visible root.
return getChildren(tree.getRoot());
}
});
return result;
}
@Override
public Object getParent(final Object child) {
Object result = EventThreadQueuerJavaFXImpl.invokeAndWait("getParent", //$NON-NLS-1$
new Callable<Object>() {
@Override
public Object call() throws Exception {
return ((TreeItem<?>) child).getParent();
}
});
return result;
}
@Override
public Object getChild(final Object parent, final int index) {
Object result = EventThreadQueuerJavaFXImpl.invokeAndWait("getChild", //$NON-NLS-1$
new Callable<Object>() {
@Override
public Object call() throws Exception {
return ((TreeItem<?>)parent).getChildren().get(index);
}
});
return result;
}
@Override
public int getNumberOfChildren(final Object parent) {
return EventThreadQueuerJavaFXImpl.invokeAndWait("getNumberOfChildren", //$NON-NLS-1$
new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return ((TreeItem<?>) parent).getChildren().size();
}
});
}
@Override
public boolean isLeaf(final Object node) {
return EventThreadQueuerJavaFXImpl.invokeAndWait("isLeaf", //$NON-NLS-1$
new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return ((TreeItem<?>) node).getChildren().size() == 0;
}
});
}
@Override
public Object[] getChildren(final Object parent) {
return EventThreadQueuerJavaFXImpl.invokeAndWait("getChildren", //$NON-NLS-1$
new Callable<Object[]>() {
@Override
public Object[] call() throws Exception {
return ((TreeItem<?>) parent).getChildren().toArray();
}
});
}
@Override
public Rectangle getNodeBounds(final Object node) {
scrollNodeToVisible(node);
Rectangle nodeBounds = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getNodeBounds", new Callable<Rectangle>() { //$NON-NLS-1$
@Override
public Rectangle call() throws Exception {
TreeTableView<?> treeTable = getTree();
treeTable.layout();
TreeItem<?> item = (TreeItem<?>) node;
List<TreeTableCell> cells = NodeTraverseHelper
.getInstancesOf(treeTable, TreeTableCell.class);
for (TreeTableCell<?, ?> cell : cells) {
// Nullchecks because of the virtual flow cells
// are created which might not be associated
// with a row or an item
TreeTableRow<?> ttRow = cell.getTreeTableRow();
if (ttRow == null) {
continue;
}
TreeItem<?> checkItem = ttRow.getTreeItem();
if (checkItem == null) {
continue;
}
if (item != null
&& checkItem.equals(item)
&& treeTable.getVisibleLeafColumns()
.indexOf(cell.getTableColumn())
== getColumn()) {
Rectangle b = NodeBounds
.getAbsoluteBounds(cell);
Rectangle treeB = NodeBounds
.getAbsoluteBounds(treeTable);
return new Rectangle(
Math.abs(treeB.x - b.x),
Math.abs(treeB.y - b.y),
Rounding.round(b.getWidth()),
Rounding.round(b.getHeight()));
}
}
return null;
}
});
if (nodeBounds == null) {
throw new StepExecutionException(
"Could not retrieve visible node bounds.", //$NON-NLS-1$
EventFactory.createActionError(TestErrorEvent.NOT_VISIBLE));
}
return nodeBounds;
}
@Override
public int getIndexOfChild(final Object parent, final Object child) {
return EventThreadQueuerJavaFXImpl.invokeAndWait("getIndexOfChild", //$NON-NLS-1$
new Callable<Integer>() {
@Override
public Integer call() throws Exception {
if (parent == null) {
Object[] rootNodes = getRootNodes();
for (int i = 0; i < rootNodes.length; i++) {
if (ObjectUtils.equals(rootNodes[i], child)) {
return i;
}
}
return -1;
}
List<?> children = ((TreeItem<?>)parent).getChildren();
if (children.contains(child)) {
return children.indexOf(child);
}
return -1;
}
});
}
/**
* Gets row index from string with index or text of first column
*
* @param row
* index or value in first row
* @param operator
* the operation used to verify
* @return integer of String of row
*/
public int getRowFromString(final String row, final String operator) {
Integer result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getRowFromString", new Callable<Integer>() { //$NON-NLS-1$
@Override
public Integer call() throws Exception {
Integer rowInt = null;
TreeTableView<?> treetable = getTree();
if (treetable.getColumns().size() <= 0) {
throw new StepExecutionException(
"No Header", //$NON-NLS-1$
EventFactory.createActionError(
TestErrorEvent.NO_HEADER));
}
try {
rowInt = IndexConverter
.toImplementationIndex(Integer
.parseInt(row));
if (rowInt != -1
&& treetable.getTreeItem(rowInt) == null) {
throw new StepExecutionException(
"Row not found", //$NON-NLS-1$
EventFactory.createActionError(
TestErrorEvent.
NOT_FOUND));
}
} catch (NumberFormatException nfe) {
TreeTableColumn<?, ?> firstColumn =
treetable.getColumns().get(0);
int i = 0;
String cellTxt = getCellText(i, 0);
while (cellTxt != null) {
cellTxt = getCellText(i, 0);
if (MatchUtil.getInstance().match(cellTxt, row,
operator)) {
return new Integer(i);
}
i++;
}
}
if (rowInt == null) {
throw new StepExecutionException(
"Row not found", //$NON-NLS-1$
EventFactory
.createActionError(TestErrorEvent.
NOT_FOUND));
}
return rowInt;
}
});
return result.intValue();
}
@Override
public int getColumnFromString(final String colPath, final String op,
final boolean leafColumn) {
// FIXME bjoern check integrity
Integer result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getColumnFromString", new Callable<Integer>() { //$NON-NLS-1$
@Override
public Integer call() throws Exception {
TreeTableView<?> treeTable = getTree();
List<String> path = StringParsing.splitToList(colPath,
TestDataConstants.PATH_CHAR_DEFAULT,
TestDataConstants.ESCAPE_CHAR_DEFAULT, false);
TreeTableColumn<?, ?> column = determineColumn(
colPath, op, treeTable, path);
if (column == null) {
throw new StepExecutionException("Column not found", //$NON-NLS-1$
EventFactory.createActionError(
TestErrorEvent.NOT_FOUND));
}
if (treeTable.getVisibleLeafColumns()
.contains(column)) {
return treeTable.getVisibleLeafColumns()
.indexOf(column);
}
if (leafColumn) {
throw new StepExecutionException("Invalid column path: " //$NON-NLS-1$
+ colPath + " not a leaf column", //$NON-NLS-1$
EventFactory.createActionError(
TestErrorEvent.INVALID_INDEX));
}
if (!m_columns.contains(column)) {
m_columns.add(column);
}
return m_columns.indexOf(column);
}
});
return result.intValue();
}
/**
* @param colPath
* index or value in first col
* @param op
* the operation used to verify
* @param treeTable
* the tree table
* @param path
* path
* @return the column matching the path
*/
private TreeTableColumn<?, ?> determineColumn(final String colPath,
final String op, TreeTableView<?> treeTable,
List<String> path) {
ObservableList<?> columns;
if (colPath.contains("" + TestDataConstants.PATH_CHAR_DEFAULT)) { //$NON-NLS-1$
columns = treeTable.getColumns();
} else {
columns = treeTable.getVisibleLeafColumns();
}
TreeTableColumn<?, ?> column = null;
Iterator<String> pathIterator = path.iterator();
String currCol = null;
while (pathIterator.hasNext()) {
try {
currCol = pathIterator.next();
int usrIdxCol = Integer.parseInt(currCol);
if (usrIdxCol == 0) {
usrIdxCol = usrIdxCol + 1;
}
int i = IndexConverter.toImplementationIndex(usrIdxCol);
if (MatchUtil.NOT_EQUALS == op) {
for (int j = 0; j < columns.size(); j++) {
if (j != i) {
if (pathIterator.hasNext()) {
columns = ((TreeTableColumn<?, ?>)
columns.get(j)).getColumns();
} else {
column = (TreeTableColumn<?, ?>) columns.get(j);
}
}
}
} else {
try {
if (pathIterator.hasNext()) {
columns = ((TreeTableColumn<?, ?>) columns.get(i))
.getColumns();
} else {
column = (TreeTableColumn<?, ?>) columns.get(i);
}
} catch (IndexOutOfBoundsException e) {
throw new StepExecutionException(
"Invalid Index: " + IndexConverter.toUserIndex(i), //$NON-NLS-1$
EventFactory.createActionError(
TestErrorEvent.INVALID_INDEX));
}
}
} catch (NumberFormatException nfe) {
try {
if (path.size() <= 1) {
columns = treeTable.getColumns();
}
if (columns.size() <= 0) {
throw new StepExecutionException(
"No Columns", EventFactory.createActionError(//$NON-NLS-1$
TestErrorEvent.NO_HEADER));
}
for (Object c: columns) {
TreeTableColumn<?, ?> col =
(TreeTableColumn<?, ?>) c;
String header = col.getText();
if (MatchUtil.getInstance().match(
header, currCol, op)) {
column = col;
if (pathIterator.hasNext()) {
columns = col.getColumns();
}
break;
}
}
} catch (IllegalArgumentException iae) {
// do nothing here
}
}
}
return column;
}
@Override
public Rectangle getHeaderBounds(final int column) {
Rectangle result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getHeaderBounds", new Callable<Rectangle>() { //$NON-NLS-1$
@Override
public Rectangle call() throws Exception {
TreeTableView<?> treeTable = getTree();
TreeTableColumn col;
if (m_columns.size() > 0) {
col = m_columns.get(column);
} else {
col = treeTable.getVisibleLeafColumn(column);
}
treeTable.scrollToColumn(col);
// Update the layout coordinates otherwise
// we would get old position values
treeTable.layout();
// DEPENDENCY TO INTERNAL API
// This should only be one node, but who knows what
// people do
List<? extends TableHeaderRow> headerRow =
NodeTraverseHelper.getInstancesOf(treeTable,
TableHeaderRow.class);
TableColumnHeader colH = null;
for (TableHeaderRow tableHeaderRow : headerRow) {
colH = tableHeaderRow.getColumnHeaderFor(col);
if (colH != null) {
break;
}
}
Rectangle b = NodeBounds.getAbsoluteBounds(colH);
Rectangle tableB = NodeBounds
.getAbsoluteBounds(treeTable);
return new Rectangle(Math.abs(tableB.x - b.x),
Math.abs(tableB.y - b.y),
Rounding.round(b.getWidth()),
Rounding.round(b.getHeight()));
}
});
return result;
}
/**
* @return The TableHeader if there is one,otherwise
* the table is returned.
*/
public Object getTableHeader() {
Object result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getTableHeader", new Callable<Object>() { //$NON-NLS-1$
@Override
public Object call() throws Exception {
return getTree().lookup("TableHeaderRow"); //$NON-NLS-1$
}
});
return result;
}
/**
* Scrolls the passed cell (as row and column) to visible.<br>
* This method must return null if there is no scrolling.
*
* @param row
* zero based index of the row.
* @param column
* zero based index of the column.
* @return The rectangle of the cell.
* @throws StepExecutionException
* If getting the cell rectangle or the scrolling fails.
*/
public Rectangle scrollCellToVisible(final int row, final int column)
throws StepExecutionException {
Rectangle result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"scrollCellToVisible", new Callable<Rectangle>() { //$NON-NLS-1$
@Override
public Rectangle call() throws Exception {
TreeTableView<?> treeTable = getTree();
TreeTableColumn col = null;
if (m_columns.size() == 0) {
col = treeTable.getVisibleLeafColumn(column);
} else {
col = m_columns.get(column);
}
treeTable.scrollTo(row);
treeTable.scrollToColumn(col);
// Update the layout coordinates otherwise
// we would get old position values
treeTable.layout();
List<? extends TreeTableCell> tCells =
NodeTraverseHelper.getInstancesOf(
treeTable, TreeTableCell.class);
for (TreeTableCell<?, ?> cell : tCells) {
if (cell.getIndex() == row
&& cell.getTableColumn() == col
&& cell.getTreeTableView() == treeTable) {
Rectangle b = NodeBounds
.getAbsoluteBounds(cell);
Rectangle tableB = NodeBounds
.getAbsoluteBounds(treeTable);
return new Rectangle(
Math.abs(tableB.x - b.x),
Math.abs(tableB.y - b.y),
Rounding.round(b.getWidth()),
Rounding.round(b.getHeight()));
}
}
return null;
}
});
return result;
}
/**
* @return The currently selected cell of the Table.
* @throws StepExecutionException
* If no cell is selected.
*/
public Cell getSelectedCell() throws StepExecutionException {
Cell result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getSelectedCell", new Callable<Cell>() { //$NON-NLS-1$
@Override
public Cell call() throws StepExecutionException {
TreeTableView<?> treeTable = getTree();
ObservableList<?> list = treeTable
.getSelectionModel().getSelectedCells();
if (list.size() > 0) {
TreeTablePosition<?, ?> pos = null;
for (Object object : list) {
TreeTablePosition<?, ?> curr =
(TreeTablePosition<?, ?>) object;
if (curr.getRow() == treeTable
.getSelectionModel()
.getSelectedIndex()) {
pos = curr;
break;
}
}
if (pos != null) {
return new Cell(pos.getRow(), pos.getColumn());
}
}
throw new StepExecutionException("No selection found", //$NON-NLS-1$
EventFactory
.createActionError(TestErrorEvent.
NO_SELECTION));
}
});
return result;
}
/**
*
* @param row
* zero based index of the row
* @param column
* zero based index of the column
* @return <code>true</code> if the Cell is editable, <code>false</code>
* otherwise
*/
public boolean isCellEditable(final int row, final int column) {
boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"isCellEditable", new Callable<Boolean>() { //$NON-NLS-1$
@Override
public Boolean call() throws Exception {
TreeTableView treeTable = getTree();
if (treeTable.isEditable()) {
TreeTableColumn<?, ?> col = null;
if (m_columns.size() == 0) {
col = treeTable.getVisibleLeafColumn(column);
} else {
col = m_columns.get(column);
}
if (col.isEditable()) {
treeTable.scrollTo(row);
treeTable.scrollToColumn(col);
treeTable.layout();
List<? extends TreeTableCell> tCells =
NodeTraverseHelper.getInstancesOf(
treeTable, TreeTableCell.class);
for (TreeTableCell<?, ?> cell : tCells) {
if (cell.getIndex() == row
&& cell.getTableColumn() == col
&& cell.getTreeTableView()
== treeTable
&& NodeTraverseHelper
.isVisible(cell)) {
return cell.isEditable();
}
}
}
}
return false;
}
});
return result;
}
/**
* checks if the given cell is editable
* @param cell the cell
* @return true if editable, otherwise false
*/
public boolean isCellEditable(final TreeTableCell<?, ?> cell) {
boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"isCellEditable", new Callable<Boolean>() { //$NON-NLS-1$
@Override
public Boolean call() throws Exception {
TreeTableView<?> treeTable = getTree();
if (treeTable.isEditable()) {
return cell.isEditable();
}
return false;
}
});
return result;
}
@Override
public String getColumnHeaderText(final int column) {
String result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getColumnHeaderText", //$NON-NLS-1$
new Callable<String>() {
@Override
public String call() throws Exception {
if (m_columns.size() > 0) {
TreeTableColumn<?, ?> tCol = m_columns.get(column);
return tCol.getText();
}
TreeTableColumn<?, ?> tCol = getTree()
.getVisibleLeafColumn(column);
return tCol.getText();
}
});
return result;
}
/**
* Gets the number of rows
*
* @return the number of rows
*/
public int getRowCount() {
int result = EventThreadQueuerJavaFXImpl.invokeAndWait("getRowCount", //$NON-NLS-1$
new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return getTree().getExpandedItemCount();
}
});
return result;
}
/**
* Gets the number of columns
*
* @return the number of columns
*/
public int getColumnCount() {
int result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getColumnCount", new Callable<Integer>() { //$NON-NLS-1$
@Override
public Integer call() throws Exception {
int counter = 0;
for (TreeTableColumn<?, ?> column
: getTree().getColumns()) {
counter += new GenericTraverseHelper
<TreeTableColumn, TreeTableColumn>()
.getInstancesOf(
new AbstractTraverser
<TreeTableColumn, TreeTableColumn>(
column) {
@Override
public Iterable<TreeTableColumn>
getTraversableData() {
return this.getObject()
.getColumns();
}
}, TreeTableColumn.class).size();
}
return counter + getTree().getColumns().size();
}
});
return result;
}
/**
* @param row
* the zero based index of the row
* @param column
* the zero based index of the column
* @return the text of the cell of the given coordinates
*/
public String getCellText(final int row, final int column) {
String result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"getCellText", new Callable<String>() { //$NON-NLS-1$
@Override
public String call() throws Exception {
TreeTableView table = getTree();
TreeTableColumn<?, ?> col = null;
if (m_columns.size() == 0) {
col = table.getVisibleLeafColumn(column);
} else {
col = m_columns.get(column);
}
table.scrollTo(row);
table.scrollToColumn(col);
table.layout();
List<? extends TreeTableCell> tCells =
NodeTraverseHelper.getInstancesOf(table,
TreeTableCell.class);
for (TreeTableCell<?, ?> cell : tCells) {
if (cell.getIndex() == row
&& cell.getTableColumn() == col
&& cell.getTreeTableView() == table
&& NodeTraverseHelper.isVisible(cell)) {
return getRenderedCellText(cell);
}
}
return null;
}
});
return result;
}
/**
*
* @return <code>true</code> if the header is visible, <code>false</code> otherwise
*/
public boolean isHeaderVisible() {
boolean result = EventThreadQueuerJavaFXImpl.invokeAndWait(
"isHeaderVisible", new Callable<Boolean>() { //$NON-NLS-1$
@Override
public Boolean call() throws Exception {
Pane header = (Pane) getTree().lookup("TableHeaderRow"); //$NON-NLS-1$
if (header != null) {
return header.isVisible();
}
return false;
}
});
return result;
}
/**
* Returns the string representation of the value of the property of the given Node
* @param node the node
* @param propertyname the name of the property
* @return string representation of the property value
*/
public String getPropteryValue(final Object node,
final String propertyname) {
Object prop = EventThreadQueuerJavaFXImpl.invokeAndWait("getPropertyValue", //$NON-NLS-1$
new Callable<String>() {
@Override
public String call() throws Exception {
try {
return getRobot().getPropertyValue(
node, propertyname);
} catch (RobotException e) {
throw new StepExecutionException(
e.getMessage(),
EventFactory
.createActionError(TestErrorEvent.
PROPERTY_NOT_ACCESSABLE));
}
}
});
return String.valueOf(prop);
}
}