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.ListView;
  26 
  27 import java.util.Collection;
  28 import java.util.HashSet;
  29 import java.util.List;
  30 import javafx.geometry.Orientation;
  31 import javafx.scene.Node;
  32 import javafx.scene.Scene;
  33 import javafx.scene.control.*;
  34 import static javafx.scene.control.test.ListView.NewListViewApp.*;
  35 import javafx.scene.control.test.util.MultipleSelectionHelper;
  36 import javafx.scene.control.test.util.MultipleSelectionHelper.Range;
  37 import javafx.scene.control.test.util.TableListCommonTests;
  38 import static javafx.scene.control.test.utils.ComponentsFactory.*;
  39 import javafx.scene.control.test.utils.SelectionFormatter;
  40 import javafx.scene.control.test.utils.ptables.AbstractPropertyController.SettingType;
  41 import static javafx.scene.control.test.utils.ptables.NodesChoserFactory.*;
  42 import javafx.scene.text.Text;
  43 import org.jemmy.Point;
  44 import org.jemmy.action.GetAction;
  45 import org.jemmy.control.Wrap;
  46 import org.jemmy.env.Environment;
  47 import org.jemmy.fx.ByID;
  48 import org.jemmy.fx.Root;
  49 import org.jemmy.fx.control.ListItemWrap.ListItemByObjectLookup;
  50 import org.jemmy.interfaces.Keyboard.KeyboardButtons;
  51 import org.jemmy.interfaces.Keyboard.KeyboardModifiers;
  52 import org.jemmy.interfaces.Mouse;
  53 import org.jemmy.interfaces.Parent;
  54 import org.jemmy.interfaces.Selectable;
  55 import org.jemmy.interfaces.Showable;
  56 import org.jemmy.lookup.Lookup;
  57 import org.jemmy.lookup.LookupCriteria;
  58 import org.jemmy.timing.State;
  59 import org.junit.After;
  60 import org.junit.Assert;
  61 import org.junit.Before;
  62 import org.junit.BeforeClass;
  63 import test.javaclient.shared.Utils;
  64 import static test.javaclient.shared.TestUtil.isEmbedded;
  65 
  66 /**
  67  * @author Alexander Kirov
  68  */
  69 public class TestBase extends TableListCommonTests {
  70 
  71     static Wrap<? extends Scene> scene;
  72     protected boolean resetHardByDefault = false;//switcher of hard and soft reset mode.
  73     protected boolean doNextResetHard = resetHardByDefault;
  74 
  75     @BeforeClass
  76     public static void setUpClass() throws Exception {
  77         NewListViewApp.main(null);
  78     }
  79 
  80     @Before
  81     public void setUp() {
  82         initWrappers();
  83         setContentSize(1, 9);
  84         selectionHelper.setPageWidth(1);
  85         selectionHelper.setPageHeight(10);
  86         scene.getEnvironment().setTimeout("wait.state", isEmbedded() ? 60000 : 2000);
  87         scene.getEnvironment().setTimeout("wait.control", isEmbedded() ? 60000 : 1000);
  88         scene.mouse().move(new Point(0, 0));
  89     }
  90 
  91     @After
  92     public void tearDown() {
  93         //It is needed in cases, when in process of testing, fail happened when
  94         //shift button was pressed and was not released because of test fail
  95         //between press and release.
  96         scene.keyboard().pushKey(KeyboardButtons.SHIFT);
  97 
  98         if (doNextResetHard) {
  99             resetSceneHard();
 100         } else {
 101             resetSceneSoft();
 102         }
 103 
 104         doNextResetHard = resetHardByDefault;
 105         currentSettingOption = SettingOption.PROGRAM;
 106     }
 107 
 108     protected void initWrappers() {
 109         scene = Root.ROOT.lookup().wrap();
 110         parent = scene.as(Parent.class, Node.class);
 111 
 112         testedControl = parent.lookup(ListView.class, new ByID<ListView>(TESTED_LIST_VIEW_ID)).wrap();
 113     }
 114 
 115     // Wraps for intellisence.
 116     protected void checkCounter(Counters counter, int value) {
 117         checkCounterValue(counter, value);
 118     }
 119 
 120     protected void checkListener(Listeners listener, int value) {
 121         checkSimpleListenerValue(listener, value);
 122     }
 123 
 124     protected void checkListener(Listeners listener, String text) {
 125         checkSimpleListenerValue(listener, text);
 126     }
 127 
 128     //                       SINGLE BUTTONS
 129     protected void resetSceneHard() {
 130         clickButtonForTestPurpose(HARD_RESET_BUTTON_ID);
 131         initWrappers();
 132     }
 133 
 134     protected void resetSceneSoft() {
 135         clickButtonForTestPurpose(SOFT_RESET_BUTTON_ID);
 136         //initWrappers();
 137     }
 138 
 139     protected void resetSceneByDefault() {
 140         if (resetHardByDefault) {
 141             resetSceneHard();
 142         } else {
 143             resetSceneSoft();
 144         }
 145     }
 146 
 147     protected void doNextResetHard() {
 148         doNextResetHard = true;
 149     }
 150 
 151     protected void doNextResetSoft() {
 152         doNextResetHard = false;
 153     }
 154 
 155     protected void addRectangleAtPos(int position) {
 156         setText(findTextField(ADD_RECTANGLE_TEXT_FIELD_ID), position);
 157         clickButtonForTestPurpose(ADD_RECTANGLE_BUTTON_ID);
 158     }
 159 
 160     protected void addTextFieldAtPos(int position) {
 161         setText(findTextField(ADD_TEXT_FIELD_TEXT_FIELD_ID), position);
 162         clickButtonForTestPurpose(ADD_TEXT_FIELD_BUTTON_ID);
 163     }
 164 
 165     protected void startMotion(int position) {
 166         setText(findTextField(START_MOTION_TEXT_FIELD_ID), position);
 167         clickButtonForTestPurpose(START_MOTION_BUTTON_ID);
 168     }
 169 
 170     protected void increaseScale(int position) {
 171         setText(findTextField(INCREASE_SCALE_TEXT_FIELD_ID), position);
 172         clickButtonForTestPurpose(INCREASE_SCALE_BUTTON_ID);
 173     }
 174 
 175     protected void decreaseScale(int position) {
 176         setText(findTextField(DECREASE_SCALE_TEXT_FIELD_ID), position);
 177         clickButtonForTestPurpose(DECREASE_SCALE_BUTTON_ID);
 178     }
 179 
 180     protected void addElement(String element, int position) {
 181         setText(findTextField(ADD_ITEM_POSITION_TEXT_FIELD_ID), position);
 182         setText(findTextField(ADD_ITEM_TEXT_FIELD_ID), element);
 183         clickButtonForTestPurpose(ADD_ITEM_BUTTON_ID);
 184     }
 185 
 186     protected void addControlToPosition(int controlIndex, int position) {
 187         setText(findTextField(LIST_VIEW_CONTROL_ADD_INDEX_TEXT_FIELD_ID), String.valueOf(position));
 188         selectControlFromFactory(controlIndex);
 189         clickButtonForTestPurpose(NODE_CHOOSER_ACTION_BUTTON_ID);
 190     }
 191 
 192     protected void addElements(int... elements) {
 193         for (int i = 0; i < elements.length; i++) {
 194             addElement(String.valueOf(elements[i]), i);
 195         }
 196     }
 197 
 198     protected void addFormAtPos(int position) {
 199         setText(findTextField(ADD_FORM_TEXT_FIELD_ID), position);
 200         clickButtonForTestPurpose(ADD_FORM_BUTTON_ID);
 201     }
 202 
 203     protected void clickFormButton() {
 204         clickButtonForTestPurpose(FORM_BUTTON_ID);
 205     }
 206 
 207     protected void checkFormClickCounter(int expectedValue) {
 208         parent.lookup(TextField.class, new ByID<TextField>(FORM_CLICK_TEXT_FIELD_ID)).wrap().waitProperty(Wrap.TEXT_PROP_NAME, String.valueOf(expectedValue));
 209     }
 210 
 211     protected void scrollFormScrollBar(int move) {
 212         parent.lookup(ScrollBar.class, new ByID<ScrollBar>(FORM_SCROLLBAR_ID)).wrap().mouse().move();
 213         parent.lookup(ScrollBar.class, new ByID<ScrollBar>(FORM_SCROLLBAR_ID)).wrap().mouse().turnWheel(move * (Utils.isMacOS() ? -1 : 1));
 214     }
 215 
 216     protected void checkFormScrollCounter(int expectedValue) {
 217         parent.lookup(TextField.class, new ByID<TextField>(FORM_SCROLL_TEXT_FIELD_ID)).wrap().waitProperty(Wrap.TEXT_PROP_NAME, String.valueOf(expectedValue));
 218     }
 219 
 220     protected void removeFromPos(int position) {
 221         setText(findTextField(REMOVE_ITEM_POS_TEXT_FIELD_ID), position);
 222         clickButtonForTestPurpose(REMOVE_BUTTON_ID);
 223     }
 224 
 225     protected void scrollTo(int position) {
 226         setText(findTextField(SCROLL_TO_TEXT_FIELD_ID), position);
 227         clickButtonForTestPurpose(SCROLL_TO_BUTTON_ID);
 228     }
 229 
 230     protected void changeSelectionModel(int position) {
 231         clickButtonForTestPurpose(CHANGE_SELECTION_MODEL_BUTTON_ID);
 232     }
 233 
 234     /**
 235      * Checks visibility states of horizontal and vertical scrollBars.
 236      */
 237     protected void checkScrollbarsStates(boolean horizontalVisibility, boolean verticalVisibility) {
 238         Assert.assertFalse(findScrollBar(testedControl.as(Parent.class, Node.class), Orientation.HORIZONTAL, horizontalVisibility) == null);
 239         Assert.assertFalse(findScrollBar(testedControl.as(Parent.class, Node.class), Orientation.VERTICAL, verticalVisibility) == null);
 240     }
 241 
 242     /**
 243      * Set size if tested control using bidirectional bindings.
 244      */
 245     protected void setSize(double width, double height) throws InterruptedException {
 246         setPropertyBySlider(SettingType.BIDIRECTIONAL, Properties.prefHeight, height);
 247         setPropertyBySlider(SettingType.BIDIRECTIONAL, Properties.prefWidth, width);
 248     }
 249 
 250     /**
 251      * Make chessboard focus.
 252      *
 253      * @param elemCount - length of list of added elements.
 254      */
 255     protected void addAndSelectElements(final int elemCount) {
 256         for (int i = 0; i < elemCount; i++) {
 257             addElement(String.valueOf(i * i), i);
 258         }
 259 
 260         new GetAction() {
 261             @Override
 262             public void run(Object... os) throws Exception {
 263                 ListView lv = (ListView) os[0];
 264                 for (int i = 0; i < elemCount; i++) {
 265                     if (Integer.valueOf((String) lv.getItems().get(i)) % 2 == 0) {
 266                         lv.getSelectionModel().select(i);
 267                     }
 268                 }
 269             }
 270         }.dispatch(Root.ROOT.getEnvironment(), (ListView) testedControl.getControl());
 271     }
 272 
 273     protected void checkScreenshotsWithStep(String name, final int elementsCount, final int step) throws Throwable {
 274         Wrap<Text> cellWrap = getCellWrap((Integer) (0)); //mouse will be over the second item.
 275         cellWrap.as(Showable.class).shower().show();
 276         cellWrap.mouse().click(1, cellWrap.getClickPoint(), Mouse.MouseButtons.BUTTON1, CTRL_DOWN_MASK_OS);
 277         for (int i = 0; i < elementsCount / step; i++) {
 278             for (int j = 0; j < step; j++) {
 279                 testedControl.keyboard().pushKey(KeyboardButtons.RIGHT, CTRL_DOWN_MASK_OS);
 280             }
 281             checkScreenshot("ListView_" + name + "_" + i, testedControl);
 282         }
 283 
 284         throwScreenshotError();
 285     }
 286 
 287     @Override
 288     protected void checkSelection() {
 289         testedControl.waitState(new State() {
 290             public Object reached() {
 291                 Collection<Point> helper_selected = selectionHelper.getSelected();
 292                 Collection<Point> selected = getSelected();
 293                 Point helper_selection = selectionHelper.focus;
 294                 Point selection = getSelectedItem();
 295 
 296                 System.out.println(SelectionFormatter.format("Helper selection: ", helper_selected, "Selection: ", selected));
 297                 System.out.println("Helper focus : " + helper_selection);
 298                 System.out.println("Focus        : " + selection);
 299                 System.out.println("Anchor : " + selectionHelper.anchor + "\n\n");
 300 
 301                 if (((helper_selected.size() == selected.size())
 302                         && helper_selected.containsAll(selected)
 303                         && selected.containsAll(helper_selected)
 304                         && selection.equals(helper_selection))
 305                         || (selectionHelper.ctrlA && (selected.size() == currentListContentSize))) {
 306                     return true;
 307                 } else {
 308                     return null;
 309                 }
 310             }
 311         });
 312     }
 313 
 314     /**
 315      * @return hashSet of selected items in listView
 316      */
 317     @Override
 318     protected HashSet<Point> getSelected() {
 319         return new GetAction<HashSet<Point>>() {
 320             @Override
 321             public void run(Object... parameters) throws Exception {
 322                 HashSet<Point> selected = new HashSet<Point>();
 323                 MultipleSelectionModel model = ((Wrap<? extends ListView>) testedControl).getControl().getSelectionModel();
 324                 for (Object obj : model.getSelectedIndices()) {
 325                     Integer pos = (Integer) obj;
 326                     selected.add(new Point(-1, pos));
 327                 }
 328                 setResult(selected);
 329             }
 330         }.dispatch(Root.ROOT.getEnvironment());
 331     }
 332 
 333     @Override
 334     protected Point getSelectedItem() {
 335         return new GetAction<Point>() {
 336             @Override
 337             public void run(Object... parameters) throws Exception {
 338                 Lookup lookup = testedControl.as(Parent.class, Node.class).lookup(new LookupCriteria<Node>() {
 339                     public boolean check(Node row) {
 340                         return ListCell.class.isAssignableFrom(row.getClass())
 341                                 && ((ListCell) row).isFocused()
 342                                 && ((ListCell) row).isVisible();
 343                     }
 344                 });
 345                 if (lookup.size() > 0) {
 346                     setResult(new Point(-1, ((ListCell) lookup.get()).getIndex()));
 347                     return;
 348                 }
 349                 setResult(new Point(-1, -1));
 350             }
 351         }.dispatch(Root.ROOT.getEnvironment());
 352     }
 353 
 354     protected void localReset() {
 355         clearList();
 356         addExponentialContent();
 357         testedControl.keyboard().pushKey(KeyboardButtons.HOME);
 358     }
 359 
 360     protected void clearList() {
 361         for (int i = 1; i < listItems; i++) {
 362             removeFromPos(0);
 363         }
 364     }
 365 
 366     protected void addExponentialContent() {
 367         for (int i = 1; i < listItems; i++) {
 368             addElement(String.valueOf(Integer.valueOf((int) Math.round(Math.pow(i, i)))), i - 1);
 369         }
 370     }
 371 
 372     protected void applyKeysPushing(int times, KeyboardButtons button, KeyboardModifiers... modifiers) {
 373         for (int i = 0; i < times; i++) {
 374             if (button == KeyboardButtons.PAGE_DOWN || button == KeyboardButtons.PAGE_UP) {
 375                 selectionHelper.setVisibleRange(getVisibleRange());
 376             }
 377             testedControl.keyboard().pushKey(button, modifiers);
 378 
 379             if (button == KeyboardButtons.RIGHT) {
 380                 selectionHelper.push(KeyboardButtons.DOWN, modifiers);
 381             } else if (button == KeyboardButtons.LEFT) {
 382                 selectionHelper.push(KeyboardButtons.UP, modifiers);
 383             } else {
 384                 selectionHelper.push(button, modifiers);
 385             }
 386             checkSelection();
 387         }
 388     }
 389 
 390     protected void selectionCycle(int firstLine, int lastLine, KeyboardButtons modifier, SelectionMode mode) throws Throwable {
 391         if (isListControl()) {
 392             selectionHelper = new MultipleSelectionHelper.ListViewMultipleSelectionHelper(1, 8);
 393         } else {
 394             selectionHelper = new MultipleSelectionHelper(1, 8);
 395         }
 396         selectionHelper.setSingleCell(false);
 397         selectionHelper.setMultiple((mode == SelectionMode.MULTIPLE ? true : false));
 398         selectionHelper.push(KeyboardButtons.HOME);
 399 
 400         if (modifier != null) {
 401             testedControl.keyboard().pressKey(modifier);
 402         }
 403         try {
 404             for (int j = firstLine; j < lastLine; j++) {
 405                 Wrap<Text> cellWrap = getCellWrap(Integer.valueOf((int) Math.round(Math.pow(j + 1, j + 1))));
 406                 mouseCellClick(cellWrap, modifier);
 407                 selectionHelper.click(-1, j, modifier);
 408                 checkSelection();
 409             }
 410 
 411             int j = firstLine + (lastLine - firstLine) / 2;
 412             Wrap<Text> cellWrap = getCellWrap(Integer.valueOf((int) Math.round(Math.pow(j + 1, j + 1))));
 413             mouseCellClick(cellWrap, modifier);
 414             selectionHelper.click(-1, j, modifier);
 415             checkSelection();
 416 
 417             j = firstLine;
 418             cellWrap = getCellWrap(Integer.valueOf((int) Math.round(Math.pow(j + 1, j + 1))));
 419             mouseCellClick(cellWrap, modifier);
 420             selectionHelper.click(-1, j, modifier);
 421             checkSelection();
 422 
 423             j = lastLine - 1;
 424             cellWrap = getCellWrap(Integer.valueOf((int) Math.round(Math.pow(j + 1, j + 1))));
 425             mouseCellClick(cellWrap, modifier);
 426             selectionHelper.click(-1, j, modifier);
 427             checkSelection();
 428 
 429         } catch (Throwable error) {
 430             throw error;
 431         } finally {
 432             if (modifier != null) {
 433                 testedControl.keyboard().releaseKey(modifier);
 434             }
 435         }
 436     }
 437 
 438     /**
 439      * @return wrapper over required data item which can be used for mouse
 440      * actions
 441      */
 442     protected Wrap<Text> getCellWrap(final Integer item) {
 443         return testedControl.as(Parent.class, String.class).lookup(
 444                 new LookupCriteria<String>() {
 445                     @Override
 446                     public boolean check(String cell_item) {
 447                         return cell_item.equals(String.valueOf(item));
 448                     }
 449                 }).wrap();
 450     }
 451 
 452     protected void mouseCellClick(Wrap<Text> cell, KeyboardButtons mod) {
 453         cell.as(Showable.class).shower().show();
 454         Point cp = cell.getClickPoint();
 455         if (mod == null) {
 456             cell.mouse().click(1, cp, Mouse.MouseButtons.BUTTON1);
 457         } else {
 458             switch (mod) {
 459                 case SHIFT:
 460                     cell.mouse().click(1, cp, Mouse.MouseButtons.BUTTON1, KeyboardModifiers.SHIFT_DOWN_MASK);
 461                     break;
 462                 case CONTROL:
 463                     cell.mouse().click(1, cp, Mouse.MouseButtons.BUTTON1, CTRL_DOWN_MASK_OS);
 464                     break;
 465             }
 466         }
 467     }
 468 
 469     protected void scrollTo(final int inXCoord, int inYCoord) {
 470         if (inXCoord > 1) {
 471             throw new IllegalArgumentException("Incorrect X coordinate!");
 472         }
 473 
 474         new GetAction() {
 475             @Override
 476             public void run(Object... os) throws Exception {
 477                 ((ListView) testedControl.getControl()).scrollTo(inXCoord);
 478             }
 479         }.dispatch(Root.ROOT.getEnvironment());
 480     }
 481 
 482     protected void switchOnMultiple() {
 483         setPropertyByChoiceBox(SettingType.BIDIRECTIONAL, SelectionMode.MULTIPLE, Properties.selectionMode);
 484     }
 485 
 486     protected void showItem(int item) {
 487         getCellWrap((Integer) (item)).as(Showable.class).shower().show();
 488     }
 489 
 490     protected void moveSelectUp(int times, Orientation orientation) {
 491         KeyboardButtons lessKey = (orientation == Orientation.HORIZONTAL ? KeyboardButtons.LEFT : KeyboardButtons.UP);
 492         applyKeysPushing(times, lessKey, KeyboardModifiers.SHIFT_DOWN_MASK);
 493     }
 494 
 495     protected void moveSelectDown(int times, Orientation orientation) {
 496         KeyboardButtons moreKey = (orientation == Orientation.HORIZONTAL ? KeyboardButtons.RIGHT : KeyboardButtons.DOWN);
 497         applyKeysPushing(times, moreKey, KeyboardModifiers.SHIFT_DOWN_MASK);
 498     }
 499 
 500     protected void moveSelectPageUp(int times) {
 501         applyKeysPushing(times, KeyboardButtons.PAGE_UP, KeyboardModifiers.SHIFT_DOWN_MASK);
 502     }
 503 
 504     protected void moveSelectPageDown(int times) {
 505         applyKeysPushing(times, KeyboardButtons.PAGE_DOWN, KeyboardModifiers.SHIFT_DOWN_MASK);
 506     }
 507 
 508     protected void moveFocusUp(int times, Orientation orientation) {
 509         KeyboardButtons lessKey = (orientation == Orientation.HORIZONTAL ? KeyboardButtons.LEFT : KeyboardButtons.UP);
 510         applyKeysPushing(times, lessKey, CTRL_DOWN_MASK_OS);
 511     }
 512 
 513     protected void moveFocusDown(int times, Orientation orientation) {
 514         KeyboardButtons moreKey = (orientation == Orientation.HORIZONTAL ? KeyboardButtons.RIGHT : KeyboardButtons.DOWN);
 515         applyKeysPushing(times, moreKey, CTRL_DOWN_MASK_OS);
 516     }
 517 
 518     protected void moveFocusPageUp(int times) {
 519         applyKeysPushing(times, KeyboardButtons.PAGE_UP, CTRL_DOWN_MASK_OS);
 520     }
 521 
 522     protected void moveFocusPageDown(int times) {
 523         applyKeysPushing(times, KeyboardButtons.PAGE_DOWN, CTRL_DOWN_MASK_OS);
 524     }
 525 
 526     protected void moveToEnd() {
 527         applyKeysPushing(1, KeyboardButtons.END, CTRL_DOWN_MASK_OS);
 528     }
 529 
 530     protected void selectToEnd() {
 531         applyKeysPushing(1, KeyboardButtons.END, KeyboardModifiers.SHIFT_DOWN_MASK);
 532     }
 533 
 534     protected void moveToHome() {
 535         applyKeysPushing(1, KeyboardButtons.HOME, CTRL_DOWN_MASK_OS);
 536     }
 537 
 538     protected void selectToHome() {
 539         applyKeysPushing(1, KeyboardButtons.HOME, KeyboardModifiers.SHIFT_DOWN_MASK);
 540     }
 541 
 542     @Override
 543     protected void adjustControl() {
 544         setPropertyByChoiceBox(SettingType.BIDIRECTIONAL, Orientation.VERTICAL, Properties.orientation);
 545         try {
 546             setSize(100, 218);
 547         } catch (InterruptedException ex) {
 548             System.out.println(ex);
 549         }
 550         for (int i = 0; i < DATA_ITEMS_NUM; i++) {
 551             addElement(String.valueOf(i), i);
 552         }
 553     }
 554 
 555     @Override
 556     protected void clickOnFirstCell() {
 557         String item = new GetAction<String>() {
 558             @Override
 559             public void run(Object... os) throws Exception {
 560                 setResult((String) ((ListView) testedControl.getControl()).getItems().get((Integer) os[1]));
 561             }
 562         }.dispatch(Root.ROOT.getEnvironment(), testedControl, 0);
 563         Wrap<Text> cellWrap = getCellWrap(Integer.valueOf(item));
 564         cellWrap.as(Showable.class).shower().show();
 565         cellWrap.mouse().click(1, cellWrap.getClickPoint(), Mouse.MouseButtons.BUTTON1);
 566     }
 567 
 568     @Override
 569     protected Wrap getCellWrap(int column, final int row) {
 570         String item = new GetAction<String>() {
 571             @Override
 572             public void run(Object... os) throws Exception {
 573                 setResult((String) ((ListView) testedControl.getControl()).getItems().get(row));
 574             }
 575         }.dispatch(Root.ROOT.getEnvironment());
 576         return getCellWrap(Integer.valueOf(item));
 577     }
 578     //must be int in [3, 9]
 579     static protected final int listItems = 9;
 580     static protected int currentListContentSize = 10;
 581 
 582     @Override
 583     protected Range getVisibleRange() {
 584         int top = -1;
 585         int bottom = -1;
 586         final List<Object> states = testedControl.as(Selectable.class).getStates();
 587         for (int i = 0; i < states.size(); i++) {
 588             final Lookup lookup = testedControl.as(Parent.class, Node.class).lookup(ListCell.class, new ListItemByObjectLookup<Object>(states.get(i)));
 589             boolean visible = lookup.size() > 0 && testedControl.getScreenBounds().contains(lookup.wrap().getScreenBounds());
 590             if (visible && top < 0) {
 591                 top = i;
 592             }
 593             if (visible) {
 594                 bottom = i;
 595             }
 596             if (!visible && top >= 0) {
 597                 bottom = i - 1;
 598                 break;
 599             }
 600         }
 601         return new Range(top, bottom);
 602     }
 603 
 604     @Override
 605     protected void setOrientation(Orientation orientation) {
 606         setPropertyByChoiceBox(SettingType.SETTER, orientation, Properties.orientation);
 607     }
 608 
 609     // All controlled properties.
 610     static protected enum Properties {
 611 
 612         editable, orientation, prefWidth, prefHeight, selectionMode, fixedCellSize
 613     };
 614 
 615     static protected enum Listeners {
 616 
 617         selectedIndex, selectedItem, focusedIndex, focusedItem, editingIndex
 618     };
 619 
 620     static protected enum Counters {
 621 
 622         set_on_edit_cancel, set_on_edit_commit, set_on_edit_start, get_on_edit_cancel, get_on_edit_commit, get_on_edit_start
 623     };
 624 }