1 /*
   2  * Copyright (c) 2011, 2015, 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;
  27 
  28 import com.sun.javafx.scene.control.behavior.TreeCellBehavior;
  29 import com.sun.javafx.scene.control.behavior.TreeCellBehavior;
  30 import javafx.collections.FXCollections;
  31 import javafx.collections.ListChangeListener;
  32 import javafx.collections.ObservableList;
  33 import javafx.scene.input.KeyCode;
  34 import java.util.List;
  35 import com.sun.javafx.PlatformUtil;
  36 import com.sun.javafx.util.Utils;
  37 import com.sun.javafx.scene.control.behavior.TreeViewAnchorRetriever;
  38 import com.sun.javafx.scene.control.infrastructure.KeyEventFirer;
  39 import com.sun.javafx.scene.control.infrastructure.KeyModifier;
  40 import com.sun.javafx.scene.control.infrastructure.StageLoader;
  41 import com.sun.javafx.scene.control.infrastructure.VirtualFlowTestUtils;
  42 import com.sun.javafx.tk.Toolkit;
  43 import org.junit.After;
  44 import org.junit.Before;
  45 import org.junit.Ignore;
  46 import org.junit.Test;
  47 import static org.junit.Assert.assertEquals;
  48 import static org.junit.Assert.assertFalse;
  49 import static org.junit.Assert.assertNotNull;
  50 import static org.junit.Assert.assertNotSame;
  51 import static org.junit.Assert.assertNull;
  52 import static org.junit.Assert.assertTrue;
  53 import static org.junit.Assert.fail;
  54 
  55 public class TreeViewKeyInputTest {
  56     private TreeView<String> treeView;
  57     private MultipleSelectionModel<TreeItem<String>> sm;
  58     private FocusModel<TreeItem<String>> fm;
  59     
  60     private KeyEventFirer keyboard;
  61     private StageLoader stageLoader;
  62     
  63     private final TreeItem<String> root = new TreeItem<String>("Root");                     // 0
  64         private final TreeItem<String> child1 = new TreeItem<String>("Child 1");            // 1
  65         private final TreeItem<String> child2 = new TreeItem<String>("Child 2");            // 2
  66         private final TreeItem<String> child3 = new TreeItem<String>("Child 3");            // 3
  67             private final TreeItem<String> subchild1 = new TreeItem<String>("Subchild 1");  // 4
  68             private final TreeItem<String> subchild2 = new TreeItem<String>("Subchild 2");  // 5
  69             private final TreeItem<String> subchild3 = new TreeItem<String>("Subchild 3");  // 6
  70         private final TreeItem<String> child4 = new TreeItem<String>("Child 4");            // 7
  71         private final TreeItem<String> child5 = new TreeItem<String>("Child 5");            // 8
  72         private final TreeItem<String> child6 = new TreeItem<String>("Child 6");            // 9
  73         private final TreeItem<String> child7 = new TreeItem<String>("Child 7");            // 10
  74         private final TreeItem<String> child8 = new TreeItem<String>("Child 8");            // 11
  75         private final TreeItem<String> child9 = new TreeItem<String>("Child 9");            // 12
  76         private final TreeItem<String> child10 = new TreeItem<String>("Child 10");          // 13
  77 
  78     @Before public void setup() {
  79         // reset tree structure
  80         root.getChildren().clear();
  81         root.setExpanded(true);
  82         root.getChildren().setAll(child1, child2, child3, child4, child5, child6, child7, child8, child9, child10 );
  83         child1.getChildren().clear();
  84         child1.setExpanded(false);
  85         child2.getChildren().clear();
  86         child2.setExpanded(false);
  87         child3.getChildren().clear();
  88         child3.setExpanded(true);
  89         child3.getChildren().setAll(subchild1, subchild2, subchild3);
  90         child4.getChildren().clear();
  91         child4.setExpanded(false);
  92         child5.getChildren().clear();
  93         child5.setExpanded(false);
  94         child6.getChildren().clear();
  95         child6.setExpanded(false);
  96         child7.getChildren().clear();
  97         child7.setExpanded(false);
  98         child8.getChildren().clear();
  99         child8.setExpanded(false);
 100         child9.getChildren().clear();
 101         child9.setExpanded(false);
 102         child10.getChildren().clear();
 103         child10.setExpanded(false);
 104         
 105         // recreate treeview and gather models
 106         treeView = new TreeView<String>();
 107         treeView.setRoot(root);
 108         sm = treeView.getSelectionModel();
 109         sm.setSelectionMode(SelectionMode.MULTIPLE);
 110         fm = treeView.getFocusModel();
 111 
 112         // set up keyboard event firer
 113         keyboard = new KeyEventFirer(treeView);
 114         
 115         // create a simple UI that will be shown (to send the keyboard events to)
 116         stageLoader = new StageLoader(treeView);
 117         stageLoader.getStage().show();
 118     }
 119     
 120     @After public void tearDown() {
 121         treeView.getSkin().dispose();
 122         stageLoader.dispose();
 123     }
 124     
 125     
 126     /***************************************************************************
 127      * Util methods
 128      **************************************************************************/
 129     
 130     private String debug() {
 131         StringBuilder sb = new StringBuilder("Selected Indices: [");
 132         
 133         List<Integer> indices = sm.getSelectedIndices();
 134         for (Integer index : indices) {
 135             sb.append(index);
 136             sb.append(", ");
 137         }
 138         
 139         sb.append("] \nFocus: " + fm.getFocusedIndex());
 140         sb.append(" \nAnchor: " + getAnchor());
 141         return sb.toString();
 142     }
 143     
 144     // Returns true if ALL indices are selected
 145     private boolean isSelected(int... indices) {
 146         for (int index : indices) {
 147             if (! sm.isSelected(index)) return false;
 148         }
 149         return true;
 150     }
 151     
 152     // Returns true if ALL indices are NOT selected
 153     private boolean isNotSelected(int... indices) {
 154         for (int index : indices) {
 155             if (sm.isSelected(index)) return false;
 156         }
 157         return true;
 158     }
 159     
 160     private int getAnchor() {
 161         return TreeViewAnchorRetriever.getAnchor(treeView);
 162     }
 163     
 164     private boolean isAnchor(int index) {
 165         return getAnchor() == index;
 166     }
 167     
 168     private int getItemCount() {
 169         return root.getChildren().size() + child3.getChildren().size();
 170     }
 171     
 172     
 173     /***************************************************************************
 174      * General tests
 175      **************************************************************************/    
 176     
 177     @Test public void testInitialState() {
 178         assertEquals(-1, sm.getSelectedIndex());
 179         assertEquals(0, sm.getSelectedIndices().size());
 180         assertEquals(0, sm.getSelectedItems().size());
 181     }
 182     
 183     /***************************************************************************
 184      * Tests for row-based single selection
 185      **************************************************************************/
 186     
 187     @Test public void testDownArrowChangesSelection() {
 188         sm.clearAndSelect(0);
 189         keyboard.doDownArrowPress();
 190         assertFalse(sm.isSelected(0));
 191         assertTrue(sm.isSelected(1));
 192     }
 193     
 194     @Test public void testDownArrowDoesNotChangeSelectionWhenAtLastIndex() {
 195         int endIndex = getItemCount();
 196         sm.clearAndSelect(endIndex);
 197         assertTrue(debug(), sm.isSelected(endIndex));
 198         keyboard.doDownArrowPress();
 199         assertTrue(sm.isSelected(endIndex));
 200     }
 201     
 202     @Test public void testUpArrowDoesNotChangeSelectionWhenAt0Index() {
 203         sm.clearAndSelect(0);
 204         keyboard.doUpArrowPress();
 205         assertTrue(sm.isSelected(0));
 206         assertEquals(1, sm.getSelectedIndices().size());
 207         assertEquals(1, sm.getSelectedItems().size());
 208     }
 209     
 210     @Test public void testUpArrowChangesSelection() {
 211         sm.clearAndSelect(1);
 212         keyboard.doUpArrowPress();
 213         assertFalse(sm.isSelected(1));
 214         assertTrue(sm.isSelected(0));
 215     }
 216     
 217     @Test public void testLeftArrowDoesNotChangeState() {
 218         sm.clearAndSelect(0);
 219         keyboard.doLeftArrowPress();
 220         assertTrue(sm.isSelected(0));
 221         assertEquals(1, sm.getSelectedIndices().size());
 222         assertEquals(1, sm.getSelectedItems().size());
 223     }
 224     
 225     // test 19
 226     @Test public void testCtrlDownMovesFocusButLeavesSelectionAlone() {
 227         sm.clearAndSelect(0);
 228         assertTrue(fm.isFocused(0));
 229         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 230         assertTrue(fm.isFocused(1));
 231         assertTrue(sm.isSelected(0));
 232         assertFalse(sm.isSelected(1));
 233     }
 234     
 235     // test 20
 236     @Test public void testCtrlUpDoesNotMoveFocus() {
 237         sm.clearAndSelect(0);
 238         assertTrue(fm.isFocused(0));
 239         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 240         assertTrue(fm.isFocused(0));
 241         assertTrue(sm.isSelected(0));
 242     }
 243     
 244     // test 21
 245     @Test public void testCtrlLeftDoesNotMoveFocus() {
 246         sm.clearAndSelect(0);
 247         assertTrue(fm.isFocused(0));
 248         keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
 249         assertTrue(fm.isFocused(0));
 250         assertTrue(sm.isSelected(0));
 251     }
 252     
 253     // test 22
 254     @Test public void testCtrlRightDoesNotMoveFocus() {
 255         sm.clearAndSelect(0);
 256         assertTrue(fm.isFocused(0));
 257         keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
 258         assertTrue(fm.isFocused(0));
 259         assertTrue(sm.isSelected(0));
 260     }
 261     
 262     // test 23
 263     @Test public void testCtrlUpMovesFocus() {
 264         sm.clearAndSelect(1);
 265         assertTrue(fm.isFocused(1));
 266         assertTrue(sm.isSelected(1));
 267         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 268         assertTrue(fm.isFocused(0));
 269         assertTrue(sm.isSelected(1));
 270     }
 271     
 272     // test 24
 273     @Test public void testCtrlDownDoesNotMoveFocusWhenAtLastIndex() {
 274         int endIndex = getItemCount();
 275         sm.clearAndSelect(endIndex);
 276         assertTrue(fm.isFocused(endIndex));
 277         assertTrue(sm.isSelected(endIndex));
 278         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 279         assertTrue(fm.isFocused(endIndex));
 280         assertTrue(sm.isSelected(endIndex));
 281     }
 282     
 283     // test 25
 284     @Test public void testCtrlDownArrowWithSpaceChangesAnchor() {
 285         sm.clearAndSelect(0);
 286         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 287         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 288         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 289                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2
 290         assertTrue(isSelected(0, 2));
 291         assertTrue(isNotSelected(1));
 292         assertTrue(isAnchor(2));
 293     }
 294     
 295     // test 26
 296     @Test public void testCtrlUpArrowWithSpaceChangesAnchor() {
 297         sm.clearAndSelect(2);
 298         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 299         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 300         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 301                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0
 302         assertTrue(isSelected(0, 2));
 303         assertTrue(isNotSelected(1));
 304         assertTrue(isAnchor(0));
 305     }
 306     
 307     // test 44
 308     @Test public void testHomeKey() {
 309         sm.clearAndSelect(3);
 310         keyboard.doKeyPress(KeyCode.HOME);
 311         assertTrue(isSelected(0));
 312         assertTrue(isNotSelected(1,2,3));
 313     }
 314     
 315     // test 45
 316     @Test public void testEndKey() {
 317         sm.clearAndSelect(3); 
 318         keyboard.doKeyPress(KeyCode.END);
 319         assertTrue(debug(), isSelected(getItemCount()));
 320         assertTrue(isNotSelected(1,2,3));
 321     }
 322     
 323     // test 53
 324     @Test public void testCtrlHome() {
 325         sm.clearAndSelect(5);
 326         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey());
 327         assertTrue(isSelected(5));
 328         assertTrue(fm.isFocused(0));
 329     }
 330     
 331     // test 54
 332     @Test public void testCtrlEnd() {
 333         sm.clearAndSelect(5);
 334         keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey());
 335         assertTrue(isSelected(5));
 336         assertTrue(fm.isFocused(getItemCount()));
 337     }
 338     
 339     // test 68
 340     @Test public void testCtrlSpaceToClearSelection() {
 341         sm.clearAndSelect(5);
 342         assertTrue(isSelected(5));
 343         assertTrue(fm.isFocused(5));
 344         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 345                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 346         assertTrue(isNotSelected(5));
 347         assertTrue(debug(), fm.isFocused(5));
 348         assertTrue(isAnchor(5));
 349     }
 350     
 351     
 352     
 353     /***************************************************************************
 354      * Tests for row-based multiple selection
 355      **************************************************************************/
 356     
 357     @Test public void testShiftDownArrowIncreasesSelection() {
 358         sm.clearAndSelect(0);
 359         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 360         assertTrue(sm.isSelected(0));
 361         assertTrue(sm.isSelected(1));
 362     }
 363     
 364     @Test public void testShiftDownArrowDoesNotChangeSelectionWhenAtLastIndex() {
 365         int endIndex = getItemCount() - 1;
 366         sm.clearAndSelect(endIndex);
 367         assertTrue(sm.isSelected(endIndex));
 368         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 369         assertTrue(sm.isSelected(endIndex));
 370     }
 371     
 372     @Test public void testShiftUpArrowIncreasesSelection() {
 373         sm.clearAndSelect(1);
 374         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 375         assertTrue(sm.isSelected(0));
 376         assertTrue(sm.isSelected(1));
 377     }
 378     
 379     @Test public void testShiftUpArrowWhenAt0Index() {
 380         sm.clearAndSelect(0);
 381         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 382         assertTrue(sm.isSelected(0));
 383     }
 384     
 385     @Test public void testShiftLeftArrowWhenAt0Index() {
 386         sm.clearAndSelect(0);
 387         keyboard.doLeftArrowPress(KeyModifier.SHIFT);
 388         assertTrue(sm.isSelected(0));
 389         assertFalse(sm.isSelected(1));
 390     }
 391     
 392     @Test public void testShiftRightArrowWhenAt0Index() {
 393         sm.clearAndSelect(0);
 394         keyboard.doRightArrowPress(KeyModifier.SHIFT);
 395         assertTrue(sm.isSelected(0));
 396         assertFalse(sm.isSelected(1));
 397     }
 398     
 399     @Test public void testShiftDownTwiceThenShiftUp() {
 400         sm.clearAndSelect(0);
 401         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 402         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 403         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 404         assertTrue(debug(), sm.isSelected(0));
 405         assertTrue(sm.isSelected(1));
 406         assertFalse(sm.isSelected(2));
 407     }
 408     
 409     @Test public void testShiftUpTwiceThenShiftDownFrom0Index() {
 410         sm.clearAndSelect(0);
 411         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 412         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 413         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 414         assertTrue(sm.isSelected(0));
 415         assertTrue(sm.isSelected(1));
 416         assertFalse(sm.isSelected(2));
 417     }
 418     
 419     @Test public void testShiftLeftTwiceThenShiftRight() {
 420         sm.clearAndSelect(0);
 421         keyboard.doLeftArrowPress(KeyModifier.SHIFT);
 422         keyboard.doLeftArrowPress(KeyModifier.SHIFT);
 423         keyboard.doRightArrowPress(KeyModifier.SHIFT);
 424         assertTrue(sm.isSelected(0));
 425         assertFalse(sm.isSelected(1));
 426         assertFalse(sm.isSelected(2));
 427     }
 428     
 429     @Test public void testShiftRightTwiceThenShiftLeft() {
 430         sm.clearAndSelect(0);
 431         keyboard.doRightArrowPress(KeyModifier.SHIFT);
 432         keyboard.doRightArrowPress(KeyModifier.SHIFT);
 433         keyboard.doLeftArrowPress(KeyModifier.SHIFT);
 434         assertTrue(sm.isSelected(0));
 435         assertFalse(sm.isSelected(1));
 436         assertFalse(sm.isSelected(2));
 437     }
 438     
 439     @Test public void testShiftUpTwiceThenShiftDown() {
 440         sm.clearAndSelect(2);
 441         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 442         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 443         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 444         assertFalse(sm.isSelected(0));
 445         assertTrue(sm.isSelected(1));
 446         assertTrue(sm.isSelected(2));
 447         assertFalse(sm.isSelected(3));
 448     }
 449     
 450     // test 18 from Jindra's testcases.rtf file
 451     @Test public void testShiftDownTwiceThenShiftUpWhenAtLastIndex() {
 452         int endIndex = getItemCount();
 453         sm.clearAndSelect(endIndex);
 454         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 455         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 456         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 457         assertTrue(sm.isSelected(endIndex));
 458         assertTrue(sm.isSelected(endIndex - 1));
 459         assertFalse(sm.isSelected(endIndex - 2));
 460     }
 461     
 462     // test 27
 463     @Test public void testCtrlDownArrowWithSpaceChangesAnchor_extended() {
 464         sm.clearAndSelect(0);
 465         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 466         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 467         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 468                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2
 469         
 470         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 471         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 472         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 473                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // deselect 0
 474         assertTrue(isSelected(2));
 475         assertTrue(isNotSelected(0, 1));
 476         assertTrue(isAnchor(0));
 477     }
 478     
 479     // test 28
 480     @Test public void testCtrlUpArrowWithSpaceChangesAnchor_extended() {
 481         sm.clearAndSelect(2);
 482         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 483         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 484         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 485                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0
 486         
 487         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 488         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 489         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 490                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // deselect 2
 491         assertTrue(isSelected(0));
 492         assertTrue(isNotSelected(1, 2));
 493         assertTrue(isAnchor(2));
 494     }
 495     
 496     // test 29
 497     @Test public void testCtrlDownArrowWithSpaceChangesAnchor_extended2() {
 498         sm.clearAndSelect(0);
 499         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 500         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 501         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 502                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2
 503         
 504         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 505         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 506         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 507                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 4
 508         assertTrue(isSelected(0, 2, 4));
 509         assertTrue(isNotSelected(1, 3, 5));
 510         assertTrue(isAnchor(4));
 511     }
 512     
 513     // test 30
 514     @Test public void testCtrlUpArrowWithSpaceChangesAnchor_extended2() {
 515         sm.clearAndSelect(4);
 516         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 517         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 518         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 519                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2
 520         
 521         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 522         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 523         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 524                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0
 525         assertTrue(isSelected(0, 2, 4));
 526         assertTrue(isNotSelected(1, 3));
 527         assertTrue(isAnchor(0));
 528     }
 529     
 530     // test 31
 531     @Test public void testCtrlDownArrowThenShiftSpaceToSelectRange() {
 532         sm.clearAndSelect(0);
 533         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 534         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 535         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
 536         assertTrue(isSelected(0, 1, 2));
 537         assertTrue(isNotSelected(3));
 538         assertTrue(isAnchor(0));
 539     }
 540     
 541     // test 32
 542     @Test public void testCtrlUpArrowThenShiftSpaceToSelectRange() {
 543         sm.clearAndSelect(2);
 544         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 545         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 546         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
 547         assertTrue(isSelected(0, 1, 2));
 548         assertTrue(isNotSelected(3));
 549         assertTrue(debug(), isAnchor(2));
 550     }
 551     
 552     // test 33
 553     @Test public void testCtrlDownArrowThenSpaceToChangeSelection() {
 554         sm.clearAndSelect(0);
 555         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 556         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 557         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 558                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2, keeping 0 selected
 559         assertTrue(isSelected(0, 2));
 560         assertTrue(isNotSelected(1, 3));
 561         assertTrue(isAnchor(2));
 562         
 563         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 564         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 565         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 2,3,4
 566         assertTrue(isSelected(2, 3, 4));
 567         assertTrue(isNotSelected(0, 1));
 568         assertTrue(isAnchor(2));
 569     }
 570     
 571     // test 34
 572     @Test public void testCtrlUpArrowThenSpaceToChangeSelection() {
 573         sm.clearAndSelect(4);
 574         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 575         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 576         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 577                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2, keeping 4 selected
 578         assertTrue(isSelected(2, 4));
 579         assertTrue(isNotSelected(0, 1, 3));
 580         assertTrue(isAnchor(2));
 581         
 582         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 583         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 584         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
 585         assertTrue(isSelected(0, 1, 2));
 586         assertTrue(isNotSelected(3, 4));
 587         assertTrue(debug(), isAnchor(2));
 588     }
 589     
 590     // test 35
 591     @Test public void testCtrlDownTwiceThenShiftDown() {
 592         sm.clearAndSelect(0);
 593         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 594         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 595         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);  // select 0,1,2,3
 596         assertTrue(isSelected(0, 1, 2, 3));
 597     }
 598     
 599     // test 36
 600     @Test public void testCtrlUpTwiceThenShiftDown() {
 601         sm.clearAndSelect(3);
 602         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 603         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 604         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 605         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);  // select 1,2,3
 606         assertTrue(isSelected(1, 2, 3));
 607         assertTrue(isNotSelected(0));
 608     }
 609     
 610     // test 37
 611     @Test public void testCtrlDownThriceThenShiftUp() {
 612         sm.clearAndSelect(0);
 613         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 614         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 615         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 616         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);  // select 0,1,2
 617         assertTrue(isSelected(0, 1, 2));
 618         assertTrue(isNotSelected(3, 4));
 619     }
 620     
 621     // test 38
 622     @Test public void testCtrlUpTwiceThenShiftUp() {
 623         sm.clearAndSelect(3);
 624         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 625         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 626         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);  // select 0,1,2,3
 627         assertTrue(isSelected(0, 1, 2, 3));
 628         assertTrue(isNotSelected(4));
 629     }
 630     
 631     // test 39
 632     @Test public void testCtrlDownTwiceThenSpace_extended() {
 633         sm.clearAndSelect(0);
 634         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 635         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 636         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 637                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0,2
 638         assertTrue(isSelected(0, 2));
 639         assertTrue(isNotSelected(1, 3));
 640         assertTrue(isAnchor(2));
 641         
 642         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 643         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 644         keyboard.doDownArrowPress(KeyModifier.SHIFT);   // select 2,3,4,5
 645         assertTrue(isSelected(2, 3, 4, 5));
 646         assertTrue(isNotSelected(0, 1));
 647         assertTrue(isAnchor(2));
 648     }
 649     
 650     // test 40
 651     @Test public void testCtrlUpTwiceThenSpace_extended() {
 652         sm.clearAndSelect(5);
 653         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 654         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 655         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 656                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 3,5
 657         assertTrue(isSelected(3,5));
 658         assertTrue(isNotSelected(0,1,2,4));
 659         assertTrue(isAnchor(3));
 660         
 661         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 662         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 663         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 664         keyboard.doDownArrowPress(KeyModifier.SHIFT);   // select 1,2,3
 665         assertTrue(isSelected(1,2,3));
 666         assertTrue(isNotSelected(0,4,5));
 667         assertTrue(isAnchor(3));
 668     }
 669     
 670     // test 41
 671     @Test public void testCtrlDownTwiceThenSpace_extended2() {
 672         sm.clearAndSelect(0);
 673         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 674         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 675         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 676                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0,2
 677         assertTrue(isSelected(0,2));
 678         assertTrue(isNotSelected(1,3,4));
 679         assertTrue(isAnchor(2));
 680         
 681         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 682         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 683         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 5
 684         keyboard.doUpArrowPress(KeyModifier.SHIFT);     // select 2,3,4
 685         assertTrue(isSelected(2,3,4));
 686         assertTrue(isNotSelected(0,1,5));
 687         assertTrue(isAnchor(2));
 688     }
 689     
 690     // test 50
 691     @Test public void testCtrlDownThenShiftHome() {
 692         sm.clearAndSelect(0);
 693         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 694         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 695         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 696                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0,2
 697         assertTrue(isSelected(0,2));
 698         assertTrue(isNotSelected(1,3,4));
 699         assertTrue(isAnchor(2));
 700         
 701         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 702         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 703         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
 704         assertTrue(isSelected(0,1,2));
 705         assertTrue(isNotSelected(3,4));
 706         assertTrue(debug(),isAnchor(2));
 707     }
 708     
 709     // test 51
 710     @Test public void testCtrlUpThenShiftEnd() {
 711         sm.clearAndSelect(5);
 712         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 713         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 714         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 715                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 3,5
 716         assertTrue(isSelected(3,5));
 717         assertTrue(isNotSelected(1,2,4));
 718         assertTrue(isAnchor(3));
 719         
 720         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 721         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 722         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
 723         assertTrue(isSelected(3,4,5,6,7,8,9));
 724         assertTrue(isNotSelected(0,1,2));
 725         assertTrue(debug(),isAnchor(3));
 726     }
 727     
 728     // test 42
 729     @Test public void testCtrlUpTwiceThenSpace_extended2() {
 730         sm.clearAndSelect(5);
 731         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 732         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 733         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 734                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 3,5
 735         assertTrue(isSelected(3,5));
 736         assertTrue(isNotSelected(0,1,2,4));
 737         assertTrue(isAnchor(3));
 738         
 739         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 740         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 741         keyboard.doUpArrowPress(KeyModifier.SHIFT);     // select 0,1,2,3
 742         assertTrue(isSelected(0,1,2,3));
 743         assertTrue(isNotSelected(4,5));
 744         assertTrue(isAnchor(3));
 745     }
 746     
 747     // test 46
 748     @Test public void testHomeKey_withSelectedItems() {
 749         sm.clearSelection();
 750         sm.selectRange(4, 11);
 751         keyboard.doKeyPress(KeyCode.HOME);
 752         assertTrue(isSelected(0));
 753         assertTrue(isNotSelected(1,2,3,4,5,6,7,8,9,10,11));
 754     }
 755     
 756     // test 47
 757     @Test public void testEndKey_withSelectedItems() {
 758         sm.clearSelection();
 759         sm.selectRange(4, 11);
 760         keyboard.doKeyPress(KeyCode.END);
 761         assertTrue(isSelected(getItemCount()));
 762         assertTrue(isNotSelected(1,2,3,4,5,6,7,8));
 763     }
 764     
 765     // test 48
 766     @Test public void testShiftHome() {
 767         sm.clearAndSelect(3);
 768         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
 769         assertTrue(isSelected(0,1,2,3));
 770         assertTrue(isNotSelected(4,5));
 771         assertTrue(debug(), isAnchor(3));
 772     }
 773     
 774     // test 49
 775     @Test public void testShiftEnd() {
 776         sm.clearAndSelect(3);
 777         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
 778         assertTrue(isSelected(3,4,5,6,7,8,9));
 779         assertTrue(isNotSelected(0,1,2));
 780         assertTrue(isAnchor(3));
 781     }
 782     
 783     // test 52
 784     @Test public void testShiftHomeThenShiftEnd() {
 785         sm.clearAndSelect(5);
 786         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
 787         assertTrue(isSelected(0,1,2,3,4,5));
 788         assertTrue(isAnchor(5));
 789         
 790         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
 791         assertTrue(isSelected(5,6,7,8,9));
 792         assertTrue(isAnchor(5));
 793     }
 794     
 795     // test 65
 796     @Test public void testShiftPageUp() {
 797         sm.clearAndSelect(0);
 798         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 799         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 800         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 801                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 802         assertTrue(isSelected(0,2));
 803         assertTrue(isAnchor(2));
 804         
 805         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 806         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 807         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
 808         assertTrue(isSelected(0,1,2));
 809         assertTrue(isAnchor(2));
 810     }
 811     
 812     // test 67
 813     @Test public void testCtrlAToSelectAll() {
 814         sm.clearAndSelect(5);
 815         keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey());
 816         assertTrue(isSelected(0,1,2,3,4,5,6,7,8,9));
 817     }
 818     
 819     
 820     /***************************************************************************
 821      * Tests for discontinuous multiple selection (RT-18952)
 822      **************************************************************************/  
 823     
 824     // Test 1
 825     @Test public void test_rt18952_1() {
 826         sm.clearAndSelect(0);
 827         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 828         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 829         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 830                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 831         assertTrue(isSelected(0,2));
 832         assertTrue(isAnchor(2));
 833         
 834         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 835         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 836         assertTrue(debug(),isSelected(0,2,3,4));
 837         assertTrue(isAnchor(2));
 838     }
 839     
 840     // Test 2
 841     @Test public void test_rt18952_2() {
 842         sm.clearAndSelect(5);
 843         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 844         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 845         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 846                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 847         assertTrue(isSelected(3,5));
 848         assertTrue(isAnchor(3));
 849         
 850         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 851         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 852         assertTrue(isSelected(1,2,3,5));
 853         assertTrue(isAnchor(3));
 854     }
 855     
 856     // Test 3
 857     @Test public void test_rt18952_3() {
 858         sm.clearAndSelect(0);
 859         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 860         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 861         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 862                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 863         assertTrue(isSelected(0,2));
 864         assertTrue(isAnchor(2));
 865         
 866         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 867         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 868         assertTrue(isSelected(0,2,3,4));
 869         assertTrue(isAnchor(2));
 870         
 871         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 872         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 873         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 874         assertTrue(isSelected(0,1,2,3,4));
 875         assertTrue(isAnchor(2));
 876     }
 877     
 878     // Test 4
 879     @Test public void test_rt18952_4() {
 880         sm.clearAndSelect(5);
 881         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 882         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 883         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 884                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 885         assertTrue(isSelected(3,5));
 886         assertTrue(isAnchor(3));
 887         
 888         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 889         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 890         assertTrue(isSelected(1,2,3,5));
 891         assertTrue(isAnchor(3));
 892         
 893         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 894         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 895         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 896         assertTrue(isSelected(1,2,3,4,5));
 897         assertTrue(isAnchor(3));
 898     }
 899     
 900     // TODO skipped some tests here (5-8)
 901     
 902     // Test 9
 903     @Test public void test_rt18952_9() {
 904         sm.clearAndSelect(0);
 905         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 906         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 907         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 908                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 909         assertTrue(isSelected(0,2));
 910         assertTrue(isAnchor(2));
 911         
 912         keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 913         assertTrue(isSelected(0,2,3,4,5,6,7,8,9));
 914         assertTrue(isAnchor(2));
 915     }
 916     
 917     // Test 10
 918     @Test public void test_rt18952_10() {
 919         sm.clearAndSelect(9);
 920         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 921         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 922         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 923                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 924         assertTrue(isSelected(7,9));
 925         assertTrue(isAnchor(7));
 926         
 927         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 928         assertTrue(isSelected(0,1,2,3,4,5,6,7,9));
 929         assertTrue(isAnchor(7));
 930     }
 931     
 932     // Test 11
 933     @Test public void test_rt18952_11() {
 934         sm.clearAndSelect(5);
 935         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 936         assertTrue(isSelected(0,1,2,3,4,5));
 937         assertTrue(isAnchor(5));
 938         
 939         keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 940         assertTrue(isSelected(0,1,2,3,4,5,6,7,8,9));
 941         assertTrue(isAnchor(5));
 942     }
 943     
 944     // Test 12
 945     @Test public void test_rt18952_12() {
 946         sm.clearAndSelect(0);
 947         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 948         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 949         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
 950                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 951         assertTrue(isSelected(0,2));
 952         assertTrue(isAnchor(2));
 953         
 954         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 955         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 956         assertTrue(isSelected(0,2,3,4));
 957         assertTrue(isAnchor(2));
 958         
 959         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 960         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 961         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
 962         assertTrue(isSelected(0,1,2,3,4));
 963         assertTrue(isAnchor(2));
 964 
 965         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 966         keyboard.doKeyPress(KeyCode.SPACE,KeyModifier.getShortcutKey(),
 967                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 968         assertTrue(isSelected(1,2,3,4));
 969         assertTrue(fm.isFocused(0));
 970         assertTrue(isAnchor(0));
 971     }
 972     
 973     
 974     
 975     /***************************************************************************
 976      * Tests for editing
 977      **************************************************************************/
 978     
 979     // test 43 (part 1)
 980     @Test public void testF2EntersEditModeAndEscapeCancelsEdit_part1() {
 981         treeView.setEditable(true);
 982         
 983         sm.clearAndSelect(0);
 984         assertNull(treeView.getEditingItem());
 985         keyboard.doKeyPress(KeyCode.F2);
 986         assertEquals(root, treeView.getEditingItem());
 987         
 988         keyboard.doKeyPress(KeyCode.ESCAPE);
 989         assertNull(treeView.getEditingItem());
 990     }
 991     
 992 //    // test 43 (part 2)
 993 //    @Test public void testF2EntersEditModeAndEscapeCancelsEdit_part2() {
 994 //        treeView.setEditable(true);
 995 //        
 996 //        sm.clearAndSelect(0);
 997 //        keyboard.doKeyPress(KeyCode.F2);
 998 //        
 999 //        
1000 //    }
1001     
1002     
1003     /***************************************************************************
1004      * Tests for TreeView-specific functionality
1005      **************************************************************************/ 
1006     
1007     // Test 1 (TreeView test cases)
1008     @Test public void testRightArrowExpandsBranch() {
1009         sm.clearAndSelect(0);
1010         root.setExpanded(false);
1011         assertFalse(root.isExpanded());
1012         keyboard.doRightArrowPress();
1013         assertTrue(root.isExpanded());
1014     }
1015     
1016     // Test 2 (TreeView test cases)
1017     @Test public void testRightArrowOnExpandedBranch() {
1018         sm.clearAndSelect(0);
1019         keyboard.doRightArrowPress();
1020         assertTrue(isNotSelected(0));
1021         assertTrue(isSelected(1));
1022     }
1023     
1024     // Test 3 (TreeView test cases)
1025     @Test public void testRightArrowOnLeafNode() {
1026         sm.clearAndSelect(1);
1027         keyboard.doRightArrowPress();
1028         assertTrue(isNotSelected(0));
1029         assertTrue(isSelected(1));
1030         assertTrue(isNotSelected(2));
1031     }
1032     
1033     // Test 4 (TreeView test cases)
1034     @Test public void testLeftArrowCollapsesBranch() {
1035         sm.clearAndSelect(0);
1036         assertTrue(root.isExpanded());
1037         keyboard.doLeftArrowPress();
1038         assertFalse(root.isExpanded());
1039     }
1040     
1041     // Test 5 (TreeView test cases)
1042     @Test public void testLeftArrowOnLeafMovesSelectionToParent() {
1043         sm.clearAndSelect(2);
1044         assertTrue(root.isExpanded());
1045         keyboard.doLeftArrowPress();
1046         assertTrue(root.isExpanded());
1047         assertTrue(isSelected(0));
1048         assertTrue(isNotSelected(2));
1049     }
1050     
1051     // Test 6 (TreeView test cases)
1052     @Test public void testLeftArrowMultipleTimes() {
1053         sm.clearAndSelect(5);
1054         keyboard.doLeftArrowPress();
1055         assertTrue(child3.isExpanded());
1056         assertTrue(isSelected(3));
1057         assertTrue(isNotSelected(5));
1058         
1059         keyboard.doLeftArrowPress();
1060         assertFalse(child3.isExpanded());
1061         assertTrue(isSelected(3));
1062         
1063         keyboard.doLeftArrowPress();
1064         assertTrue(isSelected(0));
1065         assertTrue(root.isExpanded());
1066         
1067         keyboard.doLeftArrowPress();
1068         assertTrue(isSelected(0));
1069         assertFalse(root.isExpanded());
1070     }
1071     
1072     // Test 7 (TreeView test cases)
1073     @Test public void testDownArrowTwice() {
1074         sm.clearAndSelect(0);
1075         keyboard.doDownArrowPress();
1076         keyboard.doDownArrowPress();
1077         assertTrue(isSelected(2));
1078         assertTrue(isNotSelected(0));
1079     }
1080     
1081     // Test 8 (TreeView test cases)
1082     @Test public void testDownArrowFourTimes() {
1083         // adding children to child2, but not expanding it
1084         child2.getChildren().addAll(new TreeItem("another child"), new TreeItem("And another!"));
1085         child2.setExpanded(false);
1086         
1087         child3.setExpanded(true);
1088         sm.clearAndSelect(0);
1089         keyboard.doDownArrowPress();
1090         keyboard.doDownArrowPress();
1091         keyboard.doDownArrowPress();
1092         keyboard.doDownArrowPress();
1093         assertTrue(isSelected(4));
1094         assertTrue(isNotSelected(0));
1095     }
1096     
1097     // Test 9 (TreeView test cases)
1098     @Test public void testUpArrow() {
1099         sm.clearAndSelect(1);
1100         keyboard.doUpArrowPress();
1101         assertTrue(isSelected(0));
1102         assertTrue(isNotSelected(1));
1103     }
1104     
1105     // Test 9 (TreeView test cases)
1106     @Test public void testUpArrowFourTimes() {
1107         // adding children to child2, but not expanding it
1108         child2.getChildren().addAll(new TreeItem("another child"), new TreeItem("And another!"));
1109         child2.setExpanded(false);
1110         
1111         sm.clearAndSelect(5);
1112         keyboard.doUpArrowPress();
1113         keyboard.doUpArrowPress();
1114         keyboard.doUpArrowPress();
1115         keyboard.doUpArrowPress();
1116         
1117         assertTrue(isSelected(1));
1118         assertTrue(isNotSelected(5));
1119     }
1120     
1121     // Test 20 (TreeView test cases)
1122     // NOTE: this used to be isSelected but changed when we removed functionality
1123     // for KeyCode.SLASH. Rather than remove the test I'm now testing to make
1124     // sure it does nothing.
1125     @Test public void testCtrlForwardSlashToSelectAll() {
1126         sm.clearAndSelect(1);
1127         keyboard.doKeyPress(KeyCode.SLASH, KeyModifier.getShortcutKey());
1128         assertTrue(isSelected(1));
1129         assertTrue(isNotSelected(0,2,3,4,5,6,7,8,9));
1130     }
1131     
1132     // Test 21 (TreeView test cases)
1133     // NOTE: this used to be isNotSelected but changed when we removed functionality
1134     // for KeyCode.BACK_SLASH. Rather than remove the test I'm now testing to make
1135     // sure it does nothing.
1136     @Test public void testCtrlBackSlashToClearSelection() {
1137         sm.selectAll();
1138         fm.focus(1);
1139         keyboard.doKeyPress(KeyCode.BACK_SLASH, KeyModifier.getShortcutKey());
1140         assertTrue(isSelected(0,1,2,3,4,5,6,7,8,9));
1141         assertTrue(fm.isFocused(1));
1142     }
1143     
1144     // Test 24 (TreeView test cases)
1145     @Ignore("Not yet working")
1146     @Test public void testExpandCollapseImpactOnSelection() {
1147         sm.clearAndSelect(5);
1148         assertTrue(child3.isExpanded());
1149         keyboard.doUpArrowPress(KeyModifier.SHIFT);
1150         keyboard.doUpArrowPress(KeyModifier.SHIFT);
1151         assertTrue(isSelected(3,4,5));
1152         
1153         keyboard.doLeftArrowPress();
1154         assertFalse(child3.isExpanded());
1155         assertTrue(isSelected(3));
1156         
1157         keyboard.doRightArrowPress();
1158         assertTrue(child3.isExpanded());
1159         assertTrue(isSelected(3,4,5));
1160     }
1161     
1162     // Test 54 (TreeView test cases)
1163     @Test public void testAsteriskExpandsAllBranchesFromRoot() {
1164         // adding children to child2, but not expanding it
1165         child2.getChildren().addAll(new TreeItem("another child"), new TreeItem("And another!"));
1166         child2.setExpanded(false);
1167         
1168         sm.clearAndSelect(0);
1169         assertFalse(child2.isExpanded());
1170         assertTrue(child3.isExpanded());
1171         keyboard.doKeyPress(KeyCode.MULTIPLY);
1172         
1173         assertTrue(child2.isExpanded());
1174         assertTrue(child3.isExpanded());
1175     }
1176     
1177     // Test 57 (TreeView test cases)
1178     @Test public void testMinusCollapsesBranch() {
1179         sm.clearAndSelect(3);
1180         assertTrue(child3.isExpanded());
1181         keyboard.doKeyPress(KeyCode.SUBTRACT);
1182         assertFalse(child3.isExpanded());
1183     }
1184     
1185     // Test 58 (TreeView test cases)
1186     @Test public void testPlusCollapsesBranch() {
1187         sm.clearAndSelect(3);
1188         child3.setExpanded(false);
1189         assertFalse(child3.isExpanded());
1190         keyboard.doKeyPress(KeyCode.ADD);
1191         assertTrue(child3.isExpanded());
1192     }
1193     
1194     
1195     /***************************************************************************
1196      * Tests for specific bug reports
1197      **************************************************************************/
1198     
1199     @Test public void test_rt18642() {
1200         sm.clearAndSelect(1);                          // select 1
1201         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 2
1202         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 3
1203         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
1204                 (Utils.isMac()  ? KeyModifier.CTRL : null)); // set anchor, and also select, 3
1205         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 4
1206         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 5
1207         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
1208                 (Utils.isMac()  ? KeyModifier.CTRL : null)); // set anchor, and also select, 5
1209         
1210         assertTrue(isSelected(1, 3, 5));
1211         assertTrue(isNotSelected(0, 2, 4));
1212         
1213         // anchor is at 5, so shift+UP should select rows 4 and 5 only
1214         keyboard.doUpArrowPress(KeyModifier.SHIFT);   
1215         assertTrue(isSelected(4, 5));
1216         assertTrue(isNotSelected(0, 1, 2, 3));
1217     }
1218     
1219     @Test public void test_rt14451_1() {
1220         sm.clearAndSelect(5);                          
1221 
1222         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT); 
1223         assertTrue(isSelected(0,1,2,3,4,5));
1224         assertTrue(isNotSelected(6,7,8,9));
1225         
1226         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT); 
1227         assertTrue(isNotSelected(0,1,2,3,4));
1228         assertTrue(isSelected(5,6,7,8,9));
1229         
1230         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT); 
1231         assertTrue(isSelected(0,1,2,3,4,5));
1232         assertTrue(debug(), isNotSelected(6,7,8,9));
1233     } 
1234     
1235     @Test public void test_rt14451_2() {
1236         sm.clearAndSelect(5);                          
1237 
1238         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT); 
1239         assertTrue(isNotSelected(0,1,2,3,4));
1240         assertTrue(isSelected(5,6,7,8,9));
1241         
1242         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT); 
1243         assertTrue(isSelected(0,1,2,3,4,5));
1244         assertTrue(debug(), isNotSelected(6,7,8,9));
1245         
1246         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT); 
1247         assertTrue(isNotSelected(0,1,2,3,4));
1248         assertTrue(isSelected(5,6,7,8,9));
1249     } 
1250     
1251     @Test public void test_rt26835_1() {
1252         sm.clearAndSelect(5);                          
1253         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey()); 
1254         assertTrue(fm.isFocused(0));
1255     } 
1256     
1257     @Test public void test_rt26835_2() {
1258         sm.clearAndSelect(5);                          
1259         keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey()); 
1260         assertTrue(debug(), fm.isFocused(getItemCount()));
1261     } 
1262     
1263     @Test public void test_rt27175() {
1264         sm.clearAndSelect(5);                          
1265         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT, KeyModifier.getShortcutKey()); 
1266         assertTrue(debug(), fm.isFocused(0));
1267         assertTrue(isSelected(0,1,2,3,4,5));
1268     }
1269     
1270     @Test public void test_rt28065() {
1271         sm.setSelectionMode(SelectionMode.MULTIPLE);
1272         
1273         treeView.getSelectionModel().select(0);
1274         assertEquals(0, treeView.getSelectionModel().getSelectedIndex());
1275         assertEquals(root, treeView.getSelectionModel().getSelectedItem());
1276         assertEquals(0, treeView.getFocusModel().getFocusedIndex());
1277         assertEquals(root, treeView.getFocusModel().getFocusedItem());
1278         
1279         keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey());
1280         assertEquals(0, treeView.getSelectionModel().getSelectedIndex());
1281         assertEquals(root, treeView.getSelectionModel().getSelectedItem());
1282         assertEquals(0, treeView.getFocusModel().getFocusedIndex());
1283         assertEquals(root, treeView.getFocusModel().getFocusedItem());
1284     }
1285     
1286     @Test public void test_rt29930() {
1287         sm.setSelectionMode(SelectionMode.MULTIPLE);
1288         
1289         sm.clearAndSelect(0);
1290         
1291         keyboard.doDownArrowPress(KeyModifier.SHIFT); // select rows [0,1]
1292         keyboard.doDownArrowPress(KeyModifier.SHIFT); // select rows [0,1,2]
1293         assertTrue(isSelected(0,1,2));
1294         assertEquals(2, fm.getFocusedIndex());
1295         assertEquals(0, getAnchor());
1296 
1297         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(),
1298                 (Utils.isMac()  ? KeyModifier.CTRL : null)); // set new anchor point
1299         assertTrue(isSelected(0,1));
1300         assertEquals(2, fm.getFocusedIndex());
1301         assertEquals(2, getAnchor());
1302         
1303         keyboard.doDownArrowPress(KeyModifier.SHIFT); // select rows [2,3]
1304         assertTrue(isSelected(2,3));
1305         assertTrue(isNotSelected(0,1));
1306         assertEquals(3, fm.getFocusedIndex());
1307         assertEquals(2, getAnchor());
1308     }
1309 
1310     private int rt29849_start_count = 0;
1311     private int rt29849_cancel_count = 0;
1312     @Test public void test_rt29849() {
1313         treeView.setEditable(true);
1314 
1315         treeView.setOnEditStart(event -> {
1316             rt29849_start_count++;
1317         });
1318         treeView.setOnEditCancel(event -> {
1319             rt29849_cancel_count++;
1320         });
1321 
1322         // initially the counts should be zero
1323         assertEquals(0, rt29849_start_count);
1324         assertEquals(0, rt29849_cancel_count);
1325 
1326         IndexedCell cell = VirtualFlowTestUtils.getCell(treeView, 0);
1327         assertTrue(cell.isEditable());
1328         assertFalse(cell.isEditing());
1329         assertEquals(0, cell.getIndex());
1330 
1331         // do an edit, start count should be one, cancel still zero
1332         treeView.edit(root);
1333         assertTrue(cell.isEditing());
1334         assertEquals(1, rt29849_start_count);
1335         assertEquals(0, rt29849_cancel_count);
1336 
1337         // cancel edit, now both counts should be 1
1338 //        keyboard.doKeyPress(KeyCode.ESCAPE);
1339         treeView.edit(null);
1340         assertFalse(cell.isEditing());
1341         assertEquals(1, rt29849_start_count);
1342         assertEquals(1, rt29849_cancel_count);
1343     }
1344 
1345     private int rt31577_count = 0;
1346     @Test public void test_rt31577() {
1347         final MultipleSelectionModel sm = treeView.getSelectionModel();
1348         sm.setSelectionMode(SelectionMode.SINGLE);
1349         sm.clearSelection();
1350 
1351         // the actual bug is that the selectedItem property does not fire an
1352         // event when the selected items list changes (due to deselection).
1353         // It actually does always contain the right value - it just doesn't
1354         // let anyone know it!
1355         sm.selectedItemProperty().addListener(observable -> {
1356             rt31577_count++;
1357         });
1358 
1359         assertTrue(sm.getSelectedItems().isEmpty());
1360         assertFalse(sm.isSelected(1));
1361         assertEquals(0, rt31577_count);
1362 
1363         // select the first row
1364         keyboard.doKeyPress(KeyCode.KP_DOWN);
1365         assertEquals(1, sm.getSelectedItems().size());
1366         assertTrue(sm.isSelected(0));
1367         assertTrue(sm.getSelectedItems().contains(root));
1368         assertEquals(root, sm.getSelectedItem());
1369         assertEquals(1, rt31577_count);
1370 
1371         // deselect the row
1372         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL,
1373                 Utils.isMac() ? KeyModifier.getShortcutKey() : null);
1374         assertTrue(sm.getSelectedItems().isEmpty());
1375         assertFalse(sm.isSelected(1));
1376         assertNull(sm.getSelectedItem());
1377         assertEquals(2, rt31577_count);
1378     }
1379 
1380     @Test public void test_rt32383_pageDown() {
1381         // this test requires a lot of data
1382         for (int i = 0; i < 100; i++) {
1383             root.getChildren().add(new TreeItem<String>("Row " + i));
1384         }
1385 
1386         final MultipleSelectionModel sm = treeView.getSelectionModel();
1387         sm.setSelectionMode(SelectionMode.SINGLE);
1388         sm.clearAndSelect(0);
1389 
1390         final TreeItem<String> initialFocusOwner = fm.getFocusedItem();
1391 
1392         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.getShortcutKey());
1393         Toolkit.getToolkit().firePulse();
1394         final TreeItem<String> newFocusOwner = fm.getFocusedItem();
1395         assertNotSame(initialFocusOwner, newFocusOwner);
1396 
1397         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.getShortcutKey());
1398         Toolkit.getToolkit().firePulse();
1399         final TreeItem<String> nextFocusOwner = fm.getFocusedItem();
1400         assertNotSame(initialFocusOwner, nextFocusOwner);
1401         assertNotSame(newFocusOwner, nextFocusOwner);
1402     }
1403 
1404     @Test public void test_rt32383_pageUp() {
1405         // this test requires a lot of data
1406         for (int i = 0; i < 100; i++) {
1407             root.getChildren().add(new TreeItem<String>("Row " + i));
1408         }
1409 
1410         final int lastIndex = 99;
1411 
1412         final MultipleSelectionModel sm = treeView.getSelectionModel();
1413         sm.setSelectionMode(SelectionMode.SINGLE);
1414         sm.clearAndSelect(lastIndex);
1415 
1416         // need to make sure we scroll down to the bottom!
1417         treeView.scrollTo(lastIndex);
1418         Toolkit.getToolkit().firePulse();
1419 
1420         final TreeItem<String> initialFocusOwner = fm.getFocusedItem();
1421 
1422         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.getShortcutKey());
1423         Toolkit.getToolkit().firePulse();
1424         final TreeItem<String> newFocusOwner = fm.getFocusedItem();
1425         assertNotSame(initialFocusOwner, newFocusOwner);
1426 
1427         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.getShortcutKey());
1428         Toolkit.getToolkit().firePulse();
1429         final TreeItem<String> nextFocusOwner = fm.getFocusedItem();
1430         assertNotSame(initialFocusOwner, nextFocusOwner);
1431         assertNotSame(newFocusOwner, nextFocusOwner);
1432     }
1433 
1434     @Test public void test_rt19053_pageUp() {
1435         final int items = 8;
1436         root.getChildren().clear();
1437         for (int i = 0; i < items; i++) {
1438             root.getChildren().add(new TreeItem<>("Row " + i));
1439         }
1440 
1441         final int middleIndex = items / 2;
1442 
1443         treeView.setShowRoot(false);
1444         final MultipleSelectionModel sm = treeView.getSelectionModel();
1445         sm.setSelectionMode(SelectionMode.SINGLE);
1446         sm.clearAndSelect(middleIndex);
1447 
1448         assertEquals(middleIndex, sm.getSelectedIndex());
1449 
1450         final Object initialSelectionOwner = sm.getSelectedItem();
1451 
1452         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
1453         Toolkit.getToolkit().firePulse();
1454         final Object newSelectionOwner = sm.getSelectedItem();
1455         assertNotSame(initialSelectionOwner, newSelectionOwner);
1456 
1457         // selection should go all the way to the top, but this bug
1458         // shows that instead it seems to stop midway - where the anchor is
1459         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
1460         Toolkit.getToolkit().firePulse();
1461         assertEquals(0, fm.getFocusedIndex());
1462         assertEquals(0, sm.getSelectedIndex());
1463         final Object nextSelectionOwner =  sm.getSelectedItem();
1464         assertNotSame(initialSelectionOwner, nextSelectionOwner);
1465         assertNotSame(newSelectionOwner, nextSelectionOwner);
1466     }
1467 
1468     @Test public void test_rt19053_pageDown() {
1469         final int items = 8;
1470         root.getChildren().clear();
1471         for (int i = 0; i < items; i++) {
1472             root.getChildren().add(new TreeItem<>("Row " + i));
1473         }
1474 
1475         final int middleIndex = items / 2;
1476 
1477         treeView.setShowRoot(false);
1478         final MultipleSelectionModel sm = treeView.getSelectionModel();
1479         sm.setSelectionMode(SelectionMode.SINGLE);
1480         sm.clearAndSelect(middleIndex);
1481 
1482         assertEquals(middleIndex, sm.getSelectedIndex());
1483 
1484         final Object initialSelectionOwner = sm.getSelectedItem();
1485 
1486         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
1487         Toolkit.getToolkit().firePulse();
1488         final Object newSelectionOwner = sm.getSelectedItem();
1489         assertNotSame(initialSelectionOwner, newSelectionOwner);
1490 
1491         // selection should go all the way to the bottom, but this bug
1492         // shows that instead it seems to stop midway - where the anchor is
1493         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
1494         Toolkit.getToolkit().firePulse();
1495         assertEquals(items - 1, fm.getFocusedIndex());
1496         assertEquals(items - 1, sm.getSelectedIndex());
1497         final Object nextSelectionOwner =  sm.getSelectedItem();
1498         assertNotSame(initialSelectionOwner, nextSelectionOwner);
1499         assertNotSame(newSelectionOwner, nextSelectionOwner);
1500     }
1501 
1502     private int rt32783_count_start = 0;
1503     private int rt32783_count_commit = 0;
1504     private int rt32783_count_cancel = 0;
1505     private int rt32783_count = 0;
1506     @Test public void test_rt32683() {
1507         // set up test
1508         final int items = 8;
1509         TreeItem<String> newRoot = new TreeItem<>("New root");
1510         newRoot.setExpanded(false);
1511         for (int i = 0; i < items; i++) {
1512             newRoot.getChildren().add(new TreeItem<>("Row " + i));
1513         }
1514 
1515         treeView.setRoot(newRoot);
1516         treeView.setEditable(true);
1517         treeView.setOnEditStart(t -> {
1518             rt32783_count_start++;
1519         });
1520 
1521         treeView.setOnEditCommit(t -> {
1522             rt32783_count_commit++;
1523         });
1524 
1525         treeView.setOnEditCancel(t -> {
1526             rt32783_count_cancel++;
1527         });
1528 
1529         treeView.editingItemProperty().addListener(observable -> {
1530             assertNotNull(treeView.getEditingItem());
1531             System.out.println("editing item: " + treeView.getEditingItem());
1532             rt32783_count++;
1533         });
1534 
1535         // start test
1536 //        final int middleIndex = items / 2;
1537 
1538         newRoot.setExpanded(true);
1539         Toolkit.getToolkit().firePulse();
1540         newRoot.setExpanded(false);
1541         Toolkit.getToolkit().firePulse();
1542 
1543         final MultipleSelectionModel sm = treeView.getSelectionModel();
1544         sm.clearAndSelect(0);
1545 
1546         // need to get the cell before the editing starts
1547 //        TreeCell cell = (TreeCell)VirtualFlowTestUtils.getCell(treeView, 0);
1548 
1549         // this forces the selected cell to go into editing mode
1550         keyboard.doKeyPress(KeyCode.F2);
1551 //        Toolkit.getToolkit().firePulse();
1552 
1553         assertEquals(1, rt32783_count_start);
1554         assertEquals(0, rt32783_count_commit);
1555         assertEquals(0, rt32783_count_cancel);
1556 //        assertTrue(cell.isEditing());
1557         assertEquals(newRoot, treeView.getEditingItem());
1558     }
1559 
1560     @Test public void test_rt21375_scenario_1a_down() {
1561         final int items = 8;
1562         root.getChildren().clear();
1563         for (int i = 0; i < items; i++) {
1564             root.getChildren().add(new TreeItem<>("Row " + i));
1565         }
1566 
1567         final MultipleSelectionModel sm = treeView.getSelectionModel();
1568         sm.setSelectionMode(SelectionMode.MULTIPLE);
1569         sm.clearAndSelect(0);
1570 
1571         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
1572         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
1573         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);
1574         Toolkit.getToolkit().firePulse();
1575         assertTrue(isSelected(0,1,2,3));
1576         assertEquals(4, sm.getSelectedItems().size());
1577     }
1578 
1579     @Test public void test_rt21375_scenario_1b_down() {
1580         final int items = 8;
1581         root.getChildren().clear();
1582         for (int i = 0; i < items; i++) {
1583             root.getChildren().add(new TreeItem<>("Row " + i));
1584         }
1585 
1586         final MultipleSelectionModel sm = treeView.getSelectionModel();
1587         sm.setSelectionMode(SelectionMode.MULTIPLE);
1588         sm.clearAndSelect(0);
1589 
1590         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
1591         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
1592         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1593         Toolkit.getToolkit().firePulse();
1594         assertTrue(isSelected(0,1,2,3));
1595         assertEquals(4, sm.getSelectedItems().size());
1596     }
1597 
1598     @Test public void test_rt21375_scenario_2_down() {
1599         final int items = 8;
1600         root.getChildren().clear();
1601         for (int i = 0; i < items; i++) {
1602             root.getChildren().add(new TreeItem<>("Row " + i));
1603         }
1604 
1605         final MultipleSelectionModel sm = treeView.getSelectionModel();
1606         sm.setSelectionMode(SelectionMode.MULTIPLE);
1607         sm.clearAndSelect(0);
1608 
1609         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
1610         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
1611         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), PlatformUtil.isMac() ? KeyModifier.CTRL : null);
1612         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
1613         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.SHIFT);
1614         Toolkit.getToolkit().firePulse();
1615         assertTrue(isSelected(2,3,4));
1616         assertEquals(3, sm.getSelectedItems().size());
1617     }
1618 
1619     @Test public void test_rt21375_scenario_3_down() {
1620         final int items = 8;
1621         root.getChildren().clear();
1622         for (int i = 0; i < items; i++) {
1623             root.getChildren().add(new TreeItem<>("Row " + i));
1624         }
1625 
1626         final MultipleSelectionModel sm = treeView.getSelectionModel();
1627         sm.setSelectionMode(SelectionMode.MULTIPLE);
1628         sm.clearAndSelect(0);
1629 
1630         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
1631         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
1632         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), PlatformUtil.isMac() ? KeyModifier.CTRL : null);
1633         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
1634         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1635         Toolkit.getToolkit().firePulse();
1636         assertTrue(isSelected(0,2,3,4));
1637         assertEquals(4, sm.getSelectedItems().size());
1638     }
1639 
1640     @Test public void test_rt21375_scenario_1a_up() {
1641         final int items = 8;
1642         root.getChildren().clear();
1643         for (int i = 0; i < items; i++) {
1644             root.getChildren().add(new TreeItem<>("Row " + i));
1645         }
1646 
1647         final MultipleSelectionModel sm = treeView.getSelectionModel();
1648         sm.setSelectionMode(SelectionMode.MULTIPLE);
1649         sm.clearAndSelect(7);
1650 
1651         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
1652         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
1653         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
1654         Toolkit.getToolkit().firePulse();
1655         assertTrue(isSelected(7,6,5,4));
1656         assertEquals(4, sm.getSelectedItems().size());
1657     }
1658 
1659     @Test public void test_rt21375_scenario_1b_up() {
1660         final int items = 8;
1661         root.getChildren().clear();
1662         for (int i = 0; i < items; i++) {
1663             root.getChildren().add(new TreeItem<>("Row " + i));
1664         }
1665 
1666         final MultipleSelectionModel sm = treeView.getSelectionModel();
1667         sm.setSelectionMode(SelectionMode.MULTIPLE);
1668         sm.clearAndSelect(7);
1669 
1670         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
1671         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
1672         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1673         Toolkit.getToolkit().firePulse();
1674         assertTrue(isSelected(7,6,5,4));
1675         assertEquals(4, sm.getSelectedItems().size());
1676     }
1677 
1678     @Test public void test_rt21375_scenario_2_up() {
1679         final int items = 8;
1680         root.getChildren().clear();
1681         for (int i = 0; i < items; i++) {
1682             root.getChildren().add(new TreeItem<>("Row " + i));
1683         }
1684 
1685         final MultipleSelectionModel sm = treeView.getSelectionModel();
1686         sm.setSelectionMode(SelectionMode.MULTIPLE);
1687         sm.clearAndSelect(7);
1688 
1689         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
1690         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
1691         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), PlatformUtil.isMac() ? KeyModifier.CTRL : null);
1692         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
1693         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.SHIFT);
1694         Toolkit.getToolkit().firePulse();
1695         assertTrue(isSelected(5,4,3));
1696         assertEquals(3, sm.getSelectedItems().size());
1697     }
1698 
1699     @Test public void test_rt21375_scenario_3_up() {
1700         final int items = 8;
1701         root.getChildren().clear();
1702         for (int i = 0; i < items; i++) {
1703             root.getChildren().add(new TreeItem<>("Row " + i));
1704         }
1705 
1706         final MultipleSelectionModel sm = treeView.getSelectionModel();
1707         sm.setSelectionMode(SelectionMode.MULTIPLE);
1708         sm.clearAndSelect(7);
1709 
1710         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
1711         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
1712         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), PlatformUtil.isMac() ? KeyModifier.CTRL : null);
1713         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
1714         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1715         Toolkit.getToolkit().firePulse();
1716         assertTrue(isSelected(7,5,4,3));
1717         assertEquals(4, sm.getSelectedItems().size());
1718     }
1719 
1720     @Test public void test_rt33301_multipleSelection_down() {
1721         final int items = 4;
1722         root.getChildren().clear();
1723         for (int i = 0; i < items; i++) {
1724             root.getChildren().add(new TreeItem<>("Row " + i));
1725         }
1726 
1727         final FocusModel fm = treeView.getFocusModel();
1728         final MultipleSelectionModel sm = treeView.getSelectionModel();
1729         sm.setSelectionMode(SelectionMode.MULTIPLE);
1730         sm.clearAndSelect(2);
1731 
1732         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 3
1733         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 4
1734         Toolkit.getToolkit().firePulse();
1735         assertTrue(isNotSelected(0,1));
1736         assertTrue(isSelected(2,3,4));
1737         assertEquals(3, sm.getSelectedItems().size());
1738         assertTrue(fm.isFocused(4));
1739 
1740         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
1741         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
1742         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
1743         Toolkit.getToolkit().firePulse();
1744         assertTrue(isNotSelected(0,1));
1745         assertTrue(isSelected(2,3,4));
1746         assertEquals(3, sm.getSelectedItems().size());
1747         assertTrue("Focus index incorrectly at: " + fm.getFocusedIndex(), fm.isFocused(4));
1748     }
1749 
1750     @Test public void test_rt33301_multipleSelection_up() {
1751         final int items = 4;
1752         root.getChildren().clear();
1753         for (int i = 0; i < items; i++) {
1754             root.getChildren().add(new TreeItem<>("Row " + i));
1755         }
1756 
1757         final FocusModel fm = treeView.getFocusModel();
1758         final MultipleSelectionModel sm = treeView.getSelectionModel();
1759         sm.setSelectionMode(SelectionMode.MULTIPLE);
1760         sm.clearAndSelect(2);
1761 
1762         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 1
1763         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 0
1764         Toolkit.getToolkit().firePulse();
1765         assertTrue(isNotSelected(3,4));
1766         assertTrue(isSelected(0,1,2));
1767         assertEquals(3, sm.getSelectedItems().size());
1768         assertTrue(fm.isFocused(0));
1769 
1770         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
1771         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
1772         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
1773         Toolkit.getToolkit().firePulse();
1774         assertTrue(isNotSelected(3,4));
1775         assertTrue(isSelected(0,1,2));
1776         assertEquals(3, sm.getSelectedItems().size());
1777         assertTrue(fm.isFocused(0));
1778     }
1779 
1780     @Test public void test_rt33301_singleSelection_down() {
1781         final int items = 4;
1782         root.getChildren().clear();
1783         for (int i = 0; i < items; i++) {
1784             root.getChildren().add(new TreeItem<>("Row " + i));
1785         }
1786 
1787         final FocusModel fm = treeView.getFocusModel();
1788         final MultipleSelectionModel sm = treeView.getSelectionModel();
1789         sm.setSelectionMode(SelectionMode.SINGLE);
1790         sm.clearAndSelect(2);
1791 
1792         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 3
1793         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 4
1794         Toolkit.getToolkit().firePulse();
1795         assertTrue(isNotSelected(0,1,2,3));
1796         assertTrue(isSelected(4));
1797         assertEquals(1, sm.getSelectedItems().size());
1798         assertTrue(fm.isFocused(4));
1799 
1800         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
1801         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
1802         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
1803         Toolkit.getToolkit().firePulse();
1804         assertTrue(isNotSelected(0,1,2,3));
1805         assertTrue(isSelected(4));
1806         assertEquals(1, sm.getSelectedItems().size());
1807         assertTrue(fm.isFocused(4));
1808     }
1809 
1810     @Test public void test_rt33301_singleSelection_up() {
1811         final int items = 4;
1812         root.getChildren().clear();
1813         for (int i = 0; i < items; i++) {
1814             root.getChildren().add(new TreeItem<>("Row " + i));
1815         }
1816 
1817         final FocusModel fm = treeView.getFocusModel();
1818         final MultipleSelectionModel sm = treeView.getSelectionModel();
1819         sm.setSelectionMode(SelectionMode.SINGLE);
1820         sm.clearAndSelect(2);
1821 
1822         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 1
1823         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 0
1824         Toolkit.getToolkit().firePulse();
1825         assertTrue(isNotSelected(1,2,3,4));
1826         assertTrue(isSelected(0));
1827         assertEquals(1, sm.getSelectedItems().size());
1828         assertTrue(fm.isFocused(0));
1829 
1830         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
1831         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
1832         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
1833         Toolkit.getToolkit().firePulse();
1834         assertTrue(isNotSelected(1,2,3,4));
1835         assertTrue(isSelected(0));
1836         assertEquals(1, sm.getSelectedItems().size());
1837         assertTrue(fm.isFocused(0));
1838     }
1839 
1840     private int rt_33559_count = 0;
1841     @Test public void test_rt33559() {
1842         final int items = 4;
1843         root.getChildren().clear();
1844         root.setExpanded(false);
1845         for (int i = 0; i < items; i++) {
1846             root.getChildren().add(new TreeItem<>("Row " + i));
1847         }
1848 
1849         final MultipleSelectionModel sm = treeView.getSelectionModel();
1850         sm.setSelectionMode(SelectionMode.SINGLE);
1851         sm.clearAndSelect(0);
1852 
1853         treeView.getSelectionModel().getSelectedItems().addListener((ListChangeListener) c -> {
1854             while (c.next()) {
1855                 rt_33559_count++;
1856             }
1857         });
1858 
1859         assertEquals(0, rt_33559_count);
1860         keyboard.doKeyPress(KeyCode.RIGHT); // expand root
1861         assertEquals(0, rt_33559_count);
1862     }
1863 
1864     @Test public void test_rt20915() {
1865         final FocusModel fm = treeView.getFocusModel();
1866         final MultipleSelectionModel sm = treeView.getSelectionModel();
1867 
1868         sm.clearAndSelect(0);
1869         assertEquals(0, fm.getFocusedIndex());
1870         assertEquals(0, getAnchor());
1871 
1872         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
1873         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
1874         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
1875         Toolkit.getToolkit().firePulse();
1876         assertTrue(isNotSelected(1,2,3));
1877         assertTrue(isSelected(0));
1878         assertEquals(1, sm.getSelectedItems().size());
1879         assertTrue(fm.isFocused(3));
1880 
1881         keyboard.doKeyPress(KeyCode.SPACE,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1882         Toolkit.getToolkit().firePulse();
1883         assertTrue(debug(), isSelected(0,1,2,3));
1884         assertEquals(4, sm.getSelectedItems().size());
1885         assertTrue(fm.isFocused(3));
1886     }
1887 
1888     @Test public void test_rt34200() {
1889         final int items = 100;
1890         root.getChildren().clear();
1891         root.setExpanded(true);
1892         for (int i = 0; i < items; i++) {
1893             root.getChildren().add(new TreeItem<>("Row " + i));
1894         }
1895 
1896         sm.clearAndSelect(99);
1897         treeView.scrollTo(99);
1898         assertEquals(99, getAnchor());
1899         assertEquals(99, fm.getFocusedIndex());
1900 
1901         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1902         Toolkit.getToolkit().firePulse();
1903         assertEquals(99, getAnchor());
1904         assertTrue(fm.getFocusedIndex() < 99);
1905     }
1906 
1907     @Test public void test_rt4369() {
1908         final int items = 100;
1909         root.getChildren().clear();
1910         root.setExpanded(true);
1911         for (int i = 0; i < items; i++) {
1912             root.getChildren().add(new TreeItem<>("Row " + i));
1913         }
1914 
1915         sm.clearAndSelect(99);
1916         treeView.scrollTo(99);
1917         assertEquals(99, getAnchor());
1918         assertEquals(99, fm.getFocusedIndex());
1919 
1920         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
1921         Toolkit.getToolkit().firePulse();
1922         assertEquals(99, getAnchor());
1923         assertTrue(fm.getFocusedIndex() < 99);
1924     }
1925 
1926     @Test public void test_rt33894() {
1927         final int items = 5;
1928         root.getChildren().clear();
1929         root.setExpanded(true);
1930         for (int i = 0; i < items; i++) {
1931             root.getChildren().add(new TreeItem<>("Row " + i));
1932         }
1933 
1934         sm.clearAndSelect(1);
1935         assertEquals(1, getAnchor());
1936         assertEquals(1, fm.getFocusedIndex());
1937         assertEquals(1, sm.getSelectedIndex());
1938 
1939         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
1940         Toolkit.getToolkit().firePulse();
1941         assertEquals(1, getAnchor());
1942         assertEquals(2, fm.getFocusedIndex());
1943         assertEquals(1, sm.getSelectedIndex());
1944 
1945         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1946         Toolkit.getToolkit().firePulse();
1947         assertEquals(2, getAnchor());
1948         assertEquals(2, fm.getFocusedIndex());
1949         assertEquals(2, sm.getSelectedIndex());
1950         assertTrue(isSelected(1, 2));
1951 
1952         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
1953         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
1954         Toolkit.getToolkit().firePulse();
1955         assertEquals(2, getAnchor());
1956         assertEquals(0, fm.getFocusedIndex());
1957         assertEquals(2, sm.getSelectedIndex());
1958         assertTrue(isSelected(1, 2));
1959 
1960         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1961         Toolkit.getToolkit().firePulse();
1962         assertEquals(0, getAnchor());
1963         assertEquals(0, fm.getFocusedIndex());
1964         assertEquals(0, sm.getSelectedIndex());
1965         assertTrue(isSelected(0, 1, 2));
1966     }
1967 
1968     @Test public void test_rt34425() {
1969         final int items = 5;
1970         root.getChildren().clear();
1971         root.setExpanded(true);
1972         for (int i = 0; i < items; i++) {
1973             root.getChildren().add(new TreeItem<>("Row " + i));
1974         }
1975 
1976         sm.clearAndSelect(1);
1977         assertEquals(1, getAnchor());
1978         assertEquals(1, fm.getFocusedIndex());
1979         assertEquals(1, sm.getSelectedIndex());
1980 
1981         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
1982         Toolkit.getToolkit().firePulse();
1983         assertEquals(1, getAnchor());
1984         assertEquals(2, fm.getFocusedIndex());
1985         assertEquals(1, sm.getSelectedIndex());
1986 
1987         keyboard.doKeyPress(KeyCode.SPACE);
1988         Toolkit.getToolkit().firePulse();
1989         assertEquals(2, getAnchor());
1990         assertEquals(2, fm.getFocusedIndex());
1991         assertEquals(2, sm.getSelectedIndex());
1992         assertTrue(isSelected(1, 2));
1993     }
1994 
1995     @Test public void test_rt34407_down_down_up() {
1996         final int items = 100;
1997         root.getChildren().clear();
1998         root.setExpanded(true);
1999         for (int i = 0; i < items; i++) {
2000             root.getChildren().add(new TreeItem<>("Row " + i));
2001         }
2002         treeView.setPrefHeight(130); // roughly room for four rows
2003 
2004         StageLoader sl = new StageLoader(treeView);
2005         sm.setSelectionMode(SelectionMode.MULTIPLE);
2006 
2007         sm.clearAndSelect(0);
2008         fm.focus(0);
2009         assertEquals(0, getAnchor());
2010         assertTrue(fm.isFocused(0));
2011         assertTrue(sm.isSelected(0));
2012         assertFalse(sm.isSelected(1));
2013 
2014         // we expect the final Page-up to return us back to this selected index and with the same number of selected indices
2015         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2016         final int leadSelectedIndex = sm.getSelectedIndex();
2017         final int selectedIndicesCount = sm.getSelectedIndices().size();
2018         assertEquals(6, leadSelectedIndex);
2019         assertEquals(6, fm.getFocusedIndex());
2020         assertEquals(7, selectedIndicesCount);
2021 
2022         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2023         assertEquals(leadSelectedIndex * 2, sm.getSelectedIndex());
2024         assertEquals(leadSelectedIndex * 2, fm.getFocusedIndex());
2025         assertEquals(selectedIndicesCount * 2 - 1, sm.getSelectedIndices().size());
2026 
2027         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2028         assertEquals(leadSelectedIndex, sm.getSelectedIndex());
2029         assertEquals(leadSelectedIndex, fm.getFocusedIndex());
2030         assertEquals(selectedIndicesCount, sm.getSelectedIndices().size());
2031 
2032         sl.dispose();
2033     }
2034 
2035     @Test public void test_rt34407_up_up_down() {
2036         final int items = 100;
2037         root.getChildren().clear();
2038         root.setExpanded(true);
2039         for (int i = 0; i < items; i++) {
2040             root.getChildren().add(new TreeItem<>("Row " + i));
2041         }
2042         treeView.setPrefHeight(120); // roughly room for four rows
2043 
2044         StageLoader sl = new StageLoader(treeView);
2045         sm.setSelectionMode(SelectionMode.MULTIPLE);
2046 
2047         sm.clearAndSelect(99);
2048         fm.focus(99);
2049         treeView.scrollTo(99);
2050         Toolkit.getToolkit().firePulse();
2051 
2052         assertEquals(99, getAnchor());
2053         assertTrue(fm.isFocused(99));
2054         assertTrue(sm.isSelected(99));
2055         assertFalse(sm.isSelected(98));
2056 
2057         // we expect the final Page-down to return us back to this selected index and with the same number of selected indices
2058         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2059         final int leadSelectedIndex = sm.getSelectedIndex();
2060         final int selectedIndicesCount = sm.getSelectedIndices().size();
2061         final int diff = 4;//99 - leadSelectedIndex;
2062         assertEquals(99 - diff, leadSelectedIndex);
2063         assertEquals(99 - diff, fm.getFocusedIndex());
2064         assertEquals(5, selectedIndicesCount);
2065 
2066         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2067         assertEquals(99 - diff * 2 - 1, sm.getSelectedIndex());
2068         assertEquals(selectedIndicesCount * 2, sm.getSelectedIndices().size());
2069 
2070         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2071         assertEquals(leadSelectedIndex, sm.getSelectedIndex());
2072         assertEquals(selectedIndicesCount, sm.getSelectedIndices().size());
2073 
2074         sl.dispose();
2075     }
2076 
2077     @Test public void test_rt34768() {
2078         treeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
2079         TreeTableColumn<String, String> firstNameCol = new TreeTableColumn<>("First Name");
2080         treeView.setRoot(null);
2081 
2082         // no need for an assert here - we're testing for an AIOOBE
2083         keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey());
2084     }
2085 
2086     @Test public void test_rt35853_multipleSelection_shiftDown() {
2087         final int items = 10;
2088         root.getChildren().clear();
2089         root.setExpanded(true);
2090         for (int i = 0; i < items; i++) {
2091             root.getChildren().add(new TreeItem<>("Row " + i));
2092         }
2093 
2094         sm.setSelectionMode(SelectionMode.MULTIPLE);
2095 
2096         sm.clearAndSelect(5);
2097         assertEquals(5, getAnchor());
2098         assertTrue(fm.isFocused(5));
2099         assertTrue(sm.isSelected(5));
2100 
2101         sm.selectedIndexProperty().addListener(observable -> {
2102             // we expect only one selected index change event, from 5 to 4
2103             assertEquals(4, sm.getSelectedIndex());
2104         });
2105 
2106         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
2107         assertEquals(5, getAnchor());
2108         assertTrue(fm.isFocused(4));
2109         assertTrue(sm.isSelected(4));
2110         assertTrue(sm.isSelected(5));
2111     }
2112 
2113     @Test public void test_rt35853_multipleSelection_noShiftDown() {
2114         final int items = 10;
2115         root.getChildren().clear();
2116         root.setExpanded(true);
2117         for (int i = 0; i < items; i++) {
2118             root.getChildren().add(new TreeItem<>("Row " + i));
2119         }
2120 
2121         sm.setSelectionMode(SelectionMode.MULTIPLE);
2122 
2123         sm.clearAndSelect(5);
2124         assertEquals(5, getAnchor());
2125         assertTrue(fm.isFocused(5));
2126         assertTrue(sm.isSelected(5));
2127 
2128         sm.selectedIndexProperty().addListener(observable -> {
2129             // we expect only one selected index change event, from 5 to 4
2130             assertEquals(4, sm.getSelectedIndex());
2131         });
2132 
2133         keyboard.doKeyPress(KeyCode.UP);
2134         assertEquals(4, getAnchor());
2135         assertTrue(fm.isFocused(4));
2136         assertTrue(sm.isSelected(4));
2137         assertFalse(sm.isSelected(5));
2138     }
2139 
2140     @Test public void test_rt35853_singleSelection_shiftDown() {
2141         final int items = 10;
2142         root.getChildren().clear();
2143         root.setExpanded(true);
2144         for (int i = 0; i < items; i++) {
2145             root.getChildren().add(new TreeItem<>("Row " + i));
2146         }
2147 
2148         sm.setSelectionMode(SelectionMode.SINGLE);
2149 
2150         sm.clearAndSelect(5);
2151         assertEquals(5, getAnchor());
2152         assertTrue(fm.isFocused(5));
2153         assertTrue(sm.isSelected(5));
2154 
2155         sm.selectedIndexProperty().addListener(observable -> {
2156             // we expect only one selected index change event, from 5 to 4
2157             assertEquals(4, sm.getSelectedIndex());
2158         });
2159 
2160         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
2161         assertEquals(4, getAnchor());
2162         assertTrue(fm.isFocused(4));
2163         assertTrue(sm.isSelected(4));
2164         assertFalse(sm.isSelected(5));
2165     }
2166 
2167     @Test public void test_rt35853_singleSelection_noShiftDown() {
2168         final int items = 10;
2169         root.getChildren().clear();
2170         root.setExpanded(true);
2171         for (int i = 0; i < items; i++) {
2172             root.getChildren().add(new TreeItem<>("Row " + i));
2173         }
2174 
2175         sm.setSelectionMode(SelectionMode.SINGLE);
2176 
2177         sm.clearAndSelect(5);
2178         assertEquals(5, getAnchor());
2179         assertTrue(fm.isFocused(5));
2180         assertTrue(sm.isSelected(5));
2181 
2182         sm.selectedIndexProperty().addListener(observable -> {
2183             // we expect only one selected index change event, from 5 to 4
2184             assertEquals(4, sm.getSelectedIndex());
2185         });
2186 
2187         keyboard.doKeyPress(KeyCode.UP);
2188         assertEquals(4, getAnchor());
2189         assertTrue(fm.isFocused(4));
2190         assertTrue(sm.isSelected(4));
2191         assertFalse(sm.isSelected(5));
2192     }
2193 
2194     @Test public void test_rt36800() {
2195         // get the current exception handler before replacing with our own,
2196         // as ListListenerHelp intercepts the exception otherwise
2197         final Thread.UncaughtExceptionHandler exceptionHandler = Thread.currentThread().getUncaughtExceptionHandler();
2198         Thread.currentThread().setUncaughtExceptionHandler((t, e) -> fail("We don't expect any exceptions in this test!"));
2199 
2200         final int items = 10;
2201         root.getChildren().clear();
2202         root.setExpanded(true);
2203         for (int i = 0; i < items; i++) {
2204             root.getChildren().add(new TreeItem<>("Row " + i));
2205         }
2206 
2207         sm.setSelectionMode(SelectionMode.SINGLE);
2208 
2209         sm.clearAndSelect(5);
2210         assertEquals(5, getAnchor());
2211         assertTrue(fm.isFocused(5));
2212         assertTrue(sm.isSelected(5));
2213 
2214         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // 4
2215         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // 3
2216         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // 2
2217         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // 1
2218         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // 0
2219         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // bug time?
2220 
2221         assertEquals(0, getAnchor());
2222         assertTrue(fm.isFocused(0));
2223         assertTrue(sm.isSelected(0));
2224         assertFalse(sm.isSelected(1));
2225         assertFalse(sm.isSelected(2));
2226         assertFalse(sm.isSelected(3));
2227         assertFalse(sm.isSelected(4));
2228         assertFalse(sm.isSelected(5));
2229 
2230         // reset the exception handler
2231         Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler);
2232     }
2233 
2234     @Test public void test_rt_37130_pageUpAtTop() {
2235         final int items = 100;
2236         root.getChildren().clear();
2237         root.setExpanded(true);
2238         for (int i = 0; i < items; i++) {
2239             root.getChildren().add(new TreeItem<>("Row " + i));
2240         }
2241 
2242         sm.setSelectionMode(SelectionMode.MULTIPLE);
2243 
2244         StageLoader sl = new StageLoader(treeView);
2245 
2246         sm.select(5);
2247         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2248         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2249 
2250         sl.dispose();
2251     }
2252 
2253     @Test public void test_rt_37130_pageUpAtBottom() {
2254         final int items = 100;
2255         root.getChildren().clear();
2256         root.setExpanded(true);
2257         for (int i = 0; i < items; i++) {
2258             root.getChildren().add(new TreeItem<>("Row " + i));
2259         }
2260 
2261         sm.setSelectionMode(SelectionMode.MULTIPLE);
2262 
2263         StageLoader sl = new StageLoader(treeView);
2264 
2265         sm.select(95);
2266         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2267         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2268 
2269         sl.dispose();
2270     }
2271 
2272     @Test public void test_rt_37130_pageDownAtTop() {
2273         final int items = 100;
2274         root.getChildren().clear();
2275         root.setExpanded(true);
2276         for (int i = 0; i < items; i++) {
2277             root.getChildren().add(new TreeItem<>("Row " + i));
2278         }
2279 
2280         sm.setSelectionMode(SelectionMode.MULTIPLE);
2281 
2282         StageLoader sl = new StageLoader(treeView);
2283 
2284         sm.select(5);
2285         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2286         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2287 
2288         sl.dispose();
2289     }
2290 
2291     @Test public void test_rt_37130_pageDownAtBottom() {
2292         final int items = 100;
2293         root.getChildren().clear();
2294         root.setExpanded(true);
2295         for (int i = 0; i < items; i++) {
2296             root.getChildren().add(new TreeItem<>("Row " + i));
2297         }
2298 
2299         sm.setSelectionMode(SelectionMode.MULTIPLE);
2300 
2301         StageLoader sl = new StageLoader(treeView);
2302 
2303         sm.select(95);
2304         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2305         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2306 
2307         sl.dispose();
2308     }
2309 
2310     private int rt_39088_indices_event_count = 0;
2311     private int rt_39088_items_event_count = 0;
2312     @Test public void test_rt_39088() {
2313         ObservableList<TreeItem<String>> itemsList = FXCollections.observableArrayList();
2314         for (int i = 0; i < 4; i++) {
2315             itemsList.add(new TreeItem<>("Row " + i));
2316         }
2317 
2318         root.setExpanded(true);
2319         root.getChildren().setAll(itemsList);
2320 
2321         MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel();
2322         sm.setSelectionMode(SelectionMode.MULTIPLE);
2323 
2324         ObservableList<Integer> indices = sm.getSelectedIndices();
2325         ObservableList<TreeItem<String>> items = sm.getSelectedItems();
2326 
2327         indices.addListener((ListChangeListener<Integer>) change -> rt_39088_indices_event_count++);
2328         items.addListener((ListChangeListener<TreeItem<String>>) change -> rt_39088_items_event_count++);
2329 
2330         StageLoader sl = new StageLoader(treeView);
2331 
2332         assertEquals(0, rt_39088_indices_event_count);
2333         assertEquals(0, rt_39088_items_event_count);
2334         assertEquals(0, indices.size());
2335         assertEquals(0, items.size());
2336 
2337         sm.select(3);
2338         assertEquals(1, rt_39088_indices_event_count);
2339         assertEquals(1, rt_39088_items_event_count);
2340         assertEquals(1, indices.size());
2341         assertEquals(1, items.size());
2342 
2343         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
2344         assertEquals(2, rt_39088_indices_event_count);
2345         assertEquals(2, rt_39088_items_event_count);
2346         assertEquals(2, indices.size());
2347         assertEquals(2, items.size());
2348 
2349         // this is where the test fails...
2350         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
2351         assertEquals(3, rt_39088_indices_event_count);
2352         assertEquals(3, rt_39088_items_event_count);
2353         assertEquals(3, indices.size());
2354         assertEquals(3, items.size());
2355 
2356         sl.dispose();
2357     }
2358 
2359     @Test public void test_rt_27709_singleSelection_rowSelection() {
2360         test_rt_27709(SelectionMode.SINGLE, false);
2361     }
2362 
2363     @Test public void test_rt_27709_multipleSelection_rowSelection() {
2364         test_rt_27709(SelectionMode.MULTIPLE, false);
2365     }
2366 
2367     @Test public void test_rt_27709_singleSelection_rowSelection_resetSelection() {
2368         test_rt_27709(SelectionMode.SINGLE, true);
2369     }
2370 
2371     @Test public void test_rt_27709_multipleSelection_rowSelection_resetSelection() {
2372         test_rt_27709(SelectionMode.MULTIPLE, true);
2373     }
2374 
2375     private void test_rt_27709(SelectionMode mode, boolean resetSelection) {
2376         root.getChildren().clear();
2377         for (int i = 0; i < 10; i++) {
2378             root.getChildren().add(new TreeItem<>("Row " + i));
2379         }
2380 
2381         root.setExpanded(true);
2382         treeView.setShowRoot(false);
2383 
2384         MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel();
2385         sm.setSelectionMode(mode);
2386 
2387         ObservableList<Integer> indices = sm.getSelectedIndices();
2388 
2389         int expectedSize = mode == SelectionMode.SINGLE ? 1 : 10;
2390         int lookupIndex = mode == SelectionMode.SINGLE ? 0 : 9;
2391 
2392         sm.select(0);
2393         assertEquals(1, indices.size());
2394 
2395         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
2396         assertEquals(debug(), expectedSize, indices.size());
2397         assertEquals(9, (int) indices.get(lookupIndex));
2398 
2399         if (resetSelection) {
2400             sm.clearAndSelect(9);
2401             int anchor = TreeCellBehavior.getAnchor(treeView, null);
2402             assertEquals(9, anchor);
2403         } else {
2404             expectedSize = 1;
2405         }
2406 
2407         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
2408         assertEquals(expectedSize, indices.size());
2409         assertTrue(debug(),sm.isSelected(0));
2410 
2411         if (resetSelection) {
2412             sm.clearAndSelect(0);
2413 
2414             int anchor = TreeCellBehavior.getAnchor(treeView, null);
2415             assertEquals(0, anchor);
2416         } else {
2417             expectedSize = mode == SelectionMode.SINGLE ? 1 : 10;
2418         }
2419 
2420         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
2421         assertEquals(expectedSize, indices.size());
2422         assertTrue(sm.isSelected(9));
2423     }
2424 
2425     @Test public void test_rt_24865_moveDownwards() {
2426         root.getChildren().clear();
2427         for (int i = 0; i < 100; i++) {
2428             root.getChildren().add(new TreeItem<>("Row " + i));
2429         }
2430 
2431         root.setExpanded(true);
2432         treeView.setShowRoot(false);
2433 
2434         Toolkit.getToolkit().firePulse();
2435 
2436         ObservableList<Integer> indices = sm.getSelectedIndices();
2437 
2438         sm.select(0);
2439         assertTrue(isSelected(0));
2440         assertTrue(fm.isFocused(0));
2441         assertEquals(1, indices.size());
2442         assertEquals(0, (int) TreeCellBehavior.getAnchor(treeView, -1));
2443 
2444         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2445         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2446         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2447         assertTrue(isSelected(0, 1, 2, 3));
2448         assertTrue(fm.isFocused(3));
2449         assertEquals(4, indices.size());
2450         assertEquals(0, (int) TreeCellBehavior.getAnchor(treeView, -1));
2451 
2452         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
2453         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
2454         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
2455         assertTrue(isSelected(0, 1, 2, 3));
2456         assertTrue(isNotSelected(4, 5, 6, 7, 8, 9));
2457         assertTrue(fm.isFocused(6));
2458         assertEquals(4, indices.size());
2459         assertEquals(0, (int) TreeCellBehavior.getAnchor(treeView, -1));
2460 
2461         // main point of test: selection between the last index (3) and the focus
2462         // index (6) should now be true
2463         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
2464         final int selectedRowCount = indices.size();
2465         for (int i = 0; i < selectedRowCount; i++) {
2466             assertTrue(isSelected(i));
2467         }
2468         assertTrue(fm.isFocused(selectedRowCount - 1));
2469         assertEquals(0, (int) TreeCellBehavior.getAnchor(treeView, -1));
2470 
2471         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2472         int newSelectedRowCount = selectedRowCount + 1;
2473         for (int i = 0; i < newSelectedRowCount; i++) {
2474             assertTrue(isSelected(i));
2475         }
2476         assertTrue(fm.isFocused(newSelectedRowCount - 1));
2477         assertEquals(0, (int) TreeCellBehavior.getAnchor(treeView, -1));
2478     }
2479 
2480     @Test public void test_rt_24865_moveUpwards() {
2481         root.getChildren().clear();
2482         for (int i = 0; i < 100; i++) {
2483             root.getChildren().add(new TreeItem<>("Row " + i));
2484         }
2485 
2486         root.setExpanded(true);
2487         treeView.setShowRoot(false);
2488 
2489         Toolkit.getToolkit().firePulse();
2490 
2491         ObservableList<Integer> indices = sm.getSelectedIndices();
2492 
2493         sm.select(50);
2494         treeView.scrollTo(50);
2495 
2496         Toolkit.getToolkit().firePulse();
2497 
2498         assertTrue(isSelected(50));
2499         assertTrue(fm.isFocused(50));
2500         assertEquals(1, indices.size());
2501         assertEquals(50, (int) TreeCellBehavior.getAnchor(treeView, -1));
2502 
2503         keyboard.doUpArrowPress(KeyModifier.SHIFT);
2504         keyboard.doUpArrowPress(KeyModifier.SHIFT);
2505         keyboard.doUpArrowPress(KeyModifier.SHIFT);
2506         assertTrue(isSelected(50, 49, 48, 47));
2507         assertTrue(fm.isFocused(47));
2508         assertEquals(4, indices.size());
2509         assertEquals(50, (int) TreeCellBehavior.getAnchor(treeView, -1));
2510 
2511         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
2512         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
2513         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
2514         assertTrue(isSelected(50, 49, 48, 47));
2515         assertTrue(isNotSelected(46, 45, 44, 43, 42, 41));
2516         assertTrue(fm.isFocused(44));
2517         assertEquals(4, indices.size());
2518         assertEquals(50, (int) TreeCellBehavior.getAnchor(treeView, -1));
2519 
2520         // main point of test: selection between the last index (47) and the focus
2521         // index (44) should now be true
2522         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
2523         final int selectedRowCount = indices.size();
2524         for (int i = 0; i < selectedRowCount; i++) {
2525             assertTrue(isSelected(50 - i));
2526         }
2527         assertTrue(fm.isFocused(50 - selectedRowCount + 1));
2528         assertEquals(50, (int) TreeCellBehavior.getAnchor(treeView, -1));
2529 
2530         keyboard.doUpArrowPress(KeyModifier.SHIFT);
2531         int newSelectedRowCount = selectedRowCount + 1;
2532         for (int i = 0; i < newSelectedRowCount; i++) {
2533             assertTrue(isSelected(50 - i));
2534         }
2535         assertTrue(fm.isFocused(50 - newSelectedRowCount + 1));
2536         assertEquals(50, (int) TreeCellBehavior.getAnchor(treeView, -1));
2537     }
2538 }