1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javafx.scene.control.test.tableview; 26 27 import javafx.scene.control.skin.TableColumnHeader; 28 import java.util.ArrayList; 29 import java.util.Collection; 30 import java.util.Collections; 31 import javafx.geometry.Orientation; 32 import javafx.scene.Node; 33 import javafx.scene.Scene; 34 import javafx.scene.control.Button; 35 import javafx.scene.control.CheckBox; 36 import javafx.scene.control.Control; 37 import javafx.scene.control.IndexedCell; 38 import javafx.scene.control.Label; 39 import javafx.scene.control.ScrollBar; 40 import javafx.scene.control.TableCell; 41 import javafx.scene.control.TableView; 42 import javafx.scene.control.TextField; 43 import javafx.scene.control.TreeTableCell; 44 import javafx.scene.control.TreeTableView; 45 import javafx.scene.control.test.treetable.TreeTableAsOldTableApp; 46 import javafx.scene.control.test.util.MultipleSelectionHelper; 47 import javafx.scene.control.test.util.UtilTestFunctions; 48 import org.jemmy.Point; 49 import org.jemmy.action.GetAction; 50 import org.jemmy.control.Wrap; 51 import org.jemmy.fx.ByID; 52 import org.jemmy.fx.Root; 53 import org.jemmy.interfaces.Drag; 54 import org.jemmy.interfaces.Keyboard; 55 import org.jemmy.interfaces.Parent; 56 import org.jemmy.interfaces.Text; 57 import org.jemmy.lookup.Lookup; 58 import org.jemmy.lookup.LookupCriteria; 59 import org.jemmy.timing.State; 60 import org.junit.Before; 61 import org.junit.BeforeClass; 62 import test.javaclient.shared.Utils; 63 import static javafx.commons.Consts.*; 64 import javafx.scene.control.TableColumn; 65 import java.util.Comparator; 66 import java.util.concurrent.CountDownLatch; 67 import javafx.application.Platform; 68 import javafx.scene.control.TreeTableColumn; 69 import org.jemmy.env.Timeout; 70 import org.jemmy.timing.Waiter; 71 72 /** 73 * @author Alexander Kirov 74 */ 75 public class TestBase extends UtilTestFunctions { 76 77 protected static int DATA_ITEMS_NUM = 0; 78 protected static int DATA_FIELDS_NUM = 0; 79 protected static Wrap<? extends Control> testedControl; //ListView or TableView or TreeView 80 protected static MultipleSelectionHelper selectionHelper; 81 protected static Wrap<? extends Label> labelWrap; 82 protected static Wrap<? extends Scene> sceneWrap; 83 protected static Wrap<? extends Control> tableViewWrap; 84 protected static Wrap<? extends Button> resetWrap; 85 protected static Wrap<? extends TextField> selectedWrap; 86 protected static Wrap<? extends CheckBox> multipleSelectionWrap; 87 protected static Wrap<? extends CheckBox> singleCellSelectionWrap; 88 protected static Wrap contentPane; 89 protected static Wrap btnInsertItem; 90 protected static Text txtItemInsertIndex; 91 protected static Wrap btnRemoveItem; 92 protected static Text txtItemRemoveIndex; 93 protected static Wrap btnInsertColumn; 94 protected static Text txtColumnInserIndex; 95 protected static Wrap btnRemoveColumn; 96 protected static Text txtColumnRemoveIndex; 97 protected int pageWidthInCells; 98 protected int pageHeightInCells; 99 Wrap<? extends Node> headerWrap; 100 protected static boolean isTableTests = true; 101 102 private static int getColumnCount() { 103 return isTableTests ? TableViewApp.DATA_FIELDS_NUM : TreeTableAsOldTableApp.DATA_FIELDS_NUM; 104 } 105 106 private static int getRowCount() { 107 return isTableTests ? TableViewApp.DATA_ITEMS_NUM : TreeTableAsOldTableApp.DATA_ITEMS_NUM; 108 } 109 110 private static String getContentPaneID() { 111 return TableViewApp.CONTENT_PANE_ID; 112 } 113 114 private static void initWrappers() { 115 sceneWrap = Root.ROOT.lookup().wrap(); 116 parent = sceneWrap.as(Parent.class, Node.class); 117 contentPane = parent.lookup(new ByID<Node>(getContentPaneID())).wrap(); 118 if (isTableTests) { 119 tableViewWrap = parent.lookup(TableView.class).wrap(); 120 } else { 121 tableViewWrap = parent.lookup(TreeTableView.class).wrap(); 122 } 123 tableViewWrap.getEnvironment().setTimeout(Drag.IN_DRAG_TIMEOUT, 1); 124 125 resetWrap = parent.lookup(Button.class, new ByID<Button>(RESET_BTN_ID)).wrap(); 126 selectedWrap = parent.lookup(TextField.class, new ByID<TextField>(SELECTED_ITEMS_ID)).wrap(); 127 multipleSelectionWrap = parent.lookup(CheckBox.class, new ByID<CheckBox>(ENABLE_MULTIPLE_SELECTION_ID)).wrap(); 128 btnInsertItem = parent.lookup(Button.class, new ByID<Button>(INSERT_ITEM_BTN_ID)).wrap(); 129 txtItemInsertIndex = (Text) parent.lookup(TextField.class, new ByID<TextField>(INSERT_ITEM_INDEX_ID)).wrap().as(Text.class); 130 btnInsertColumn = parent.lookup(Button.class, new ByID<Button>(INSERT_COLUMN_BTN_ID)).wrap(); 131 txtColumnInserIndex = (Text) parent.lookup(TextField.class, new ByID<TextField>(INSERT_COLUMN_INDEX_ID)).wrap().as(Text.class); 132 btnRemoveItem = parent.lookup(Button.class, new ByID<Button>(REMOVE_ITEM_BTN_ID)).wrap(); 133 txtItemRemoveIndex = (Text) parent.lookup(TextField.class, new ByID<TextField>(ITEM_INDEX_TO_REMOVE_ID)).wrap().as(Text.class); 134 btnRemoveColumn = parent.lookup(Button.class, new ByID<Button>(REMOVE_COLUMN_BTN_ID)).wrap(); 135 txtColumnRemoveIndex = (Text) parent.lookup(TextField.class, new ByID<TextField>(COLUMN_INDEX_TO_REMOVE_ID)).wrap().as(Text.class); 136 137 testedControl = tableViewWrap; 138 setContentSize(getColumnCount(), getRowCount()); 139 if (isTableTests) { 140 singleCellSelectionWrap = parent.lookup(CheckBox.class, new ByID<CheckBox>(TableViewApp.SINGLE_CELL_SELECTION_ID)).wrap(); 141 } else { 142 singleCellSelectionWrap = parent.lookup(CheckBox.class, new ByID<CheckBox>(TreeTableAsOldTableApp.SINGLE_CELL_SELECTION_ID)).wrap(); 143 } 144 } 145 146 @BeforeClass 147 public static void setUpClass() throws Exception { 148 if (isTableTests) { 149 System.out.println("Starting an old TableView application with simple controllers."); 150 TableViewApp.main(null); 151 } else { 152 System.out.println("Starting a new TreeTable application created as an old TableView application."); 153 TreeTableAsOldTableApp.main(null); 154 } 155 initWrappers(); 156 } 157 158 @Before 159 public void setUp() throws Exception { 160 resetWrap.mouse().click(); 161 selectionHelper.setMultiple(false); 162 selectionHelper.setSingleCell(false); 163 pageWidthInCells = (int) (tableViewWrap.getScreenBounds().getWidth() / (TestBaseCommon.getCellWrap(testedControl, 1, 0).getScreenBounds().getX() - TestBaseCommon.getCellWrap(testedControl, 0, 0).getScreenBounds().getX())); 164 pageHeightInCells = (int) ((tableViewWrap.getScreenBounds().getHeight() - TestBaseCommon.getHeaderWrap(tableViewWrap).getScreenBounds().getHeight()) / (TestBaseCommon.getCellWrap(testedControl, 0, 1).getScreenBounds().getY() - TestBaseCommon.getCellWrap(testedControl, 0, 0).getScreenBounds().getY())); 165 headerWrap = TestBaseCommon.getHeaderWrap(tableViewWrap); 166 selectionHelper.setPageHeight(pageHeightInCells); 167 selectionHelper.setPageWidth(pageWidthInCells); 168 } 169 170 protected static void setContentSize(int x, int y) { 171 DATA_FIELDS_NUM = x; 172 DATA_ITEMS_NUM = y; 173 selectionHelper = new MultipleSelectionHelper(DATA_FIELDS_NUM, DATA_ITEMS_NUM); 174 } 175 176 protected void selectionCycle(Keyboard.KeyboardButtons modifier) throws Throwable { 177 if (Utils.isSmokeTesting()) { 178 selectionCycle(0, 2, 0, 2, modifier); 179 } else { 180 selectionCycle(0, DATA_FIELDS_NUM, 0, DATA_ITEMS_NUM, modifier); 181 } 182 //selectionCycle(0, 3, 0, 3, modifier); 183 } 184 185 protected void selectionCycle(int first_column, int last_column, int first_row, int last_row, Keyboard.KeyboardButtons modifier) throws Throwable { 186 if (modifier != null) { 187 testedControl.keyboard().pressKey(modifier); 188 } 189 try { 190 for (int j = first_column; j < last_column; j++) { 191 final int column = j; 192 for (int i = first_row; i < last_row; i++) { 193 final int row = i; 194 TestBaseCommon.scrollTo(testedControl, j, i); 195 TestBaseCommon.getCellWrap(testedControl, column, row).mouse().click(); 196 selectionHelper.click(column, row, modifier); 197 checkSelection(); 198 } 199 } 200 } catch (Throwable error) { 201 throw error; 202 } finally { 203 if (modifier != null) { 204 testedControl.keyboard().releaseKey(modifier); 205 } 206 } 207 } 208 209 protected Lookup getScrollLookup(final Orientation orientation) { 210 return parent.lookup(ScrollBar.class, new LookupCriteria<ScrollBar>() { 211 public boolean check(ScrollBar cntrl) { 212 return (cntrl.getOrientation() == orientation) && cntrl.isVisible(); 213 } 214 }); 215 } 216 217 protected void insertAt(int pos) { 218 txtItemInsertIndex.clear(); 219 txtItemInsertIndex.type(String.valueOf(pos)); 220 btnInsertItem.mouse().click(); 221 } 222 223 protected void insertColumnAt(int pos) { 224 txtColumnInserIndex.clear(); 225 txtColumnInserIndex.type(String.valueOf(pos)); 226 btnInsertColumn.mouse().click(); 227 } 228 229 protected void removeAt(int pos) { 230 txtItemRemoveIndex.clear(); 231 txtItemRemoveIndex.type(String.valueOf(pos)); 232 btnRemoveItem.mouse().click(); 233 } 234 235 protected void removeColumnAt(int pos) { 236 txtColumnRemoveIndex.clear(); 237 txtColumnRemoveIndex.type(String.valueOf(pos)); 238 btnRemoveColumn.mouse().click(); 239 } 240 241 protected void keyboardCycle(int counter, Keyboard.KeyboardButtons btn, Keyboard.KeyboardModifiers modifier) { 242 for (int i = 0; i < counter; i++) { 243 tableViewWrap.keyboard().pushKey(btn, modifier); 244 } 245 } 246 247 protected void keyboardSelectionCheckCycle(int counter, Keyboard.KeyboardButtons btn, Keyboard.KeyboardModifiers... modifier) { 248 for (int i = 0; i < counter; i++) { 249 keyboardCheck(btn, modifier); 250 } 251 } 252 253 protected Wrap<? extends IndexedCell> getCellWrap(final int column, final int row) { 254 return TestBaseCommon.getCellWrap(testedControl, column, row); 255 } 256 257 public static class ByPosition implements LookupCriteria<Node> { 258 259 private int column, row; 260 261 public ByPosition(int column, int row) { 262 this.column = column; 263 this.row = row; 264 } 265 266 public boolean check(Node control) { 267 if (TableCell.class.isAssignableFrom(control.getClass())) { 268 return getColumnIndex((TableCell) control) == column 269 && getRowIndex((TableCell) control) == row; 270 } else if (TreeTableCell.class.isAssignableFrom(control.getClass())) { 271 return getColumnIndex((TreeTableCell) control) == column 272 && getRowIndex((TreeTableCell) control) == row; 273 } else { 274 return false; 275 } 276 } 277 } 278 279 protected static void switchOnMultiple() { 280 new GetAction() { 281 @Override 282 public void run(Object... os) throws Exception { 283 multipleSelectionWrap.getControl().setSelected(true); 284 } 285 }.dispatch(Root.ROOT.getEnvironment()); 286 } 287 288 protected void scrollTo(final int column, final int row) { 289 TestBaseCommon.scrollTo(testedControl, column, row); 290 } 291 292 private static int getRowIndex(TableCell tableCell) { 293 return TestBaseCommon.getRowIndex(tableCell); 294 } 295 296 private static int getRowIndex(TreeTableCell tableCell) { 297 return TestBaseCommon.getRowIndex(tableCell); 298 } 299 300 private static int getColumnIndex(TableCell tableCell) { 301 return TestBaseCommon.getColumnIndex(tableCell); 302 } 303 304 private static int getColumnIndex(TreeTableCell tableCell) { 305 return TestBaseCommon.getColumnIndex(tableCell); 306 } 307 308 protected void checkSelection() { 309 testedControl.waitState(new State() { 310 Collection<Point> helper_selected; 311 Collection<Point> selected; 312 Point helperFocus; 313 Point focus; 314 315 public Object reached() { 316 helper_selected = selectionHelper.getSelected(); 317 selected = TestBaseCommon.getSelected(testedControl); 318 helperFocus = selectionHelper.focus; 319 focus = TestBaseCommon.getSelectedItem(testedControl); 320 321 if (helper_selected.size() == selected.size() 322 && helper_selected.containsAll(selected) 323 && (focus.equals(helperFocus) || selectionHelper.ctrlA)) { 324 return true; 325 } else { 326 return null; 327 } 328 } 329 330 @Override 331 public String toString() { 332 helper_selected = new ArrayList<Point>(helper_selected); 333 selected = new ArrayList<Point>(selected); 334 335 final Comparator<Point> comparator = new Comparator<Point>() { 336 public int compare(Point p1, Point p2) { 337 return p1.y - p2.y; 338 } 339 }; 340 Collections.sort((ArrayList) helper_selected, comparator); 341 Collections.sort((ArrayList) selected, comparator); 342 343 StringBuilder sb; 344 sb = new StringBuilder("{") 345 .append("Helper selected : ").append(helper_selected).append("\n") 346 .append("Selected : ").append(selected).append("\n") 347 .append("Helper focus : ").append(helperFocus).append("\n") 348 .append("Contol focus : ").append(focus).append("}"); 349 return sb.toString(); 350 } 351 }); 352 } 353 354 protected void keyboardCheck(Keyboard.KeyboardButtons btn, Keyboard.KeyboardModifiers... modifier) { 355 if (btn == Keyboard.KeyboardButtons.PAGE_DOWN || btn == Keyboard.KeyboardButtons.PAGE_UP) { 356 selectionHelper.setVisibleRange(TestBaseCommon.getVisibleRange(testedControl)); 357 } 358 testedControl.keyboard().pushKey(btn, modifier); 359 selectionHelper.push(btn, modifier); 360 checkSelection(); 361 } 362 363 protected String getControlName() { 364 if (isTableTests) { 365 return "TableView"; 366 } else { 367 return "TreeTableView"; 368 } 369 } 370 371 Wrap scrollToColumnByIndexBtn; 372 Text columnIndexToScroll; 373 374 void scrollToColumnByIndex(final int index) { 375 if (null == scrollToColumnByIndexBtn) { 376 scrollToColumnByIndexBtn = parent.lookup(Button.class, new ByID<Button>(Table.SCROLL_TO_COLUMN_BTN_ID)).wrap(); 377 } 378 if (null == columnIndexToScroll) { 379 columnIndexToScroll = (Text) parent.lookup(TextField.class, new ByID<TextField>(Table.SCROLL_TO_COLUMN_INDEX_ID)).wrap().as(Text.class); 380 } 381 382 columnIndexToScroll.clear(); 383 columnIndexToScroll.type(String.valueOf(index)); 384 scrollToColumnByIndexBtn.mouse().click(); 385 } 386 387 class Helper extends ApplicationInteractionFunctions { 388 389 { 390 testedControl = TestBase.testedControl; 391 } 392 } 393 394 boolean isColumnHeaderVisible(final int index) { 395 396 Boolean state = new Waiter(new Timeout("", 1000)).waitState(new State<Boolean>() { 397 Helper helper = new Helper(); 398 Wrap<? extends TableColumnHeader> headerWrap; 399 400 public Boolean reached() { 401 headerWrap = helper.getTableColumnHeaderWrap(getSimpleColumnHeaderText(index)); 402 TableColumnHeader header = headerWrap.getControl(); 403 if (header.isVisible() 404 && getSimpleColumnHeaderText(index).equals(header.getTableColumn().getText()) 405 && testedControl.getScreenBounds().contains(headerWrap.getScreenBounds())) { 406 return Boolean.TRUE; 407 } else { 408 return null; 409 } 410 } 411 }); 412 413 return (null == state) ? false : true; 414 } 415 416 void scrollToColumn(final int index) { 417 new GetAction<Void>() { 418 419 @Override 420 public void run(Object... parameters) throws Exception { 421 if (isTableTests) { 422 TableView tableView = (TableView) testedControl.getControl(); 423 TableColumn col = (TableColumn) tableView.getColumns().get(index); 424 tableView.scrollToColumn(col); 425 } else { 426 // TreeTableView treeTableView = (TreeTableView) testedControl.getControl(); 427 // TreeTableColumn col = (TreeTableColumn) treeTableView.getColumns().get(index); 428 // treeTableView.scrollToColumn(col); 429 throw new RuntimeException("TreeTableView#scrollToColumn doesn't support TreeTableColumn type " 430 + "\nrefer: https://javafx-jira.kenai.com/browse/RT-31856"); 431 } 432 } 433 }.dispatch(testedControl.getEnvironment()); 434 } 435 436 void refill(final int cols, final int rows) { 437 438 final String colsTextID = Table.COLUMNS_NUMBER_ID; 439 final Text columnsText = (Text) parent.lookup(TextField.class, new ByID(colsTextID)).wrap().as(Text.class); 440 columnsText.clear(); 441 columnsText.type(String.valueOf(cols)); 442 443 final String rowsTextID = Table.ROWS_NUMBER_ID; 444 final Text rowsText = (Text) parent.lookup(TextField.class, new ByID(rowsTextID)).wrap().as(Text.class); 445 rowsText.clear(); 446 rowsText.type(String.valueOf(rows)); 447 448 final String refillBtnID = Table.REFILL_BNT_ID; 449 parent.lookup(Button.class, new ByID<Button>(refillBtnID)).wrap().mouse().click(); 450 } 451 452 String getSimpleColumnHeaderText(final int index) { 453 return "field " + index; 454 } 455 456 double getScrollBarValue(final Orientation orientation) { 457 return new GetAction<Double>() { 458 459 @Override 460 public void run(Object... parameters) throws Exception { 461 Lookup hScrollBar = getScrollLookup(orientation); 462 setResult(((ScrollBar) hScrollBar.wrap().getControl()).getValue()); 463 } 464 }.dispatch(testedControl.getEnvironment()); 465 } 466 467 double getScrollBarMaxValue(final Orientation orientation) { 468 return new GetAction<Double>() { 469 470 @Override 471 public void run(Object... parameters) throws Exception { 472 Lookup hScrollBar = getScrollLookup(orientation); 473 setResult(((ScrollBar) hScrollBar.wrap().getControl()).getMax()); 474 } 475 }.dispatch(testedControl.getEnvironment()); 476 } 477 478 double getScrollBarMinValue(final Orientation orientation) { 479 return new GetAction<Double>() { 480 481 @Override 482 public void run(Object... parameters) throws Exception { 483 Lookup hScrollBar = getScrollLookup(orientation); 484 setResult(((ScrollBar) hScrollBar.wrap().getControl()).getMin()); 485 } 486 }.dispatch(testedControl.getEnvironment()); 487 } 488 489 void resizeColumn(final int index, final double delta) { 490 491 final double initialWidth = getColumnWidth(index); 492 493 new GetAction<Void>() { 494 @Override 495 public void run(Object... os) throws Exception { 496 if (isTableTests) { 497 TableView table = (TableView) testedControl.getControl(); 498 table.resizeColumn((TableColumn) table.getColumns().get(index), delta); 499 } else { 500 TreeTableView treeTable = (TreeTableView) testedControl.getControl(); 501 treeTable.resizeColumn((TreeTableColumn) treeTable.getColumns().get(index), delta); 502 } 503 } 504 }.dispatch(testedControl.getEnvironment()); 505 506 new Waiter(new Timeout("", 1000)).waitState(new State<Boolean>() { 507 public Boolean reached() { 508 return (Math.abs(getColumnWidth(index) - initialWidth - delta) <= 1e-7) ? Boolean.TRUE : null; 509 } 510 }); 511 } 512 513 protected void setColumnTextSync(final int index, final String text) { 514 assert !Platform.isFxApplicationThread(); 515 CountDownLatch latch = new CountDownLatch(1); 516 Platform.runLater(() -> { 517 if (isTableTests) { 518 TableView table = (TableView) testedControl.getControl(); 519 ((TableColumn) table.getColumns().get(index)).setText(text); 520 } else { 521 TreeTableView treeTable = (TreeTableView) testedControl.getControl(); 522 ((TreeTableColumn) treeTable.getColumns().get(index)).setText(text); 523 } 524 latch.countDown(); 525 }); 526 try { 527 latch.await(); 528 } catch (InterruptedException ex) { 529 System.out.println("Exception while awaiting text to set: " + ex); 530 } 531 } 532 533 protected String getColumnText(final int index) { 534 if (isTableTests) { 535 TableView table = (TableView) testedControl.getControl(); 536 return ((TableColumn) table.getColumns().get(index)).getText(); 537 } else { 538 TreeTableView treeTable = (TreeTableView) testedControl.getControl(); 539 return ((TreeTableColumn) treeTable.getColumns().get(index)).getText(); 540 } 541 } 542 543 protected double getColumnWidth(final int index) { 544 return new Helper().getCellWrap(index, 0).getScreenBounds().getWidth(); 545 } 546 }