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.treeview;
  26 
  27 import java.util.ArrayList;
  28 import java.util.HashMap;
  29 import java.util.HashSet;
  30 import java.util.Iterator;
  31 import java.util.List;
  32 import java.util.Map;
  33 import java.util.logging.Level;
  34 import java.util.logging.Logger;
  35 import javafx.collections.ObservableList;
  36 import javafx.event.EventHandler;
  37 import javafx.geometry.Orientation;
  38 import javafx.scene.Node;
  39 import javafx.scene.Scene;
  40 import javafx.scene.control.Control;
  41 import javafx.scene.control.IndexedCell;
  42 import javafx.scene.control.ScrollBar;
  43 import javafx.scene.control.SelectionMode;
  44 import javafx.scene.control.TreeCell;
  45 import javafx.scene.control.TreeItem;
  46 import javafx.scene.control.TreeTableCell;
  47 import javafx.scene.control.TreeTableColumn;
  48 import javafx.scene.control.TreeTableView;
  49 import javafx.scene.control.TreeView;
  50 import javafx.scene.control.test.treetable.TreeTableNewApp;
  51 import static javafx.scene.control.test.treetable.TreeTableNewApp.*;
  52 import javafx.scene.control.test.treeview.TreeViewCommonFunctionality.Properties;
  53 import static javafx.scene.control.test.treeview.TreeViewConstants.EDIT_BUTTON_ID;
  54 import static javafx.scene.control.test.treeview.TreeViewConstants.EDIT_TEXT_FIELD_ID;
  55 import static javafx.scene.control.test.treeview.TreeViewConstants.GET_CONTROL_OVER_TREEITEM_BUTTON_ID;
  56 import static javafx.scene.control.test.treeview.TreeViewConstants.GET_CONTROL_OVER_TREEITEM_TEXTFIELD_ID;
  57 import static javafx.scene.control.test.treeview.TreeViewConstants.REMOVE_ITEM_BUTTON_ID;
  58 import static javafx.scene.control.test.treeview.TreeViewConstants.REMOVE_ITEM_TEXT_FIELD_ID;
  59 import static javafx.scene.control.test.treeview.TreeViewConstants.SCROLL_TO_BUTTON_ID;
  60 import static javafx.scene.control.test.treeview.TreeViewConstants.SCROLL_TO_TEXT_FIELD_ID;
  61 import javafx.scene.control.test.util.MultipleSelectionHelper;
  62 import javafx.scene.control.test.util.UtilTestFunctions;
  63 import javafx.scene.control.test.utils.ptables.AbstractPropertyController.SettingType;
  64 import static javafx.scene.control.test.utils.ptables.NodeControllerFactory.TreeItemControllers.*;
  65 import static javafx.scene.control.test.utils.ptables.PropertyValueListener.LISTENER_SUFFIX;
  66 import static javafx.scene.control.test.utils.ptables.SpecialTablePropertiesProvider.ForTreeItem.*;
  67 import javafx.scene.layout.StackPane;
  68 import javafx.scene.text.Text;
  69 import org.jemmy.Point;
  70 import org.jemmy.action.GetAction;
  71 import org.jemmy.control.Wrap;
  72 import org.jemmy.env.Environment;
  73 import org.jemmy.env.Timeout;
  74 import org.jemmy.fx.ByID;
  75 import org.jemmy.fx.ByStyleClass;
  76 import org.jemmy.fx.NodeWrap;
  77 import org.jemmy.fx.Root;
  78 import org.jemmy.interfaces.Keyboard;
  79 import org.jemmy.interfaces.Parent;
  80 import org.jemmy.lookup.Lookup;
  81 import org.jemmy.lookup.LookupCriteria;
  82 import org.jemmy.timing.State;
  83 import org.jemmy.timing.Waiter;
  84 import org.junit.*;
  85 import static org.junit.Assert.*;
  86 import org.junit.runner.RunWith;
  87 import test.javaclient.shared.FilteredTestRunner;
  88 import static test.javaclient.shared.TestUtil.isEmbedded;
  89 
  90 /**
  91  * @author Alexander Kirov, Dmitry Zinkevich
  92  */
  93 @RunWith(FilteredTestRunner.class)
  94 public class TestBase extends UtilTestFunctions {
  95 
  96     protected Wrap<? extends Scene> scene;
  97     protected Wrap<? extends Control> testedControl;
  98     protected static boolean isTreeTests = true;
  99     protected boolean resetHardByDefault = true;//switcher of hard and soft reset mode.
 100     protected boolean doNextResetHard = resetHardByDefault;
 101     protected static MultipleSelectionHelper selectionHelper;
 102     protected static int DATA_ITEMS_NUM = 0;
 103 
 104     @BeforeClass
 105     public static void setUpClass() throws Exception {
 106         if (isTreeTests) {
 107             System.out.println("Starting a TreeView applications with properties control.");
 108             TreeViewNewApp.main(null);
 109         } else {
 110             System.out.println("Starting a TreeTable application with properties control.");
 111             TreeTableNewApp.main(null);
 112         }
 113     }
 114 
 115     @Before
 116     public void setUp() {
 117         TreeViewCommonFunctionality.setCheckFocus(true);
 118         initWrappers();
 119         setContentSize(1, 21);
 120         selectionHelper.setPageWidth(1);
 121         if (selectionHelper.pageHeight != 7) {
 122             selectionHelper.setPageHeight(10);
 123         }
 124         Environment.getEnvironment().setTimeout("wait.state", isEmbedded() ? 60000 : 2000);
 125         Environment.getEnvironment().setTimeout("wait.control", isEmbedded() ? 60000 : 1000);
 126         scene.mouse().move(new Point(0, 0));
 127     }
 128 
 129     @After
 130     public void tearDown() {
 131         if (doNextResetHard) {
 132             resetSceneHard();
 133         } else {
 134             resetSceneSoft();
 135         }
 136 
 137         doNextResetHard = resetHardByDefault;
 138         currentSettingOption = SettingOption.PROGRAM;
 139     }
 140 
 141     protected static void setContentSize(int x, int y) {
 142         DATA_ITEMS_NUM = y;
 143         selectionHelper = new MultipleSelectionHelper(x, y);
 144     }
 145 
 146     protected void initWrappers() {
 147         scene = Root.ROOT.lookup().wrap();
 148         parent = scene.as(Parent.class, Node.class);
 149         if (isTreeTests) {
 150             testedControl = (Wrap<? extends TreeView>) parent.lookup(TreeView.class, new ByID<TreeView>(TreeViewNewApp.TESTED_TREEVIEW_ID)).wrap();
 151         } else {
 152             testedControl = (Wrap<? extends TreeTableView>) parent.lookup(TreeTableView.class, new ByID<TreeTableView>(TreeTableNewApp.TESTED_TREETABLEVIEW_ID)).wrap();
 153         }
 154     }
 155 
 156     protected void getControlOverTreeItem(String treeItemName) {
 157         setText(findTextField(GET_CONTROL_OVER_TREEITEM_TEXTFIELD_ID), treeItemName);
 158         clickButtonForTestPurpose(GET_CONTROL_OVER_TREEITEM_BUTTON_ID);
 159     }
 160 
 161     /**
 162      * Set size if tested control using bidirectional bindings.
 163      */
 164     protected void setSize(double width, double height) throws InterruptedException {
 165         setPropertyBySlider(SettingType.BIDIRECTIONAL, Properties.prefHeight, height);
 166         setPropertyBySlider(SettingType.BIDIRECTIONAL, Properties.prefWidth, width);
 167     }
 168 
 169     protected void doIntermediateStateCheck() {
 170         arrowsChecker();
 171     }
 172 
 173     protected void scrollTo(final int inXCoord, final int inYCoord) {
 174         TreeViewCommonFunctionality.scrollTo(testedControl, inXCoord, inYCoord);
 175     }
 176 
 177     protected void switchOnMultiple() {
 178         setPropertyByChoiceBox(SettingType.BIDIRECTIONAL, SelectionMode.MULTIPLE, Properties.selectionMode);
 179     }
 180 
 181     protected void clickOnFirstCell() {
 182         TreeViewCommonFunctionality.clickOnFirstCell(testedControl);
 183     }
 184 
 185     protected void keyboardCheck(Keyboard.KeyboardButtons btn, Keyboard.KeyboardModifiers... modifier) {
 186         if (btn == Keyboard.KeyboardButtons.PAGE_DOWN || btn == Keyboard.KeyboardButtons.PAGE_UP) {
 187             selectionHelper.setVisibleRange(TreeViewCommonFunctionality.getVisibleRange(testedControl));
 188         }
 189         testedControl.keyboard().pushKey(btn, modifier);
 190         selectionHelper.push(btn, modifier);
 191         checkSelection();
 192     }
 193 
 194     /**
 195      * Be extremely careful, changing this function, don't change amount of
 196      * content.
 197      */
 198     protected void adjustControl() {
 199         DATA_ITEMS_NUM = 21;
 200         if (!isTreeTests) {
 201             switchToPropertiesTab(TREE_TABLE_VIEW_TAB_NAME);
 202         }
 203         TreeViewCommonFunctionality.adjustControl(DATA_ITEMS_NUM);
 204     }
 205 
 206     protected void editItem(int index) {
 207         setText(findTextField(EDIT_TEXT_FIELD_ID), String.valueOf(index));
 208         clickButtonForTestPurpose(EDIT_BUTTON_ID);
 209     }
 210 
 211     protected void scrollTo(int position) {
 212         setText(findTextField(SCROLL_TO_TEXT_FIELD_ID), position);
 213         clickButtonForTestPurpose(SCROLL_TO_BUTTON_ID);
 214         try {//"Animation" time.
 215             Thread.sleep(500);
 216         } catch (InterruptedException ex) {
 217             Logger.getLogger(TestBase.class.getName()).log(Level.SEVERE, null, ex);
 218         }
 219     }
 220 
 221     /**
 222      * @return wrapper over required data item which can be used for mouse
 223      * actions
 224      */
 225     protected Wrap<Text> getCellWrap(final Integer item) {
 226         final String content = new GetAction<String>() {
 227             @Override
 228             public void run(Object... os) throws Exception {
 229                 if (isTreeTests) {
 230                     setResult(((TreeView) testedControl.getControl()).getTreeItem(item).getValue().toString());
 231                 } else {
 232                     setResult(((TreeTableView) testedControl.getControl()).getTreeItem(item).getValue().toString());
 233                 }
 234             }
 235         }.dispatch(Root.ROOT.getEnvironment());
 236 
 237         return getCellWrap(content);
 238     }
 239 
 240     protected Wrap<Text> getCellWrap(String item) {
 241         return TreeViewCommonFunctionality.getCellWrap(testedControl, item);
 242     }
 243 
 244     protected void checkLeafness(String itemName, boolean leaf) {
 245         intermediateStateCheck();
 246         switchToPropertiesTab(itemName);
 247         checkTextFieldText(Properties.leaf, leaf ? "true" : "false");
 248     }
 249 
 250     private void resetSceneHard() {
 251         clickButtonForTestPurpose(HARD_RESET_BUTTON_ID);
 252 //        initWrappers();
 253     }
 254 
 255     private void resetSceneSoft() {
 256         clickButtonForTestPurpose(SOFT_RESET_BUTTON_ID);
 257 //        initWrappers();
 258     }
 259 
 260     protected void checkSiblings(String expectedPreviousSibling, String expectedNextSibling) {
 261         clickButtonForTestPurpose(GET_NEXT_SIBLING_TREEITEM_BUTTON_ID);
 262         checkText(GET_NEXT_SIBLING_TREEITEM_TEXTFIELD_ID, expectedNextSibling);
 263         clickButtonForTestPurpose(GET_PREVIOUS_SIBLING_TREEITEM_BUTTON_ID);
 264         checkText(GET_PREVIOUS_SIBLING_TREEITEM_TEXTFIELD_ID, expectedPreviousSibling);
 265     }
 266 
 267     protected void checkParent(final String expectedParentValue) {
 268         new Waiter(new Timeout("s", 20000)).ensureState(new State() {
 269             public Object reached() {
 270                 String text = findTextField("PARENT" + LISTENER_SUFFIX).getControl().getText();
 271                 if (text.equals("null")) {
 272                     if ((expectedParentValue == null) || expectedParentValue.equals("null")) {
 273                         return true;
 274                     } else {
 275                         return null;
 276                     }
 277                 } else {
 278                     if (text.substring(text.indexOf("value:") + "value:".length(), text.indexOf("]")).trim().equals(expectedParentValue)) {
 279                         return true;
 280                     } else {
 281                         return null;
 282                     }
 283                 }
 284             }
 285         });
 286     }
 287 
 288     protected void checkExpandedCounter(String itemName, int expectedCounterValue) {
 289         switchToPropertiesTab(itemName);
 290         intermediateStateCheck();
 291         checkCounterValue(BRANCH_EXPANDED_EVENT_COUNTER, expectedCounterValue);
 292     }
 293 
 294     protected void checkCollapsedCounter(String itemName, int expectedCounterValue) {
 295         switchToPropertiesTab(itemName);
 296         intermediateStateCheck();
 297         checkCounterValue(BRANCH_COLLAPSED_EVENT_COUNTER, expectedCounterValue);
 298     }
 299 
 300     /*
 301      * It is supposed, that there is a unique TreeItem in the tested treeView,
 302      * with written itemName.
 303      */
 304     protected void removeItem(String itemName) {
 305         setText(findTextField(REMOVE_ITEM_TEXT_FIELD_ID), itemName);
 306         clickButtonForTestPurpose(REMOVE_ITEM_BUTTON_ID);
 307     }
 308 
 309     protected HashSet<Point> getSelected() {
 310         return TreeViewCommonFunctionality.getSelected(testedControl);
 311     }
 312 
 313     protected Point getSelectedItem() {
 314         return TreeViewCommonFunctionality.getSelectedItem(testedControl);
 315     }
 316 
 317     protected void checkSelection() {
 318         TreeViewCommonFunctionality.checkSelection(testedControl, selectionHelper, DATA_ITEMS_NUM);
 319     }
 320 
 321     protected void checkScrollingState(final double scrollValue, boolean beginVisible, boolean endVisible, int size) {
 322         testedControl.waitState(new State() {
 323             public Object reached() {
 324                 Wrap<? extends ScrollBar> sb = findScrollBar((Parent<Node>)testedControl.as(Parent.class, Node.class), Orientation.VERTICAL, true);
 325                 if (Math.abs(sb.getControl().getValue() - scrollValue) < 0.01) {
 326                     return true;
 327                 } else {
 328                     return null;
 329                 }
 330             }
 331         });
 332 
 333         if (beginVisible) {
 334             assertTrue(isCellShown(0));
 335         }
 336         if (endVisible) {
 337             assertTrue(isCellShown(size - 1));
 338         }
 339     }
 340 
 341     /**
 342      * This function will find all arrows, and check, that their orientation
 343      * corresponds to the expanded/collapsed value of TreeItem
 344      */
 345     protected void arrowsChecker() {
 346         final List<Throwable> lastThrown = new ArrayList<Throwable>();
 347         try {
 348             testedControl.waitState(new State<Boolean>() {
 349                 public Boolean reached() {
 350                     try {
 351                         final Map<String, TreeItem> treeItemsStringRepresentation = new GetAction<Map<String, TreeItem>>() {
 352                             @Override
 353                             public void run(Object... os) throws Exception {
 354                                 Map<String, TreeItem> treeItemsToString = new HashMap<String, TreeItem>();
 355                                 try {
 356                                     final List<TreeItem> allTreeItems = new ArrayList<TreeItem>();
 357                                     TreeItem root;
 358                                     if (testedControl.getControl() instanceof TreeView) {
 359                                         root = ((TreeView) testedControl.getControl()).getRoot();
 360                                     } else {
 361                                         root = ((TreeTableView) testedControl.getControl()).getRoot();
 362                                     }
 363                                     recursiveActionMaker(root, new ActionMaker<TreeItem>() {
 364                                         public void act(TreeItem argument) {
 365                                             allTreeItems.add(argument);
 366                                         }
 367                                     });
 368 
 369                                     for (TreeItem item : allTreeItems) {
 370                                         treeItemsToString.put(item.getValue().toString(), item);
 371                                     }
 372                                 } catch (Exception ex) {
 373                                     System.err.println(ex.getMessage());
 374                                     ex.printStackTrace(System.err);
 375 
 376                                 }
 377 
 378                                 setResult(treeItemsToString);
 379                             }
 380                         }.dispatch(Root.ROOT.getEnvironment());
 381 
 382                         final Lookup<Text> allTextNodes = testedControl.as(Parent.class, Node.class).lookup(Text.class);
 383                         final int nodesCount = allTextNodes.size();
 384                         final Map<String, Boolean> textOnExpandedMatching = new GetAction<Map<String, Boolean>>() {
 385                             @Override
 386                             public void run(Object... os) throws Exception {
 387                                 Map<String, Boolean> toReturn = new HashMap<String, Boolean>();
 388                                 try {
 389                                     for (int i = 0; i < nodesCount; i++) {
 390                                         TreeItem correspondingItem = treeItemsStringRepresentation.get(allTextNodes.get(i).getText());
 391                                         if (correspondingItem == null || correspondingItem.getChildren().size() == 0) {
 392                                             toReturn.put(allTextNodes.get(i).getText(), null);
 393                                         } else {
 394                                             toReturn.put(allTextNodes.get(i).getText(), correspondingItem.isExpanded());
 395                                         }
 396                                     }
 397                                 } catch (Exception ex) {
 398                                     System.err.println(ex.getMessage());
 399                                     ex.printStackTrace(System.err);
 400                                 }
 401                                 setResult(toReturn);
 402                             }
 403                         }.dispatch(Root.ROOT.getEnvironment());
 404 
 405                         Lookup<TreeCell> allVisibleCells = testedControl.as(Parent.class, Node.class).lookup(TreeCell.class);
 406                         final int cellsCount = allVisibleCells.size();
 407                         for (int i = 0; i < cellsCount; i++) {
 408                             final Lookup lookup = allVisibleCells.wrap(i).as(Parent.class, Node.class).lookup(Text.class);
 409                             Text text = null;
 410                             if (lookup.size() > 1) {
 411                                 for (int j = 0; j < lookup.size(); j++) {
 412                                     if ("This is custom node".equals(((Text) lookup.get(j)).getText())) continue;
 413                                     text = (Text) lookup.get(j);
 414                                 }
 415                             } else {
 416                                 text = (Text) lookup.get();
 417                             }
 418                             Boolean expectedExpandedState = textOnExpandedMatching.get(text.getText());
 419 
 420                             Lookup<StackPane> foundStackPanes = allVisibleCells.wrap(i).as(Parent.class, Node.class).lookup(StackPane.class, new ByStyleClass("arrow"));
 421                             final int foundStackPanesCount = foundStackPanes.size();
 422 
 423                             Boolean foundArrowExpandedState;
 424                             if (foundStackPanesCount == 0) {
 425                                 foundArrowExpandedState = null;
 426                             } else {
 427                                 if (foundStackPanesCount > 1) {
 428                                     throw new IllegalStateException("There are too many stack panes with the same style class under the same TreeCell.");
 429                                 } else {
 430                                     //Be careful: this could become different.
 431                                     //Also, if it fails, this means, that there is an arrow with strange size.
 432                                     //it needs evaluation.
 433                                     Assert.assertEquals("For " + text.getText(), foundStackPanes.get().getBoundsInLocal().getWidth(), 7.0, 2.01);
 434                                     Assert.assertEquals("For " + text.getText(), foundStackPanes.get().getBoundsInLocal().getHeight(), 7.0, 2.01);
 435                                     foundArrowExpandedState = foundStackPanes.get().getRotate() == 90 ? Boolean.TRUE : Boolean.FALSE;
 436                                 }
 437                             }
 438 
 439                             Assert.assertEquals("For " + text.getText(), expectedExpandedState, foundArrowExpandedState);
 440                         }
 441                     } catch (Throwable ex) {
 442                         lastThrown.add(ex);
 443                         return null;
 444                     }
 445                     return Boolean.TRUE;
 446                 }
 447             });
 448         } catch (Throwable ex) {
 449             //We couldn't reach the state, when all arrows are correctly shown.
 450             for (Throwable thrown : lastThrown) {
 451                 thrown.printStackTrace(System.err);
 452             }
 453             throw new IllegalStateException("Could reach the state of arrows correctness", ex);
 454         }
 455     }
 456 
 457     private void recursiveActionMaker(TreeItem rootItem, ActionMaker<TreeItem> actionForThatItem) {
 458         if (rootItem != null) {
 459             actionForThatItem.act(rootItem);
 460             for (TreeItem item : (ObservableList<TreeItem>) rootItem.getChildren()) {
 461                 recursiveActionMaker(item, actionForThatItem);
 462             }
 463         }
 464     }
 465 
 466     protected boolean isCellShown(final int item) {
 467         Wrap<Text> cellWrap = getCellWrap(item);
 468         org.jemmy.Rectangle cellRect = cellWrap.getScreenBounds();
 469         org.jemmy.Rectangle control = testedControl.getScreenBounds();
 470         return control.contains(cellRect);
 471     }
 472 
 473     /**
 474      * This function checks some thing, which should be actual during the whole
 475      * time of control's functioning.
 476      */
 477     protected void intermediateStateCheck() {
 478         arrowsChecker();
 479     }
 480 
 481     /**
 482      * This function modify standart selection helper's state, according to the
 483      * expansion or collapsing of some TreeItem.
 484      *
 485      * Rules:
 486      *
 487      * 1) if focus|anchor was into collapsed branch, focus|anchor is moved to
 488      * the according branch's root (treeItem).
 489      *
 490      * 2) if some selection was done into collapsed branch, this selection will
 491      * be lost.
 492      *
 493      * 3) no changes happen out of the collapsed branch.
 494      *
 495      * @param treeItemContent string - which represents the treeItem.
 496      * @param expanding true - for expanding, false - for collapsing.
 497      */
 498     protected void modifySelectionHelper(final String treeItemContent, boolean wasExpanded) {
 499         int treeItemRowIndex = new GetAction<Integer>() {
 500             @Override
 501             public void run(Object... os) throws Exception {
 502                 int row;
 503                 final Control control = testedControl.getControl();
 504                 if (control instanceof TreeView) {
 505                     final TreeView treeView = (TreeView) control;
 506                     row = treeView.getRow(TreeViewNewApp.searchTreeItem(treeView, treeItemContent));
 507                 } else {
 508                     final TreeTableView treeTableView = (TreeTableView) control;
 509                     row = treeTableView.getRow(TreeTableNewApp.searchTreeItem(treeTableView, treeItemContent));
 510                 }
 511                 setResult(row);
 512             }
 513         }.dispatch(Root.ROOT.getEnvironment());
 514 
 515         int subtreeSize = subtreeVisibleSize(treeItemContent);
 516 
 517         if (selectionHelper.ctrlA) {
 518             //Some nodes inside will be added, so we need to convert ctrlA
 519             //into selection set with all items, and after that work with
 520             //the set.
 521             selectionHelper.selectedSet.clear();
 522             selectionHelper.ctrlA = false;
 523 
 524             for (int i = 0; i < selectionHelper.rows; i++) {
 525                 selectionHelper.selectedSet.add(new Point(-1, i));
 526             }
 527         }
 528 
 529         if (wasExpanded) {
 530             for (Point point : selectionHelper.selectedSet) {
 531                 if (point.y > treeItemRowIndex) {
 532                     point.y += subtreeSize;
 533                 }
 534             }
 535 
 536             if (selectionHelper.focus.y > treeItemRowIndex) {
 537                 selectionHelper.focus.y += subtreeSize;
 538             }
 539 
 540             if (selectionHelper.anchor.y > treeItemRowIndex) {
 541                 selectionHelper.anchor.y += subtreeSize;
 542             }
 543             //Because now we have more cells then there exist
 544             //we need to remove those which are redundant.
 545             Iterator<Point> it = selectionHelper.selectedSet.iterator();
 546             while (it.hasNext()) {
 547                 Point pt = it.next();
 548                 if (pt.y > selectionHelper.rows - 1) {
 549                     it.remove();
 550                 }
 551             }
 552 
 553         } else {//was collapsed
 554             Point[] copy = selectionHelper.selectedSet.toArray(new Point[0]);
 555             for (Point point : copy) {
 556                 if (point.y > treeItemRowIndex) {
 557                     if (point.y > treeItemRowIndex + subtreeSize) {
 558                         point.y -= subtreeSize;
 559                     } else {
 560                         //All other points in the selection will be lost, except
 561                         //anchor and focus. They jump to the treeItem, and
 562                         //selection is moved with them
 563                         removePointFromSet(point.y);
 564                         if ((selectionHelper.anchor.y == point.y) || (selectionHelper.focus.y == point.y)) {
 565                             removePointFromSet(treeItemRowIndex);
 566                             selectionHelper.selectedSet.add(new Point(-1, treeItemRowIndex));
 567                         }
 568                     }
 569                 }
 570             }
 571 
 572             if (selectionHelper.focus.y > treeItemRowIndex) {
 573                 if (selectionHelper.focus.y > treeItemRowIndex + subtreeSize) {
 574                     selectionHelper.focus.y -= subtreeSize;
 575                 } else {
 576                     selectionHelper.focus.y = treeItemRowIndex;
 577                 }
 578             }
 579 
 580             if (selectionHelper.anchor.y > treeItemRowIndex) {
 581                 if (selectionHelper.anchor.y > treeItemRowIndex + subtreeSize) {
 582                     selectionHelper.anchor.y -= subtreeSize;
 583                 } else {
 584                     selectionHelper.anchor.y = treeItemRowIndex;
 585                 }
 586             }
 587         }
 588 
 589         //Invalidate:
 590         selectionHelper.bottomVisible = -1;
 591         selectionHelper.topVisible = -1;
 592     }
 593 
 594     private void removePointFromSet(int y) {
 595         Point[] copy = selectionHelper.selectedSet.toArray(new Point[0]);
 596         for (Point point : copy) {
 597             if (point.y == y) {
 598                 selectionHelper.selectedSet.remove(point);
 599             }
 600         }
 601     }
 602 
 603     /**
 604      * Founds the size of subtree, which is found under the specified data item,
 605      * not depending on the expanded or collapsed state of specified treeItem.
 606      *
 607      * @param treeItemName
 608      * @return - size
 609      */
 610     private int subtreeVisibleSize(final String treeItemName) {
 611         return new GetAction<Integer>() {
 612             @Override
 613             public void run(Object... os) throws Exception {
 614                 TreeItem item;
 615                 if (testedControl.getControl() instanceof TreeView) {
 616                     item = TreeViewNewApp.searchTreeItem((TreeView) testedControl.getControl(), treeItemName);
 617                 } else {
 618                     item = TreeTableNewApp.searchTreeItem((TreeTableView) testedControl.getControl(), treeItemName);
 619                 }
 620                 setResult(countSubItemSize(item));
 621             }
 622         }.dispatch(Root.ROOT.getEnvironment());
 623     }
 624 
 625     private static int countSubItemSize(TreeItem item) {
 626         if (item == null) {
 627             throw new NullPointerException("Null pointer.");
 628         }
 629 
 630         int counter = item.getChildren().size();
 631 
 632         for (TreeItem i : (ObservableList<TreeItem>) item.getChildren()) {
 633             if (i.isExpanded()) {
 634                 counter += countSubItemSize(i);
 635             }
 636         }
 637 
 638         return counter;
 639     }
 640 
 641     private interface ActionMaker<ArgumentType> {
 642 
 643         public void act(ArgumentType argument);
 644     }
 645 
 646     protected Wrap<? extends IndexedCell> getIndexedCellWrap(final String text) {
 647 
 648         final String styleClass = isTreeTests ? "tree-cell" : "tree-table-cell";
 649 
 650         Lookup<IndexedCell> lookup = testedControl.as(Parent.class, IndexedCell.class)
 651                 .lookup(IndexedCell.class, new LookupCriteria<IndexedCell>() {
 652             public boolean check(IndexedCell cell) {
 653                 return text.equals(cell.getText()) && cell.getStyleClass().contains(styleClass);
 654             }
 655         });
 656 
 657         final int size = lookup.size();
 658 
 659         testedControl.waitState(new State<Boolean>() {
 660             public Boolean reached() {
 661                 if (1 == size) {
 662                     return Boolean.TRUE;
 663                 } else {
 664                     return null;
 665                 }
 666             }
 667         });
 668 
 669         return lookup.wrap();
 670     }
 671 
 672     protected Wrap getDisclosureNode(final Wrap<? extends IndexedCell> cellWrap) {
 673 
 674         final IndexedCell cell = cellWrap.getControl();
 675         final String arrowStyle = "tree-disclosure-node";
 676 
 677         if (TreeCell.class.isAssignableFrom(cell.getClass())) {
 678             return cellWrap.as(Parent.class, Node.class).lookup(new ByStyleClass(arrowStyle)).wrap();
 679         } else if (TreeTableCell.class.isAssignableFrom(cell.getClass())) {
 680             final NodeWrap<IndexedCell> nodeWrap = new NodeWrap(cellWrap.getEnvironment(), cellWrap.getControl().getParent());
 681             Parent cellAsParent = nodeWrap.as(Parent.class, IndexedCell.class);
 682             return cellAsParent.lookup(new ByStyleClass(arrowStyle)).wrap();
 683         } else {
 684             throw new IllegalStateException();
 685         }
 686     }
 687 
 688     protected Wrap<Node> levelWrapUp(Wrap<? extends Node> wrap) {
 689         return (Wrap<Node>) new NodeWrap(wrap.getEnvironment(), wrap.getControl().getParent());
 690     }
 691 
 692     EventHandler getOnEditStart(final int columnIndex) {
 693         return new GetAction<EventHandler>() {
 694             @Override
 695             public void run(Object... os) throws Exception {
 696                 if (isTreeTests) {
 697                     setResult(((TreeView) (testedControl.getControl())).getOnEditStart());
 698                 } else {
 699                     TreeTableView treeTable = (TreeTableView) (testedControl.getControl());
 700                     setResult(((TreeTableColumn) treeTable.getColumns().get(columnIndex)).getOnEditStart());
 701                 }
 702             }
 703         }.dispatch(testedControl.getEnvironment());
 704     }
 705 
 706     EventHandler getOnEditCancel(final int columnIndex) {
 707         return new GetAction<EventHandler>() {
 708             @Override
 709             public void run(Object... os) throws Exception {
 710                 if (isTreeTests) {
 711                     setResult(((TreeView) (testedControl.getControl())).getOnEditCancel());
 712                 } else {
 713                     TreeTableView treeTable = (TreeTableView) (testedControl.getControl());
 714                     setResult(((TreeTableColumn) treeTable.getColumns().get(columnIndex)).getOnEditCancel());
 715                 }
 716             }
 717         }.dispatch(testedControl.getEnvironment());
 718     }
 719 
 720     EventHandler getOnEditCommit(final int columnIndex) {
 721         return new GetAction<EventHandler>() {
 722             @Override
 723             public void run(Object... os) throws Exception {
 724                 if (isTreeTests) {
 725                     setResult(((TreeView) (testedControl.getControl())).getOnEditCommit());
 726                 } else {
 727                     TreeTableView treeTable = (TreeTableView) (testedControl.getControl());
 728                     setResult(((TreeTableColumn) treeTable.getColumns().get(columnIndex)).getOnEditCommit());
 729                 }
 730             }
 731         }.dispatch(testedControl.getEnvironment());
 732     }
 733 
 734     void setOnEditStart(EventHandler handler, final int columnIndex) {
 735         new GetAction<Void>() {
 736             @Override
 737             public void run(Object... args) throws Exception {
 738                 if (isTreeTests) {
 739                     ((TreeView) (testedControl.getControl())).setOnEditStart((EventHandler) args[0]);
 740                 } else {
 741                     TreeTableView treeTable = (TreeTableView) (testedControl.getControl());
 742                     ((TreeTableColumn) treeTable.getColumns().get(columnIndex)).setOnEditStart((EventHandler) args[0]);
 743                 }
 744             }
 745         }.dispatch(testedControl.getEnvironment(), handler);
 746     }
 747 
 748     void setOnEditCancel(EventHandler handler, final int columnIndex) {
 749         new GetAction<Void>() {
 750             @Override
 751             public void run(Object... args) throws Exception {
 752                 if (isTreeTests) {
 753                     ((TreeView) (testedControl.getControl())).setOnEditCancel((EventHandler) args[0]);
 754                 } else {
 755                     TreeTableView treeTable = (TreeTableView) (testedControl.getControl());
 756                     ((TreeTableColumn) treeTable.getColumns().get(columnIndex)).setOnEditCancel((EventHandler) args[0]);
 757                 }
 758             }
 759         }.dispatch(testedControl.getEnvironment(), handler);
 760     }
 761 
 762     void setOnEditCommit(EventHandler handler, final int columnIndex) {
 763         new GetAction<Void>() {
 764             @Override
 765             public void run(Object... args) throws Exception {
 766                 if (isTreeTests) {
 767                     ((TreeView) (testedControl.getControl())).setOnEditCommit((EventHandler) args[0]);
 768                 } else {
 769                     TreeTableView treeTable = (TreeTableView) (testedControl.getControl());
 770                     ((TreeTableColumn) treeTable.getColumns().get(columnIndex)).setOnEditCommit((EventHandler) args[0]);
 771                 }
 772             }
 773         }.dispatch(testedControl.getEnvironment(), handler);
 774     }
 775 
 776 }