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 
  26 package javafx.scene.control.test.tableview;
  27 
  28 import client.test.Smoke;
  29 import javafx.scene.control.skin.NestedTableColumnHeader;
  30 import javafx.scene.control.skin.TableColumnHeader;
  31 import javafx.scene.control.skin.TableHeaderRow;
  32 import java.awt.Robot;
  33 import java.awt.event.InputEvent;
  34 import java.util.ArrayList;
  35 import java.util.List;
  36 import java.util.logging.Level;
  37 import java.util.logging.Logger;
  38 import static javafx.collections.FXCollections.*;
  39 import javafx.collections.ObservableList;
  40 import static javafx.commons.Consts.*;
  41 import javafx.commons.Consts.CellEditorType;
  42 import javafx.geometry.Orientation;
  43 import javafx.scene.Group;
  44 import javafx.scene.Node;
  45 import javafx.scene.Scene;
  46 import javafx.scene.control.Cell;
  47 import javafx.scene.control.ChoiceBox;
  48 import javafx.scene.control.ComboBox;
  49 import javafx.scene.control.Control;
  50 import javafx.scene.control.IndexedCell;
  51 import javafx.scene.control.Label;
  52 import javafx.scene.control.ListView;
  53 import javafx.scene.control.TableCell;
  54 import javafx.scene.control.TableColumn;
  55 import javafx.scene.control.TableColumnBase;
  56 import javafx.scene.control.TableRow;
  57 import javafx.scene.control.TableView;
  58 import javafx.scene.control.TextField;
  59 import javafx.scene.control.TreeTableCell;
  60 import javafx.scene.control.TreeTableColumn;
  61 import javafx.scene.control.TreeTableRow;
  62 import javafx.scene.control.TreeTableView;
  63 import static javafx.scene.control.test.tableview.ApplicationInteractionFunctions.addColumn;
  64 import static javafx.scene.control.test.tableview.ApplicationInteractionFunctions.isTableTests;
  65 import static javafx.scene.control.test.tableview.ApplicationInteractionFunctions.testedControl;
  66 import static javafx.scene.control.test.util.TableListCommonTests.fixedCellSizePropertyTestCommon;
  67 import javafx.scene.control.test.utils.ptables.AbstractPropertyController.SettingType;
  68 import javafx.scene.control.test.utils.ptables.PropertyTablesFactory.CustomReversedComparator;
  69 import javafx.scene.text.Text;
  70 import org.jemmy.Point;
  71 import org.jemmy.Rectangle;
  72 import org.jemmy.action.GetAction;
  73 import org.jemmy.control.Wrap;
  74 import org.jemmy.env.Timeout;
  75 import org.jemmy.fx.ByStyleClass;
  76 import org.jemmy.fx.ByText;
  77 import org.jemmy.interfaces.Keyboard.KeyboardButtons;
  78 import org.jemmy.interfaces.Keyboard.KeyboardModifiers;
  79 import org.jemmy.interfaces.Parent;
  80 import org.jemmy.interfaces.Selectable;
  81 import org.jemmy.lookup.Lookup;
  82 import org.jemmy.lookup.LookupCriteria;
  83 import org.jemmy.timing.State;
  84 import org.jemmy.timing.Waiter;
  85 import static org.junit.Assert.*;
  86 import org.junit.Test;
  87 import static javafx.scene.control.test.tableview.TableUtils.*;
  88 import static javafx.scene.control.test.treetable.TreeTableNewApp.DataItem;
  89 import javafx.stage.PopupWindow;
  90 import javafx.util.Callback;
  91 import org.jemmy.fx.ByWindowType;
  92 import org.jemmy.fx.Root;
  93 
  94 /**
  95  * @author Alexander Kirov
  96  */
  97 public class TableViewNewTest extends ApplicationInteractionFunctions {
  98 
  99     @Test(timeout = 300000)
 100     /**
 101      * This test will sort content of some column and check, that other columns
 102      * were sorted in the way, so that data in the same row is preserved (that
 103      * there is no data confusing).
 104      */
 105     public void correctSortConsistencyTest() throws InterruptedException {
 106         setSize(200, 200);
 107         final int columns = 2;
 108         final int rows = 5;
 109         for (int i = 0; i < columns; i++) {
 110             addColumn("items" + String.valueOf(i), i, true);
 111         }
 112         setNewDataSize(rows);
 113         createNestedColumn("nested", 0, 0, 1);
 114         requestFocusOnControl(testedControl);
 115 
 116         if (!isTableTests) {
 117             new GetAction<Object>() {
 118                 @Override
 119                 public void run(Object... os) throws Exception {
 120                     TreeTableView ttv = (TreeTableView) testedControl.getControl();
 121                     ttv.showRootProperty().set(false);
 122                 }
 123             }.dispatch(testedControl.getEnvironment());
 124         }
 125 
 126         switchToPropertiesTab("items0");
 127         setPropertyBySlider(SettingType.UNIDIRECTIONAL, Properties.prefWidth, 80);
 128         switchToPropertiesTab("items1");
 129         setPropertyBySlider(SettingType.UNIDIRECTIONAL, Properties.prefWidth, 80);
 130 
 131         Wrap<? extends TableColumnHeader> header1 = getTableColumnHeaderWrap("items0");
 132         Wrap<? extends TableColumnHeader> header2 = getTableColumnHeaderWrap("items1");
 133 
 134         checkKeyCellsContent("items0-0", "items1-0", "items0-4", "items1-4", columns, rows);
 135         //Direct sort.
 136         header1.mouse().click();
 137         checkKeyCellsContent("items0-0", "items1-0", "items0-4", "items1-4", columns, rows);
 138         //Reversed sort.
 139         header1.mouse().click();
 140         checkKeyCellsContent("items0-4", "items1-4", "items0-0", "items1-0", columns, rows);
 141         //Direct sort.
 142         header2.mouse().click();
 143         checkKeyCellsContent("items0-0", "items1-0", "items0-4", "items1-4", columns, rows);
 144         //Reversed sort.
 145         header2.mouse().click();
 146         checkKeyCellsContent("items0-4", "items1-4", "items0-0", "items1-0", columns, rows);
 147 
 148         switchToPropertiesTab("items0");
 149         setPropertyByToggleClick(SettingType.BIDIRECTIONAL, Properties.sortable, Boolean.FALSE);
 150 
 151         header1.mouse().click();
 152         checkKeyCellsContent("items0-4", "items1-4", "items0-0", "items1-0", columns, rows);
 153 
 154         switchToPropertiesTab("items1");
 155         setPropertyByToggleClick(SettingType.UNIDIRECTIONAL, Properties.sortable, Boolean.FALSE);
 156         header2.mouse().click();
 157         checkKeyCellsContent("items0-4", "items1-4", "items0-0", "items1-0", columns, rows);
 158     }
 159 
 160     protected void checkKeyCellsContent(String upperLeftText, String upperRightText, String downLeftText, String downRightText, int columns, int rows) {
 161         checkTextContainment(getCellWrap(0, 0), upperLeftText);
 162         checkTextContainment(getCellWrap(columns - 1, 0), upperRightText);
 163         checkTextContainment(getCellWrap(0, rows - 1), downLeftText);
 164         checkTextContainment(getCellWrap(columns - 1, rows - 1), downRightText);
 165     }
 166 
 167     protected void checkTextContainment(final Wrap<? extends TableCell> cellWrap, final String textExpectToFind) {
 168         new Waiter(new Timeout("", 1000)).ensureState(new State() {
 169             public Object reached() {
 170                 LookupCriteria<Node> lookupCriteria = new LookupCriteria<Node>() {
 171                     public boolean check(Node cntrl) {
 172                         return Text.class.isAssignableFrom(cntrl.getClass())
 173                                 || ((Text) cntrl).getText().equals(textExpectToFind);
 174                     }
 175                 };
 176 
 177                 if (cellWrap.as(Parent.class, Node.class).lookup(Text.class, new ByText(textExpectToFind)).size() == 1) {
 178                     return true;
 179                 } else if (cellWrap.as(Parent.class, Node.class).lookup(lookupCriteria).size() == 1) {
 180                     return true;
 181                 } else {
 182                     return null;
 183                 }
 184 
 185             }
 186         });
 187     }
 188 
 189     @Test(timeout = 300000)
 190     /**
 191      * When you scroll (in horizontal dimension) to some column, and sort it,
 192      * then scrolling will be dropped. This test checks, that scrolling will be
 193      * preserved after sorting.
 194      */
 195     public void tableViewNotScrollingOnSortTest() throws InterruptedException {
 196         setSize(200, 200);
 197         int count = 10;
 198         for (int i = 0; i < count; i++) {
 199             addColumn("items" + String.valueOf(i), i);
 200         }
 201         setNewDataSize(25);
 202         switchToPropertiesTab("TreeTableView");
 203         setPropertyBySlider(SettingType.UNIDIRECTIONAL, Properties.prefWidth, 170);
 204         setPropertyBySlider(SettingType.UNIDIRECTIONAL, Properties.prefHeight, 170);
 205 
 206         for (int i = 0; i < count; i++) {
 207             checkSortNotScrollingFor("items" + String.valueOf(i), i);
 208         }
 209     }
 210 
 211     private void checkSortNotScrollingFor(String name, int index) {
 212         scrollTo(index, 0);
 213         final double initialScrollPos = getScrollBarValue(findScrollBar((Parent<Node>)testedControl.as(Parent.class, Node.class), Orientation.HORIZONTAL, true));
 214         getTableColumnHeaderWrap(name).mouse().click();
 215         getTableColumnHeaderWrap(name).mouse().click();
 216         getTableColumnHeaderWrap(name).mouse().click();
 217         getTableColumnHeaderWrap(name).mouse().click();
 218         new Waiter(new Timeout("", 500)).ensureState(new State() {
 219             public Object reached() {
 220                 if (Math.abs(initialScrollPos - getScrollBarValue(findScrollBar((Parent<Node>)testedControl.as(Parent.class, Node.class), Orientation.HORIZONTAL, true))) < 0.001) {
 221                     return true;
 222                 } else {
 223                     return null;
 224                 }
 225             }
 226         });
 227     }
 228 
 229     @Test(timeout = 300000)
 230     /**
 231      * This test applies new sortNode and checks, that it was applied.
 232      */
 233     public void actualChangeSortNodeTest() throws InterruptedException {
 234         setSize(200, 200);
 235         String columnName = "column1";
 236         addColumn(columnName, 0, true);
 237         setNewDataSize(10);
 238         requestFocusOnControl(testedControl);
 239 
 240         final Wrap<? extends TableColumnHeader> header = getTableColumnHeaderWrap(columnName);
 241         final Rectangle columnNameCoords = header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds();
 242 
 243         switchToPropertiesTab(columnName);
 244         selectObjectFromChoiceBox(SettingType.SETTER, Properties.sortNode, javafx.scene.shape.Rectangle.class);
 245 
 246         //Direct sort.
 247         header.mouse().click();
 248         new Waiter(new Timeout("", 500)).ensureState(new State() {
 249             public Object reached() {
 250                 if (!(header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds().equals(columnNameCoords))) {
 251                     return true;
 252                 } else {
 253                     return null;
 254                 }
 255             }
 256         });
 257         checkRectanglesRelation(header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds(), RectanglesRelations.LEFTER,
 258                 header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).wrap().getScreenBounds());
 259         new Waiter(new Timeout("", 500)).ensureState(new State() {
 260             public Object reached() {
 261                 if (header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).size() == 1) {
 262                     return true;
 263                 } else {
 264                     return null;
 265                 }
 266             }
 267         });
 268 
 269         //Reversed sort.
 270         header.mouse().click();
 271         new Waiter(new Timeout("", 500)).ensureState(new State() {
 272             public Object reached() {
 273                 if (!(header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds().equals(columnNameCoords))) {
 274                     return true;
 275                 } else {
 276                     return null;
 277                 }
 278             }
 279         });
 280 
 281         checkRectanglesRelation(header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds(), RectanglesRelations.LEFTER,
 282                 header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).wrap().getScreenBounds());
 283 
 284         new Waiter(new Timeout("", 500)).ensureState(new State() {
 285             public Object reached() {
 286                 if (header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).size() == 1) {
 287                     return true;
 288                 } else {
 289                     return null;
 290                 }
 291             }
 292         });
 293 
 294         //Unsort.
 295         header.mouse().click();
 296         new Waiter(new Timeout("", 500)).ensureState(new State() {
 297             public Object reached() {
 298                 if (header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds().equals(columnNameCoords)) {
 299                     return true;
 300                 } else {
 301                     return null;
 302                 }
 303             }
 304         });
 305 
 306         new Waiter(new Timeout("", 500)).ensureState(new State() {
 307             public Object reached() {
 308                 if (header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).size() == 0) {
 309                     return true;
 310                 } else {
 311                     return null;
 312                 }
 313             }
 314         });
 315     }
 316 
 317     @Test(timeout = 300000)
 318     /**
 319      * This test checks, that using different types of setting or binding,
 320      * sortNode can be set. Standart property test.
 321      */
 322     public void sortNodePropertyTest() throws InterruptedException {
 323         assertNull(new TableColumn().getSortNode());
 324         setSize(200, 200);
 325         String columnName = "column1";
 326         addColumn(columnName, 0, true);
 327         setNewDataSize(10);
 328         requestFocusOnControl(testedControl);
 329         switchToPropertiesTab(columnName);
 330 
 331         selectObjectFromChoiceBox(SettingType.SETTER, Properties.sortNode, javafx.scene.shape.Rectangle.class);
 332         checkTextFieldTextContaining(Properties.sortNode, "Rectangle");
 333 
 334         selectObjectFromChoiceBox(SettingType.BIDIRECTIONAL, Properties.sortNode, Text.class);
 335         checkTextFieldTextContaining(Properties.sortNode, "Text");
 336 
 337         selectObjectFromChoiceBox(SettingType.UNIDIRECTIONAL, Properties.sortNode, Group.class);
 338         checkTextFieldTextContaining(Properties.sortNode, "Group");
 339     }
 340 
 341     @Test(timeout = 300000)
 342     /**
 343      * This test checks, that sort node is applied right at the same moment, as
 344      * it was set.
 345      */
 346     public void sortNodeImmidiateApplying() throws InterruptedException {
 347         setSize(200, 200);
 348         String columnName = "column1";
 349         addColumn(columnName, 0, true);
 350         setNewDataSize(10);
 351         requestFocusOnControl(testedControl);
 352         switchToPropertiesTab(columnName);
 353 
 354         //Direct sort.
 355         Wrap<? extends TableColumnHeader> header = getTableColumnHeaderWrap(columnName);
 356         header.mouse().click();
 357 
 358         assertTrue(header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).size() == 0);
 359 
 360         selectObjectFromChoiceBox(SettingType.SETTER, Properties.sortNode, javafx.scene.shape.Rectangle.class);
 361         assertTrue(header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).size() == 1);
 362         header.mouse().click();
 363         assertTrue(header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).size() == 1);
 364         selectObjectFromChoiceBox(SettingType.SETTER, Properties.sortNode, null);
 365         assertTrue(header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).size() == 0);
 366         selectObjectFromChoiceBox(SettingType.BIDIRECTIONAL, Properties.sortNode, javafx.scene.shape.Rectangle.class);
 367         assertTrue(header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).size() == 1);
 368     }
 369 
 370     @Test(timeout = 300000)
 371     /**
 372      * This test checks, that if comparator is set, then it is applied
 373      * immediately.
 374      */
 375     public void comparatorPropertyImmidiateAndCorrectApplyingTest() throws InterruptedException {
 376         setSize(200, 200);
 377         final int columns = 2;
 378         final int rows = 5;
 379         for (int i = 0; i < columns; i++) {
 380             addColumn("items" + String.valueOf(i), i, true);
 381         }
 382         setNewDataSize(rows);
 383 
 384         createNestedColumn("nested", 0, 0, 1);
 385         requestFocusOnControl(testedControl);
 386 
 387         if (!isTableTests) {
 388             switchToPropertiesTab("ROOT");
 389             setPropertyByToggleClick(SettingType.SETTER, Properties.expanded, true);
 390         }
 391 
 392         Wrap<? extends TableColumnHeader> header1 = getTableColumnHeaderWrap("items0");
 393 
 394         checkKeyCellsContent("items0-0", "items1-0", "items0-4", "items1-4", columns, rows);
 395         //Direct sort.
 396         header1.mouse().click();
 397         checkKeyCellsContent("items0-0", "items1-0", "items0-4", "items1-4", columns, rows);
 398         switchToPropertiesTab("items0");
 399         //Change comparator to reversed one.
 400         selectObjectFromChoiceBox(SettingType.SETTER, Properties.comparator, CustomReversedComparator.class);
 401         checkTextFieldText(Properties.comparator, CustomReversedComparator.comparatorName);
 402         //Expect, that reversed sorting will be applied.
 403         checkKeyCellsContent("items0-4", "items1-4", "items0-0", "items1-0", columns, rows);
 404         header1.mouse().click();
 405         //Expect, that ascending sorting will be applied.
 406         checkKeyCellsContent("items0-0", "items1-0", "items0-4", "items1-4", columns, rows);
 407     }
 408 
 409     @Test(timeout = 300000)
 410     /**
 411      * Checks, that comparator property can be set by setter or any of bindings.
 412      * That is a standard test.
 413      */
 414     public void comparatorPropertyTest() throws InterruptedException {
 415         assertTrue(new TableColumn().getComparator().getClass().equals(TableColumn.DEFAULT_COMPARATOR.getClass()));
 416         setSize(200, 200);
 417         final int rows = 5;
 418         addColumn("items0", 0, true);
 419         setNewDataSize(rows);
 420 
 421         switchToPropertiesTab("items0");
 422         Wrap<? extends TableColumnHeader> header1 = getTableColumnHeaderWrap("items0");
 423         header1.mouse().click();
 424         checkKeyCellsContent("items0-0", "items0-4", rows);
 425         selectObjectFromChoiceBox(SettingType.SETTER, Properties.comparator, CustomReversedComparator.class);
 426         checkTextFieldText(Properties.comparator, CustomReversedComparator.comparatorName);
 427         checkKeyCellsContent("items0-4", "items0-0", rows);
 428         selectObjectFromChoiceBox(SettingType.UNIDIRECTIONAL, Properties.comparator, CustomReversedComparator.class);
 429         checkTextFieldText(Properties.comparator, CustomReversedComparator.comparatorName);
 430         checkKeyCellsContent("items0-0", "items0-4", rows);
 431     }
 432 
 433     protected void checkKeyCellsContent(String upperText, String downText, int rows) {
 434         checkTextContainment(getCellWrap(0, 0), upperText);
 435         checkTextContainment(getCellWrap(0, rows - 1), downText);
 436     }
 437 
 438     @Test(timeout = 300000)
 439     /**
 440      * Standard test on graphic property: setting with setter, bidirectional of
 441      * unidirectional binding, checking with getter.
 442      */
 443     public void graphicPropertyTest() throws InterruptedException {
 444         assertNull(new TableColumn().getGraphic());
 445         setSize(200, 200);
 446         addColumn("items0", 0, true);
 447         setNewDataSize(5);
 448 
 449         switchToPropertiesTab("items0");
 450         final Wrap<? extends TableColumnHeader> header = getTableColumnHeaderWrap("items0");
 451         final Rectangle initialColumnNameCoords = header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds();
 452 
 453         selectObjectFromChoiceBox(SettingType.SETTER, Properties.graphic, javafx.scene.shape.Rectangle.class);
 454         checkTextFieldTextContaining(Properties.graphic, "Rectangle");
 455         new Waiter(new Timeout("", 500)).ensureState(new State() {
 456             public Object reached() {
 457                 if (!(header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds().equals(initialColumnNameCoords))
 458                         && header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).size() == 1) {
 459                     return true;
 460                 } else {
 461                     return null;
 462                 }
 463             }
 464         });
 465         checkRectanglesRelation(header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds(), RectanglesRelations.RIGHTER,
 466                 header.as(Parent.class, Node.class).lookup(javafx.scene.shape.Rectangle.class).wrap().getScreenBounds());
 467 
 468         selectObjectFromChoiceBox(SettingType.BIDIRECTIONAL, Properties.graphic, Group.class);
 469         checkTextFieldTextContaining(Properties.graphic, "Group");
 470         new Waiter(new Timeout("", 500)).ensureState(new State() {
 471             public Object reached() {
 472                 if (!(header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds().equals(initialColumnNameCoords))
 473                         && header.as(Parent.class, Node.class).lookup(Group.class).size() == 1) {
 474                     return true;
 475                 } else {
 476                     return null;
 477                 }
 478             }
 479         });
 480         checkRectanglesRelation(header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds(), RectanglesRelations.RIGHTER,
 481                 header.as(Parent.class, Node.class).lookup(Group.class).wrap().getScreenBounds());
 482 
 483         selectObjectFromChoiceBox(SettingType.UNIDIRECTIONAL, Properties.graphic, null);
 484         checkTextFieldText(Properties.graphic, "null");
 485         new Waiter(new Timeout("", 500)).ensureState(new State() {
 486             public Object reached() {
 487 
 488                 if ((header.as(Parent.class, Node.class).lookup(Text.class).wrap().getScreenBounds().equals(initialColumnNameCoords))
 489                         && header.as(Parent.class, Node.class).lookup(Group.class).size() == 0) {
 490                     return true;
 491                 } else {
 492                     return null;
 493                 }
 494             }
 495         });
 496     }
 497 
 498     @Test(timeout = 300000)
 499     public void reorderablePropertyTest() throws InterruptedException {
 500         final String ITEMS_0 = "items0";
 501         final String ITEMS_1 = "items1";
 502 
 503         setSize(200, 200);
 504         addColumn(ITEMS_0, 0, true);
 505         addColumn(ITEMS_1, 1, true);
 506         setNewDataSize(5);
 507 
 508         Wrap columnHeader1 = testedControl.as(Parent.class, Node.class).lookup(Text.class, new ByText(ITEMS_0)).wrap();
 509         Wrap columnHeader2 = testedControl.as(Parent.class, Node.class).lookup(Text.class, new ByText(ITEMS_1)).wrap();
 510 
 511         switchToPropertiesTab(ITEMS_0);
 512         setPropertyByToggleClick(SettingType.BIDIRECTIONAL, Properties.reorderable, false);
 513         checkTextFieldText(Properties.reorderable, "false");
 514         columnHeader1.drag().dnd(columnHeader2, columnHeader2.getClickPoint());
 515         assertTrue(columnHeader1.getScreenBounds().x < columnHeader2.getScreenBounds().x);
 516 
 517         setPropertyByToggleClick(SettingType.UNIDIRECTIONAL, Properties.reorderable, true);
 518         checkTextFieldText(Properties.reorderable, "true");
 519         columnHeader1.drag().dnd(columnHeader2, columnHeader2.getClickPoint().translate(5, 0));
 520 
 521         columnHeader1 = testedControl.as(Parent.class, Node.class).lookup(Text.class, new ByText(ITEMS_0)).wrap();
 522         columnHeader2 = testedControl.as(Parent.class, Node.class).lookup(Text.class, new ByText(ITEMS_1)).wrap();
 523         assertTrue(columnHeader1.getScreenBounds().x > columnHeader2.getScreenBounds().x);
 524     }
 525 
 526     @Test(timeout = 300000)
 527     /**
 528      * Standard test on resizable property test. Checked with getter, setter,
 529      * initial value, bindings, behavior is checked too. Checked for resizing of
 530      * nested columns and for autosizing cases.
 531      */
 532     public void resizablePropertyTest() throws InterruptedException {
 533         if (isTableTests) {
 534             assertTrue(new TableColumn().isResizable());
 535         } else {
 536             assertTrue(new TreeTableColumn().isResizable());
 537         }
 538         setSize(200, 200);
 539         addColumn("items0", 0, true);
 540         addColumn("items1", 1, true);
 541         createNestedColumn("nested", 0, 0, 1);
 542         setNewDataSize(5);
 543 
 544         final Wrap<? extends TableColumnHeader> items0 = getTableColumnHeaderWrap("items0");
 545         final Wrap<? extends TableColumnHeader> nested = getTableColumnHeaderWrap("nested");
 546 
 547         switchToPropertiesTab("items0");
 548         checkTextFieldValue(Properties.width, 80, 1);
 549         switchToPropertiesTab("nested");
 550         checkTextFieldValue(Properties.width, 160, 1);
 551 
 552         switchToPropertiesTab("items0");
 553         setPropertyByToggleClick(SettingType.SETTER, Properties.resizable, false);
 554         checkTextFieldText(Properties.resizable, "false");
 555         DnDInHorizontalDimnsion(getColumnResizablePoint(items0), 10);
 556         checkTextFieldValue(Properties.width, 80, 1);
 557         DnDInHorizontalDimnsion(getColumnResizablePoint(nested), 10);
 558         checkTextFieldValue(Properties.width, 80, 1);
 559         switchToPropertiesTab("nested");
 560         checkTextFieldValue(Properties.width, 170, 1);
 561 
 562         switchToPropertiesTab("items0");
 563         setPropertyByToggleClick(SettingType.BIDIRECTIONAL, Properties.resizable, true);
 564         checkTextFieldText(Properties.resizable, "true");
 565         DnDInHorizontalDimnsion(getColumnResizablePoint(items0), -10);
 566         checkTextFieldValue(Properties.width, 70, 1);
 567         DnDInHorizontalDimnsion(getColumnResizablePoint(nested), -10);
 568         checkTextFieldValue(Properties.width, 65, 3);
 569         switchToPropertiesTab("nested");
 570         checkTextFieldValue(Properties.width, 160, 1);
 571 
 572         switchToPropertiesTab("items0");
 573         setPropertyByToggleClick(SettingType.UNIDIRECTIONAL, Properties.resizable, false);
 574         checkTextFieldText(Properties.resizable, "false");
 575         DnDInHorizontalDimnsion(getColumnResizablePoint(items0), 10);
 576         checkTextFieldValue(Properties.width, 65, 1);
 577         DnDInHorizontalDimnsion(getColumnResizablePoint(nested), 10);
 578         checkTextFieldValue(Properties.width, 65, 3);
 579         switchToPropertiesTab("nested");
 580         checkTextFieldValue(Properties.width, 170, 1);
 581 
 582         switchToPropertiesTab("items0");
 583         setPropertyByToggleClick(SettingType.UNIDIRECTIONAL, Properties.resizable, true);
 584         checkTextFieldText(Properties.resizable, "true");
 585         DnDInHorizontalDimnsion(getColumnResizablePoint(items0), 50);
 586 
 587         Point endPoint = getColumnResizablePoint(items0);
 588         setPropertyByToggleClick(SettingType.UNIDIRECTIONAL, Properties.resizable, false);
 589         checkTextFieldText(Properties.resizable, "false");
 590         items0.mouse().click(1, getColumnResizablePoint(items0));
 591         items0.mouse().click(1, getColumnResizablePoint(items0));
 592         //Expect, that width doesn't change even on request of autosizing. Issue RT-25###.
 593         assertTrue(endPoint.equals(getColumnResizablePoint(items0)));
 594     }
 595 
 596     protected Point getColumnResizablePoint(Wrap<? extends TableColumnHeader> wrap) {
 597         return new Point(wrap.getScreenBounds().getX() + wrap.getScreenBounds().width, wrap.getScreenBounds().getY() + wrap.getScreenBounds().height / 2);
 598     }
 599 
 600     protected void DnDInHorizontalDimnsion(Point initialPoint, int movement) throws InterruptedException, InterruptedException {
 601         try {
 602             Point point = new Point(initialPoint.x + movement, initialPoint.y);
 603             Robot robot = new Robot();
 604             robot.mouseMove(initialPoint.x, initialPoint.y);
 605             robot.mousePress(InputEvent.BUTTON1_MASK);
 606             Thread.sleep(100);
 607             final int STEPS = 20;
 608             int differenceX = point.x - initialPoint.x;
 609             int differenceY = point.y - initialPoint.y;
 610             for (int i = 0; i <= STEPS; i++) {
 611                 robot.mouseMove(initialPoint.x + differenceX * i / STEPS, initialPoint.y + differenceY * i / STEPS);
 612                 Thread.sleep(20);
 613             }
 614             robot.mouseRelease(InputEvent.BUTTON1_MASK);
 615             Thread.sleep(SLEEP);
 616         } catch (Exception ex) {
 617             Logger.getLogger(TableViewNewTest.class.getName()).log(Level.SEVERE, null, ex);
 618         }
 619     }
 620 
 621     @Test(timeout = 300000)
 622     /**
 623      * Test on width property - readonly one. Check correct behavior on resizing
 624      * for simple and nested columns
 625      */
 626     public void widthPropertyTest() throws InterruptedException {
 627         setSize(200, 200);
 628         addColumn("items0", 0, true);
 629         addColumn("items1", 1, true);
 630         createNestedColumn("nested", 0, 0, 1);
 631         setNewDataSize(5);
 632 
 633 //        final Wrap<? extends TableColumnHeader> items0 = getTableColumnHeaderWrap("items0");
 634 //        final Wrap<? extends TableColumnHeader> items1 = getTableColumnHeaderWrap("items1");
 635 //        final Wrap<? extends TableColumnHeader> nested = getTableColumnHeaderWrap("nested");
 636         switchToPropertiesTab("items0");
 637         checkTextFieldValue(Properties.width, 80, 1);
 638         switchToPropertiesTab("items1");
 639         checkTextFieldValue(Properties.width, 80, 1);
 640         switchToPropertiesTab("nested");
 641         checkTextFieldValue(Properties.width, 160, 1);
 642 
 643         DnDInHorizontalDimnsion(getResizingPointOfColumn("nested"), +20);
 644         switchToPropertiesTab("items0");
 645         checkTextFieldValue(Properties.width, 90, 1);
 646         switchToPropertiesTab("items1");
 647         checkTextFieldValue(Properties.width, 90, 1);
 648         switchToPropertiesTab("nested");
 649         checkTextFieldValue(Properties.width, 180, 1);
 650 
 651         DnDInHorizontalDimnsion(getResizingPointOfColumn("items0"), -20);
 652         switchToPropertiesTab("items0");
 653         checkTextFieldValue(Properties.width, 70, 1);
 654         switchToPropertiesTab("items1");
 655         checkTextFieldValue(Properties.width, 90, 1);
 656         switchToPropertiesTab("nested");
 657         checkTextFieldValue(Properties.width, 160, 1);
 658     }
 659 
 660     @Test(timeout = 300000)
 661     /**
 662      * This test checks, that TableCell are resized correctly according to the
 663      * resizing of the tableColumnHeaders. That is, if you resize headers, do
 664      * autosizing, at least left and right borders have the same x-coordinates
 665      * as columnHeaders have.
 666      */
 667     public void correctAllocationOnResizingTest() throws InterruptedException {
 668         setSize(210, 210);
 669         addColumn("items0", 0, true);
 670         addColumn("items1", 1, true);
 671         createNestedColumn("nested", 0, 0, 1);
 672         final int rows = 5;
 673         setNewDataSize(rows);
 674 
 675         final Wrap<? extends TableColumnHeader> items0 = getTableColumnHeaderWrap("items0");
 676         final Wrap<? extends TableColumnHeader> items1 = getTableColumnHeaderWrap("items1");
 677         checkCorrectCoordinatesAllocation(items0, items1, rows + (isTableTests ? 0 : 1));
 678 
 679         DnDInHorizontalDimnsion(getResizingPointOfColumn("nested"), +20);
 680         checkCorrectCoordinatesAllocation(items0, items1, rows);
 681 
 682         DnDInHorizontalDimnsion(getResizingPointOfColumn("items1"), +20);
 683         checkCorrectCoordinatesAllocation(items0, items1, rows);
 684 
 685         DnDInHorizontalDimnsion(getResizingPointOfColumn("items0"), -20);
 686         checkCorrectCoordinatesAllocation(items0, items1, rows);
 687 
 688         Point colResizablePoint = items1.toLocal(getColumnResizablePoint(items1));
 689 
 690         items1.mouse().click(1, colResizablePoint);
 691         items1.mouse().click(1, colResizablePoint);
 692 
 693         checkCorrectCoordinatesAllocation(items0, items1, rows);
 694     }
 695 
 696     /**
 697      * Checks the state of control after removing all its observable data.
 698      */
 699     @Test(timeout = 300000)
 700     public void testAllDataRemoving() throws Throwable {
 701         final int COLS = 4;
 702         final int ROWS = 10;
 703         final String noContent = isTableTests ? "TableView_no_content" : "TreeTableView_no_content";
 704         final String noColumns = isTableTests ? "TableView_no_columns" : "TreeTableView_no_columns";
 705 
 706         setSize(200, 200);
 707 
 708         if (!isTableTests) {
 709             setPropertyByToggleClick(SettingType.SETTER, Properties.showRoot, false);
 710         }
 711 
 712         checkScreenshot(noColumns, testedControl);
 713 
 714         for (boolean bulkClear : new boolean[]{true, false}) {
 715 
 716             for (int i = 0; i < COLS; i++) {
 717                 addColumn(String.format("column%d", i), i, true);
 718             }
 719 
 720             checkScreenshot(noContent, testedControl);
 721 
 722             if (bulkClear) {
 723                 new GetAction<Object>() {
 724                     public void run(Object... parameters) throws Exception {
 725                         if (isTableTests) {
 726                             ((TableView) testedControl.getControl()).getColumns().clear();
 727                         } else {
 728                             ((TreeTableView) testedControl.getControl()).getColumns().clear();
 729                         }
 730                     }
 731                 }.dispatch(testedControl.getEnvironment());
 732             } else {
 733                 for (int i = COLS - 1; i >= 0; --i) {
 734                     removeColumns(i);
 735                 }
 736             }
 737 
 738             checkScreenshot(noColumns, testedControl);
 739         }
 740 
 741         for (int i = 0; i < COLS; i++) {
 742             addColumn(String.format("column%d", i), i, true);
 743         }
 744 
 745         setNewDataSize(ROWS);
 746 
 747         new GetAction<Object>() {
 748             @Override
 749             public void run(Object... os) throws Exception {
 750                 Control control = testedControl.getControl();
 751 
 752                 if (isTableTests) {
 753                     TableView tv = (TableView) control;
 754                     tv.getItems().clear();
 755                 } else {
 756                     TreeTableView ttv = (TreeTableView) control;
 757                     ttv.getRoot().getChildren().clear();
 758                 }
 759             }
 760         }.dispatch(testedControl.getEnvironment());
 761 
 762         //Wait for animation to finish
 763         try {
 764             Thread.sleep(100);
 765         } catch (Exception e) {
 766         }
 767 
 768         checkScreenshot(noContent, testedControl);
 769 
 770         for (int i = COLS - 1; i >= 0; --i) {
 771             removeColumns(i);
 772         }
 773 
 774         checkScreenshot(noColumns, testedControl);
 775 
 776         throwScreenshotError();
 777     }
 778 
 779     @Test(timeout = 300000)
 780     public void columnHeaderAndRowCustomisation() throws InterruptedException {
 781         setSize(200, 200);
 782         addColumn("items0", 0, true);
 783         addColumn("items1", 1, true);
 784         createNestedColumn("nested", 0, 0, 1);
 785         setNewDataSize(5);
 786 
 787         checkHeaderCustomizedState(false);
 788 
 789         clickButtonForTestPurpose(javafx.commons.Consts.REPLACE_SKIN_IMPLEMENTATION_BUTTON_ID);
 790 
 791         checkHeaderCustomizedState(true);
 792     }
 793 
 794     private void checkHeaderCustomizedState(final boolean isCustomized) {
 795         Lookup<TableColumnHeader> headers = testedControl.as(Parent.class, Node.class).lookup(TableColumnHeader.class);
 796         Wrap<TableHeaderRow> headerRow = testedControl.as(Parent.class, Node.class).lookup(TableHeaderRow.class).wrap();
 797 
 798         for (int i = 0; i < headers.size(); i++) {
 799             final String columnHeaderId = getId(headers.wrap(i));
 800 
 801             testedControl.waitState(new State() {
 802                 public Object reached() {
 803                     final String expectedId = isCustomized ? javafx.commons.Consts.CUSTOM_IMPLEMENTATION_MARKER : null;
 804                     if (expectedId == null) {
 805                         if (columnHeaderId == null) {
 806                             return Boolean.TRUE;
 807                         } else {
 808                             return null;
 809                         }
 810                     } else {
 811                         return expectedId.equals(columnHeaderId);
 812                     }
 813                 }
 814             });
 815         }
 816 
 817         final String headerRowId = getId(headerRow);
 818         testedControl.waitState(new State() {
 819             public Object reached() {
 820                 final String expectedId = isCustomized ? javafx.commons.Consts.CUSTOM_IMPLEMENTATION_MARKER : null;
 821                 if (expectedId == null) {
 822                     if (headerRowId == null) {
 823                         return Boolean.TRUE;
 824                     } else {
 825                         return null;
 826                     }
 827                 } else {
 828                     return expectedId.equals(headerRowId);
 829                 }
 830             }
 831         });
 832     }
 833 
 834     private String getId(final Wrap<? extends Node> node) {
 835         return new GetAction<String>() {
 836             @Override
 837             public void run(Object... os) throws Exception {
 838                 setResult(node.getControl().getId());
 839             }
 840         }.dispatch(Root.ROOT.getEnvironment());
 841     }
 842 
 843     /**
 844      * Checks control behavior when sortOrder list is changed.
 845      */
 846     @Test(timeout = 300000)
 847     public void testSortOrderAPI() throws InterruptedException {
 848         testSortTypeCombinations(false);
 849     }
 850 
 851     @Test(timeout = 300000)
 852     public void testOnEditStartCancel() throws InterruptedException {
 853         testDifferentCellEditors(false);
 854     }
 855 
 856     @Test(timeout = 300000)
 857     public void testOnEditStartCommit() throws InterruptedException {
 858         testDifferentCellEditors(true);
 859     }
 860 
 861     /**
 862      * Tests that sorting in column may be disabled via the API.
 863      */
 864     @Test(timeout = 380000)
 865     public void columnSortablePropertyTest() throws InterruptedException {
 866         testSortTypeCombinations(true);
 867     }
 868 
 869     /**
 870      * Tests, that cells/rows correctly answer on a question about row, column,
 871      * and control.
 872      */
 873     @Test(timeout = 300000)
 874     public void columnPropertyOfCellTest() throws InterruptedException {
 875         setSize(210, 210);
 876         addColumn("items0", 0, false);
 877         addColumn("items1", 1, false);
 878         final int rows = 5;
 879         setNewDataSize(rows);
 880 
 881         Class<?> rowClass = isTableTests ? TableRow.class : TreeTableRow.class;
 882         Class<?> cellClass = isTableTests ? TableCell.class : TreeTableCell.class;
 883         List<Cell> allCells = new ArrayList<Cell>();
 884         final Control control = testedControl.getControl();
 885         List<TableColumnBase> columns = new GetAction<List<TableColumnBase>>() {
 886             @Override
 887             public void run(Object... os) throws Exception {
 888                 if (isTableTests) {
 889                     setResult(((TableView) control).getColumns());
 890                 } else {
 891                     setResult(((TreeTableView) control).getColumns());
 892                 }
 893             }
 894         }.dispatch(Root.ROOT.getEnvironment());
 895 
 896         final Lookup<?> rowsLookup = testedControl.as(Parent.class, Node.class).lookup(rowClass);
 897         for (int i = 0; i < rowsLookup.size(); i++) {
 898             Wrap<?> rowWrap = rowsLookup.wrap(i);
 899             final Object row = rowWrap.getControl();
 900             Control controlResRow = new GetAction<Control>() {
 901                 @Override
 902                 public void run(Object... os) throws Exception {
 903                     if (isTableTests) {
 904                         setResult(((TableRow) row).getTableView());
 905                     } else {
 906                         setResult(((TreeTableRow) row).getTreeTableView());
 907                     }
 908                 }
 909             }.dispatch(Root.ROOT.getEnvironment());
 910             assertEquals(controlResRow, control);
 911 
 912             final Lookup<Cell> cellsInRowLookup = rowWrap.as(Parent.class, Node.class).lookup(Cell.class);
 913             for (int j = 0; j < cellsInRowLookup.size(); j++) {
 914                 Object rowRes = new GetAction<Object>() {
 915                     @Override
 916                     public void run(Object... os) throws Exception {
 917                         if (isTableTests) {
 918                             setResult(((TableCell) os[0]).getTableRow());
 919                         } else {
 920                             setResult(((TreeTableCell) os[0]).getTreeTableRow());
 921                         }
 922                     }
 923                 }.dispatch(Root.ROOT.getEnvironment(), cellsInRowLookup.get(j));
 924                 assertEquals(rowRes, row);
 925 
 926                 Control controlRes = new GetAction<Control>() {
 927                     @Override
 928                     public void run(Object... os) throws Exception {
 929                         if (isTableTests) {
 930                             setResult(((TableCell) os[0]).getTableView());
 931                         } else {
 932                             setResult(((TreeTableCell) os[0]).getTreeTableView());
 933                         }
 934                     }
 935                 }.dispatch(Root.ROOT.getEnvironment(), cellsInRowLookup.get(j));
 936                 assertEquals(controlRes, control);
 937 
 938                 TableColumnBase column = new GetAction<TableColumnBase>() {
 939                     @Override
 940                     public void run(Object... os) throws Exception {
 941                         if (isTableTests) {
 942                             setResult(((TableCell) os[0]).getTableColumn());
 943                         } else {
 944                             setResult(((TreeTableCell) os[0]).getTableColumn());
 945                         }
 946                     }
 947                 }.dispatch(Root.ROOT.getEnvironment(), cellsInRowLookup.get(j));
 948                 assertEquals(column, columns.get(j));
 949 
 950                 allCells.add(cellsInRowLookup.get(j));
 951             }
 952         }
 953 
 954         assertEquals(testedControl.as(Parent.class, Node.class).lookup(cellClass).size(), allCells.size());
 955         assertTrue(allCells.size() >= 2 * rows);
 956     }
 957 
 958     /**
 959      * Checks that when columns collection is ordered it will be rendered
 960      * properly.
 961      */
 962     @Test(timeout = 300000)
 963     public void columnsOrderTest() throws InterruptedException {
 964         setSize(210, 210);
 965         final int COLS = 3;
 966         final int ROWS = 5;
 967 
 968         setNewDataSize(ROWS);
 969 
 970         final String[] names = new String[]{"A", "B", "C"};
 971 
 972         for (String n : names) {
 973             addColumn(n, 0);
 974         }
 975 
 976         if (isTableTests) {
 977             checkKeyCellsContent("C-0", "A-0", "C-4", "A-4", COLS, ROWS);
 978         } else {
 979             setShowRoot(false);
 980             checkKeyCellsContent("C-1", "A-1", "C-5", "A-5", COLS, ROWS);
 981         }
 982 
 983         sortColumnsByName(true);
 984 
 985         if (isTableTests) {
 986             checkKeyCellsContent("A-0", "C-0", "A-4", "C-4", COLS, ROWS);
 987         } else {
 988             checkKeyCellsContent("A-1", "C-1", "A-5", "C-5", COLS, ROWS);
 989         }
 990 
 991         //check column headers
 992         final Lookup<TableColumnHeader> lookup = testedControl.waitState(new State<Lookup<TableColumnHeader>>() {
 993             public Lookup reached() {
 994                 final Lookup lookup = parent.lookup(TableColumnHeader.class, new LookupCriteria<TableColumnHeader>() {
 995                     public boolean check(TableColumnHeader cntrl) {
 996                         return (cntrl.getBoundsInLocal().getMaxY() > 15) && (!(cntrl instanceof NestedTableColumnHeader));
 997                     }
 998                 });
 999 
1000                 return (lookup.size() == 3) ? lookup : null;
1001             }
1002 
1003             @Override
1004             public String toString() {
1005                 return "[Correct number of column headers]";
1006             }
1007         });
1008 
1009         for (int i = 0; i < lookup.size(); i++) {
1010             final int x = i;
1011 
1012             assertEquals(names[i], new GetAction<String>() {
1013                 @Override
1014                 public void run(Object... os) throws Exception {
1015                     setResult(((Label) lookup.wrap(x).getControl().getChildrenUnmodifiable().get(0)).getText());
1016                 }
1017             }.dispatch(testedControl.getEnvironment()));
1018         }
1019     }
1020 
1021     /**
1022      * Checks the public 'sort' method and 'onSort' event. Features are
1023      * described here:
1024      * <a href="http://javafx-jira.kenai.com/browse/RT-26505">RT-19482</a>
1025      * and here <a
1026      * href="http://javafx-jira.kenai.com/browse/RT-26505">RT-17550</a>
1027      */
1028     @Test(timeout = 300000)
1029     public void onSortTest() throws InterruptedException {
1030         setSize(250, 250);
1031         final int COLS = 3;
1032 
1033         createRowsForSortPurposes(COLS);
1034         String[][] testData = NewTableViewApp.getDataForSorting(COLS);
1035 
1036         checkCounterValue(COUNTER_ON_SORT, 0);
1037 
1038         new GetAction<Void>() {
1039             @Override
1040             public void run(Object... os) throws Exception {
1041                 if (isTableTests) {
1042                     ((TableView) testedControl.getControl()).setSortPolicy(getAlwaysReverseTableSortPolicy());
1043                 } else {
1044                     Callback<TreeTableView<DataItem>, Boolean> treeTableSortPolicy = getAlwaysReverseTreeTableSortPolicy();
1045                     ((TreeTableView) testedControl.getControl()).setSortPolicy(treeTableSortPolicy);
1046                 }
1047             }
1048         }.dispatch(testedControl.getEnvironment());
1049 
1050         checkCounterValue(COUNTER_ON_SORT, 1);
1051         reverseTestData(testData);
1052         assertTrue("Sort order is wrong", checkSortResult(testData));
1053 
1054         createRowsForSortPurposes(COLS);
1055         testData = NewTableViewApp.getDataForSorting(COLS);
1056         assertTrue("Sort order is wrong", checkSortResult(testData));
1057 
1058         new GetAction<Void>() {
1059             @Override
1060             public void run(Object... os) throws Exception {
1061                 if (isTableTests) {
1062                     ((TableView) testedControl.getControl()).sort();
1063                 } else {
1064                     ((TreeTableView) testedControl.getControl()).sort();
1065                 }
1066             }
1067         }.dispatch(testedControl.getEnvironment());
1068 
1069         reverseTestData(testData);
1070         checkCounterValue(COUNTER_ON_SORT, 2);
1071         assertTrue("Sort order is wrong", checkSortResult(testData));
1072     }
1073 
1074     /**
1075      * Checks the returning to the unsorted state.
1076      * Feature is described here: <a href="https://javafx-jira.kenai.com/browse/RT-19487">RT-19487</a>
1077      */
1078     @Test(timeout = 60000)
1079     public void SortedListAsModel() throws InterruptedException {
1080         if (!isTableTests) {
1081             return;//pass all the time as this feature is not applicable to the tree table.
1082         }
1083         setSize(250, 250);
1084 
1085         final int COLS = 3;
1086 
1087         createRowsForSortPurposes(COLS);
1088 
1089         clickButtonForTestPurpose(BTN_SET_SORTED_LIST_FOR_MODEL_ID);
1090 
1091         String[][] testData = NewTableViewApp.getDataForSorting(COLS);
1092 
1093         List<ColumnState> columnStates = new ArrayList<ColumnState>(COLS);
1094 
1095         //Ascending
1096         getTableColumnHeaderWrap("column 2").mouse().click();
1097         columnStates.add(new ColumnState(2, ColumnState.SortType.ASCENDING));
1098         sortTestData(testData, columnStates);
1099         assertTrue("Sort order is wrong", checkSortResult(testData));
1100 
1101         //Descending
1102         getTableColumnHeaderWrap("column 2").mouse().click();
1103         columnStates.clear();
1104         columnStates.add(new ColumnState(2, ColumnState.SortType.DESCENDING));
1105         sortTestData(testData, columnStates);
1106         assertTrue("Sort order is wrong", checkSortResult(testData));
1107 
1108         //Initial state
1109         getTableColumnHeaderWrap("column 2").mouse().click();
1110         testData = NewTableViewApp.getDataForSorting(COLS);
1111         assertTrue("Sort order is wrong", checkSortResult(testData));
1112     }
1113 
1114     /*
1115      * Helper methods
1116      */
1117     private void testSortTypeCombinations(boolean testSortableProp) throws InterruptedException {
1118         setSize(250, 250);
1119 
1120         final int COLS = 3;
1121         createRowsForSortPurposes(COLS);
1122 
1123         String[][] testData = NewTableViewApp.getDataForSorting(COLS);
1124 
1125         //Check initial state
1126         assertTrue("Initial sort order is wrong", checkSortResult(testData));
1127 
1128         List<ColumnState> columnStates = new ArrayList<ColumnState>(COLS);
1129         ColumnState.SortType[] sortTypes = ColumnState.SortType.values();
1130 
1131         int sortTypesCount = sortTypes.length + 1;
1132 
1133         boolean[] sortableCols = {true, true, true};
1134 
1135         for (int col = 0; col < COLS; col++) {
1136 
1137             if (!testSortableProp) {
1138                 //When all columns are sortable it is enough to
1139                 //run outer loop once to test different combinations
1140                 //of the sort orders
1141                 if (col > 0) {
1142                     break;
1143                 }
1144             } else {
1145                 //Disable sortable property of each col sequentialy and
1146                 //test all sort type combinations.
1147                 sortableCols[col] = false;
1148                 System.out.println(String.format("Column %d.sortable = false", col));
1149             }
1150 
1151             for (int x = 0; x < sortTypesCount; x++) {
1152                 for (int y = 0; y < sortTypesCount; y++) {
1153                     for (int z = 0; z < sortTypesCount; z++) {
1154 
1155                         columnStates.clear();
1156 
1157                         if (x != 0) {
1158                             columnStates.add(new ColumnState(0, sortTypes[x - 1], sortableCols[0]));
1159                         }
1160                         if (y != 0) {
1161                             columnStates.add(new ColumnState(1, sortTypes[y - 1], sortableCols[1]));
1162                         }
1163                         if (z != 0) {
1164                             columnStates.add(new ColumnState(2, sortTypes[z - 1], sortableCols[2]));
1165                         }
1166 
1167                         for (int i = 0; i < columnStates.size(); i++) {
1168                             ColumnState pr = columnStates.get(i);
1169                             System.out.format("Column %d; Sort type %s; ", pr.columnIndex, pr.sortType);
1170                         }
1171                         setSortOrder(columnStates);
1172                         checkSortNodes(columnStates);
1173                         sortTestData(testData, columnStates);
1174                         assertTrue("Sort order is wrong", checkSortResult(testData));
1175                     }
1176                 }
1177             }
1178         }
1179     }
1180 
1181     private void checkSortNodes(final List<ColumnState> columnStates) {
1182 
1183         int sortableColsCount = 0;
1184 
1185         for (ColumnState state : columnStates) {
1186             if (state.sortable) {
1187                 ++sortableColsCount;
1188             }
1189         }
1190 
1191         int curPosInSortOrder = 0;
1192 
1193         for (final ColumnState state : columnStates) {
1194             Wrap<? extends TableColumnHeader> header = getTableColumnHeaderWrap(String.format("column %d", state.columnIndex));
1195             final Parent prnt = header.as(Parent.class, Node.class);
1196 
1197             header.waitState(new State<Boolean>() {
1198                 public Boolean reached() {
1199                     return ((state.sortable ? 1 : 0) == prnt.lookup(new ByStyleClass("arrow")).size()) ? Boolean.TRUE : null;
1200                 }
1201 
1202                 public String tiString() {
1203                     return state.sortable ? "[Sort node not found in sortable column]" : "[Sort node found in unsortable column]";
1204                 }
1205             });
1206 
1207             if (state.sortable) {
1208                 ++curPosInSortOrder;
1209 
1210                 if (sortableColsCount > 1) {
1211                     assertEquals("[Sort order dots container not found]", 1, prnt.lookup(new ByStyleClass("sort-order-dots-container")).size());
1212                     assertEquals("[Sort order dots not found]", curPosInSortOrder, prnt.lookup(new LookupCriteria<Node>() {
1213                         public boolean check(Node node) {
1214                             return node.getStyleClass().contains("sort-order-dot")
1215                                     && node.getStyleClass().contains(state.sortType.toString().toLowerCase());
1216                         }
1217                     }).size());
1218                 }
1219             }
1220         }
1221     }
1222 
1223     void setSortOrder(final List<ColumnState> newColumnStates) {
1224         new GetAction<Object>() {
1225             @Override
1226             public void run(Object... parameters) throws Exception {
1227                 ObservableList<TableColumnBase> columns = observableArrayList(getTopLevelColumns());
1228 
1229                 ObservableList<TableColumnBase> columnSortOrder
1230                         = isTableTests
1231                         ? ((TableView) testedControl.getControl()).getSortOrder()
1232                         : ((TreeTableView) testedControl.getControl()).getSortOrder();
1233 
1234                 columnSortOrder.clear();
1235 
1236                 for (ColumnState columnState : newColumnStates) {
1237                     TableColumnBase col = columns.get(columnState.columnIndex);
1238                     setSortType(col, columnState.sortType);
1239                     checkSortType(col, columnState.sortType);
1240                     col.setSortable(columnState.sortable);
1241                     columnSortOrder.add(col);
1242                 }
1243             }
1244         }.dispatch(testedControl.getEnvironment());
1245 
1246         //Animation delay
1247         try {
1248             Thread.sleep(100);
1249         } catch (Exception e) {
1250         }
1251     }
1252 
1253     static void checkSortType(TableColumnBase col, ColumnState.SortTypeProvider type) {
1254         if (isTableTests) {
1255             assertTrue(((TableColumn) col).getSortType().equals(type.forTableColumn()));
1256         } else {
1257             assertTrue(((TreeTableColumn) col).getSortType().equals(type.forTreeTableColumn()));
1258         }
1259     }
1260 
1261     static void setSortType(TableColumnBase col, ColumnState.SortTypeProvider type) {
1262         if (isTableTests) {
1263             ((TableColumn) col).setSortType(type.forTableColumn());
1264         } else {
1265             ((TreeTableColumn) col).setSortType(type.forTreeTableColumn());
1266         }
1267     }
1268 
1269     boolean checkSortResult(String[][] testData) {
1270         Boolean state = Boolean.TRUE;
1271 
1272         for (int j = 0; j < testData[0].length; j++) {
1273             final int fj = j;
1274             for (int i = 0; i < testData.length; i++) {
1275                 final int fi = i;
1276                 final Wrap<? extends IndexedCell> cellWrap = getCellWrap(j, i);
1277                 final String expected = testData[i][j];
1278 
1279                 state = cellWrap.waitState(new State<Boolean>() {
1280                     public Boolean reached() {
1281                         String actual = cellWrap.getControl().getText();
1282                         if (!expected.equals(actual)) {
1283                             System.out.println("i = " + fi + " j = " + fj);
1284                             System.out.println(String.format("exp|act:%s|%s", expected, actual));
1285                         }
1286                         return expected.equals(actual) ? Boolean.TRUE : Boolean.FALSE;
1287                     }
1288                 });
1289             }
1290 
1291             if (Boolean.FALSE == state) {
1292                 System.out.println(String.format("Column %d ended.", j));
1293             }
1294         }
1295         return state.booleanValue();
1296     }
1297 
1298     public void checkCorrectCoordinatesAllocation(Wrap<? extends TableColumnHeader> header1, Wrap<? extends TableColumnHeader> header2, int rows) {
1299         for (int i = 0; i < rows; i++) {
1300             Wrap wrap1 = getCellWrap(0, i);
1301             Wrap wrap2 = getCellWrap(1, i);
1302 
1303             if (false) {
1304                 System.out.println("wrap1.getScreenBounds().x = " + wrap1.getScreenBounds().x);
1305                 System.out.println("header1.getScreenBounds().x = " + header1.getScreenBounds().x);
1306                 System.out.println("wrap2.getScreenBounds().x = " + wrap2.getScreenBounds().x);
1307                 System.out.println("header2.getScreenBounds().x = " + header2.getScreenBounds().x);
1308                 System.out.println("wrap1.getScreenBounds().x + wrap1.getScreenBounds().width = " + (wrap1.getScreenBounds().x + wrap1.getScreenBounds().width));
1309                 System.out.println("header1.getScreenBounds().x + header1.getScreenBounds().width = " + (header1.getScreenBounds().x + header1.getScreenBounds().width));
1310                 System.out.println("wrap2.getScreenBounds().x + wrap2.getScreenBounds().width = " + (wrap2.getScreenBounds().x + wrap2.getScreenBounds().width));
1311                 System.out.println("header2.getScreenBounds().x + header2.getScreenBounds().width = " + (header2.getScreenBounds().x + header2.getScreenBounds().width));
1312             }
1313 
1314             if (isTableTests) {
1315                 assertEquals(wrap1.getScreenBounds().x, header1.getScreenBounds().x, 0);
1316             } else {
1317                 //For treeTable - there are nodes for showing tree structure
1318                 //(arrows), so cells are less, and left border is not aligned
1319                 //according to the left border of the column header.
1320                 assertTrue(wrap1.getScreenBounds().x > header1.getScreenBounds().x);
1321                 assertTrue(wrap1.getScreenBounds().x < wrap2.getScreenBounds().x);
1322                 assertTrue(wrap1.getScreenBounds().x < wrap1.getScreenBounds().x + wrap1.getScreenBounds().width);
1323             }
1324             assertEquals(wrap2.getScreenBounds().x, header2.getScreenBounds().x, 0);
1325             assertEquals(wrap1.getScreenBounds().x + wrap1.getScreenBounds().width, header1.getScreenBounds().x + header1.getScreenBounds().width, 0);
1326             assertEquals(wrap2.getScreenBounds().x + wrap2.getScreenBounds().width, header2.getScreenBounds().x + header2.getScreenBounds().width, 0);
1327         }
1328     }
1329 
1330     protected void testDifferentCellEditors(boolean commit) throws InterruptedException {
1331         setSize(212.5, 209.3);
1332         setPropertyByToggleClick(SettingType.SETTER, Properties.editable, true);
1333 
1334         addColumn("colA", 0, true);
1335         addColumn("colB", 1, true);
1336         addColumn("colC", 2, true);
1337 
1338         final int ROWS = 10;
1339         setNewDataSize(ROWS);
1340 
1341         clickButtonForTestPurpose(BTN_SET_ON_EDIT_EVENT_HANDLERS);
1342 
1343         int editStartCounter = 0;
1344         int editCancelCounter = 0;
1345         int editCommitCounter = 0;
1346 
1347         final class GetCellControlClassAction extends GetAction<Class> {
1348 
1349             int rowIndex = -1;
1350             int columnIndex = -1;
1351 
1352             public GetCellControlClassAction(int rowIndex, int columnIndex) {
1353                 this.columnIndex = columnIndex;
1354                 this.rowIndex = rowIndex;
1355             }
1356 
1357             @Override
1358             public void run(Object... os) throws Exception {
1359                 TableCell cell = getCellWrap(columnIndex, rowIndex).getControl();
1360                 setResult((null != cell.getGraphic()) ? cell.getGraphic().getClass() : Object.class);
1361             }
1362 
1363         }
1364 
1365         Wrap<? extends TableCell> cellWrap;
1366         for (CellEditorType type : CellEditorType.values()) {
1367 
1368             for (boolean isCustom : new boolean[]{true, false}) {
1369 
1370                 switch (type) {
1371                     case TEXT_FIELD:
1372                         setCellEditor(CellEditorType.TEXT_FIELD, isCustom);
1373                         cellWrap = getCellWrap(1, 4);
1374                         String initialText = getCellText(cellWrap);
1375 
1376                         cellWrap.mouse().click();
1377                         cellWrap.keyboard().pushKey(KeyboardButtons.F2);
1378                         cellWrap.keyboard().pushKey(KeyboardButtons.A, KeyboardModifiers.CTRL_DOWN_MASK);
1379                         cellWrap.keyboard().pushKey(KeyboardButtons.A);
1380                         cellWrap.keyboard().pushKey(KeyboardButtons.B);
1381                         cellWrap.keyboard().pushKey(KeyboardButtons.C);
1382 
1383                         final TextField textField = (TextField) cellWrap.as(Parent.class, Node.class).lookup(TextField.class).get();
1384                         cellWrap.waitState(new State() {
1385 
1386                             @Override
1387                             public Object reached() {
1388                                 if (textField == null) {
1389                                     System.out.println("TextField null");
1390                                     return null;
1391                                 }
1392                                 if (textField.getText().equals("abc")) {
1393                                     return true;
1394                                 } else {
1395                                     return null;
1396                                 }
1397                             }
1398                         });
1399 
1400                         cellWrap.keyboard().pushKey(commit ? KeyboardButtons.ENTER : KeyboardButtons.ESCAPE);
1401 
1402                         if (commit) {
1403                             assertEquals("Text didn't changed", "abc", getCellText(cellWrap));
1404                         } else {
1405                             assertEquals("[Text changed unexpectedly]", initialText, getCellText(cellWrap));
1406                         }
1407                         break;
1408                     case COMBOBOX:
1409                         setCellEditor(CellEditorType.COMBOBOX, isCustom);
1410                         cellWrap = getCellWrap(1, 4);
1411 
1412                         GetAction<Class> getCellClassAction = new GetCellControlClassAction(4, 1);
1413                         Class cellControlType = getCellClassAction.dispatch(cellWrap.getEnvironment());
1414                         while ( !ComboBox.class.equals(cellControlType) )
1415                         {
1416                             cellWrap.mouse().click();
1417                             cellControlType = getCellClassAction.dispatch(cellWrap.getEnvironment());
1418                         }
1419 
1420                         Wrap<ComboBox> combobox = cellWrap.as(Parent.class, Node.class).lookup(ComboBox.class).wrap();
1421 
1422                         //Select nothing
1423                         if (!commit) {
1424                             combobox.mouse().click();
1425                             assertTrue("Popup hasn't appeared",
1426                                         new GetAction<Boolean>() {
1427                                             @Override
1428                                             public void run(Object... os) throws Exception {
1429                                                 Wrap<? extends Scene> popupScene = Root.ROOT.lookup(new ByWindowType(PopupWindow.class)).lookup(Scene.class).wrap(0);
1430                                                 setResult(popupScene.getControl().getWindow().showingProperty().getValue());
1431                                             }
1432                                         }.dispatch(Root.ROOT.getEnvironment()));
1433 
1434                             //First escape to close popup
1435                             scene.keyboard().pushKey(KeyboardButtons.ESCAPE);
1436                             //Second escape to cancel editing
1437                             scene.keyboard().pushKey(KeyboardButtons.ESCAPE);
1438                         } else {
1439                             combobox.as(Selectable.class).selector().select("colB-1");
1440                         }
1441                         break;
1442                     case CHOICEBOX:
1443                         setCellEditor(CellEditorType.CHOICEBOX, isCustom);
1444                         cellWrap = getCellWrap(1, 4);
1445 
1446                         getCellClassAction = new GetCellControlClassAction(4, 1);
1447                         cellControlType = getCellClassAction.dispatch(cellWrap.getEnvironment());
1448                         while ( !ChoiceBox.class.equals(cellControlType) )
1449                         {
1450                             cellWrap.mouse().click();
1451                             cellControlType = getCellClassAction.dispatch(cellWrap.getEnvironment());
1452                         }
1453 
1454                         Wrap<ChoiceBox> choicebox = cellWrap.as(Parent.class, Node.class).lookup(ChoiceBox.class).wrap();
1455 
1456                         //Select nothing
1457                         if (!commit) {
1458                             choicebox.mouse().click();
1459 
1460                             choicebox.waitState(new State<Boolean>() {
1461                                 @Override
1462                                 public Boolean reached() {
1463                                     return new GetAction<Boolean>() {
1464                                                @Override
1465                                                public void run(Object... os) throws Exception {
1466                                                    Wrap<? extends Scene> popupScene = Root.ROOT.lookup(new ByWindowType(PopupWindow.class)).lookup(Scene.class).wrap(0);
1467                                                    setResult(popupScene.getControl().getWindow().showingProperty().getValue());
1468                                                }
1469                                            }.dispatch(Root.ROOT.getEnvironment())
1470                                            ? Boolean.TRUE : null;
1471                                 }
1472 
1473                                 @Override
1474                                 public String toString() {
1475                                     return "[Popup expected to appear]";
1476                                 }
1477                             });
1478                             //First escape to close popup
1479                             scene.keyboard().pushKey(KeyboardButtons.ESCAPE);
1480                             //Second escape to cancel editing
1481                             scene.keyboard().pushKey(KeyboardButtons.ESCAPE);
1482                         } else {
1483                             choicebox.as(Selectable.class).selector().select("colB-1");
1484                         }
1485                         break;
1486                 }
1487 
1488                 checkCounterValue(COUNTER_EDIT_START, ++editStartCounter);
1489 
1490                 if (commit) {
1491                     ++editCommitCounter;
1492                 } else {
1493                     ++editCancelCounter;
1494                 }
1495 
1496                 checkCounterValue(COUNTER_EDIT_CANCEL, editCancelCounter);
1497                 checkCounterValue(COUNTER_EDIT_COMMIT, editCommitCounter);
1498             }
1499         }
1500     }
1501 
1502     @Smoke
1503     @Test(timeout = 300000)
1504     public void fixedCellSizePropertyTest() throws InterruptedException {
1505         setSize(200, 200);
1506         addColumn("items0", 0, true);
1507         addColumn("items1", 1, true);
1508         createNestedColumn("nested", 0, 0, 1);
1509         setNewDataSize(5);
1510         fixedCellSizePropertyTestCommon(testedControl, Properties.fixedCellSize, 24);
1511     }
1512 
1513     @Smoke
1514     @Test(timeout = 300000)
1515     public void fixedCellSizePropertyCSSTest() throws InterruptedException {
1516         setSize(200, 200);
1517         addColumn("items0", 0, true);
1518         addColumn("items1", 1, true);
1519         createNestedColumn("nested", 0, 0, 1);
1520         setNewDataSize(5);
1521         fixedCellSizePropertyTestCommon(testedControl, Properties.fixedCellSize, 24);
1522     }
1523 
1524     @Test(timeout = 300000)
1525     public void styleOnCellsApplyingTest() throws InterruptedException, Throwable {
1526         setSize(200, 200);
1527         addColumn("items0", 0, true);
1528         addColumn("items1", 1, true);
1529         createNestedColumn("nested", 0, 0, 1);
1530         setNewDataSize(5);
1531 
1532         final Wrap<? extends TableColumnHeader> nested = getTableColumnHeaderWrap("nested");
1533         final Wrap<? extends TableColumnHeader> items0 = getTableColumnHeaderWrap("items1");
1534 
1535         applyStyleOnColumn(nested.getControl().getTableColumn(), "-fx-background-color: blue;");
1536         applyStyleOnColumn(items0.getControl().getTableColumn(), "-fx-background-color: red;");
1537 
1538         checkScreenshot((isTableTests ? "TableView-" : "TreeTableView-") + "styleOnColumnApplication", testedControl);
1539         throwScreenshotError();
1540     }
1541 
1542     protected void applyStyleOnColumn(final TableColumnBase column, final String style) {
1543         new GetAction() {
1544             @Override
1545             public void run(Object... os) throws Exception {
1546                 column.setStyle(style);
1547             }
1548         }.dispatch(testedControl.getEnvironment());
1549     }
1550 }