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.TableCellBehavior;
  29 import com.sun.javafx.scene.control.behavior.TreeTableCellBehavior;
  30 import javafx.beans.property.ReadOnlyStringWrapper;
  31 import javafx.collections.FXCollections;
  32 import javafx.collections.ListChangeListener;
  33 import javafx.collections.ObservableList;
  34 import javafx.scene.input.KeyCode;
  35 import java.util.List;
  36 import java.util.function.Function;
  37 
  38 import com.sun.javafx.PlatformUtil;
  39 import com.sun.javafx.util.Utils;
  40 import com.sun.javafx.scene.control.behavior.TreeTableViewAnchorRetriever;
  41 import com.sun.javafx.scene.control.infrastructure.KeyEventFirer;
  42 import com.sun.javafx.scene.control.infrastructure.KeyModifier;
  43 import com.sun.javafx.scene.control.infrastructure.StageLoader;
  44 import com.sun.javafx.scene.control.infrastructure.VirtualFlowTestUtils;
  45 import com.sun.javafx.tk.Toolkit;
  46 import org.junit.After;
  47 import org.junit.Before;
  48 import org.junit.Ignore;
  49 import org.junit.Test;
  50 import static org.junit.Assert.assertEquals;
  51 import static org.junit.Assert.assertFalse;
  52 import static org.junit.Assert.assertNotSame;
  53 import static org.junit.Assert.assertNull;
  54 import static org.junit.Assert.assertTrue;
  55 import static org.junit.Assert.fail;
  56 
  57 public class TreeTableViewKeyInputTest {
  58     private TreeTableView<String> tableView;
  59     private TreeTableView.TreeTableViewSelectionModel<String> sm;
  60     private TreeTableView.TreeTableViewFocusModel<String> fm;
  61     
  62     private KeyEventFirer keyboard;
  63     
  64     private StageLoader stageLoader;
  65     
  66     private TreeTableColumn<String, String> col0;
  67     private TreeTableColumn<String, String> col1;
  68     private TreeTableColumn<String, String> col2;
  69     private TreeTableColumn<String, String> col3;
  70     private TreeTableColumn<String, String> col4;
  71     
  72     private final TreeItem<String> root = new TreeItem<String>("Root");                     // 0
  73         private final TreeItem<String> child1 = new TreeItem<String>("Child 1");            // 1
  74         private final TreeItem<String> child2 = new TreeItem<String>("Child 2");            // 2
  75         private final TreeItem<String> child3 = new TreeItem<String>("Child 3");            // 3
  76             private final TreeItem<String> subchild1 = new TreeItem<String>("Subchild 1");  // 4
  77             private final TreeItem<String> subchild2 = new TreeItem<String>("Subchild 2");  // 5
  78             private final TreeItem<String> subchild3 = new TreeItem<String>("Subchild 3");  // 6
  79         private final TreeItem<String> child4 = new TreeItem<String>("Child 4");            // 7
  80         private final TreeItem<String> child5 = new TreeItem<String>("Child 5");            // 8
  81         private final TreeItem<String> child6 = new TreeItem<String>("Child 6");            // 9
  82         private final TreeItem<String> child7 = new TreeItem<String>("Child 7");            // 10
  83         private final TreeItem<String> child8 = new TreeItem<String>("Child 8");            // 11
  84         private final TreeItem<String> child9 = new TreeItem<String>("Child 9");            // 12
  85         private final TreeItem<String> child10 = new TreeItem<String>("Child 10");          // 13
  86     
  87     @Before public void setup() {
  88         // reset tree structure
  89         root.getChildren().clear();
  90         root.setExpanded(true);
  91         root.getChildren().setAll(child1, child2, child3, child4, child5, child6, child7, child8, child9, child10 );
  92         child1.getChildren().clear();
  93         child1.setExpanded(false);
  94         child2.getChildren().clear();
  95         child2.setExpanded(false);
  96         child3.getChildren().clear();
  97         child3.setExpanded(true);
  98         child3.getChildren().setAll(subchild1, subchild2, subchild3);
  99         child4.getChildren().clear();
 100         child4.setExpanded(false);
 101         child5.getChildren().clear();
 102         child5.setExpanded(false);
 103         child6.getChildren().clear();
 104         child6.setExpanded(false);
 105         child7.getChildren().clear();
 106         child7.setExpanded(false);
 107         child8.getChildren().clear();
 108         child8.setExpanded(false);
 109         child9.getChildren().clear();
 110         child9.setExpanded(false);
 111         child10.getChildren().clear();
 112         child10.setExpanded(false);
 113         
 114         tableView = new TreeTableView<String>();
 115         sm = tableView.getSelectionModel();
 116         fm = tableView.getFocusModel();
 117         
 118         sm.setSelectionMode(SelectionMode.MULTIPLE);
 119         sm.setCellSelectionEnabled(false);
 120         
 121         tableView.setRoot(root);
 122 
 123         col0 = new TreeTableColumn<String, String>("col0");
 124         col1 = new TreeTableColumn<String, String>("col1");
 125         col2 = new TreeTableColumn<String, String>("col2");
 126         col3 = new TreeTableColumn<String, String>("col3");
 127         col4 = new TreeTableColumn<String, String>("col4");
 128         tableView.getColumns().setAll(col0, col1, col2, col3, col4);
 129         
 130         keyboard = new KeyEventFirer(tableView);
 131         
 132         stageLoader = new StageLoader(tableView);
 133         stageLoader.getStage().show();
 134     }
 135     
 136     @After public void tearDown() {
 137         tableView.getSkin().dispose();
 138         stageLoader.dispose();
 139     }
 140     
 141     /***************************************************************************
 142      * Util methods
 143      **************************************************************************/
 144     
 145     private String debug() {
 146         StringBuilder sb = new StringBuilder("Selected Cells: [");
 147         
 148         List<TreeTablePosition<String,?>> cells = sm.getSelectedCells();
 149         for (TreeTablePosition<String,?> tp : cells) {
 150             sb.append("(");
 151             sb.append(tp.getRow());
 152             sb.append(",");
 153             sb.append(tp.getColumn());
 154             sb.append("), ");
 155         }
 156         
 157         sb.append("] \nFocus: (" + fm.getFocusedCell().getRow() + ", " + fm.getFocusedCell().getColumn() + ")");
 158         
 159         TreeTablePosition anchor = getAnchor();
 160         sb.append(" \nAnchor: (" + (anchor == null ? "null" : anchor.getRow()) + 
 161                 ", " + (anchor == null ? "null" : anchor.getColumn()) + ")");
 162         return sb.toString();
 163     }
 164     
 165     // Returns true if ALL indices are selected
 166     private boolean isSelected(int... indices) {
 167         for (int index : indices) {
 168             if (! sm.isSelected(index)) {
 169                 System.out.println("Index " + index + " is not selected, but it is expected to be (selected indices: " + sm.getSelectedIndices() + ")");
 170                 return false;
 171             }
 172         }
 173         return true;
 174     }
 175     
 176     // Returns true if ALL indices are NOT selected
 177     private boolean isNotSelected(int... indices) {
 178         for (int index : indices) {
 179             if (sm.isSelected(index)) {
 180                 System.out.println("Index " + index + " is selected, but it is not expected to be");
 181                 return false;
 182             }
 183         }
 184         return true;
 185     }
 186     
 187     private TreeTablePosition getAnchor() {
 188         return TreeTableViewAnchorRetriever.getAnchor(tableView);
 189     }
 190     
 191     private boolean isAnchor(int row) {
 192         TreeTablePosition tp = new TreeTablePosition(tableView, row, null);
 193         return getAnchor() != null && getAnchor().equals(tp);
 194     }
 195     
 196     private boolean isAnchor(int row, int col) {
 197         TreeTablePosition tp = new TreeTablePosition(tableView, row, tableView.getColumns().get(col));
 198         return getAnchor() != null && getAnchor().equals(tp);
 199     }
 200     
 201     private int getItemCount() {
 202         return root.getChildren().size() + child3.getChildren().size();
 203     }
 204     
 205     
 206     
 207     /***************************************************************************
 208      * 
 209      * 
 210      * Tests taken from TableViewKeyInputTest
 211      * (scroll down further for the TreeViewKeyInputTests)
 212      * 
 213      * 
 214      **************************************************************************/    
 215     
 216     
 217     /***************************************************************************
 218      * General tests
 219      **************************************************************************/    
 220     
 221     @Test public void testInitialState() {
 222         assertEquals(-1, sm.getSelectedIndex());
 223         assertEquals(0, sm.getSelectedCells().size());
 224         assertEquals(0, sm.getSelectedIndices().size());
 225         assertEquals(0, sm.getSelectedItems().size());
 226     }
 227     
 228     
 229     /***************************************************************************
 230      * Tests for row-based single selection
 231      **************************************************************************/
 232     
 233     @Test public void testDownArrowChangesSelection() {
 234         sm.clearAndSelect(0);
 235         keyboard.doDownArrowPress();
 236         assertFalse(sm.isSelected(0));
 237         assertTrue(sm.isSelected(1));
 238     }
 239     
 240     @Test public void testDownArrowDoesNotChangeSelectionWhenAtLastIndex() {
 241         int endIndex = tableView.getExpandedItemCount() - 1;
 242         sm.clearAndSelect(endIndex);
 243         assertTrue(sm.isSelected(endIndex));
 244         keyboard.doDownArrowPress();
 245         assertTrue(sm.isSelected(endIndex));
 246     }
 247     
 248     @Test public void testUpArrowDoesNotChangeSelectionWhenAt0Index() {
 249         sm.clearAndSelect(0);
 250         keyboard.doUpArrowPress();
 251         assertTrue(sm.isSelected(0));
 252         assertEquals(1, sm.getSelectedCells().size());
 253         assertEquals(1, sm.getSelectedIndices().size());
 254         assertEquals(1, sm.getSelectedItems().size());
 255     }
 256     
 257     @Test public void testUpArrowChangesSelection() {
 258         sm.clearAndSelect(1);
 259         keyboard.doUpArrowPress();
 260         assertFalse(sm.isSelected(1));
 261         assertTrue(sm.isSelected(0));
 262     }
 263     
 264     @Test public void testLeftArrowDoesNotChangeState() {
 265         keyboard.doLeftArrowPress();
 266         testInitialState();
 267     }
 268     
 269 //    @Test public void testRightArrowDoesNotChangeState() {
 270 //        keyboard.doRightArrowPress();
 271 //        testInitialState();
 272 //    }
 273     
 274     /* test 19
 275     @Test public void testCtrlDownMovesFocusButLeavesSelectionAlone() {
 276         assertTrue(fm.isFocused(0));
 277         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 278         assertTrue(fm.isFocused(1));
 279         assertTrue(sm.isSelected(0));
 280         assertFalse(sm.isSelected(1));
 281     } */
 282     
 283     // test 20
 284     @Test public void testCtrlUpDoesNotMoveFocus() {
 285         sm.clearAndSelect(0);
 286         assertTrue(fm.isFocused(0));
 287         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 288         assertTrue(fm.isFocused(0));
 289         assertTrue(sm.isSelected(0));
 290     }
 291     
 292     // test 21
 293     @Test public void testCtrlLeftDoesNotMoveFocus() {
 294         sm.clearAndSelect(0);
 295         assertTrue(fm.isFocused(0));
 296         keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
 297         assertTrue(fm.isFocused(0));
 298         assertTrue(sm.isSelected(0));
 299     }
 300     
 301     // test 22
 302     @Test public void testCtrlRightDoesNotMoveFocus() {
 303         sm.clearAndSelect(0);
 304         assertTrue(fm.isFocused(0));
 305         keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
 306         assertTrue(fm.isFocused(0));
 307         assertTrue(sm.isSelected(0));
 308     }
 309     
 310     /* test 23
 311     @Test public void testCtrlUpMovesFocus() {
 312         sm.clearAndSelect(1);
 313         assertTrue(fm.isFocused(1));
 314         assertTrue(sm.isSelected(1));
 315         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 316         assertTrue(fm.isFocused(0));
 317         assertTrue(sm.isSelected(1));
 318     } */
 319     
 320     // test 24
 321     @Test public void testCtrlDownDoesNotMoveFocusWhenAtLastIndex() {
 322         int endIndex = tableView.getExpandedItemCount() - 1;
 323         sm.clearAndSelect(endIndex);
 324         assertTrue(fm.isFocused(endIndex));
 325         assertTrue(sm.isSelected(endIndex));
 326         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 327         assertTrue(fm.isFocused(endIndex));
 328         assertTrue(sm.isSelected(endIndex));
 329     }
 330     
 331     /* test 25
 332     @Test public void testCtrlDownArrowWithSpaceChangesAnchor() {
 333         sm.clearAndSelect(0);
 334         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 335         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 336         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
 337         assertTrue(isSelected(0, 2));
 338         assertTrue(isNotSelected(1));
 339         assertTrue(isAnchor(2));
 340     } */
 341     
 342     /* test 26
 343     @Test public void testCtrlUpArrowWithSpaceChangesAnchor() {
 344         sm.clearAndSelect(2);
 345         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 346         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 347         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0
 348         assertTrue(isSelected(0, 2));
 349         assertTrue(isNotSelected(1));
 350         assertTrue(isAnchor(0));
 351     } */
 352     
 353     // test 44
 354     @Test public void testHomeKey() {
 355         sm.clearAndSelect(3);
 356         keyboard.doKeyPress(KeyCode.HOME);
 357         assertTrue(isSelected(0));
 358         assertTrue(isNotSelected(1,2,3));
 359     }
 360     
 361     // test 45
 362     @Test public void testEndKey() {
 363         sm.clearAndSelect(3);
 364         keyboard.doKeyPress(KeyCode.END);
 365         assertTrue(isSelected(tableView.getExpandedItemCount() - 1));
 366         assertTrue(isNotSelected(1,2,3));
 367     }
 368     
 369     /* test 53
 370     @Test public void testCtrlHome() {
 371         sm.clearAndSelect(5);
 372         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey());
 373         assertTrue(isSelected(5));
 374         assertTrue(fm.isFocused(0));
 375     } */
 376     
 377     /* test 54
 378     @Test public void testCtrlEnd() {
 379         sm.clearAndSelect(5);
 380         keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey());
 381         assertTrue(isSelected(5));
 382         assertTrue(fm.isFocused(tableView.getItems().size() - 1));
 383     } */
 384     
 385     /* test 68
 386     @Test public void testCtrlSpaceToClearSelection() {
 387         sm.clearAndSelect(5);
 388         assertTrue(isSelected(5));
 389         assertTrue(fm.isFocused(5));
 390         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());
 391         assertTrue(isNotSelected(5));
 392         assertTrue(debug(), fm.isFocused(5));
 393         assertTrue(isAnchor(5));
 394     } */
 395     
 396     
 397     
 398     /***************************************************************************
 399      * Tests for row-based multiple selection
 400      **************************************************************************/
 401     
 402     @Test public void testShiftDownArrowIncreasesSelection() {
 403         sm.clearAndSelect(0);
 404         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 405         assertTrue(sm.isSelected(0));
 406         assertTrue(sm.isSelected(1));
 407     }
 408     
 409     @Test public void testShiftDownArrowDoesNotChangeSelectionWhenAtLastIndex() {
 410         int endIndex = tableView.getExpandedItemCount() - 1;
 411         sm.clearAndSelect(endIndex);
 412         assertTrue(sm.isSelected(endIndex));
 413         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 414         assertTrue(sm.isSelected(endIndex));
 415     }
 416     
 417     @Test public void testShiftUpArrowIncreasesSelection() {
 418         sm.clearAndSelect(1);
 419         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 420         assertTrue(sm.isSelected(0));
 421         assertTrue(sm.isSelected(1));
 422     }
 423     
 424     @Test public void testShiftUpArrowWhenAt0Index() {
 425         sm.clearAndSelect(0);
 426         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 427         assertTrue(sm.isSelected(0));
 428     }
 429     
 430     @Test public void testShiftLeftArrowWhenAt0Index() {
 431         sm.clearAndSelect(0);
 432         keyboard.doLeftArrowPress(KeyModifier.SHIFT);
 433         assertTrue(sm.isSelected(0));
 434         assertFalse(sm.isSelected(1));
 435     }
 436     
 437     @Test public void testShiftRightArrowWhenAt0Index() {
 438         sm.clearAndSelect(0);
 439         keyboard.doRightArrowPress(KeyModifier.SHIFT);
 440         assertTrue(sm.isSelected(0));
 441         assertFalse(sm.isSelected(1));
 442     }
 443     
 444     @Test public void testShiftDownTwiceThenShiftUp() {
 445         sm.clearAndSelect(0);
 446         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 447         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 448         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 449         assertTrue(debug(), isSelected(0, 1));
 450         assertTrue(debug(), isNotSelected(2));
 451     }
 452     
 453     @Test public void testShiftUpTwiceThenShiftDownFrom0Index() {
 454         sm.clearAndSelect(0);
 455         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 456         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 457         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 458         assertTrue(sm.isSelected(0));
 459         assertTrue(sm.isSelected(1));
 460         assertFalse(sm.isSelected(2));
 461     }
 462     
 463     @Test public void testShiftLeftTwiceThenShiftRight() {
 464         sm.clearAndSelect(0);
 465         keyboard.doLeftArrowPress(KeyModifier.SHIFT);
 466         keyboard.doLeftArrowPress(KeyModifier.SHIFT);
 467         keyboard.doRightArrowPress(KeyModifier.SHIFT);
 468         assertTrue(sm.isSelected(0));
 469         assertFalse(sm.isSelected(1));
 470         assertFalse(sm.isSelected(2));
 471     }
 472     
 473     @Test public void testShiftRightTwiceThenShiftLeft() {
 474         sm.clearAndSelect(0);
 475         keyboard.doRightArrowPress(KeyModifier.SHIFT);
 476         keyboard.doRightArrowPress(KeyModifier.SHIFT);
 477         keyboard.doLeftArrowPress(KeyModifier.SHIFT);
 478         assertTrue(sm.isSelected(0));
 479         assertFalse(sm.isSelected(1));
 480         assertFalse(sm.isSelected(2));
 481     }
 482     
 483     @Test public void testShiftUpTwiceThenShiftDown() {
 484         sm.clearAndSelect(2);                           // select 2
 485         keyboard.doUpArrowPress(KeyModifier.SHIFT);     // also select 1
 486         keyboard.doUpArrowPress(KeyModifier.SHIFT);     // also select 0
 487         keyboard.doDownArrowPress(KeyModifier.SHIFT);   // deselect 0
 488         assertFalse(debug(), sm.isSelected(0));
 489         assertTrue(sm.isSelected(1));
 490         assertTrue(sm.isSelected(2));
 491         assertFalse(sm.isSelected(3));
 492     }
 493     
 494     // test 18 from Jindra's testcases.rtf file
 495     @Test public void testShiftDownTwiceThenShiftUpWhenAtLastIndex() {
 496         int endIndex = tableView.getExpandedItemCount() - 1;
 497         sm.clearAndSelect(endIndex);
 498         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 499         keyboard.doDownArrowPress(KeyModifier.SHIFT);
 500         keyboard.doUpArrowPress(KeyModifier.SHIFT);
 501         assertTrue(sm.isSelected(endIndex));
 502         assertTrue(sm.isSelected(endIndex - 1));
 503         assertFalse(sm.isSelected(endIndex - 2));
 504     }
 505     
 506     // test 27
 507     @Test public void testCtrlDownArrowWithSpaceChangesAnchor_extended() {
 508         sm.clearAndSelect(0);
 509         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 510         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 511         keyboard.doKeyPress(KeyCode.SPACE, 
 512                 KeyModifier.getShortcutKey(),
 513                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2
 514         
 515         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 516         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 517         keyboard.doKeyPress(KeyCode.SPACE, 
 518                 KeyModifier.getShortcutKey(),
 519                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // deselect 0
 520         assertTrue(isSelected(2));
 521         assertTrue(isNotSelected(0, 1));
 522         assertTrue(isAnchor(0));
 523     } 
 524     
 525     // test 28
 526     @Test public void testCtrlUpArrowWithSpaceChangesAnchor_extended() {
 527         sm.clearAndSelect(2);
 528         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 529         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 530         keyboard.doKeyPress(KeyCode.SPACE, 
 531                 KeyModifier.getShortcutKey(),
 532                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0
 533         
 534         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 535         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 536         keyboard.doKeyPress(KeyCode.SPACE, 
 537                 KeyModifier.getShortcutKey(),
 538                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // deselect 2
 539         assertTrue(isSelected(0));
 540         assertTrue(isNotSelected(1, 2));
 541         assertTrue(isAnchor(2));
 542     }
 543     
 544     // test 29
 545     @Test public void testCtrlDownArrowWithSpaceChangesAnchor_extended2() {
 546         sm.clearAndSelect(0);
 547         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 548         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 549         keyboard.doKeyPress(KeyCode.SPACE, 
 550                 KeyModifier.getShortcutKey(),
 551                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2
 552         
 553         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 554         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 555         keyboard.doKeyPress(KeyCode.SPACE, 
 556                 KeyModifier.getShortcutKey(),
 557                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 4
 558         assertTrue(isSelected(0, 2, 4));
 559         assertTrue(isNotSelected(1, 3, 5));
 560         assertTrue(isAnchor(4));
 561     }
 562     
 563     // test 30
 564     @Test public void testCtrlUpArrowWithSpaceChangesAnchor_extended2() {
 565         sm.clearAndSelect(4);
 566         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 567         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 568         keyboard.doKeyPress(KeyCode.SPACE, 
 569                 KeyModifier.getShortcutKey(),
 570                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2
 571         
 572         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 573         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 574         keyboard.doKeyPress(KeyCode.SPACE, 
 575                 KeyModifier.getShortcutKey(),
 576                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0
 577         assertTrue(isSelected(0, 2, 4));
 578         assertTrue(isNotSelected(1, 3));
 579         assertTrue(isAnchor(0));
 580     }
 581     
 582     // test 31
 583     @Test public void testCtrlDownArrowThenShiftSpaceToSelectRange() {
 584         sm.clearAndSelect(0);
 585         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 586         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 587         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
 588         assertTrue(isSelected(0, 1, 2));
 589         assertTrue(isNotSelected(3));
 590         assertTrue(isAnchor(0));
 591     }
 592     
 593     // test 32
 594     @Test public void testCtrlUpArrowThenShiftSpaceToSelectRange() {
 595         sm.clearAndSelect(2);
 596         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 597         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 598         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
 599         assertTrue(isSelected(0, 1, 2));
 600         assertTrue(isNotSelected(3));
 601         assertTrue(debug(), isAnchor(2));
 602     }
 603     
 604     // test 33
 605     @Test public void testCtrlDownArrowThenSpaceToChangeSelection() {
 606         sm.clearAndSelect(0);
 607         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 608         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 609         keyboard.doKeyPress(KeyCode.SPACE, 
 610                 KeyModifier.getShortcutKey(),
 611                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2, keeping 0 selected
 612         assertTrue(isSelected(0, 2));
 613         assertTrue(isNotSelected(1, 3));
 614         assertTrue(isAnchor(2));
 615         
 616         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 617         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 618         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 2,3,4
 619         assertTrue(isSelected(2, 3, 4));
 620         assertTrue(isNotSelected(0, 1));
 621         assertTrue(isAnchor(2));
 622     }
 623     
 624     // test 34
 625     @Test public void testCtrlUpArrowThenSpaceToChangeSelection() {
 626         sm.clearAndSelect(4);
 627         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 628         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 629         keyboard.doKeyPress(KeyCode.SPACE, 
 630                 KeyModifier.getShortcutKey(),
 631                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2, keeping 4 selected
 632         assertTrue(isSelected(2, 4));
 633         assertTrue(isNotSelected(0, 1, 3));
 634         assertTrue(isAnchor(2));
 635         
 636         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 637         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 638         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
 639         assertTrue(isSelected(0, 1, 2));
 640         assertTrue(isNotSelected(3, 4));
 641         assertTrue(debug(), isAnchor(2));
 642     }
 643     
 644     // test 35
 645     @Test public void testCtrlDownTwiceThenShiftDown() {
 646         sm.clearAndSelect(0);
 647         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 648         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 649         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);  // select 0,1,2,3
 650         assertTrue(isSelected(0, 1, 2, 3));
 651     }
 652     
 653     // test 36
 654     @Test public void testCtrlUpTwiceThenShiftDown() {
 655         sm.clearAndSelect(3);
 656         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 657         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 658         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 659         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);  // select 1,2,3
 660         assertTrue(isSelected(1, 2, 3));
 661         assertTrue(isNotSelected(0));
 662     }
 663     
 664     // test 37
 665     @Test public void testCtrlDownThriceThenShiftUp() {
 666         sm.clearAndSelect(0);
 667         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 668         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 669         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 670         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);  // select 0,1,2
 671         assertTrue(isSelected(0, 1, 2));
 672         assertTrue(isNotSelected(3, 4));
 673     }
 674     
 675     // test 38
 676     @Test public void testCtrlUpTwiceThenShiftUp() {
 677         sm.clearAndSelect(3);
 678         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 679         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 680         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);  // select 0,1,2,3
 681         assertTrue(isSelected(0, 1, 2, 3));
 682         assertTrue(isNotSelected(4));
 683     }
 684     
 685     // test 39
 686     @Test public void testCtrlDownTwiceThenSpace_extended() {
 687         sm.clearAndSelect(0);
 688         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 689         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 690         keyboard.doKeyPress(KeyCode.SPACE, 
 691                 KeyModifier.getShortcutKey(),
 692                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0,2
 693         assertTrue(isSelected(0, 2));
 694         assertTrue(isNotSelected(1, 3));
 695         assertTrue(isAnchor(2));
 696         
 697         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 698         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 699         keyboard.doDownArrowPress(KeyModifier.SHIFT);   // select 2,3,4,5
 700         assertTrue(isSelected(2, 3, 4, 5));
 701         assertTrue(isNotSelected(0, 1));
 702         assertTrue(isAnchor(2));
 703     }
 704     
 705     // test 40
 706     @Test public void testCtrlUpTwiceThenSpace_extended() {
 707         sm.clearAndSelect(5);
 708         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 709         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 710         keyboard.doKeyPress(KeyCode.SPACE, 
 711                 KeyModifier.getShortcutKey(),
 712                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 3,5
 713         assertTrue(isSelected(3,5));
 714         assertTrue(isNotSelected(0,1,2,4));
 715         assertTrue(isAnchor(3));
 716         
 717         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 718         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 719         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
 720         keyboard.doDownArrowPress(KeyModifier.SHIFT);   // select 1,2,3
 721         assertTrue(isSelected(1,2,3));
 722         assertTrue(isNotSelected(0,4,5));
 723         assertTrue(isAnchor(3));
 724     }
 725     
 726     // test 41
 727     @Test public void testCtrlDownTwiceThenSpace_extended2() {
 728         sm.clearAndSelect(0);
 729         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 730         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 731         keyboard.doKeyPress(KeyCode.SPACE, 
 732                 KeyModifier.getShortcutKey(),
 733                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0,2
 734         assertTrue(isSelected(0,2));
 735         assertTrue(isNotSelected(1,3,4));
 736         assertTrue(isAnchor(2));
 737         
 738         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 739         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 740         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 5
 741         keyboard.doUpArrowPress(KeyModifier.SHIFT);     // select 2,3,4
 742         assertTrue(isSelected(2,3,4));
 743         assertTrue(isNotSelected(0,1,5));
 744         assertTrue(isAnchor(2));
 745     }
 746     
 747     // test 50
 748     @Test public void testCtrlDownThenShiftHome() {
 749         sm.clearAndSelect(0);
 750         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 751         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 752         keyboard.doKeyPress(KeyCode.SPACE, 
 753                 KeyModifier.getShortcutKey(),
 754                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0,2
 755         assertTrue(isSelected(0,2));
 756         assertTrue(isNotSelected(1,3,4));
 757         assertTrue(isAnchor(2));
 758         
 759         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 760         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 761         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
 762         assertTrue(isSelected(0,1,2));
 763         assertTrue(isNotSelected(3,4));
 764         assertTrue(debug(),isAnchor(2));
 765     }
 766     
 767     // test 51
 768     @Test public void testCtrlUpThenShiftEnd() {
 769         sm.clearAndSelect(5);
 770         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 771         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 772         keyboard.doKeyPress(KeyCode.SPACE, 
 773                 KeyModifier.getShortcutKey(),
 774                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 3,5
 775         assertTrue(isSelected(3,5));
 776         assertTrue(isNotSelected(1,2,4));
 777         assertTrue(isAnchor(3));
 778         
 779         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 780         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 781         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
 782         assertTrue(isSelected(3,4,5,6,7,8,9));
 783         assertTrue(isNotSelected(0,1,2));
 784         assertTrue(debug(),isAnchor(3));
 785     }
 786     
 787     // test 42
 788     @Test public void testCtrlUpTwiceThenSpace_extended2() {
 789         sm.clearAndSelect(5);
 790         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
 791         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
 792         keyboard.doKeyPress(KeyCode.SPACE, 
 793                 KeyModifier.getShortcutKey(),
 794                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 3,5
 795         assertTrue(isSelected(3,5));
 796         assertTrue(isNotSelected(0,1,2,4));
 797         assertTrue(isAnchor(3));
 798         
 799         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
 800         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
 801         keyboard.doUpArrowPress(KeyModifier.SHIFT);     // select 0,1,2,3
 802         assertTrue(isSelected(0,1,2,3));
 803         assertTrue(isNotSelected(4,5));
 804         assertTrue(isAnchor(3));
 805     }
 806     
 807     // test 46
 808     @Test public void testHomeKey_withSelectedItems() {
 809         sm.clearSelection();
 810         sm.selectRange(4, 11);
 811         keyboard.doKeyPress(KeyCode.HOME);
 812         assertTrue(isSelected(0));
 813         assertTrue(isNotSelected(1,2,3,4,5,6,7,8,9,10,11));
 814     }
 815     
 816     // test 47
 817     @Test public void testEndKey_withSelectedItems() {
 818         sm.clearSelection();
 819         sm.selectRange(4, 11);
 820         keyboard.doKeyPress(KeyCode.END);
 821         assertTrue(isSelected(tableView.getExpandedItemCount() - 1));
 822         assertTrue(isNotSelected(1,2,3,4,5,6,7,8));
 823     }
 824     
 825     // test 48
 826     @Test public void testShiftHome() {
 827         sm.clearAndSelect(3);
 828         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
 829         assertTrue(isSelected(0,1,2,3));
 830         assertTrue(isNotSelected(4,5));
 831         assertTrue(debug(), isAnchor(3));
 832     }
 833     
 834     // test 49
 835     @Test public void testShiftEnd() {
 836         sm.clearAndSelect(3);
 837         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
 838         assertTrue(isSelected(3,4,5,6,7,8,9));
 839         assertTrue(isNotSelected(0,1,2));
 840         assertTrue(debug(), isAnchor(3));
 841     }
 842     
 843     // test 52
 844     @Test public void testShiftHomeThenShiftEnd() {
 845         sm.clearAndSelect(5);
 846         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
 847         assertTrue(isSelected(0,1,2,3,4,5));
 848         assertTrue(isAnchor(5));
 849         
 850         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
 851         assertTrue(isSelected(5,6,7,8,9));
 852         assertTrue(isAnchor(5));
 853     }
 854     
 855     // test 65
 856     @Test public void testShiftPageUp() {
 857         sm.clearAndSelect(0);
 858         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 859         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 860         keyboard.doKeyPress(KeyCode.SPACE, 
 861                 KeyModifier.getShortcutKey(),
 862                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 863         assertTrue(isSelected(0,2));
 864         assertTrue(isAnchor(2));
 865         
 866         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 867         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 868         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
 869         assertTrue(isSelected(0,1,2));
 870         assertTrue(isAnchor(2));
 871     }
 872     
 873     // test 67
 874     @Test public void testCtrlAToSelectAll() {
 875         sm.clearAndSelect(5);
 876         keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey());
 877         assertTrue(isSelected(0,1,2,3,4,5,6,7,8,9));
 878     }
 879     
 880     
 881     /***************************************************************************
 882      * Tests for cell-based multiple selection
 883      **************************************************************************/    
 884     
 885     @Ignore("Bug persists")
 886     @Test public void testSelectionPathDeviationWorks1() {
 887         // select horizontally, then select two items vertically, then go back
 888         // in opposite direction
 889         sm.setCellSelectionEnabled(true);
 890         sm.clearAndSelect(1, col0);
 891         
 892         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // select (1, col2)
 893         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // select (1, col3)
 894         keyboard.doDownArrowPress(KeyModifier.SHIFT);    // select (2, col3)
 895         keyboard.doDownArrowPress(KeyModifier.SHIFT);    // select (3, col3)
 896         assertTrue(sm.isSelected(1, col2));
 897         assertTrue(sm.isSelected(2, col2));
 898         assertTrue(sm.isSelected(3, col2));
 899         
 900         keyboard.doUpArrowPress(KeyModifier.SHIFT);    // deselect (3, col3)
 901         assertTrue(sm.isSelected(1, col2));
 902         assertTrue(sm.isSelected(2, col2));
 903         assertFalse(sm.isSelected(3, col2));
 904         
 905         keyboard.doUpArrowPress(KeyModifier.SHIFT);    // deselect (2, col3)
 906         assertTrue(sm.isSelected(1, col2));
 907         assertFalse(sm.isSelected(2, col2));
 908         assertFalse(sm.isSelected(3, col2));
 909         
 910         keyboard.doUpArrowPress(KeyModifier.SHIFT);    // deselect (1, col3)
 911         assertFalse(debug(), sm.isSelected(1, col2));
 912         assertFalse(sm.isSelected(2, col2));
 913         assertFalse(sm.isSelected(3, col2));
 914         
 915         keyboard.doLeftArrowPress(KeyModifier.SHIFT);    // deselect (1, col2)
 916         assertFalse(sm.isSelected(1, col1));
 917     }
 918     
 919     
 920     /***************************************************************************
 921      * Tests for discontinuous multiple row selection (RT-18951)
 922      **************************************************************************/    
 923     
 924     // Test 1
 925     @Test public void test_rt18591_row_1() {
 926         sm.clearAndSelect(0);
 927         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 928         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 929         keyboard.doKeyPress(KeyCode.SPACE, 
 930                 KeyModifier.getShortcutKey(),
 931                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 932         assertTrue(isSelected(0,2));
 933         assertTrue(isAnchor(2));
 934         
 935         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 936         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 937         assertTrue(isSelected(0,2,3,4));
 938         assertTrue(isAnchor(2));
 939     }
 940     
 941     // Test 2
 942     @Test public void test_rt18591_row_2() {
 943         sm.clearAndSelect(5);
 944         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 945         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 946         keyboard.doKeyPress(KeyCode.SPACE, 
 947                 KeyModifier.getShortcutKey(),
 948                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 949         assertTrue(isSelected(3,5));
 950         assertTrue(isAnchor(3));
 951         
 952         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 953         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 954         assertTrue(isSelected(1,2,3,5));
 955         assertTrue(isAnchor(3));
 956     }
 957     
 958     // Test 3
 959     @Test public void test_rt18591_row_3() {
 960         // same as test 1 above
 961         sm.clearAndSelect(0);
 962         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 963         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
 964         keyboard.doKeyPress(KeyCode.SPACE, 
 965                 KeyModifier.getShortcutKey(),
 966                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 967         assertTrue(isSelected(0,2));
 968         assertTrue(isAnchor(2));
 969         
 970         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 971         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 972         assertTrue(isSelected(0,2,3,4));
 973         assertTrue(isAnchor(2));
 974         // end of similarities
 975         
 976         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 977         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 978         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 979         assertTrue(isSelected(0,1,2,3,4));
 980         assertTrue(isAnchor(2));
 981     }
 982     
 983     // Test 4
 984     @Test public void test_rt18591_row_4() {
 985         // same as test 2 above
 986         sm.clearAndSelect(5);
 987         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 988         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
 989         keyboard.doKeyPress(KeyCode.SPACE, 
 990                 KeyModifier.getShortcutKey(),
 991                 (Utils.isMac()  ? KeyModifier.CTRL : null));
 992         assertTrue(isSelected(3,5));
 993         assertTrue(isAnchor(3));
 994         
 995         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 996         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
 997         assertTrue(isSelected(1,2,3,5));
 998         assertTrue(isAnchor(3));
 999         // end of similarities
1000         
1001         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1002         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1003         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1004         assertTrue(isSelected(1,2,3,4,5));
1005         assertTrue(isAnchor(3));
1006     }
1007     
1008     // Test 5 (need Page down support)
1009 //    @Test public void test_5() {
1010 //        // same as test 1 above
1011 //        sm.clearAndSelect(0);
1012 //        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1013 //        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1014 //        keyboard.doKeyPress(KeyCode.SPACE, 
1015 //                KeyModifier.getShortcutKey(),
1016 //                (Utils.isMac()  ? KeyModifier.CTRL : null));
1017 //        assertTrue(isSelected(0,2));
1018 //        assertTrue(isAnchor(2));
1019 //        // end of similarities
1020 //        
1021 //        keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1022 //        assertTrue(isSelected(0,2,/*until end of page */));
1023 //        assertTrue(isAnchor(2));
1024 //    }
1025     
1026     // Test 6
1027     @Test public void test_rt18591_row_6() {
1028         sm.clearAndSelect(10);
1029         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1030         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1031         keyboard.doKeyPress(KeyCode.SPACE, 
1032                 KeyModifier.getShortcutKey(),
1033                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1034         assertTrue(debug(), isSelected(8,10));
1035         assertTrue(isAnchor(8));
1036         
1037         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1038         assertTrue(isSelected(0,1,2,3,4,5,6,7,8,10));
1039         assertTrue(isAnchor(8));
1040     }
1041     
1042 //    // Test 7
1043 //    @Test public void test_rt18591_row_7() {
1044 //        sm.clearAndSelect(0);
1045 //        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1046 //        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1047 //        keyboard.doKeyPress(KeyCode.SPACE, 
1048 //                KeyModifier.getShortcutKey(),
1049 //                (Utils.isMac()  ? KeyModifier.CTRL : null));
1050 //        assertTrue(isSelected(0,2));
1051 //        assertTrue(isAnchor(2));
1052 //        
1053 //        keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1054 //        keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1055 //        assertTrue(isSelected(0,2,3,4,5,6,7,8,10)); // this isn't right
1056 //        assertTrue(isAnchor(8));
1057 //        
1058 //        // NOT COMPLETE
1059 //    }
1060 //    
1061 //    // Test 8
1062 //    @Test public void test_rt18591_row_8() {
1063 //        // NOT COMPLETE
1064 //    }
1065     
1066     // Test 9
1067     @Test public void test_rt18591_row_9() {
1068         sm.clearAndSelect(0);
1069         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1070         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1071         keyboard.doKeyPress(KeyCode.SPACE, 
1072                 KeyModifier.getShortcutKey(),
1073                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1074         assertTrue(isSelected(0,2));
1075         assertTrue(isAnchor(2));
1076         
1077         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1078         assertTrue(isSelected(0,2,3,4,5,6,7,8,9));
1079         assertTrue(isAnchor(2));
1080     }
1081     
1082     // Test 10
1083     @Test public void test_rt18591_row_10() {
1084         sm.clearAndSelect(8);
1085         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1086         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1087         keyboard.doKeyPress(KeyCode.SPACE, 
1088                 KeyModifier.getShortcutKey(),
1089                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1090         assertTrue(isSelected(6,8));
1091         assertTrue(isAnchor(6));
1092         
1093         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1094         assertTrue(isSelected(0,1,2,3,4,5,6,8));
1095         assertTrue(isAnchor(6));
1096     }
1097     
1098     // Test 11
1099     @Test public void test_rt18591_row_11() {
1100         sm.clearAndSelect(5);
1101         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1102         assertTrue(isSelected(0,1,2,3,4,5));
1103         assertTrue(isAnchor(5));
1104         
1105         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1106         assertTrue(isSelected(0,1,2,3,4,5,6,7,8,9));
1107         assertTrue(isAnchor(5));
1108     }
1109     
1110     // Test 12
1111     @Test public void test_rt18591_row_12() {
1112         sm.clearAndSelect(0);
1113         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1114         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1115         keyboard.doKeyPress(KeyCode.SPACE, 
1116                 KeyModifier.getShortcutKey(),
1117                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1118         assertTrue(isSelected(0,2));
1119         assertTrue(isAnchor(2));
1120         
1121         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1122         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1123         assertTrue(isSelected(0,2,3,4));
1124         assertTrue(isAnchor(2));
1125         
1126         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1127         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1128         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1129         assertTrue(isSelected(0,1,2,3,4));
1130         assertTrue(isAnchor(2));
1131         
1132         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1133         keyboard.doKeyPress(KeyCode.SPACE, 
1134                 KeyModifier.getShortcutKey(),
1135                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1136         assertTrue(isSelected(1,2,3,4));
1137         assertTrue(isAnchor(0));
1138         assertTrue(fm.isFocused(0));
1139     }
1140     
1141     
1142     /***************************************************************************
1143      * Tests for discontinuous multiple cell selection (RT-18951)
1144      **************************************************************************/  
1145     
1146     // Test 1
1147     @Test public void test_rt18591_cell_1() {
1148         sm.setSelectionMode(SelectionMode.MULTIPLE);
1149         sm.setCellSelectionEnabled(true);
1150         sm.select(0, col0);
1151         keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
1152         keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
1153         keyboard.doKeyPress(KeyCode.SPACE, 
1154                 KeyModifier.getShortcutKey(),
1155                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1156         assertTrue(sm.isSelected(0,col0));
1157         assertTrue(sm.isSelected(0,col2));
1158         assertTrue(isAnchor(0,2));
1159         
1160         keyboard.doRightArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1161         keyboard.doRightArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1162         assertTrue(sm.isSelected(0,col0));
1163         assertTrue(sm.isSelected(0,col2));
1164         assertTrue(sm.isSelected(0,col3));
1165         assertTrue(sm.isSelected(0,col4));
1166         assertTrue(isAnchor(0,2));
1167     }
1168     
1169     // Test 2
1170     @Test public void test_rt18591_cell_2() {
1171         sm.setSelectionMode(SelectionMode.MULTIPLE);
1172         sm.setCellSelectionEnabled(true);
1173         sm.select(0, col4);
1174         keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
1175         keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
1176         keyboard.doKeyPress(KeyCode.SPACE, 
1177                 KeyModifier.getShortcutKey(),
1178                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1179         assertTrue(sm.isSelected(0,col4));
1180         assertTrue(sm.isSelected(0,col2));
1181         assertTrue(isAnchor(0,2));
1182         
1183         keyboard.doLeftArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1184         keyboard.doLeftArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1185         assertTrue(sm.isSelected(0,col0));
1186         assertTrue(sm.isSelected(0,col1));
1187         assertTrue(sm.isSelected(0,col2));
1188         assertTrue(sm.isSelected(0,col4));
1189         assertTrue(isAnchor(0,2));
1190     }
1191     
1192     // Test 3
1193     @Test public void test_rt18591_cell_3() {
1194         sm.setSelectionMode(SelectionMode.MULTIPLE);
1195         sm.setCellSelectionEnabled(true);
1196         sm.select(0, col0);
1197         keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
1198         keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
1199         keyboard.doKeyPress(KeyCode.SPACE, 
1200                 KeyModifier.getShortcutKey(),
1201                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1202         assertTrue(sm.isSelected(0,col0));
1203         assertTrue(sm.isSelected(0,col2));
1204         assertTrue(isAnchor(0,2));
1205         
1206         keyboard.doRightArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1207         keyboard.doRightArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1208         assertTrue(sm.isSelected(0,col0));
1209         assertTrue(sm.isSelected(0,col2));
1210         assertTrue(sm.isSelected(0,col3));
1211         assertTrue(sm.isSelected(0,col4));
1212         assertTrue(isAnchor(0,2));
1213         
1214         keyboard.doLeftArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1215         keyboard.doLeftArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1216         keyboard.doLeftArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1217         assertTrue(sm.isSelected(0,col0));
1218         assertTrue(sm.isSelected(0,col1));
1219         assertTrue(sm.isSelected(0,col2));
1220         assertTrue(sm.isSelected(0,col3));
1221         assertTrue(sm.isSelected(0,col4));
1222         assertTrue(isAnchor(0,2));
1223     }
1224     
1225     // Test 4
1226     @Test public void test_rt18591_cell_4() {
1227         sm.setSelectionMode(SelectionMode.MULTIPLE);
1228         sm.setCellSelectionEnabled(true);
1229         sm.select(0, col4);
1230         keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
1231         keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
1232         keyboard.doKeyPress(KeyCode.SPACE, 
1233                 KeyModifier.getShortcutKey(),
1234                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1235         assertTrue(sm.isSelected(0,col4));
1236         assertTrue(sm.isSelected(0,col2));
1237         assertTrue(isAnchor(0,2));
1238         
1239         keyboard.doLeftArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1240         keyboard.doLeftArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1241         assertTrue(sm.isSelected(0,col0));
1242         assertTrue(sm.isSelected(0,col1));
1243         assertTrue(sm.isSelected(0,col2));
1244         assertTrue(sm.isSelected(0,col4));
1245         assertTrue(isAnchor(0,2));
1246         
1247         keyboard.doRightArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1248         keyboard.doRightArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1249         keyboard.doRightArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1250         assertTrue(sm.isSelected(0,col0));
1251         assertTrue(sm.isSelected(0,col1));
1252         assertTrue(sm.isSelected(0,col2));
1253         assertTrue(sm.isSelected(0,col3));
1254         assertTrue(sm.isSelected(0,col4));
1255         assertTrue(isAnchor(0,2));
1256     }
1257     
1258     // Test 5
1259     @Test public void test_rt18591_cell_5() {
1260         sm.setSelectionMode(SelectionMode.MULTIPLE);
1261         sm.setCellSelectionEnabled(true);
1262         sm.select(0, col1);
1263         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1264         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1265         keyboard.doKeyPress(KeyCode.SPACE, 
1266                 KeyModifier.getShortcutKey(),
1267                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1268         assertTrue(sm.isSelected(0,col1));
1269         assertTrue(sm.isSelected(2,col1));
1270         assertTrue(isAnchor(2,1));
1271         
1272         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1273         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1274         assertTrue(sm.isSelected(0,col1));
1275         assertTrue(sm.isSelected(2,col1));
1276         assertTrue(sm.isSelected(3,col1));
1277         assertTrue(sm.isSelected(4,col1));
1278         assertTrue(isAnchor(2,1));
1279     }
1280     
1281     // Test 6
1282     @Test public void test_rt18591_cell_6() {
1283         sm.setSelectionMode(SelectionMode.MULTIPLE);
1284         sm.setCellSelectionEnabled(true);
1285         sm.select(5, col1);
1286         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1287         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1288         keyboard.doKeyPress(KeyCode.SPACE, 
1289                 KeyModifier.getShortcutKey(),
1290                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1291         assertTrue(sm.isSelected(5,col1));
1292         assertTrue(sm.isSelected(3,col1));
1293         assertTrue(isAnchor(3,1));
1294         
1295         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1296         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1297         assertTrue(sm.isSelected(1,col1));
1298         assertTrue(sm.isSelected(2,col1));
1299         assertTrue(sm.isSelected(3,col1));
1300         assertTrue(sm.isSelected(5,col1));
1301         assertTrue(isAnchor(3,1));
1302     }
1303     
1304     // Test 7
1305     @Test public void test_rt18591_cell_7() {
1306         sm.setSelectionMode(SelectionMode.MULTIPLE);
1307         sm.setCellSelectionEnabled(true);
1308         sm.select(0, col1);
1309         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1310         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1311         keyboard.doKeyPress(KeyCode.SPACE, 
1312                 KeyModifier.getShortcutKey(),
1313                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1314         assertTrue(sm.isSelected(0,col1));
1315         assertTrue(sm.isSelected(2,col1));
1316         assertTrue(isAnchor(2,1));
1317         
1318         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1319         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1320         assertTrue(sm.isSelected(0,col1));
1321         assertTrue(sm.isSelected(2,col1));
1322         assertTrue(sm.isSelected(3,col1));
1323         assertTrue(sm.isSelected(4,col1));
1324         assertTrue(isAnchor(2,1));
1325         
1326         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1327         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1328         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1329         assertTrue(sm.isSelected(0,col1));
1330         assertTrue(sm.isSelected(1,col1));
1331         assertTrue(sm.isSelected(2,col1));
1332         assertTrue(sm.isSelected(3,col1));
1333         assertTrue(sm.isSelected(4,col1));
1334         assertTrue(isAnchor(2,1));
1335     }
1336     
1337     // Test 8
1338     @Test public void test_rt18591_cell_8() {
1339         sm.setSelectionMode(SelectionMode.MULTIPLE);
1340         sm.setCellSelectionEnabled(true);
1341         sm.select(5, col1);
1342         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1343         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1344         keyboard.doKeyPress(KeyCode.SPACE, 
1345                 KeyModifier.getShortcutKey(),
1346                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1347         assertTrue(sm.isSelected(5,col1));
1348         assertTrue(sm.isSelected(3,col1));
1349         assertTrue(isAnchor(3,1));
1350         
1351         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1352         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1353         assertTrue(sm.isSelected(1,col1));
1354         assertTrue(sm.isSelected(2,col1));
1355         assertTrue(sm.isSelected(3,col1));
1356         assertTrue(sm.isSelected(5,col1));
1357         assertTrue(isAnchor(3,1));
1358         
1359         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1360         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1361         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1362         assertTrue(sm.isSelected(1,col1));
1363         assertTrue(sm.isSelected(2,col1));
1364         assertTrue(sm.isSelected(3,col1));
1365         assertTrue(sm.isSelected(4,col1));
1366         assertTrue(sm.isSelected(5,col1));
1367         assertTrue(isAnchor(3,1));
1368     }
1369     
1370     // Skipped tests 9 - 12 as they require Page Up/Down support
1371     
1372     // Test 13
1373     @Test public void test_rt18591_cell_13() {
1374         sm.setSelectionMode(SelectionMode.MULTIPLE);
1375         sm.setCellSelectionEnabled(true);
1376         sm.select(0, col1);
1377         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1378         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1379         keyboard.doKeyPress(KeyCode.SPACE, 
1380                 KeyModifier.getShortcutKey(),
1381                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1382         assertTrue(sm.isSelected(0,col1));
1383         assertTrue(sm.isSelected(2,col1));
1384         assertTrue(isAnchor(2,1));
1385         
1386         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1387         assertTrue(sm.isSelected(0,col1));
1388         for (int i = 2; i < tableView.getExpandedItemCount(); i++) {
1389             assertTrue(debug(),sm.isSelected(i,col1));
1390         }
1391         assertTrue(isAnchor(2,1));
1392     }
1393     
1394     // Test 14
1395     @Test public void test_rt18591_cell_14() {
1396         int n = tableView.getExpandedItemCount() - 1;
1397         sm.setSelectionMode(SelectionMode.MULTIPLE);
1398         sm.setCellSelectionEnabled(true);
1399         sm.select(n, col1);
1400         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1401         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1402         keyboard.doKeyPress(KeyCode.SPACE, 
1403                 KeyModifier.getShortcutKey(),
1404                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1405         assertTrue(sm.isSelected(n,col1));
1406         assertTrue(sm.isSelected(n - 2,col1));
1407         assertTrue(isAnchor(n - 2,1));
1408         
1409         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1410         assertTrue(sm.isSelected(n,col1));
1411         for (int i = 0; i < n - 2; i++) {
1412             assertTrue(sm.isSelected(i,col1));
1413         }
1414         assertTrue(isAnchor(n - 2,1));
1415     }
1416     
1417     // Test 15
1418     @Test public void test_rt18591_cell_15() {
1419         sm.setSelectionMode(SelectionMode.MULTIPLE);
1420         sm.setCellSelectionEnabled(true);
1421         sm.select(5, col1);
1422 
1423         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1424         for (int i = 0; i <= 5; i++) {
1425             assertTrue(sm.isSelected(i,col1));
1426         }
1427         assertTrue(debug(), isAnchor(5,1));
1428         
1429         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1430         for (int i = 0; i < tableView.getExpandedItemCount() - 1; i++) {
1431             assertTrue(sm.isSelected(i,col1));
1432         }
1433         assertTrue(isAnchor(5,1));
1434     }
1435     
1436     // Test 16
1437     @Test public void test_rt18591_cell_16() {
1438         sm.setSelectionMode(SelectionMode.MULTIPLE);
1439         sm.setCellSelectionEnabled(true);
1440         sm.select(0, col1);
1441         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1442         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1443         keyboard.doKeyPress(KeyCode.SPACE, 
1444                 KeyModifier.getShortcutKey(),
1445                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1446         assertTrue(sm.isSelected(0,col1));
1447         assertTrue(sm.isSelected(2,col1));
1448         assertTrue(isAnchor(2,1));
1449         
1450         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1451         keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1452         assertTrue(sm.isSelected(0,col1));
1453         assertTrue(sm.isSelected(2,col1));
1454         assertTrue(sm.isSelected(3,col1));
1455         assertTrue(sm.isSelected(4,col1));
1456         assertTrue(isAnchor(2,1));
1457         
1458         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1459         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1460         keyboard.doUpArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1461         assertTrue(sm.isSelected(0,col1));
1462         assertTrue(sm.isSelected(1,col1));
1463         assertTrue(sm.isSelected(2,col1));
1464         assertTrue(sm.isSelected(3,col1));
1465         assertTrue(sm.isSelected(4,col1));
1466         assertTrue(isAnchor(2,1));
1467         
1468         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1469         keyboard.doKeyPress(KeyCode.SPACE, 
1470                 KeyModifier.getShortcutKey(),
1471                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1472         assertFalse(sm.isSelected(0,col1));
1473         assertTrue(sm.isSelected(1,col1));
1474         assertTrue(sm.isSelected(2,col1));
1475         assertTrue(sm.isSelected(3,col1));
1476         assertTrue(sm.isSelected(4,col1));
1477         assertTrue(isAnchor(0,1));
1478         assertTrue(fm.isFocused(0,col1));
1479     }
1480     
1481 //    // Test 17
1482 //    @Test public void test_rt18591_cell_17() {
1483 //        sm.setSelectionMode(SelectionMode.MULTIPLE);
1484 //        sm.setCellSelectionEnabled(true);
1485 //        sm.select(3, col1);
1486 //        keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
1487 //        keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
1488 //        keyboard.doKeyPress(KeyCode.SPACE, 
1489 //                KeyModifier.getShortcutKey(),
1490 //                (Utils.isMac()  ? KeyModifier.CTRL : null));
1491 //        assertTrue(sm.isSelected(3,col1));
1492 //        assertTrue(sm.isSelected(3,col3));
1493 //        assertTrue(isAnchor(3,3));
1494 //        
1495 //        keyboard.doRightArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1496 //        assertTrue(sm.isSelected(3,col1));
1497 //        assertTrue(sm.isSelected(3,col3));
1498 //        assertTrue(sm.isSelected(3,col4));
1499 //        assertTrue(isAnchor(3,3));
1500 //        
1501 //        keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1502 //        keyboard.doDownArrowPress(KeyModifier.SHIFT, KeyModifier.getShortcutKey());
1503 //        assertTrue(sm.isSelected(3,col1));
1504 //        assertTrue(sm.isSelected(3,col3));
1505 //        assertTrue(sm.isSelected(3,col4));
1506 //        assertTrue(sm.isSelected(4,col3));
1507 //        assertTrue(sm.isSelected(5,col3));
1508 //        assertTrue(isAnchor(3,3));
1509 //    }
1510     
1511     
1512     /***************************************************************************
1513      * Tests for specific bug reports
1514      **************************************************************************/
1515     
1516     @Test public void test_rt18488_selectToLeft() {
1517         sm.setCellSelectionEnabled(true);
1518         sm.clearAndSelect(1, col4);
1519         
1520         keyboard.doLeftArrowPress(KeyModifier.SHIFT);   // select (1, col4)
1521         keyboard.doLeftArrowPress(KeyModifier.SHIFT);   // select (1, col3)
1522         keyboard.doLeftArrowPress(KeyModifier.SHIFT);   // select (1, col2)
1523         keyboard.doLeftArrowPress(KeyModifier.SHIFT);   // select (1, col1)
1524         assertTrue(sm.isSelected(1, col4));
1525         assertTrue(sm.isSelected(1, col3));
1526         assertTrue(sm.isSelected(1, col2));
1527         assertTrue(sm.isSelected(1, col1));
1528         assertTrue(sm.isSelected(1, col0));
1529         
1530         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // deselect (1, col1)
1531         assertTrue(sm.isSelected(1, col4));
1532         assertTrue(sm.isSelected(1, col3));
1533         assertTrue(sm.isSelected(1, col2));
1534         assertTrue(debug(), sm.isSelected(1, col1));
1535         assertFalse(sm.isSelected(1, col0));
1536     }
1537     
1538     @Test public void test_rt18488_selectToRight() {
1539         sm.setCellSelectionEnabled(true);
1540         sm.clearAndSelect(1, col0);
1541         
1542         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // select (1, col2)
1543         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // select (1, col3)
1544         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // select (1, col4)
1545         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // select (1, col5)
1546         assertTrue(sm.isSelected(1, col4));
1547         assertTrue(sm.isSelected(1, col3));
1548         assertTrue(sm.isSelected(1, col2));
1549         assertTrue(sm.isSelected(1, col1));
1550         assertTrue(sm.isSelected(1, col0));
1551         
1552         keyboard.doLeftArrowPress(KeyModifier.SHIFT);   // deselect (1, col5)
1553         assertFalse(sm.isSelected(1, col4));
1554         assertTrue(sm.isSelected(1, col3));
1555         assertTrue(sm.isSelected(1, col2));
1556         assertTrue(sm.isSelected(1, col1));
1557         assertTrue(sm.isSelected(1, col0));
1558     }
1559     
1560     @Test public void test_rt18488_comment1() {
1561         sm.setCellSelectionEnabled(true);
1562         sm.clearAndSelect(1, col0);
1563         
1564         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // select (1, col2)
1565         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // select (1, col3)
1566         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // select (1, col4)
1567         keyboard.doRightArrowPress(KeyModifier.SHIFT);   // select (1, col5)
1568         keyboard.doDownArrowPress(KeyModifier.SHIFT);    // select (2, col5)
1569         
1570         assertTrue(sm.isSelected(2, col4));
1571         assertTrue(sm.isSelected(1, col4));
1572         assertTrue(sm.isSelected(1, col3));
1573         assertTrue(sm.isSelected(1, col2));
1574         assertTrue(sm.isSelected(1, col1));
1575         assertTrue(sm.isSelected(1, col0));
1576         
1577         keyboard.doUpArrowPress(KeyModifier.SHIFT);     // deselect (2, col5)
1578         assertFalse(sm.isSelected(2, col4));
1579         assertTrue(sm.isSelected(1, col4));
1580         assertTrue(sm.isSelected(1, col3));
1581         assertTrue(sm.isSelected(1, col2));
1582         assertTrue(sm.isSelected(1, col1));
1583         assertTrue(sm.isSelected(1, col0));
1584     }
1585     
1586     @Test public void test_rt18536_positive_horizontal() {
1587         // Test shift selection when focus is elsewhere (so as to select a range)
1588         sm.setCellSelectionEnabled(true);
1589         sm.clearAndSelect(1, col0);
1590         
1591         // move focus by holding down ctrl button
1592         keyboard.doRightArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col2)
1593         keyboard.doRightArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col3)
1594         keyboard.doRightArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col4)
1595         keyboard.doRightArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col5)
1596         assertTrue(fm.isFocused(1, col4));
1597         
1598         // press shift + space to select all cells between (1, col1) and (1, col5)
1599         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
1600         assertTrue(sm.isSelected(1, col4));
1601         assertTrue(debug(), sm.isSelected(1, col3));
1602         assertTrue(sm.isSelected(1, col2));
1603         assertTrue(sm.isSelected(1, col1));
1604         assertTrue(sm.isSelected(1, col0));
1605     }
1606     
1607     @Test public void test_rt18536_negative_horizontal() {
1608         // Test shift selection when focus is elsewhere (so as to select a range)
1609         sm.setCellSelectionEnabled(true);
1610         sm.clearAndSelect(1, col4);
1611         
1612         // move focus by holding down ctrl button
1613         keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col4)
1614         keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col3)
1615         keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col2)
1616         keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col1)
1617         assertTrue(fm.isFocused(1, col0));
1618         
1619         // press shift + space to select all cells between (1, col1) and (1, col5)
1620         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
1621         assertTrue(debug(), sm.isSelected(1, col4));
1622         assertTrue(sm.isSelected(1, col3));
1623         assertTrue(sm.isSelected(1, col2));
1624         assertTrue(sm.isSelected(1, col1));
1625         assertTrue(sm.isSelected(1, col0));
1626     }
1627 
1628     //
1629     @Test public void test_rt18536_positive_vertical() {
1630         // Test shift selection when focus is elsewhere (so as to select a range)
1631         sm.setCellSelectionEnabled(true);
1632         sm.clearAndSelect(1, col4);
1633         
1634         // move focus by holding down ctrl button
1635         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // move focus to (2, col5)
1636         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // move focus to (3, col5)
1637         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // move focus to (4, col5)
1638         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // move focus to (5, col5)
1639         assertTrue(fm.isFocused(5, col4));
1640         
1641         // press shift + space to select all cells between (1, col5) and (5, col5)
1642         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
1643         assertTrue(sm.isSelected(1, col4));
1644         assertTrue(sm.isSelected(2, col4));
1645         assertTrue(sm.isSelected(3, col4));
1646         assertTrue(sm.isSelected(4, col4));
1647         assertTrue(sm.isSelected(5, col4));
1648     }
1649     
1650     //
1651     @Test public void test_rt18536_negative_vertical() {
1652         // Test shift selection when focus is elsewhere (so as to select a range)
1653         sm.setCellSelectionEnabled(true);
1654         sm.clearAndSelect(5, col4);
1655         
1656         // move focus by holding down ctrl button
1657         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());   // move focus to (4, col5)
1658         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());   // move focus to (3, col5)
1659         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());   // move focus to (2, col5)
1660         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col5)
1661         assertTrue(fm.isFocused(1, col4));
1662         
1663         // press shift + space to select all cells between (1, col5) and (5, col5)
1664         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
1665         assertTrue(sm.isSelected(1, col4));
1666         assertTrue(sm.isSelected(2, col4));
1667         assertTrue(sm.isSelected(3, col4));
1668         assertTrue(sm.isSelected(4, col4));
1669         assertTrue(sm.isSelected(5, col4));
1670     }
1671     
1672     //
1673     @Test public void test_rt18642() {
1674         sm.setCellSelectionEnabled(false);
1675         sm.clearAndSelect(1);                          // select 1
1676         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 2
1677         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 3
1678         keyboard.doKeyPress(KeyCode.SPACE, 
1679                 KeyModifier.getShortcutKey(),
1680                 (Utils.isMac()  ? KeyModifier.CTRL : null)); // set anchor, and also select, 3
1681         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 4
1682         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 5
1683         keyboard.doKeyPress(KeyCode.SPACE, 
1684                 KeyModifier.getShortcutKey(),
1685                 (Utils.isMac()  ? KeyModifier.CTRL : null)); // set anchor, and also select, 5
1686         
1687         assertTrue(isSelected(1, 3, 5));
1688         assertTrue(isNotSelected(0, 2, 4));
1689         
1690         // anchor is at 5, so shift+UP should select rows 4 and 5 only
1691         keyboard.doUpArrowPress(KeyModifier.SHIFT);   
1692         assertTrue(isSelected(4, 5));
1693         assertTrue(isNotSelected(0, 1, 2, 3));
1694     }
1695     
1696     
1697     
1698     
1699     
1700     /***************************************************************************
1701      * 
1702      * 
1703      * Tests taken from TreeViewKeyInputTest
1704      * 
1705      * 
1706      **************************************************************************/  
1707     
1708     /***************************************************************************
1709      * Tests for row-based single selection
1710      **************************************************************************/
1711     
1712     // test 19
1713     @Test public void testCtrlDownMovesFocusButLeavesSelectionAlone() {
1714         sm.clearAndSelect(0);
1715         assertTrue(fm.isFocused(0));
1716         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1717         assertTrue(fm.isFocused(1));
1718         assertTrue(sm.isSelected(0));
1719         assertFalse(sm.isSelected(1));
1720     }
1721     
1722     // test 23
1723     @Test public void testCtrlUpMovesFocus() {
1724         sm.clearAndSelect(1);
1725         assertTrue(fm.isFocused(1));
1726         assertTrue(sm.isSelected(1));
1727         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1728         assertTrue(fm.isFocused(0));
1729         assertTrue(sm.isSelected(1));
1730     }
1731     
1732     // test 25
1733     @Test public void testCtrlDownArrowWithSpaceChangesAnchor() {
1734         sm.clearAndSelect(0);
1735         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
1736         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
1737         keyboard.doKeyPress(KeyCode.SPACE, 
1738                 KeyModifier.getShortcutKey(),
1739                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 2
1740         assertTrue(isSelected(0, 2));
1741         assertTrue(isNotSelected(1));
1742         assertTrue(isAnchor(2));
1743     }
1744     
1745     // test 26
1746     @Test public void testCtrlUpArrowWithSpaceChangesAnchor() {
1747         sm.clearAndSelect(2);
1748         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
1749         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
1750         keyboard.doKeyPress(KeyCode.SPACE, 
1751                 KeyModifier.getShortcutKey(),
1752                 (Utils.isMac()  ? KeyModifier.CTRL : null));  // select 0
1753         assertTrue(isSelected(0, 2));
1754         assertTrue(isNotSelected(1));
1755         assertTrue(isAnchor(0));
1756     }
1757     
1758     // test 53
1759     @Test public void testCtrlHome() {
1760         sm.clearAndSelect(5);
1761         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey());
1762         assertTrue(isSelected(5));
1763         assertTrue(fm.isFocused(0));
1764     }
1765     
1766     // test 54
1767     @Test public void testCtrlEnd() {
1768         sm.clearAndSelect(5);
1769         keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey());
1770         assertTrue(isSelected(5));
1771         assertTrue(fm.isFocused(getItemCount()));
1772     }
1773     
1774     // test 68
1775     @Test public void testCtrlSpaceToClearSelection() {
1776         sm.clearAndSelect(5);
1777         assertTrue(isSelected(5));
1778         assertTrue(fm.isFocused(5));
1779         keyboard.doKeyPress(KeyCode.SPACE, 
1780                 KeyModifier.getShortcutKey(),
1781                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1782         assertTrue(isNotSelected(5));
1783         assertTrue(debug(), fm.isFocused(5));
1784         assertTrue(isAnchor(5));
1785     }
1786     
1787     /***************************************************************************
1788      * Tests for discontinuous multiple selection (RT-18952)
1789      **************************************************************************/  
1790     
1791     // Test 1
1792     @Test public void test_rt18952_1() {
1793         sm.clearAndSelect(0);
1794         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1795         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1796         keyboard.doKeyPress(KeyCode.SPACE, 
1797                 KeyModifier.getShortcutKey(),
1798                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1799         assertTrue(isSelected(0,2));
1800         assertTrue(isAnchor(2));
1801         
1802         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1803         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1804         assertTrue(debug(),isSelected(0,2,3,4));
1805         assertTrue(isAnchor(2));
1806     }
1807     
1808     // Test 2
1809     @Test public void test_rt18952_2() {
1810         sm.clearAndSelect(5);
1811         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1812         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1813         keyboard.doKeyPress(KeyCode.SPACE, 
1814                 KeyModifier.getShortcutKey(),
1815                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1816         assertTrue(isSelected(3,5));
1817         assertTrue(isAnchor(3));
1818         
1819         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1820         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1821         assertTrue(isSelected(1,2,3,5));
1822         assertTrue(isAnchor(3));
1823     }
1824     
1825     // Test 3
1826     @Test public void test_rt18952_3() {
1827         sm.clearAndSelect(0);
1828         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1829         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1830         keyboard.doKeyPress(KeyCode.SPACE, 
1831                 KeyModifier.getShortcutKey(),
1832                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1833         assertTrue(isSelected(0,2));
1834         assertTrue(isAnchor(2));
1835         
1836         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1837         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1838         assertTrue(isSelected(0,2,3,4));
1839         assertTrue(isAnchor(2));
1840         
1841         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1842         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1843         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1844         assertTrue(isSelected(0,1,2,3,4));
1845         assertTrue(isAnchor(2));
1846     }
1847     
1848     // Test 4
1849     @Test public void test_rt18952_4() {
1850         sm.clearAndSelect(5);
1851         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1852         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1853         keyboard.doKeyPress(KeyCode.SPACE, 
1854                 KeyModifier.getShortcutKey(),
1855                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1856         assertTrue(isSelected(3,5));
1857         assertTrue(isAnchor(3));
1858         
1859         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1860         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1861         assertTrue(isSelected(1,2,3,5));
1862         assertTrue(isAnchor(3));
1863         
1864         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1865         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1866         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1867         assertTrue(isSelected(1,2,3,4,5));
1868         assertTrue(isAnchor(3));
1869     }
1870     
1871     // TODO skipped some tests here (5-8)
1872     
1873     // Test 9
1874     @Test public void test_rt18952_9() {
1875         sm.clearAndSelect(0);
1876         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1877         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1878         keyboard.doKeyPress(KeyCode.SPACE, 
1879                 KeyModifier.getShortcutKey(),
1880                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1881         assertTrue(isSelected(0,2));
1882         assertTrue(isAnchor(2));
1883         
1884         keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1885         assertTrue(isSelected(0,2,3,4,5,6,7,8,9));
1886         assertTrue(isAnchor(2));
1887     }
1888     
1889     // Test 10
1890     @Test public void test_rt18952_10() {
1891         sm.clearAndSelect(9);
1892         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1893         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1894         keyboard.doKeyPress(KeyCode.SPACE, 
1895                 KeyModifier.getShortcutKey(),
1896                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1897         assertTrue(isSelected(7,9));
1898         assertTrue(isAnchor(7));
1899         
1900         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1901         assertTrue(isSelected(0,1,2,3,4,5,6,7,9));
1902         assertTrue(isAnchor(7));
1903     }
1904     
1905     // Test 11
1906     @Test public void test_rt18952_11() {
1907         sm.clearAndSelect(5);
1908         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1909         assertTrue(isSelected(0,1,2,3,4,5));
1910         assertTrue(isAnchor(5));
1911         
1912         keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1913         assertTrue(isSelected(0,1,2,3,4,5,6,7,8,9));
1914         assertTrue(isAnchor(5));
1915     }
1916     
1917     // Test 12
1918     @Test public void test_rt18952_12() {
1919         sm.clearAndSelect(0);
1920         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1921         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
1922         keyboard.doKeyPress(KeyCode.SPACE,
1923                 KeyModifier.getShortcutKey(),
1924                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1925         assertTrue(isSelected(0,2));
1926         assertTrue(isAnchor(2));
1927         
1928         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1929         keyboard.doDownArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1930         assertTrue(isSelected(0,2,3,4));
1931         assertTrue(isAnchor(2));
1932         
1933         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1934         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1935         keyboard.doUpArrowPress(KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
1936         assertTrue(isSelected(0,1,2,3,4));
1937         assertTrue(isAnchor(2));
1938 
1939         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
1940         keyboard.doKeyPress(KeyCode.SPACE, 
1941                 KeyModifier.getShortcutKey(),
1942                 (Utils.isMac()  ? KeyModifier.CTRL : null));
1943         assertTrue(isSelected(1,2,3,4));
1944         assertTrue(fm.isFocused(0));
1945         assertTrue(isAnchor(0));
1946     }
1947     
1948     
1949     
1950     /***************************************************************************
1951      * Tests for editing
1952      **************************************************************************/
1953     
1954 //    // test 43 (part 1)
1955 //    @Test public void testF2EntersEditModeAndEscapeCancelsEdit_part1() {
1956 //        tableView.setEditable(true);
1957 //        
1958 //        sm.clearAndSelect(0);
1959 //        assertNull(tableView.getEditingItem());
1960 //        keyboard.doKeyPress(KeyCode.F2);
1961 //        assertEquals(root, tableView.getEditingItem());
1962 //        
1963 //        keyboard.doKeyPress(KeyCode.ESCAPE);
1964 //        assertNull(tableView.getEditingItem());
1965 //    }
1966 //    
1967 //    // test 43 (part 2)
1968 //    @Test public void testF2EntersEditModeAndEscapeCancelsEdit_part2() {
1969 //        tableView.setEditable(true);
1970 //        
1971 //        sm.clearAndSelect(0);
1972 //        keyboard.doKeyPress(KeyCode.F2);
1973 //        
1974 //        
1975 //    }
1976     
1977     
1978     /***************************************************************************
1979      * Tests for Tree(Table)View-specific functionality
1980      **************************************************************************/ 
1981     
1982     // Test 1 (TreeView test cases)
1983     @Test public void testRightArrowExpandsBranch() {
1984         sm.clearAndSelect(0);
1985         root.setExpanded(false);
1986         assertFalse(root.isExpanded());
1987         keyboard.doRightArrowPress();
1988         assertTrue(root.isExpanded());
1989     }
1990     
1991     // Test 2 (TreeView test cases)
1992     @Test public void testRightArrowOnExpandedBranch() {
1993         sm.clearAndSelect(0);
1994         keyboard.doRightArrowPress();
1995         assertTrue(isNotSelected(0));
1996         assertTrue(isSelected(1));
1997     }
1998     
1999     // Test 3 (TreeView test cases)
2000     @Test public void testRightArrowOnLeafNode() {
2001         sm.clearAndSelect(1);
2002         keyboard.doRightArrowPress();
2003         assertTrue(isNotSelected(0));
2004         assertTrue(isSelected(1));
2005         assertTrue(isNotSelected(2));
2006     }
2007     
2008     // Test 4 (TreeView test cases)
2009     @Test public void testLeftArrowCollapsesBranch() {
2010         sm.clearAndSelect(0);
2011         assertTrue(root.isExpanded());
2012         keyboard.doLeftArrowPress();
2013         assertFalse(root.isExpanded());
2014     }
2015     
2016     // Test 5 (TreeView test cases)
2017     @Test public void testLeftArrowOnLeafMovesSelectionToParent() {
2018         sm.clearAndSelect(2);
2019         assertTrue(root.isExpanded());
2020         keyboard.doLeftArrowPress();
2021         assertTrue(root.isExpanded());
2022         assertTrue(isSelected(0));
2023         assertTrue(isNotSelected(2));
2024     }
2025     
2026     // Test 6 (TreeView test cases)
2027     @Test public void testLeftArrowMultipleTimes() {
2028         sm.clearAndSelect(5);
2029         keyboard.doLeftArrowPress();
2030         assertTrue(child3.isExpanded());
2031         assertTrue(isSelected(3));
2032         assertTrue(isNotSelected(5));
2033         
2034         keyboard.doLeftArrowPress();
2035         assertFalse(child3.isExpanded());
2036         assertTrue(isSelected(3));
2037         
2038         keyboard.doLeftArrowPress();
2039         assertTrue(isSelected(0));
2040         assertTrue(root.isExpanded());
2041         
2042         keyboard.doLeftArrowPress();
2043         assertTrue(isSelected(0));
2044         assertFalse(root.isExpanded());
2045     }
2046     
2047     // Test 7 (TreeView test cases)
2048     @Test public void testDownArrowTwice() {
2049         sm.clearAndSelect(0);
2050         keyboard.doDownArrowPress();
2051         keyboard.doDownArrowPress();
2052         assertTrue(isSelected(2));
2053         assertTrue(isNotSelected(0));
2054     }
2055     
2056     // Test 8 (TreeView test cases)
2057     @Test public void testDownArrowFourTimes() {
2058         // adding children to child2, but not expanding it
2059         child2.getChildren().addAll(new TreeItem("another child"), new TreeItem("And another!"));
2060         child2.setExpanded(false);
2061         
2062         child3.setExpanded(true);
2063         sm.clearAndSelect(0);
2064         keyboard.doDownArrowPress();
2065         keyboard.doDownArrowPress();
2066         keyboard.doDownArrowPress();
2067         keyboard.doDownArrowPress();
2068         assertTrue(isSelected(4));
2069         assertTrue(isNotSelected(0));
2070     }
2071     
2072     // Test 9 (TreeView test cases)
2073     @Test public void testUpArrow() {
2074         sm.clearAndSelect(1);
2075         keyboard.doUpArrowPress();
2076         assertTrue(isSelected(0));
2077         assertTrue(isNotSelected(1));
2078     }
2079     
2080     // Test 9 (TreeView test cases)
2081     @Test public void testUpArrowFourTimes() {
2082         // adding children to child2, but not expanding it
2083         child2.getChildren().addAll(new TreeItem("another child"), new TreeItem("And another!"));
2084         child2.setExpanded(false);
2085         
2086         sm.clearAndSelect(5);
2087         keyboard.doUpArrowPress();
2088         keyboard.doUpArrowPress();
2089         keyboard.doUpArrowPress();
2090         keyboard.doUpArrowPress();
2091         
2092         assertTrue(isSelected(1));
2093         assertTrue(isNotSelected(5));
2094     }
2095     
2096     // Test 20 (TreeView test cases)
2097     // NOTE: this used to be isSelected but changed when we removed functionality
2098     // for KeyCode.SLASH. Rather than remove the test I'm now testing to make
2099     // sure it does nothing.
2100     @Test public void testCtrlForwardSlashToSelectAll() {
2101         sm.clearAndSelect(1);
2102         keyboard.doKeyPress(KeyCode.SLASH, KeyModifier.getShortcutKey());
2103         assertTrue(isSelected(1));
2104         assertTrue(isNotSelected(0,2,3,4,5,6,7,8,9));
2105     }
2106     
2107     // Test 21 (TreeView test cases)
2108     // NOTE: this used to be isNotSelected but changed when we removed functionality
2109     // for KeyCode.BACK_SLASH. Rather than remove the test I'm now testing to make
2110     // sure it does nothing.
2111     @Test public void testCtrlBackSlashToClearSelection() {
2112         sm.selectAll();
2113         fm.focus(1);
2114         keyboard.doKeyPress(KeyCode.BACK_SLASH, KeyModifier.getShortcutKey());
2115         assertTrue(debug(), isSelected(0,1,2,3,4,5,6,7,8,9));
2116         assertTrue(fm.isFocused(1));
2117     }
2118     
2119     // Test 24 (TreeView test cases)
2120     @Ignore("Not yet working")
2121     @Test public void testExpandCollapseImpactOnSelection() {
2122         sm.clearAndSelect(5);
2123         assertTrue(child3.isExpanded());
2124         keyboard.doUpArrowPress(KeyModifier.SHIFT);
2125         keyboard.doUpArrowPress(KeyModifier.SHIFT);
2126         assertTrue(isSelected(3,4,5));
2127         
2128         keyboard.doLeftArrowPress();
2129         assertFalse(child3.isExpanded());
2130         assertTrue(isSelected(3));
2131         
2132         keyboard.doRightArrowPress();
2133         assertTrue(child3.isExpanded());
2134         assertTrue(isSelected(3,4,5));
2135     }
2136     
2137     // Test 54 (TreeView test cases)
2138     @Test public void testAsteriskExpandsAllBranchesFromRoot() {
2139         // adding children to child2, but not expanding it
2140         child2.getChildren().addAll(new TreeItem("another child"), new TreeItem("And another!"));
2141         child2.setExpanded(false);
2142         
2143         sm.clearAndSelect(0);
2144         assertFalse(child2.isExpanded());
2145         assertTrue(child3.isExpanded());
2146         keyboard.doKeyPress(KeyCode.MULTIPLY);
2147         
2148         assertTrue(child2.isExpanded());
2149         assertTrue(child3.isExpanded());
2150     }
2151     
2152     // Test 57 (TreeView test cases)
2153     @Test public void testMinusCollapsesBranch() {
2154         sm.clearAndSelect(3);
2155         assertTrue(child3.isExpanded());
2156         keyboard.doKeyPress(KeyCode.SUBTRACT);
2157         assertFalse(child3.isExpanded());
2158     }
2159     
2160     // Test 58 (TreeView test cases)
2161     @Test public void testPlusCollapsesBranch() {
2162         sm.clearAndSelect(3);
2163         child3.setExpanded(false);
2164         assertFalse(child3.isExpanded());
2165         keyboard.doKeyPress(KeyCode.ADD);
2166         assertTrue(child3.isExpanded());
2167     }
2168     
2169     
2170     /***************************************************************************
2171      * Tests for specific bug reports
2172      **************************************************************************/
2173     
2174 //    @Test public void test_rt18642() {
2175 //        sm.clearAndSelect(1);                          // select 1
2176 //        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 2
2177 //        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 3
2178 //        keyboard.doKeyPress(KeyCode.SPACE, 
2179 //                KeyModifier.getShortcutKey(),
2180 //                (Utils.isMac()  ? KeyModifier.CTRL : null)); // set anchor, and also select, 3
2181 //        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 4
2182 //        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 5
2183 //        keyboard.doKeyPress(KeyCode.SPACE, 
2184 //                KeyModifier.getShortcutKey(),
2185 //                (Utils.isMac()  ? KeyModifier.CTRL : null)); // set anchor, and also select, 5
2186 //        
2187 //        assertTrue(isSelected(1, 3, 5));
2188 //        assertTrue(isNotSelected(0, 2, 4));
2189 //        
2190 //        // anchor is at 5, so shift+UP should select rows 4 and 5 only
2191 //        keyboard.doUpArrowPress(KeyModifier.SHIFT);   
2192 //        assertTrue(isSelected(4, 5));
2193 //        assertTrue(isNotSelected(0, 1, 2, 3));
2194 //    }
2195     
2196     @Test public void test_rt14451_1() {
2197         sm.clearAndSelect(5);                          
2198 
2199         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT); 
2200         assertTrue(debug(), isSelected(0,1,2,3,4,5));
2201         assertTrue(isNotSelected(6,7,8,9));
2202         
2203         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT); 
2204         assertTrue(isNotSelected(0,1,2,3,4));
2205         assertTrue(isSelected(5,6,7,8,9));
2206         
2207         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT); 
2208         assertTrue(isSelected(0,1,2,3,4,5));
2209         assertTrue(debug(), isNotSelected(6,7,8,9));
2210     } 
2211     
2212     @Test public void test_rt14451_2() {
2213         sm.clearAndSelect(5);                          
2214 
2215         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT); 
2216         assertTrue(isNotSelected(0,1,2,3,4));
2217         assertTrue(isSelected(5,6,7,8,9));
2218         
2219         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT); 
2220         assertTrue(isSelected(0,1,2,3,4,5));
2221         assertTrue(debug(), isNotSelected(6,7,8,9));
2222         
2223         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT); 
2224         assertTrue(isNotSelected(0,1,2,3,4));
2225         assertTrue(isSelected(5,6,7,8,9));
2226     } 
2227     
2228     @Test public void test_rt26835_1() {
2229         sm.clearAndSelect(5);                          
2230         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey()); 
2231         assertTrue(fm.isFocused(0));
2232     } 
2233     
2234     @Test public void test_rt26835_2() {
2235         sm.clearAndSelect(5);                          
2236         keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey()); 
2237         assertTrue(debug(), fm.isFocused(getItemCount()));
2238     } 
2239     
2240     @Test public void test_rt27175() {
2241         sm.clearAndSelect(5);                          
2242         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT, KeyModifier.getShortcutKey()); 
2243         assertTrue(debug(), fm.isFocused(0));
2244         assertTrue(isSelected(0,1,2,3,4,5));
2245     } 
2246     
2247     @Test public void test_rt28065() {
2248         sm.setSelectionMode(SelectionMode.MULTIPLE);
2249         
2250         tableView.getSelectionModel().select(0);
2251         assertEquals(0, tableView.getSelectionModel().getSelectedIndex());
2252         assertEquals(root, tableView.getSelectionModel().getSelectedItem());
2253         assertEquals(0, tableView.getFocusModel().getFocusedIndex());
2254         assertEquals(root, tableView.getFocusModel().getFocusedItem());
2255         
2256         keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey());
2257         assertEquals(0, tableView.getSelectionModel().getSelectedIndex());
2258         assertEquals(root, tableView.getSelectionModel().getSelectedItem());
2259         assertEquals(0, tableView.getFocusModel().getFocusedIndex());
2260         assertEquals(root, tableView.getFocusModel().getFocusedItem());
2261     }
2262     
2263     @Test public void test_rt27583_cellSelection_1() {
2264         sm.setCellSelectionEnabled(true);
2265         sm.setSelectionMode(SelectionMode.MULTIPLE);
2266         
2267         sm.select(0, col0);
2268         assertTrue(fm.isFocused(0, col0));
2269         
2270         // focus should not go out the top of the table
2271         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2272         assertTrue(fm.isFocused(1, col0));
2273         keyboard.doUpArrowPress(KeyModifier.SHIFT);
2274         assertTrue(fm.isFocused(0, col0));
2275         keyboard.doUpArrowPress(KeyModifier.SHIFT);
2276         assertTrue(debug(), fm.isFocused(0, col0));
2277         
2278     }
2279     
2280     @Test public void test_rt27583_cellSelection_2() {
2281         sm.setCellSelectionEnabled(true);
2282         sm.setSelectionMode(SelectionMode.MULTIPLE);
2283         
2284         sm.select(10, col0);
2285         assertTrue(fm.isFocused(10, col0));
2286         
2287         // focus should not go out the bottom of the table
2288         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2289         assertTrue(fm.isFocused(11, col0));
2290         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2291         assertTrue(fm.isFocused(12, col0));
2292         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2293         assertTrue(fm.isFocused(13, col0));
2294         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2295         assertTrue(debug(), fm.isFocused(13, col0));
2296     }
2297     
2298     @Test public void test_rt27583_rowSelection_1() {
2299         sm.setCellSelectionEnabled(false);
2300         sm.setSelectionMode(SelectionMode.MULTIPLE);
2301         
2302         sm.select(0);
2303         assertTrue(fm.isFocused(0));
2304         
2305         // focus should not go out the top of the table
2306         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2307         assertTrue(fm.isFocused(1));
2308         keyboard.doUpArrowPress(KeyModifier.SHIFT);
2309         assertTrue(fm.isFocused(0));
2310         keyboard.doUpArrowPress(KeyModifier.SHIFT);
2311         assertTrue(debug(), fm.isFocused(0));
2312         
2313     }
2314     
2315     @Test public void test_rt27583_rowSelection_2() {
2316         sm.setCellSelectionEnabled(false);
2317         sm.setSelectionMode(SelectionMode.MULTIPLE);
2318         
2319         sm.select(10);
2320         assertTrue(fm.isFocused(10));
2321         
2322         // focus should not go out the bottom of the table
2323         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2324         assertTrue(fm.isFocused(11));
2325         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2326         assertTrue(fm.isFocused(12));
2327         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2328         assertTrue(fm.isFocused(13));
2329         keyboard.doDownArrowPress(KeyModifier.SHIFT);
2330         assertTrue(debug(), fm.isFocused(13));
2331     }
2332     
2333     @Test public void test_rt29930() {
2334         sm.setCellSelectionEnabled(false);
2335         sm.setSelectionMode(SelectionMode.MULTIPLE);
2336         
2337         sm.clearAndSelect(0);
2338         
2339         keyboard.doDownArrowPress(KeyModifier.SHIFT); // select rows [0,1]
2340         keyboard.doDownArrowPress(KeyModifier.SHIFT); // select rows [0,1,2]
2341         assertTrue(isSelected(0,1,2));
2342         assertEquals(2, fm.getFocusedIndex());
2343         assertEquals(0, getAnchor().getRow());
2344         
2345         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), PlatformUtil.isMac() ? KeyModifier.CTRL : null); // set new anchor point
2346         assertTrue(isSelected(0,1));
2347         assertEquals(2, fm.getFocusedIndex());
2348         assertEquals(2, getAnchor().getRow());
2349         
2350         keyboard.doDownArrowPress(KeyModifier.SHIFT); // select rows [2,3]
2351         assertTrue(isSelected(2,3));
2352         assertTrue(debug(), isNotSelected(0,1));
2353         assertEquals(3, fm.getFocusedIndex());
2354         assertEquals(2, getAnchor().getRow());
2355     }
2356 
2357     private int rt29849_start_count = 0;
2358     private int rt29849_cancel_count = 0;
2359     @Test public void test_rt29849() {
2360         tableView.setEditable(true);
2361         col0.setEditable(true);
2362 
2363         col0.setCellValueFactory(param -> new ReadOnlyStringWrapper("DUMMY TEXT"));
2364 
2365         col0.setOnEditStart(t -> {
2366             rt29849_start_count++;
2367         });
2368         col0.setOnEditCancel(t -> {
2369             rt29849_cancel_count++;
2370         });
2371 
2372         // initially the counts should be zero
2373         assertEquals(0, rt29849_start_count);
2374         assertEquals(0, rt29849_cancel_count);
2375 
2376         IndexedCell cell = VirtualFlowTestUtils.getCell(tableView, 0, 0);
2377         assertTrue(cell.isEditable());
2378         assertFalse(cell.isEditing());
2379         assertEquals(0, cell.getIndex());
2380 
2381         // do an edit, start count should be one, cancel still zero
2382         tableView.edit(0, col0);
2383         assertTrue(cell.isEditing());
2384         assertEquals(1, rt29849_start_count);
2385         assertEquals(0, rt29849_cancel_count);
2386 
2387         // cancel edit, now both counts should be 1
2388         keyboard.doKeyPress(KeyCode.ESCAPE);
2389         assertFalse(cell.isEditing());
2390         assertEquals(1, rt29849_start_count);
2391         assertEquals(1, rt29849_cancel_count);
2392     }
2393 
2394     private int rt31577_count = 0;
2395     @Test public void test_rt31577() {
2396         final TableSelectionModel sm = tableView.getSelectionModel();
2397         sm.setCellSelectionEnabled(false);
2398         sm.setSelectionMode(SelectionMode.SINGLE);
2399         sm.clearSelection();
2400 
2401         // the actual bug is that the selectedItem property does not fire an
2402         // event when the selected items list changes (due to deselection).
2403         // It actually does always contain the right value - it just doesn't
2404         // let anyone know it!
2405         sm.selectedItemProperty().addListener(observable -> {
2406             rt31577_count++;
2407         });
2408 
2409         assertTrue(sm.getSelectedItems().isEmpty());
2410         assertFalse(sm.isSelected(1));
2411         assertEquals(0, rt31577_count);
2412 
2413         // select the first row
2414         keyboard.doKeyPress(KeyCode.KP_DOWN);
2415         assertEquals(1, sm.getSelectedItems().size());
2416         assertTrue(sm.isSelected(0));
2417         assertTrue(sm.getSelectedItems().contains(root));
2418         assertEquals(root, sm.getSelectedItem());
2419         assertEquals(1, rt31577_count);
2420 
2421         // deselect the row
2422         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL,
2423                 Utils.isMac() ? KeyModifier.getShortcutKey() : null);
2424         assertTrue(sm.getSelectedItems().isEmpty());
2425         assertFalse(sm.isSelected(1));
2426         assertNull(sm.getSelectedItem());
2427         assertEquals(2, rt31577_count);
2428     }
2429 
2430     @Test public void test_rt32383_pageDown() {
2431         // this test requires a lot of data
2432         for (int i = 0; i < 100; i++) {
2433             root.getChildren().add(new TreeItem<String>("Row " + i));
2434         }
2435 
2436         final MultipleSelectionModel sm = tableView.getSelectionModel();
2437         sm.setSelectionMode(SelectionMode.SINGLE);
2438         sm.clearAndSelect(0);
2439 
2440         final TreeItem<String> initialFocusOwner = fm.getFocusedItem();
2441 
2442         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.getShortcutKey());
2443         Toolkit.getToolkit().firePulse();
2444         final TreeItem<String> newFocusOwner = fm.getFocusedItem();
2445         assertNotSame(initialFocusOwner, newFocusOwner);
2446 
2447         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.getShortcutKey());
2448         Toolkit.getToolkit().firePulse();
2449         final TreeItem<String> nextFocusOwner = fm.getFocusedItem();
2450         assertNotSame(initialFocusOwner, nextFocusOwner);
2451         assertNotSame(newFocusOwner, nextFocusOwner);
2452     }
2453 
2454     @Test public void test_rt32383_pageUp() {
2455         // this test requires a lot of data
2456         for (int i = 0; i < 100; i++) {
2457             root.getChildren().add(new TreeItem<String>("Row " + i));
2458         }
2459 
2460         final int lastIndex = 99;
2461 
2462         final MultipleSelectionModel sm = tableView.getSelectionModel();
2463         sm.setSelectionMode(SelectionMode.SINGLE);
2464         sm.clearAndSelect(lastIndex);
2465 
2466         // need to make sure we scroll down to the bottom!
2467         tableView.scrollTo(lastIndex);
2468         Toolkit.getToolkit().firePulse();
2469 
2470         final TreeItem<String> initialFocusOwner = fm.getFocusedItem();
2471 
2472         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.getShortcutKey());
2473         Toolkit.getToolkit().firePulse();
2474         final TreeItem<String> newFocusOwner = fm.getFocusedItem();
2475         assertNotSame(initialFocusOwner, newFocusOwner);
2476 
2477         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.getShortcutKey());
2478         Toolkit.getToolkit().firePulse();
2479         final TreeItem<String> nextFocusOwner = fm.getFocusedItem();
2480         assertNotSame(initialFocusOwner, nextFocusOwner);
2481         assertNotSame(newFocusOwner, nextFocusOwner);
2482     }
2483 
2484     @Test public void test_rt27710_pageDown_singleSelection_cell() {
2485         // this test requires a lot of data
2486         for (int i = 0; i < 100; i++) {
2487             root.getChildren().add(new TreeItem<String>("Row " + i));
2488         }
2489 
2490         col0.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
2491 
2492         final TableSelectionModel sm = tableView.getSelectionModel();
2493         sm.setSelectionMode(SelectionMode.SINGLE);
2494         sm.setCellSelectionEnabled(true);
2495         sm.clearAndSelect(0, col0);
2496 
2497         final TreeItem<String> initialFocusOwner = fm.getFocusedItem();
2498 
2499         // because single selection is enabled, shift+pgDown should result in
2500         // the same result as ctrl+pgDown
2501         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2502         Toolkit.getToolkit().firePulse();
2503         final TreeItem<String> newFocusOwner = fm.getFocusedItem();
2504         assertNotSame(initialFocusOwner, newFocusOwner);
2505 
2506         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2507         Toolkit.getToolkit().firePulse();
2508         final TreeItem<String> nextFocusOwner = fm.getFocusedItem();
2509         assertNotSame(initialFocusOwner, nextFocusOwner);
2510         assertNotSame(newFocusOwner, nextFocusOwner);
2511     }
2512 
2513     @Test public void test_rt27710_pageUp_singleSelection_cell() {
2514         // this test requires a lot of data
2515         for (int i = 0; i < 100; i++) {
2516             root.getChildren().add(new TreeItem<String>("Row " + i));
2517         }
2518 
2519         col0.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
2520 
2521         final int lastIndex = 99;
2522 
2523         final TableSelectionModel sm = tableView.getSelectionModel();
2524         sm.setSelectionMode(SelectionMode.SINGLE);
2525         sm.setCellSelectionEnabled(true);
2526         sm.clearAndSelect(lastIndex, col0);
2527 
2528         // need to make sure we scroll down to the bottom!
2529         tableView.scrollTo(lastIndex);
2530         Toolkit.getToolkit().firePulse();
2531 
2532         final TreeItem<String> initialFocusOwner = fm.getFocusedItem();
2533 
2534         // because single selection is enabled, shift+pgUp should result in
2535         // the same result as ctrl+pgUp
2536         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2537         Toolkit.getToolkit().firePulse();
2538         final TreeItem<String> newFocusOwner = fm.getFocusedItem();
2539         assertNotSame(initialFocusOwner, newFocusOwner);
2540 
2541         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2542         Toolkit.getToolkit().firePulse();
2543         final TreeItem<String> nextFocusOwner = fm.getFocusedItem();
2544         assertNotSame(initialFocusOwner, nextFocusOwner);
2545         assertNotSame(newFocusOwner, nextFocusOwner);
2546     }
2547 
2548     @Test public void test_rt19053_pageUp() {
2549         final int items = 8;
2550         root.getChildren().clear();
2551         for (int i = 0; i < items; i++) {
2552             root.getChildren().add(new TreeItem<>("Row " + i));
2553         }
2554 
2555         final int middleIndex = items / 2;
2556 
2557         final MultipleSelectionModel sm = tableView.getSelectionModel();
2558         tableView.setShowRoot(false);
2559         sm.setSelectionMode(SelectionMode.SINGLE);
2560         sm.clearAndSelect(middleIndex);
2561 
2562         assertEquals(middleIndex, sm.getSelectedIndex());
2563 
2564         final Object initialSelectionOwner = sm.getSelectedItem();
2565 
2566         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2567         Toolkit.getToolkit().firePulse();
2568         final Object newSelectionOwner = sm.getSelectedItem();
2569         assertNotSame(initialSelectionOwner + " == " + newSelectionOwner, initialSelectionOwner, newSelectionOwner);
2570 
2571         // selection should go all the way to the top, but this bug
2572         // shows that instead it seems to stop midway - where the anchor is
2573         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2574         Toolkit.getToolkit().firePulse();
2575         assertEquals(0, fm.getFocusedIndex());
2576         assertEquals(0, sm.getSelectedIndex());
2577         final Object nextSelectionOwner =  sm.getSelectedItem();
2578         assertNotSame(initialSelectionOwner, nextSelectionOwner);
2579         assertNotSame(newSelectionOwner, nextSelectionOwner);
2580     }
2581 
2582     @Test public void test_rt19053_pageDown() {
2583         final int items = 8;
2584         root.getChildren().clear();
2585         for (int i = 0; i < items; i++) {
2586             root.getChildren().add(new TreeItem<>("Row " + i));
2587         }
2588 
2589         final int middleIndex = items / 2;
2590 
2591         final MultipleSelectionModel sm = tableView.getSelectionModel();
2592         tableView.setShowRoot(false);
2593         sm.setSelectionMode(SelectionMode.SINGLE);
2594         sm.clearAndSelect(middleIndex);
2595 
2596         assertEquals(middleIndex, sm.getSelectedIndex());
2597 
2598         final Object initialSelectionOwner = sm.getSelectedItem();
2599 
2600         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2601         Toolkit.getToolkit().firePulse();
2602         final Object newSelectionOwner = sm.getSelectedItem();
2603         assertNotSame(initialSelectionOwner, newSelectionOwner);
2604 
2605         // selection should go all the way to the bottom, but this bug
2606         // shows that instead it seems to stop midway - where the anchor is
2607         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
2608         Toolkit.getToolkit().firePulse();
2609         assertEquals(items - 1, fm.getFocusedIndex());
2610         assertEquals(items - 1, sm.getSelectedIndex());
2611         final Object nextSelectionOwner =  sm.getSelectedItem();
2612         assertNotSame(initialSelectionOwner, nextSelectionOwner);
2613         assertNotSame(newSelectionOwner, nextSelectionOwner);
2614     }
2615 
2616     @Test public void test_rt21375_scenario_1a_down() {
2617         sm.clearSelection();
2618 
2619         final int items = 8;
2620         root.getChildren().clear();
2621         for (int i = 0; i < items; i++) {
2622             root.getChildren().add(new TreeItem<>("Row " + i));
2623         }
2624 
2625         final MultipleSelectionModel sm = tableView.getSelectionModel();
2626         sm.setSelectionMode(SelectionMode.MULTIPLE);
2627         sm.clearAndSelect(0);
2628 
2629         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
2630         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
2631         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);
2632         Toolkit.getToolkit().firePulse();
2633         assertTrue(isSelected(0,1,2,3));
2634         assertEquals(4, sm.getSelectedItems().size());
2635     }
2636 
2637     @Test public void test_rt21375_scenario_1b_down() {
2638         final int items = 8;
2639         root.getChildren().clear();
2640         for (int i = 0; i < items; i++) {
2641             root.getChildren().add(new TreeItem<>("Row " + i));
2642         }
2643 
2644         final MultipleSelectionModel sm = tableView.getSelectionModel();
2645         sm.setSelectionMode(SelectionMode.MULTIPLE);
2646         sm.clearAndSelect(0);
2647 
2648         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
2649         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
2650         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
2651         Toolkit.getToolkit().firePulse();
2652         assertTrue(isSelected(0,1,2,3));
2653         assertEquals(4, sm.getSelectedItems().size());
2654     }
2655 
2656     @Test public void test_rt21375_scenario_2_down() {
2657         final int items = 8;
2658         root.getChildren().clear();
2659         for (int i = 0; i < items; i++) {
2660             root.getChildren().add(new TreeItem<>("Row " + i));
2661         }
2662 
2663         final MultipleSelectionModel sm = tableView.getSelectionModel();
2664         sm.setSelectionMode(SelectionMode.MULTIPLE);
2665         sm.clearAndSelect(0);
2666 
2667         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
2668         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
2669         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), PlatformUtil.isMac() ? KeyModifier.CTRL : null);
2670         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
2671         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.SHIFT);
2672         Toolkit.getToolkit().firePulse();
2673         assertTrue(isSelected(2,3,4));
2674         assertEquals(3, sm.getSelectedItems().size());
2675     }
2676 
2677     @Test public void test_rt21375_scenario_3_down() {
2678         final int items = 8;
2679         root.getChildren().clear();
2680         for (int i = 0; i < items; i++) {
2681             root.getChildren().add(new TreeItem<>("Row " + i));
2682         }
2683 
2684         final MultipleSelectionModel sm = tableView.getSelectionModel();
2685         sm.setSelectionMode(SelectionMode.MULTIPLE);
2686         sm.clearAndSelect(0);
2687 
2688         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
2689         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
2690         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), PlatformUtil.isMac() ? KeyModifier.CTRL : null);
2691         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey());
2692         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
2693         Toolkit.getToolkit().firePulse();
2694         assertTrue(isSelected(0,2,3,4));
2695         assertEquals(4, sm.getSelectedItems().size());
2696     }
2697 
2698     @Test public void test_rt21375_scenario_1a_up() {
2699         sm.clearSelection();
2700 
2701         final int items = 8;
2702         root.getChildren().clear();
2703         for (int i = 0; i < items; i++) {
2704             root.getChildren().add(new TreeItem<>("Row " + i));
2705         }
2706 
2707         final MultipleSelectionModel sm = tableView.getSelectionModel();
2708         sm.setSelectionMode(SelectionMode.MULTIPLE);
2709         sm.clearAndSelect(7);
2710 
2711         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
2712         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
2713         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
2714         Toolkit.getToolkit().firePulse();
2715         assertTrue(isSelected(7,6,5,4));
2716         assertEquals(4, sm.getSelectedItems().size());
2717     }
2718 
2719     @Test public void test_rt21375_scenario_1b_up() {
2720         sm.clearSelection();
2721 
2722         final int items = 8;
2723         root.getChildren().clear();
2724         for (int i = 0; i < items; i++) {
2725             root.getChildren().add(new TreeItem<>("Row " + i));
2726         }
2727 
2728         final MultipleSelectionModel sm = tableView.getSelectionModel();
2729         sm.setSelectionMode(SelectionMode.MULTIPLE);
2730         sm.clearAndSelect(7);
2731 
2732         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
2733         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
2734         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
2735         Toolkit.getToolkit().firePulse();
2736         assertTrue(isSelected(7,6,5,4));
2737         assertEquals(4, sm.getSelectedItems().size());
2738     }
2739 
2740     @Test public void test_rt21375_scenario_2_up() {
2741         final int items = 8;
2742         root.getChildren().clear();
2743         for (int i = 0; i < items; i++) {
2744             root.getChildren().add(new TreeItem<>("Row " + i));
2745         }
2746 
2747         final MultipleSelectionModel sm = tableView.getSelectionModel();
2748         sm.setSelectionMode(SelectionMode.MULTIPLE);
2749         sm.clearAndSelect(7);
2750 
2751         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
2752         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
2753         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), PlatformUtil.isMac() ? KeyModifier.CTRL : null);
2754         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
2755         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.SHIFT);
2756         Toolkit.getToolkit().firePulse();
2757         assertTrue(isSelected(5,4,3));
2758         assertEquals(3, sm.getSelectedItems().size());
2759     }
2760 
2761     @Test public void test_rt21375_scenario_3_up() {
2762         final int items = 8;
2763         root.getChildren().clear();
2764         for (int i = 0; i < items; i++) {
2765             root.getChildren().add(new TreeItem<>("Row " + i));
2766         }
2767 
2768         final MultipleSelectionModel sm = tableView.getSelectionModel();
2769         sm.setSelectionMode(SelectionMode.MULTIPLE);
2770         sm.clearAndSelect(7);
2771 
2772         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
2773         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
2774         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), PlatformUtil.isMac() ? KeyModifier.CTRL : null);
2775         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey());
2776         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
2777         Toolkit.getToolkit().firePulse();
2778         assertTrue(isSelected(7,5,4,3));
2779         assertEquals(4, sm.getSelectedItems().size());
2780     }
2781 
2782     @Test public void test_rt33301_multipleSelection_down() {
2783         final int items = 4;
2784         root.getChildren().clear();
2785         for (int i = 0; i < items; i++) {
2786             root.getChildren().add(new TreeItem<>("Row " + i));
2787         }
2788 
2789         final TableFocusModel fm = tableView.getFocusModel();
2790         final TableSelectionModel sm = tableView.getSelectionModel();
2791         sm.setSelectionMode(SelectionMode.MULTIPLE);
2792         sm.setCellSelectionEnabled(false);
2793         sm.clearAndSelect(2);
2794 
2795         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 3
2796         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 4
2797         Toolkit.getToolkit().firePulse();
2798         assertTrue(isNotSelected(0,1));
2799         assertTrue(isSelected(2,3,4));
2800         assertEquals(3, sm.getSelectedItems().size());
2801         assertTrue(fm.isFocused(4));
2802 
2803         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
2804         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
2805         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
2806         Toolkit.getToolkit().firePulse();
2807         assertTrue(isNotSelected(0,1));
2808         assertTrue(isSelected(2,3,4));
2809         assertEquals(3, sm.getSelectedItems().size());
2810         assertTrue("Focus index incorrectly at: " + fm.getFocusedIndex(), fm.isFocused(4));
2811     }
2812 
2813     @Test public void test_rt33301_multipleSelection_up() {
2814         final int items = 4;
2815         root.getChildren().clear();
2816         for (int i = 0; i < items; i++) {
2817             root.getChildren().add(new TreeItem<>("Row " + i));
2818         }
2819 
2820         final TableFocusModel fm = tableView.getFocusModel();
2821         final TableSelectionModel sm = tableView.getSelectionModel();
2822         sm.setSelectionMode(SelectionMode.MULTIPLE);
2823         sm.setCellSelectionEnabled(false);
2824         sm.clearAndSelect(2);
2825 
2826         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 1
2827         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 0
2828         Toolkit.getToolkit().firePulse();
2829         assertTrue(isNotSelected(3,4));
2830         assertTrue(isSelected(0,1,2));
2831         assertEquals(3, sm.getSelectedItems().size());
2832         assertTrue(fm.isFocused(0));
2833 
2834         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
2835         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
2836         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
2837         Toolkit.getToolkit().firePulse();
2838         assertTrue(isNotSelected(3,4));
2839         assertTrue(isSelected(0,1,2));
2840         assertEquals(3, sm.getSelectedItems().size());
2841         assertTrue(fm.isFocused(0));
2842     }
2843 
2844     @Test public void test_rt33301_singleSelection_down() {
2845         final int items = 4;
2846         root.getChildren().clear();
2847         for (int i = 0; i < items; i++) {
2848             root.getChildren().add(new TreeItem<>("Row " + i));
2849         }
2850 
2851         final TableFocusModel fm = tableView.getFocusModel();
2852         final TableSelectionModel sm = tableView.getSelectionModel();
2853         sm.setSelectionMode(SelectionMode.SINGLE);
2854         sm.setCellSelectionEnabled(false);
2855         sm.clearAndSelect(2);
2856 
2857         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 3
2858         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 4
2859         Toolkit.getToolkit().firePulse();
2860         assertTrue(isNotSelected(0,1,2,3));
2861         assertTrue(isSelected(4));
2862         assertEquals(1, sm.getSelectedItems().size());
2863         assertTrue(fm.isFocused(4));
2864 
2865         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
2866         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
2867         keyboard.doKeyPress(KeyCode.DOWN,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 4
2868         Toolkit.getToolkit().firePulse();
2869         assertTrue(isNotSelected(0,1,2,3));
2870         assertTrue(isSelected(4));
2871         assertEquals(1, sm.getSelectedItems().size());
2872         assertTrue(fm.isFocused(4));
2873     }
2874 
2875     @Test public void test_rt33301_singleSelection_up() {
2876         final int items = 4;
2877         root.getChildren().clear();
2878         for (int i = 0; i < items; i++) {
2879             root.getChildren().add(new TreeItem<>("Row " + i));
2880         }
2881 
2882         final TableFocusModel fm = tableView.getFocusModel();
2883         final TableSelectionModel sm = tableView.getSelectionModel();
2884         sm.setSelectionMode(SelectionMode.SINGLE);
2885         sm.setCellSelectionEnabled(false);
2886         sm.clearAndSelect(2);
2887 
2888         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 1
2889         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // row 0
2890         Toolkit.getToolkit().firePulse();
2891         assertTrue(isNotSelected(1,2,3,4));
2892         assertTrue(isSelected(0));
2893         assertEquals(1, sm.getSelectedItems().size());
2894         assertTrue(fm.isFocused(0));
2895 
2896         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
2897         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
2898         keyboard.doKeyPress(KeyCode.UP,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT); // should stay at row 0
2899         Toolkit.getToolkit().firePulse();
2900         assertTrue(isNotSelected(1,2,3,4));
2901         assertTrue(isSelected(0));
2902         assertEquals(1, sm.getSelectedItems().size());
2903         assertTrue(fm.isFocused(0));
2904     }
2905 
2906     private int rt_33559_count = 0;
2907     @Test public void test_rt33559() {
2908         final int items = 4;
2909         root.getChildren().clear();
2910         root.setExpanded(false);
2911         for (int i = 0; i < items; i++) {
2912             root.getChildren().add(new TreeItem<>("Row " + i));
2913         }
2914 
2915         final MultipleSelectionModel sm = tableView.getSelectionModel();
2916         sm.setSelectionMode(SelectionMode.SINGLE);
2917         sm.clearAndSelect(0);
2918 
2919         tableView.getSelectionModel().getSelectedItems().addListener((ListChangeListener) c -> {
2920             while (c.next()) {
2921                 rt_33559_count++;
2922             }
2923         });
2924 
2925         assertEquals(0, rt_33559_count);
2926         keyboard.doKeyPress(KeyCode.RIGHT); // expand root
2927         assertEquals(0, rt_33559_count);
2928     }
2929 
2930     @Test public void test_rt20915() {
2931         final FocusModel fm = tableView.getFocusModel();
2932         final MultipleSelectionModel sm = tableView.getSelectionModel();
2933         sm.clearAndSelect(0);
2934 
2935         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
2936         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
2937         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
2938         Toolkit.getToolkit().firePulse();
2939         assertTrue(isNotSelected(1,2,3));
2940         assertTrue(isSelected(0));
2941         assertEquals(1, sm.getSelectedItems().size());
2942         assertTrue(fm.isFocused(3));
2943 
2944         keyboard.doKeyPress(KeyCode.SPACE,  KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
2945         Toolkit.getToolkit().firePulse();
2946         assertTrue(isSelected(0,1,2,3));
2947         assertEquals(4, sm.getSelectedItems().size());
2948         assertTrue(fm.isFocused(3));
2949     }
2950 
2951     @Test public void test_rt34200() {
2952         final int items = 100;
2953         root.getChildren().clear();
2954         root.setExpanded(true);
2955         for (int i = 0; i < items; i++) {
2956             root.getChildren().add(new TreeItem<>("Row " + i));
2957         }
2958 
2959         sm.clearAndSelect(99);
2960         tableView.scrollTo(99);
2961         assertEquals(99, getAnchor().getRow());
2962         assertEquals(99, fm.getFocusedIndex());
2963 
2964         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
2965         Toolkit.getToolkit().firePulse();
2966         assertEquals(99, getAnchor().getRow());
2967         assertTrue(fm.getFocusedIndex() < 99);
2968     }
2969 
2970     @Test public void test_rt34369_cellSelection() {
2971         final int items = 100;
2972         root.getChildren().clear();
2973         root.setExpanded(true);
2974         for (int i = 0; i < items; i++) {
2975             root.getChildren().add(new TreeItem<>("Row " + i));
2976         }
2977 
2978         sm.setCellSelectionEnabled(true);
2979 
2980         sm.clearAndSelect(99, col0);
2981         tableView.scrollTo(99);
2982         assertEquals(99, getAnchor().getRow());
2983         assertEquals(col0, getAnchor().getTableColumn());
2984         assertEquals(99, fm.getFocusedIndex());
2985 
2986         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
2987         Toolkit.getToolkit().firePulse();
2988         assertEquals(99, getAnchor().getRow());
2989         assertEquals(col0, getAnchor().getTableColumn());
2990         assertTrue(fm.getFocusedIndex() < 99);
2991     }
2992 
2993     @Test public void test_rt34369_rowSelection() {
2994         final int items = 100;
2995         root.getChildren().clear();
2996         root.setExpanded(true);
2997         for (int i = 0; i < items; i++) {
2998             root.getChildren().add(new TreeItem<>("Row " + i));
2999         }
3000 
3001         sm.setCellSelectionEnabled(false);
3002 
3003         sm.clearAndSelect(99);
3004         tableView.scrollTo(99);
3005         assertEquals(99, getAnchor().getRow());
3006         assertEquals(99, fm.getFocusedIndex());
3007 
3008         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
3009         Toolkit.getToolkit().firePulse();
3010         assertEquals(99, getAnchor().getRow());
3011         assertTrue(fm.getFocusedIndex() < 99);
3012     }
3013 
3014     @Test public void test_rt33894() {
3015         final int items = 5;
3016         root.getChildren().clear();
3017         root.setExpanded(true);
3018         for (int i = 0; i < items; i++) {
3019             root.getChildren().add(new TreeItem<>("Row " + i));
3020         }
3021 
3022         sm.clearAndSelect(1);
3023         assertEquals(1, getAnchor().getRow());
3024         assertEquals(1, fm.getFocusedIndex());
3025         assertEquals(1, sm.getSelectedIndex());
3026 
3027         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3028         Toolkit.getToolkit().firePulse();
3029         assertEquals(1, getAnchor().getRow());
3030         assertEquals(2, fm.getFocusedIndex());
3031         assertEquals(1, sm.getSelectedIndex());
3032 
3033         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
3034         Toolkit.getToolkit().firePulse();
3035         assertEquals(2, getAnchor().getRow());
3036         assertEquals(2, fm.getFocusedIndex());
3037         assertEquals(2, sm.getSelectedIndex());
3038         assertTrue(isSelected(1, 2));
3039 
3040         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3041         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3042         Toolkit.getToolkit().firePulse();
3043         assertEquals(2, getAnchor().getRow());
3044         assertEquals(0, fm.getFocusedIndex());
3045         assertEquals(2, sm.getSelectedIndex());
3046         assertTrue(isSelected(1, 2));
3047 
3048         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
3049         Toolkit.getToolkit().firePulse();
3050         assertEquals(0, getAnchor().getRow());
3051         assertEquals(0, fm.getFocusedIndex());
3052         assertEquals(0, sm.getSelectedIndex());
3053         assertTrue(isSelected(0, 1, 2));
3054     }
3055 
3056     @Test public void test_rt34425() {
3057         final int items = 5;
3058         root.getChildren().clear();
3059         root.setExpanded(true);
3060         for (int i = 0; i < items; i++) {
3061             root.getChildren().add(new TreeItem<>("Row " + i));
3062         }
3063 
3064         sm.clearAndSelect(1);
3065         assertEquals(1, getAnchor().getRow());
3066         assertEquals(1, fm.getFocusedIndex());
3067         assertEquals(1, sm.getSelectedIndex());
3068 
3069         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3070         Toolkit.getToolkit().firePulse();
3071         assertEquals(1, getAnchor().getRow());
3072         assertEquals(2, fm.getFocusedIndex());
3073         assertEquals(1, sm.getSelectedIndex());
3074 
3075         keyboard.doKeyPress(KeyCode.SPACE);
3076         Toolkit.getToolkit().firePulse();
3077         assertEquals(2, getAnchor().getRow());
3078         assertEquals(2, fm.getFocusedIndex());
3079         assertEquals(2, sm.getSelectedIndex());
3080         assertTrue(isSelected(1, 2));
3081     }
3082 
3083     @Test public void test_rt33613_up_oneColumn() {
3084         final int items = 10;
3085         root.getChildren().clear();
3086         root.setExpanded(true);
3087         for (int i = 0; i < items; i++) {
3088             root.getChildren().add(new TreeItem<>("Row " + i));
3089         }
3090 
3091         sm.setCellSelectionEnabled(true);
3092 
3093         sm.clearAndSelect(6, col0);
3094         assertEquals(6, getAnchor().getRow());
3095         assertEquals(0, getAnchor().getColumn());
3096         assertEquals(6, fm.getFocusedIndex());
3097         assertEquals(6, sm.getSelectedIndex());
3098 
3099         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3100         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3101         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3102         Toolkit.getToolkit().firePulse();
3103         assertEquals(6, getAnchor().getRow());
3104         assertEquals(0, getAnchor().getColumn());
3105         assertEquals(3, fm.getFocusedIndex());
3106         assertEquals(6, sm.getSelectedIndex());
3107 
3108         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
3109         Toolkit.getToolkit().firePulse();
3110         assertEquals(6, getAnchor().getRow());
3111         assertEquals(0, getAnchor().getColumn());
3112         assertEquals(3, fm.getFocusedIndex());
3113         assertEquals(3, sm.getSelectedIndex());
3114     }
3115 
3116     @Test public void test_rt33613_up_multipleColumn_right() {
3117         final int items = 10;
3118         root.getChildren().clear();
3119         root.setExpanded(true);
3120         for (int i = 0; i < items; i++) {
3121             root.getChildren().add(new TreeItem<>("Row " + i));
3122         }
3123 
3124         sm.setCellSelectionEnabled(true);
3125 
3126         sm.clearAndSelect(6, col0);
3127         assertEquals(6, getAnchor().getRow());
3128         assertEquals(0, getAnchor().getColumn());
3129         assertTrue(fm.isFocused(6, col0));
3130         assertTrue(sm.isSelected(6, col0));
3131 
3132         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3133         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3134         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3135         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.getShortcutKey());
3136         Toolkit.getToolkit().firePulse();
3137         assertEquals(6, getAnchor().getRow());
3138         assertEquals(0, getAnchor().getColumn());
3139         assertTrue(fm.isFocused(3, col1));
3140         assertTrue(sm.isSelected(6, col0));
3141         assertFalse(sm.isSelected(3, col1));
3142 
3143         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
3144         Toolkit.getToolkit().firePulse();
3145         assertEquals(6, getAnchor().getRow());
3146         assertEquals(0, getAnchor().getColumn());
3147         assertTrue(fm.isFocused(3, col1));
3148         assertTrue(sm.isSelected(3, col1));
3149         assertTrue(sm.isSelected(6, col0));
3150     }
3151 
3152     @Test public void test_rt33613_up_multipleColumn_left() {
3153         final int items = 10;
3154         root.getChildren().clear();
3155         root.setExpanded(true);
3156         for (int i = 0; i < items; i++) {
3157             root.getChildren().add(new TreeItem<>("Row " + i));
3158         }
3159 
3160         sm.setCellSelectionEnabled(true);
3161 
3162         sm.clearAndSelect(6, col1);
3163         assertEquals(6, getAnchor().getRow());
3164         assertEquals(1, getAnchor().getColumn());
3165         assertTrue(fm.isFocused(6, col1));
3166         assertTrue(sm.isSelected(6, col1));
3167 
3168         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3169         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3170         keyboard.doKeyPress(KeyCode.UP, KeyModifier.getShortcutKey());
3171         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.getShortcutKey());
3172         Toolkit.getToolkit().firePulse();
3173         assertEquals(6, getAnchor().getRow());
3174         assertEquals(1, getAnchor().getColumn());
3175         assertTrue(fm.isFocused(3, col0));
3176         assertTrue(sm.isSelected(6, col1));
3177         assertFalse(sm.isSelected(3, col0));
3178 
3179         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
3180         Toolkit.getToolkit().firePulse();
3181         assertEquals(6, getAnchor().getRow());
3182         assertEquals(1, getAnchor().getColumn());
3183         assertTrue(fm.isFocused(3, col0));
3184         assertTrue(sm.isSelected(3, col0));
3185         assertTrue(sm.isSelected(6, col1));
3186     }
3187 
3188     @Test public void test_rt33613_down_oneColumn() {
3189         final int items = 10;
3190         root.getChildren().clear();
3191         root.setExpanded(true);
3192         for (int i = 0; i < items; i++) {
3193             root.getChildren().add(new TreeItem<>("Row " + i));
3194         }
3195 
3196         sm.setCellSelectionEnabled(true);
3197 
3198         sm.clearAndSelect(3, col0);
3199         assertEquals(3, getAnchor().getRow());
3200         assertEquals(0, getAnchor().getColumn());
3201         assertEquals(3, fm.getFocusedIndex());
3202         assertEquals(3, sm.getSelectedIndex());
3203 
3204         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3205         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3206         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3207         Toolkit.getToolkit().firePulse();
3208         assertEquals(3, getAnchor().getRow());
3209         assertEquals(0, getAnchor().getColumn());
3210         assertEquals(6, fm.getFocusedIndex());
3211         assertEquals(3, sm.getSelectedIndex());
3212 
3213         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
3214         Toolkit.getToolkit().firePulse();
3215         assertEquals(3, getAnchor().getRow());
3216         assertEquals(0, getAnchor().getColumn());
3217         assertEquals(6, fm.getFocusedIndex());
3218         assertEquals(6, sm.getSelectedIndex());
3219     }
3220 
3221     @Test public void test_rt33613_down_multipleColumn_right() {
3222         final int items = 10;
3223         root.getChildren().clear();
3224         root.setExpanded(true);
3225         for (int i = 0; i < items; i++) {
3226             root.getChildren().add(new TreeItem<>("Row " + i));
3227         }
3228 
3229         sm.setCellSelectionEnabled(true);
3230 
3231         sm.clearAndSelect(3, col0);
3232         assertEquals(3, getAnchor().getRow());
3233         assertEquals(0, getAnchor().getColumn());
3234         assertTrue(fm.isFocused(3, col0));
3235         assertTrue(sm.isSelected(3, col0));
3236 
3237         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3238         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3239         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3240         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.getShortcutKey());
3241         Toolkit.getToolkit().firePulse();
3242         assertEquals(3, getAnchor().getRow());
3243         assertEquals(0, getAnchor().getColumn());
3244         assertTrue(fm.isFocused(6, col1));
3245         assertTrue(sm.isSelected(3, col0));
3246         assertFalse(sm.isSelected(6, col1));
3247 
3248         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
3249         Toolkit.getToolkit().firePulse();
3250         assertEquals(3, getAnchor().getRow());
3251         assertEquals(0, getAnchor().getColumn());
3252         assertTrue(fm.isFocused(6, col1));
3253         assertTrue(sm.isSelected(6, col1));
3254         assertTrue(sm.isSelected(3, col0));
3255     }
3256 
3257     @Test public void test_rt33613_down_multipleColumn_left() {
3258         final int items = 10;
3259         root.getChildren().clear();
3260         root.setExpanded(true);
3261         for (int i = 0; i < items; i++) {
3262             root.getChildren().add(new TreeItem<>("Row " + i));
3263         }
3264 
3265         sm.setCellSelectionEnabled(true);
3266 
3267         sm.clearAndSelect(3, col1);
3268         assertEquals(3, getAnchor().getRow());
3269         assertEquals(1, getAnchor().getColumn());
3270         assertTrue(fm.isFocused(3, col1));
3271         assertTrue(sm.isSelected(3, col1));
3272 
3273         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3274         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3275         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3276         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.getShortcutKey());
3277         Toolkit.getToolkit().firePulse();
3278         assertEquals(3, getAnchor().getRow());
3279         assertEquals(1, getAnchor().getColumn());
3280         assertTrue(fm.isFocused(6, col0));
3281         assertTrue(sm.isSelected(3, col1));
3282         assertFalse(sm.isSelected(6, col0));
3283 
3284         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
3285         Toolkit.getToolkit().firePulse();
3286         assertEquals(3, getAnchor().getRow());
3287         assertEquals(1, getAnchor().getColumn());
3288         assertTrue(fm.isFocused(6, col0));
3289         assertTrue(sm.isSelected(6, col0));
3290         assertTrue(sm.isSelected(3, col1));
3291     }
3292 
3293     @Test public void test_rt18439() {
3294         final int items = 10;
3295         root.getChildren().clear();
3296         root.setExpanded(true);
3297         for (int i = 0; i < items; i++) {
3298             root.getChildren().add(new TreeItem<>("Row " + i));
3299         }
3300 
3301         sm.setCellSelectionEnabled(true);
3302         sm.setSelectionMode(SelectionMode.MULTIPLE);
3303 
3304         sm.clearAndSelect(0, col0);
3305 
3306         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 1
3307         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 2
3308         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 3
3309         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 4
3310         assertEquals(0, getAnchor().getRow());
3311         assertEquals(debug(), 0, getAnchor().getColumn());              // anchor does not move
3312         assertTrue(fm.isFocused(0, col4));
3313         assertTrue(sm.isSelected(0, col0));
3314         assertTrue(sm.isSelected(0, col1));
3315         assertTrue(sm.isSelected(0, col2));
3316         assertTrue(sm.isSelected(0, col3));
3317         assertTrue(sm.isSelected(0, col4));
3318 
3319         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 1
3320         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 2
3321         assertEquals(0, getAnchor().getRow());
3322         assertEquals(0, getAnchor().getColumn());             // anchor does not move
3323         assertTrue(fm.isFocused(2, col4));
3324         assertTrue(sm.isSelected(0, col0));
3325         assertTrue(sm.isSelected(0, col1));
3326         assertTrue(sm.isSelected(0, col2));
3327         assertTrue(sm.isSelected(0, col3));
3328         assertTrue(sm.isSelected(0, col4));
3329         assertTrue(sm.isSelected(1, col4));
3330         assertTrue(sm.isSelected(2, col4));
3331 
3332         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 3
3333         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 2
3334         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 1
3335         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 0
3336         assertEquals(0, getAnchor().getRow());
3337         assertEquals(0, getAnchor().getColumn());             // anchor does not move
3338         assertTrue(fm.isFocused(2, col0));
3339         assertTrue(sm.isSelected(0, col0));
3340         assertTrue(sm.isSelected(0, col1));
3341         assertTrue(sm.isSelected(0, col2));
3342         assertTrue(sm.isSelected(0, col3));
3343         assertTrue(sm.isSelected(0, col4));
3344         assertTrue(sm.isSelected(1, col4));
3345         assertTrue(sm.isSelected(2, col4));
3346         assertTrue(sm.isSelected(2, col3));
3347         assertTrue(sm.isSelected(2, col2));
3348         assertTrue(sm.isSelected(2, col1));
3349         assertTrue(sm.isSelected(2, col0));
3350 
3351         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // row 1
3352         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // row 0
3353         assertEquals(0, getAnchor().getRow());
3354         assertEquals(0, getAnchor().getColumn());           // anchor does not move
3355         assertTrue(fm.isFocused(0, col0));
3356         assertFalse(sm.isSelected(0, col0));                // we've gone right around - this cell is now unselected
3357         assertTrue(sm.isSelected(0, col1));
3358         assertTrue(sm.isSelected(0, col2));
3359         assertTrue(sm.isSelected(0, col3));
3360         assertTrue(sm.isSelected(0, col4));
3361         assertTrue(sm.isSelected(1, col4));
3362         assertTrue(sm.isSelected(2, col4));
3363         assertTrue(sm.isSelected(2, col3));
3364         assertTrue(sm.isSelected(2, col2));
3365         assertTrue(sm.isSelected(2, col1));
3366         assertTrue(sm.isSelected(2, col0));
3367         assertTrue(sm.isSelected(1, col0));
3368     }
3369 
3370     // this is an extension of the previous test, where we had a bug where going up resulted in all cells between the
3371     // anchor (at (0,0)) and the first selected cell in column 0 were being selected. This wasn't visible in the previous
3372     // test as we only went down two rows, so when we went up everything looked as expected
3373     @Test public void test_rt18439_startAt_row0_col0_clockwise() {
3374         final int items = 10;
3375         root.getChildren().clear();
3376         root.setExpanded(true);
3377         for (int i = 0; i < items; i++) {
3378             root.getChildren().add(new TreeItem<>("Row " + i));
3379         }
3380 
3381         sm.setCellSelectionEnabled(true);
3382         sm.setSelectionMode(SelectionMode.MULTIPLE);
3383 
3384         sm.clearAndSelect(0, col0);
3385 
3386         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 1
3387         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 2
3388         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 3
3389         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 4
3390 
3391         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 1
3392         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 2
3393         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 3
3394         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 4
3395 
3396         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 3
3397         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 2
3398         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 1
3399         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 0
3400 
3401         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // row 3
3402         assertEquals(0, getAnchor().getRow());
3403         assertEquals(0, getAnchor().getColumn());           // anchor does not move
3404         assertTrue(fm.isFocused(3, col0));
3405         assertTrue(sm.isSelected(0, col0));
3406         assertTrue(sm.isSelected(0, col1));
3407         assertTrue(sm.isSelected(0, col2));
3408         assertTrue(sm.isSelected(0, col3));
3409         assertTrue(sm.isSelected(0, col4));
3410         assertTrue(sm.isSelected(1, col4));
3411         assertTrue(sm.isSelected(2, col4));
3412         assertTrue(sm.isSelected(3, col4));
3413         assertTrue(sm.isSelected(4, col4));
3414         assertTrue(sm.isSelected(4, col3));
3415         assertTrue(sm.isSelected(4, col2));
3416         assertTrue(sm.isSelected(4, col1));
3417         assertTrue(sm.isSelected(4, col0));
3418         assertTrue(sm.isSelected(3, col0));
3419 
3420         // critical part - these cells should not be selected!
3421         assertFalse(sm.isSelected(1, col0));
3422         assertFalse(sm.isSelected(2, col0));
3423     }
3424 
3425     @Test public void test_rt18439_startAt_row0_col4_clockwise() {
3426         final int items = 10;
3427         root.getChildren().clear();
3428         root.setExpanded(true);
3429         for (int i = 0; i < items; i++) {
3430             root.getChildren().add(new TreeItem<>("Row " + i));
3431         }
3432 
3433         sm.setCellSelectionEnabled(true);
3434         sm.setSelectionMode(SelectionMode.MULTIPLE);
3435 
3436         sm.clearAndSelect(0, col4);
3437 
3438         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 1
3439         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 2
3440         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 3
3441         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 4
3442 
3443         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 3
3444         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 2
3445         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 1
3446         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 0
3447 
3448         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);   // row 3
3449         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);   // row 2
3450         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);   // row 1
3451         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);   // row 0
3452 
3453         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 1
3454         assertEquals(0, getAnchor().getRow());
3455         assertEquals(4, getAnchor().getColumn());           // anchor does not move
3456         assertTrue(fm.isFocused(0, col1));
3457         assertTrue(sm.isSelected(0, col4));
3458         assertTrue(sm.isSelected(1, col4));
3459         assertTrue(sm.isSelected(2, col4));
3460         assertTrue(sm.isSelected(3, col4));
3461         assertTrue(sm.isSelected(4, col4));
3462         assertTrue(sm.isSelected(4, col3));
3463         assertTrue(sm.isSelected(4, col2));
3464         assertTrue(sm.isSelected(4, col1));
3465         assertTrue(sm.isSelected(4, col0));
3466         assertTrue(sm.isSelected(3, col0));
3467         assertTrue(sm.isSelected(2, col0));
3468         assertTrue(sm.isSelected(1, col0));
3469         assertTrue(sm.isSelected(0, col0));
3470         assertTrue(sm.isSelected(0, col1));
3471 
3472         // critical part - these cells should not be selected!
3473         assertFalse(sm.isSelected(0, col2));
3474         assertFalse(sm.isSelected(0, col3));
3475     }
3476 
3477     @Test public void test_rt18439_startAt_row4_col4_clockwise() {
3478         final int items = 10;
3479         root.getChildren().clear();
3480         root.setExpanded(true);
3481         for (int i = 0; i < items; i++) {
3482             root.getChildren().add(new TreeItem<>("Row " + i));
3483         }
3484 
3485         sm.setCellSelectionEnabled(true);
3486         sm.setSelectionMode(SelectionMode.MULTIPLE);
3487 
3488         sm.clearAndSelect(4, col4);
3489 
3490         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 3
3491         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 2
3492         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 1
3493         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 0
3494 
3495         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);   // row 3
3496         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);   // row 2
3497         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);   // row 1
3498         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);   // row 0
3499 
3500         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 1
3501         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 2
3502         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 3
3503         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT); // col 4
3504 
3505         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 1
3506         assertEquals(4, getAnchor().getRow());
3507         assertEquals(4, getAnchor().getColumn());           // anchor does not move
3508         assertTrue(fm.isFocused(1, col4));
3509         assertTrue(sm.isSelected(4, col4));
3510         assertTrue(sm.isSelected(4, col2));
3511         assertTrue(sm.isSelected(4, col2));
3512         assertTrue(sm.isSelected(4, col1));
3513         assertTrue(sm.isSelected(4, col0));
3514         assertTrue(sm.isSelected(3, col0));
3515         assertTrue(sm.isSelected(2, col0));
3516         assertTrue(sm.isSelected(1, col0));
3517         assertTrue(sm.isSelected(0, col0));
3518         assertTrue(sm.isSelected(0, col1));
3519         assertTrue(sm.isSelected(0, col2));
3520         assertTrue(sm.isSelected(0, col3));
3521         assertTrue(sm.isSelected(0, col4));
3522         assertTrue(sm.isSelected(1, col4));
3523 
3524         // critical part - these cells should not be selected!
3525         assertFalse(sm.isSelected(2, col4));
3526         assertFalse(sm.isSelected(3, col4));
3527     }
3528 
3529     @Test public void test_rt18439_startAt_row4_col0_clockwise() {
3530         final int items = 10;
3531         root.getChildren().clear();
3532         root.setExpanded(true);
3533         for (int i = 0; i < items; i++) {
3534             root.getChildren().add(new TreeItem<>("Row " + i));
3535         }
3536 
3537         sm.setCellSelectionEnabled(true);
3538         sm.setSelectionMode(SelectionMode.MULTIPLE);
3539 
3540         sm.clearAndSelect(4, col0);
3541 
3542         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // row 3
3543         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // row 2
3544         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // row 1
3545         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // row 0
3546 
3547         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT);   // col 1
3548         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT);   // col 2
3549         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT);   // col 3
3550         keyboard.doKeyPress(KeyCode.RIGHT, KeyModifier.SHIFT);   // col 4
3551 
3552         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 1
3553         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 2
3554         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 3
3555         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT); // row 4
3556 
3557         keyboard.doKeyPress(KeyCode.LEFT, KeyModifier.SHIFT); // col 3
3558         assertEquals(4, getAnchor().getRow());
3559         assertEquals(0, getAnchor().getColumn());           // anchor does not move
3560         assertTrue(fm.isFocused(4, col3));
3561         assertTrue(sm.isSelected(4, col0));
3562         assertTrue(sm.isSelected(3, col0));
3563         assertTrue(sm.isSelected(2, col0));
3564         assertTrue(sm.isSelected(1, col0));
3565         assertTrue(sm.isSelected(0, col0));
3566         assertTrue(sm.isSelected(0, col1));
3567         assertTrue(sm.isSelected(0, col2));
3568         assertTrue(sm.isSelected(0, col3));
3569         assertTrue(sm.isSelected(0, col4));
3570         assertTrue(sm.isSelected(1, col4));
3571         assertTrue(sm.isSelected(2, col4));
3572         assertTrue(sm.isSelected(3, col4));
3573         assertTrue(sm.isSelected(4, col4));
3574         assertTrue(sm.isSelected(4, col3));
3575 
3576         // critical part - these cells should not be selected!
3577         assertFalse(sm.isSelected(4, col2));
3578         assertFalse(sm.isSelected(4, col1));
3579     }
3580 
3581     @Test public void test_rt34461_cellSelection() {
3582         final int items = 10;
3583         root.getChildren().clear();
3584         root.setExpanded(true);
3585         for (int i = 0; i < items; i++) {
3586             root.getChildren().add(new TreeItem<>("Row " + i));
3587         }
3588 
3589         sm.setCellSelectionEnabled(true);
3590         sm.setSelectionMode(SelectionMode.MULTIPLE);
3591 
3592         sm.clearAndSelect(0, col0);
3593         assertEquals(0, getAnchor().getRow());
3594         assertEquals(0, getAnchor().getColumn());
3595         assertTrue(fm.isFocused(0, col0));
3596         assertTrue(sm.isSelected(0, col0));
3597         assertFalse(sm.isSelected(1, col0));
3598 
3599         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3600         assertEquals(0, getAnchor().getRow());
3601         assertEquals(0, getAnchor().getColumn());
3602         assertTrue(fm.isFocused(1, col0));
3603         assertTrue(sm.isSelected(0, col0));
3604         assertFalse(sm.isSelected(1, col0));
3605 
3606         keyboard.doKeyPress(KeyCode.SPACE);
3607         assertEquals(1, getAnchor().getRow());      // new anchor point
3608         assertEquals(0, getAnchor().getColumn());
3609         assertTrue(fm.isFocused(1, col0));
3610         assertTrue(sm.isSelected(0, col0));
3611         assertTrue(sm.isSelected(1, col0));
3612 
3613         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);
3614         assertEquals(1, getAnchor().getRow());
3615         assertEquals(0, getAnchor().getColumn());
3616         assertTrue(fm.isFocused(2, col0));
3617         assertFalse(sm.isSelected(0, col0));    // selection moves off here as the anchor point moved with the space
3618         assertTrue(sm.isSelected(1, col0));
3619         assertTrue(sm.isSelected(2, col0));
3620     }
3621 
3622     @Test public void test_rt34461_rowSelection() {
3623         final int items = 10;
3624         root.getChildren().clear();
3625         root.setExpanded(true);
3626         for (int i = 0; i < items; i++) {
3627             root.getChildren().add(new TreeItem<>("Row " + i));
3628         }
3629 
3630         sm.setCellSelectionEnabled(false);
3631         sm.setSelectionMode(SelectionMode.MULTIPLE);
3632 
3633         sm.clearAndSelect(0);
3634         assertEquals(0, getAnchor().getRow());
3635         assertEquals(-1, getAnchor().getColumn());
3636         assertTrue(fm.isFocused(0));
3637         assertTrue(sm.isSelected(0));
3638         assertFalse(sm.isSelected(1));
3639 
3640         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.getShortcutKey());
3641         assertEquals(0, getAnchor().getRow());
3642         assertEquals(-1, getAnchor().getColumn());
3643         assertTrue(fm.isFocused(1));
3644         assertTrue(sm.isSelected(0));
3645         assertFalse(sm.isSelected(1));
3646 
3647         keyboard.doKeyPress(KeyCode.SPACE);
3648         assertEquals(1, getAnchor().getRow());      // new anchor point
3649         assertEquals(-1, getAnchor().getColumn());
3650         assertTrue(fm.isFocused(1));
3651         assertTrue(sm.isSelected(0));
3652         assertTrue(sm.isSelected(1));
3653 
3654         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);
3655         assertEquals(1, getAnchor().getRow());
3656         assertEquals(-1, getAnchor().getColumn());
3657         assertTrue(fm.isFocused(2));
3658         assertFalse(sm.isSelected(0));    // selection moves off here as the anchor point moved with the space
3659         assertTrue(sm.isSelected(1));
3660         assertTrue(sm.isSelected(2));
3661     }
3662 
3663     @Test public void test_rt34407_down_down_up() {
3664         final int items = 100;
3665         root.getChildren().clear();
3666         root.setExpanded(true);
3667         for (int i = 0; i < items; i++) {
3668             root.getChildren().add(new TreeItem<>("Row " + i));
3669         }
3670         tableView.setPrefHeight(130); // roughly room for four rows
3671 
3672         StageLoader sl = new StageLoader(tableView);
3673         sm.setCellSelectionEnabled(false);
3674         sm.setSelectionMode(SelectionMode.MULTIPLE);
3675 
3676         sm.clearAndSelect(0);
3677         fm.focus(0);
3678         assertEquals(0, getAnchor().getRow());
3679         assertEquals(-1, getAnchor().getColumn());
3680         assertTrue(fm.isFocused(0));
3681         assertTrue(sm.isSelected(0));
3682         assertFalse(sm.isSelected(1));
3683 
3684         // we expect the final Page-up to return us back to this selected index and with the same number of selected indices
3685         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
3686         final int leadSelectedIndex = sm.getSelectedIndex();
3687         final int selectedIndicesCount = sm.getSelectedIndices().size();
3688         assertEquals(3, leadSelectedIndex);
3689         assertEquals(3, fm.getFocusedIndex());
3690         assertEquals(4, selectedIndicesCount);
3691 
3692         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
3693         assertEquals(leadSelectedIndex * 2, sm.getSelectedIndex());
3694         assertEquals(leadSelectedIndex * 2, fm.getFocusedIndex());
3695         assertEquals(selectedIndicesCount * 2 - 1, sm.getSelectedIndices().size());
3696 
3697         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
3698         assertEquals(leadSelectedIndex, sm.getSelectedIndex());
3699         assertEquals(leadSelectedIndex, fm.getFocusedIndex());
3700         assertEquals(selectedIndicesCount, sm.getSelectedIndices().size());
3701 
3702         sl.dispose();
3703     }
3704 
3705     @Test public void test_rt34407_up_up_down() {
3706         final int items = 100;
3707         root.getChildren().clear();
3708         root.setExpanded(true);
3709         for (int i = 0; i < items; i++) {
3710             root.getChildren().add(new TreeItem<>("Row " + i));
3711         }
3712         tableView.setPrefHeight(160); // roughly room for four rows
3713 
3714         StageLoader sl = new StageLoader(tableView);
3715         sm.setCellSelectionEnabled(false);
3716         sm.setSelectionMode(SelectionMode.MULTIPLE);
3717 
3718         sm.clearAndSelect(99);
3719         fm.focus(99);
3720         tableView.scrollTo(99);
3721         Toolkit.getToolkit().firePulse();
3722 
3723         assertEquals(99, getAnchor().getRow());
3724         assertEquals(-1, getAnchor().getColumn());
3725         assertTrue(fm.isFocused(99));
3726         assertTrue(sm.isSelected(99));
3727         assertFalse(sm.isSelected(98));
3728 
3729         // we expect the final Page-down to return us back to this selected index and with the same number of selected indices
3730         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
3731         final int leadSelectedIndex = sm.getSelectedIndex();
3732         final int selectedIndicesCount = sm.getSelectedIndices().size();
3733         final int diff = 99 - leadSelectedIndex;
3734         assertEquals(99 - diff, leadSelectedIndex);
3735         assertEquals(99 - diff, fm.getFocusedIndex());
3736         assertEquals(4, selectedIndicesCount);
3737 
3738         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
3739         assertEquals(99 - diff * 2 - 1, sm.getSelectedIndex());
3740         assertEquals(selectedIndicesCount * 2, sm.getSelectedIndices().size());
3741 
3742         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
3743         assertEquals(leadSelectedIndex, sm.getSelectedIndex());
3744         assertEquals(selectedIndicesCount, sm.getSelectedIndices().size());
3745 
3746         sl.dispose();
3747     }
3748 
3749     @Test public void test_rt34768() {
3750         tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
3751         TreeTableColumn<String, String> firstNameCol = new TreeTableColumn<>("First Name");
3752         tableView.getColumns().setAll(firstNameCol);
3753         tableView.setRoot(null);
3754 
3755         // no need for an assert here - we're testing for an AIOOBE
3756         keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey());
3757     }
3758 
3759     @Test public void test_rt35853_multipleSelection_rowSelection_shiftDown() {
3760         final int items = 10;
3761         root.getChildren().clear();
3762         root.setExpanded(true);
3763         for (int i = 0; i < items; i++) {
3764             root.getChildren().add(new TreeItem<>("Row " + i));
3765         }
3766 
3767         sm.setSelectionMode(SelectionMode.MULTIPLE);
3768 
3769         sm.clearAndSelect(5);
3770         assertEquals(5, getAnchor().getRow());
3771         assertTrue(fm.isFocused(5));
3772         assertTrue(sm.isSelected(5));
3773 
3774         sm.selectedIndexProperty().addListener(observable -> {
3775             // we expect only one selected index change event, from 5 to 4
3776             assertEquals(4, sm.getSelectedIndex());
3777         });
3778 
3779         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
3780         assertEquals(5, getAnchor().getRow());
3781         assertTrue(fm.isFocused(4));
3782         assertTrue(sm.isSelected(4));
3783         assertTrue(sm.isSelected(5));
3784     }
3785 
3786     @Test public void test_rt35853_multipleSelection_rowSelection_noShiftDown() {
3787         final int items = 10;
3788         root.getChildren().clear();
3789         root.setExpanded(true);
3790         for (int i = 0; i < items; i++) {
3791             root.getChildren().add(new TreeItem<>("Row " + i));
3792         }
3793 
3794         sm.setSelectionMode(SelectionMode.MULTIPLE);
3795 
3796         sm.clearAndSelect(5);
3797         assertEquals(5, getAnchor().getRow());
3798         assertTrue(fm.isFocused(5));
3799         assertTrue(sm.isSelected(5));
3800 
3801         sm.selectedIndexProperty().addListener(observable -> {
3802             // we expect only one selected index change event, from 5 to 4
3803             assertEquals(4, sm.getSelectedIndex());
3804         });
3805 
3806         keyboard.doKeyPress(KeyCode.UP);
3807         assertEquals(4, getAnchor().getRow());
3808         assertTrue(fm.isFocused(4));
3809         assertTrue(sm.isSelected(4));
3810         assertFalse(sm.isSelected(5));
3811     }
3812 
3813     @Test public void test_rt35853_singleSelection_rowSelection_shiftDown() {
3814         final int items = 10;
3815         root.getChildren().clear();
3816         root.setExpanded(true);
3817         for (int i = 0; i < items; i++) {
3818             root.getChildren().add(new TreeItem<>("Row " + i));
3819         }
3820 
3821         sm.setSelectionMode(SelectionMode.SINGLE);
3822 
3823         sm.clearAndSelect(5);
3824         assertEquals(5, getAnchor().getRow());
3825         assertTrue(fm.isFocused(5));
3826         assertTrue(sm.isSelected(5));
3827 
3828         sm.selectedIndexProperty().addListener(observable -> {
3829             // we expect only one selected index change event, from 5 to 4
3830             assertEquals(4, sm.getSelectedIndex());
3831         });
3832 
3833         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
3834         assertEquals(4, getAnchor().getRow());
3835         assertTrue(fm.isFocused(4));
3836         assertTrue(sm.isSelected(4));
3837         assertFalse(sm.isSelected(5));
3838     }
3839 
3840     @Test public void test_rt35853_singleSelection_rowSelection_noShiftDown() {
3841         final int items = 10;
3842         root.getChildren().clear();
3843         root.setExpanded(true);
3844         for (int i = 0; i < items; i++) {
3845             root.getChildren().add(new TreeItem<>("Row " + i));
3846         }
3847 
3848         sm.setSelectionMode(SelectionMode.SINGLE);
3849 
3850         sm.clearAndSelect(5);
3851         assertEquals(5, getAnchor().getRow());
3852         assertTrue(fm.isFocused(5));
3853         assertTrue(sm.isSelected(5));
3854 
3855         sm.selectedIndexProperty().addListener(observable -> {
3856             // we expect only one selected index change event, from 5 to 4
3857             assertEquals(4, sm.getSelectedIndex());
3858         });
3859 
3860         keyboard.doKeyPress(KeyCode.UP);
3861         assertEquals(4, getAnchor().getRow());
3862         assertTrue(fm.isFocused(4));
3863         assertTrue(sm.isSelected(4));
3864         assertFalse(sm.isSelected(5));
3865     }
3866 
3867     @Test public void test_rt35853_multipleSelection_cellSelection_shiftDown() {
3868         final int items = 10;
3869         root.getChildren().clear();
3870         root.setExpanded(true);
3871         for (int i = 0; i < items; i++) {
3872             root.getChildren().add(new TreeItem<>("Row " + i));
3873         }
3874 
3875         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
3876         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
3877         tableView.getColumns().setAll(col);
3878 
3879         sm.setSelectionMode(SelectionMode.MULTIPLE);
3880         sm.setCellSelectionEnabled(true);
3881 
3882         sm.clearAndSelect(5, col);
3883         assertEquals(5, getAnchor().getRow());
3884         assertTrue(fm.isFocused(5, col));
3885         assertTrue(sm.isSelected(5, col));
3886 
3887         sm.selectedIndexProperty().addListener(observable -> {
3888             // we expect only one selected index change event, from 5 to 4
3889             assertEquals(4, sm.getSelectedIndex());
3890         });
3891 
3892         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
3893         assertEquals(5, getAnchor().getRow());
3894         assertTrue(fm.isFocused(4, col));
3895         assertTrue(sm.isSelected(4, col));
3896         assertTrue(sm.isSelected(5, col));
3897     }
3898 
3899     @Test public void test_rt35853_multipleSelection_cellSelection_noShiftDown() {
3900         final int items = 10;
3901         root.getChildren().clear();
3902         root.setExpanded(true);
3903         for (int i = 0; i < items; i++) {
3904             root.getChildren().add(new TreeItem<>("Row " + i));
3905         }
3906 
3907         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
3908         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
3909         tableView.getColumns().setAll(col);
3910 
3911         sm.setSelectionMode(SelectionMode.MULTIPLE);
3912         sm.setCellSelectionEnabled(true);
3913 
3914         sm.clearAndSelect(5, col);
3915         assertEquals(5, getAnchor().getRow());
3916         assertTrue(fm.isFocused(5, col));
3917         assertTrue(sm.isSelected(5, col));
3918 
3919         sm.selectedIndexProperty().addListener(observable -> {
3920             // we expect only one selected index change event, from 5 to 4
3921             assertEquals(4, sm.getSelectedIndex());
3922         });
3923 
3924         keyboard.doKeyPress(KeyCode.UP);
3925         assertEquals(4, getAnchor().getRow());
3926         assertTrue(fm.isFocused(4, col));
3927         assertTrue(sm.isSelected(4, col));
3928         assertFalse(sm.isSelected(5, col));
3929     }
3930 
3931     @Test public void test_rt35853_singleSelection_cellSelection_shiftDown() {
3932         final int items = 10;
3933         root.getChildren().clear();
3934         root.setExpanded(true);
3935         for (int i = 0; i < items; i++) {
3936             root.getChildren().add(new TreeItem<>("Row " + i));
3937         }
3938 
3939         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
3940         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
3941         tableView.getColumns().setAll(col);
3942 
3943         sm.setSelectionMode(SelectionMode.SINGLE);
3944         sm.setCellSelectionEnabled(true);
3945 
3946         sm.clearAndSelect(5, col);
3947         assertEquals(5, getAnchor().getRow());
3948         assertTrue(fm.isFocused(5, col));
3949         assertTrue(sm.isSelected(5, col));
3950 
3951         sm.selectedIndexProperty().addListener(observable -> {
3952             // we expect only one selected index change event, from 5 to 4
3953             assertEquals(4, sm.getSelectedIndex());
3954         });
3955 
3956         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
3957         assertEquals(4, getAnchor().getRow());
3958         assertTrue(fm.isFocused(4, col));
3959         assertTrue(sm.isSelected(4, col));
3960         assertFalse(sm.isSelected(5, col));
3961     }
3962 
3963     @Test public void test_rt35853_singleSelection_cellSelection_noShiftDown() {
3964         final int items = 10;
3965         root.getChildren().clear();
3966         root.setExpanded(true);
3967         for (int i = 0; i < items; i++) {
3968             root.getChildren().add(new TreeItem<>("Row " + i));
3969         }
3970 
3971         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
3972         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
3973         tableView.getColumns().setAll(col);
3974 
3975         sm.setSelectionMode(SelectionMode.SINGLE);
3976         sm.setCellSelectionEnabled(true);
3977 
3978         sm.clearAndSelect(5, col);
3979         assertEquals(5, getAnchor().getRow());
3980         assertTrue(fm.isFocused(5, col));
3981         assertTrue(sm.isSelected(5, col));
3982 
3983         sm.selectedIndexProperty().addListener(observable -> {
3984             // we expect only one selected index change event, from 5 to 4
3985             assertEquals(4, sm.getSelectedIndex());
3986         });
3987 
3988         keyboard.doKeyPress(KeyCode.UP);
3989         assertEquals(4, getAnchor().getRow());
3990         assertTrue(fm.isFocused(4, col));
3991         assertTrue(sm.isSelected(4, col));
3992         assertFalse(sm.isSelected(5, col));
3993     }
3994 
3995     @Test public void test_rt36800_rowSelection() {
3996         test_rt36800(false);
3997     }
3998 
3999     @Test public void test_rt36800_cellSelection() {
4000         test_rt36800(true);
4001     }
4002 
4003     private void test_rt36800(boolean cellSelection) {
4004         // get the current exception handler before replacing with our own,
4005         // as ListListenerHelp intercepts the exception otherwise
4006         final Thread.UncaughtExceptionHandler exceptionHandler = Thread.currentThread().getUncaughtExceptionHandler();
4007         Thread.currentThread().setUncaughtExceptionHandler((t, e) -> {
4008             e.printStackTrace();
4009             fail("We don't expect any exceptions in this test!");
4010         });
4011 
4012         final int items = 10;
4013         root.getChildren().clear();
4014         root.setExpanded(true);
4015         for (int i = 0; i < items; i++) {
4016             root.getChildren().add(new TreeItem<>("Row " + i));
4017         }
4018 
4019         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
4020         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4021         tableView.getColumns().setAll(col);
4022 
4023         sm.setSelectionMode(SelectionMode.SINGLE);
4024         sm.setCellSelectionEnabled(cellSelection);
4025 
4026         if (cellSelection) {
4027             sm.clearAndSelect(5, col);
4028             assertEquals(5, getAnchor().getRow());
4029             assertEquals(col, getAnchor().getTableColumn());
4030             assertTrue(fm.isFocused(5, col));
4031             assertTrue(sm.isSelected(5, col));
4032         } else {
4033             sm.clearAndSelect(5);
4034             assertEquals(5, getAnchor().getRow());
4035             assertTrue(fm.isFocused(5));
4036             assertTrue(sm.isSelected(5));
4037         }
4038 
4039         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // 4
4040         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // 3
4041         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // 2
4042         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // 1
4043         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // 0
4044         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT); // bug time?
4045 
4046         if (cellSelection) {
4047             assertEquals(0, getAnchor().getRow());
4048             assertEquals(col, getAnchor().getTableColumn());
4049             assertTrue(fm.isFocused(0, col));
4050             assertTrue(sm.isSelected(0, col));
4051             assertFalse(sm.isSelected(1, col));
4052             assertFalse(sm.isSelected(2, col));
4053             assertFalse(sm.isSelected(3, col));
4054             assertFalse(sm.isSelected(4, col));
4055             assertFalse(sm.isSelected(5, col));
4056         } else {
4057             assertEquals(0, getAnchor().getRow());
4058             assertTrue(fm.isFocused(0));
4059             assertTrue(sm.isSelected(0));
4060             assertFalse(sm.isSelected(1));
4061             assertFalse(sm.isSelected(2));
4062             assertFalse(sm.isSelected(3));
4063             assertFalse(sm.isSelected(4));
4064             assertFalse(sm.isSelected(5));
4065         }
4066 
4067         // reset the exception handler
4068         Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler);
4069     }
4070 
4071     @Test public void test_rt_37130_pageUpAtTop() {
4072         final int items = 100;
4073         root.getChildren().clear();
4074         root.setExpanded(true);
4075         for (int i = 0; i < items; i++) {
4076             root.getChildren().add(new TreeItem<>("Row " + i));
4077         }
4078 
4079         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
4080         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4081         tableView.getColumns().setAll(col);
4082 
4083         sm.setSelectionMode(SelectionMode.MULTIPLE);
4084         sm.setCellSelectionEnabled(true);
4085 
4086         StageLoader sl = new StageLoader(tableView);
4087 
4088         sm.select(5, col);
4089         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
4090         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
4091 
4092         sl.dispose();
4093     }
4094 
4095     @Test public void test_rt_37130_pageUpAtBottom() {
4096         final int items = 100;
4097         root.getChildren().clear();
4098         root.setExpanded(true);
4099         for (int i = 0; i < items; i++) {
4100             root.getChildren().add(new TreeItem<>("Row " + i));
4101         }
4102 
4103         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
4104         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4105         tableView.getColumns().setAll(col);
4106 
4107         sm.setSelectionMode(SelectionMode.MULTIPLE);
4108         sm.setCellSelectionEnabled(true);
4109 
4110         StageLoader sl = new StageLoader(tableView);
4111 
4112         sm.select(95, col);
4113         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
4114         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
4115 
4116         sl.dispose();
4117     }
4118 
4119     @Test public void test_rt_37130_pageDownAtTop() {
4120         final int items = 100;
4121         root.getChildren().clear();
4122         root.setExpanded(true);
4123         for (int i = 0; i < items; i++) {
4124             root.getChildren().add(new TreeItem<>("Row " + i));
4125         }
4126 
4127         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
4128         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4129         tableView.getColumns().setAll(col);
4130 
4131         sm.setSelectionMode(SelectionMode.MULTIPLE);
4132         sm.setCellSelectionEnabled(true);
4133 
4134         StageLoader sl = new StageLoader(tableView);
4135 
4136         sm.select(5, col);
4137         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
4138         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
4139 
4140         sl.dispose();
4141     }
4142 
4143     @Test public void test_rt_37130_pageDownAtBottom() {
4144         final int items = 100;
4145         root.getChildren().clear();
4146         root.setExpanded(true);
4147         for (int i = 0; i < items; i++) {
4148             root.getChildren().add(new TreeItem<>("Row " + i));
4149         }
4150 
4151         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
4152         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4153         tableView.getColumns().setAll(col);
4154 
4155         sm.setSelectionMode(SelectionMode.MULTIPLE);
4156         sm.setCellSelectionEnabled(true);
4157 
4158         StageLoader sl = new StageLoader(tableView);
4159 
4160         sm.select(95, col);
4161         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
4162         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.SHIFT);
4163 
4164         sl.dispose();
4165     }
4166 
4167 //    @Test public void test_rt_38326() {
4168 //        int argCount = 4;
4169 //        int testCount = (int) Math.pow(2, argCount);
4170 //        for (int test = 0; test < testCount; test++) {
4171 //            boolean moveUp                                      = (test & 0b1000) == 0b1000;
4172 //            boolean singleSelection                             = (test & 0b0100) == 0b0100;
4173 //            boolean cellSelection                               = (test & 0b0010) == 0b0010;
4174 //            boolean updateItemsListBeforeSelectionModelChanges  = (test & 0b0001) == 0b0001;
4175 //
4176 //            StringBuilder sb = new StringBuilder("@Test public void test_rt_38326_focusLostOnShortcutKeyNav_");
4177 //            sb.append(moveUp ? "moveUp_" : "moveDown_");
4178 //            sb.append(singleSelection ? "singleSelection_" : "multipleSelection_");
4179 //            sb.append(cellSelection ? "cellSelection_" : "rowSelection_");
4180 //            sb.append(updateItemsListBeforeSelectionModelChanges ? "updateItemsListBeforeSelectionModelChanges" : "updateItemsListAfterSelectionModelChanges");
4181 //            sb.append("() {\n    ");
4182 //            sb.append("test_rt_38326(");
4183 //            sb.append(moveUp + ", ");
4184 //            sb.append(singleSelection + ", ");
4185 //            sb.append(cellSelection + ", ");
4186 //            sb.append(updateItemsListBeforeSelectionModelChanges);
4187 //            sb.append(");\n}");
4188 //
4189 //            System.out.println(sb);
4190 //        }
4191 //    }
4192 
4193     // -- tests generated by above commented out code
4194     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveDown_multipleSelection_rowSelection_updateItemsListAfterSelectionModelChanges() {
4195         test_rt_38326(false, false, false, false);
4196     }
4197     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveDown_multipleSelection_rowSelection_updateItemsListBeforeSelectionModelChanges() {
4198         test_rt_38326(false, false, false, true);
4199     }
4200     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveDown_multipleSelection_cellSelection_updateItemsListAfterSelectionModelChanges() {
4201         test_rt_38326(false, false, true, false);
4202     }
4203     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveDown_multipleSelection_cellSelection_updateItemsListBeforeSelectionModelChanges() {
4204         test_rt_38326(false, false, true, true);
4205     }
4206     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveDown_singleSelection_rowSelection_updateItemsListAfterSelectionModelChanges() {
4207         test_rt_38326(false, true, false, false);
4208     }
4209     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveDown_singleSelection_rowSelection_updateItemsListBeforeSelectionModelChanges() {
4210         test_rt_38326(false, true, false, true);
4211     }
4212     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveDown_singleSelection_cellSelection_updateItemsListAfterSelectionModelChanges() {
4213         test_rt_38326(false, true, true, false);
4214     }
4215     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveDown_singleSelection_cellSelection_updateItemsListBeforeSelectionModelChanges() {
4216         test_rt_38326(false, true, true, true);
4217     }
4218     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveUp_multipleSelection_rowSelection_updateItemsListAfterSelectionModelChanges() {
4219         test_rt_38326(true, false, false, false);
4220     }
4221     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveUp_multipleSelection_rowSelection_updateItemsListBeforeSelectionModelChanges() {
4222         test_rt_38326(true, false, false, true);
4223     }
4224     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveUp_multipleSelection_cellSelection_updateItemsListAfterSelectionModelChanges() {
4225         test_rt_38326(true, false, true, false);
4226     }
4227     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveUp_multipleSelection_cellSelection_updateItemsListBeforeSelectionModelChanges() {
4228         test_rt_38326(true, false, true, true);
4229     }
4230     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveUp_singleSelection_rowSelection_updateItemsListAfterSelectionModelChanges() {
4231         test_rt_38326(true, true, false, false);
4232     }
4233     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveUp_singleSelection_rowSelection_updateItemsListBeforeSelectionModelChanges() {
4234         test_rt_38326(true, true, false, true);
4235     }
4236     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveUp_singleSelection_cellSelection_updateItemsListAfterSelectionModelChanges() {
4237         test_rt_38326(true, true, true, false);
4238     }
4239     @Test public void test_rt_38326_focusLostOnShortcutKeyNav_moveUp_singleSelection_cellSelection_updateItemsListBeforeSelectionModelChanges() {
4240         test_rt_38326(true, true, true, true);
4241     }
4242 
4243     private void test_rt_38326(boolean moveUp, boolean singleSelection, boolean cellSelection, boolean updateItemsListBeforeSelectionModelChanges) {
4244         final int items = 10;
4245         ObservableList<TreeItem<String>> itemsList = FXCollections.observableArrayList();
4246         for (int i = 0; i < items; i++) {
4247             itemsList.add(new TreeItem<>("Row " + i));
4248         }
4249 
4250         root.setExpanded(true);
4251 
4252         if (updateItemsListBeforeSelectionModelChanges) {
4253             root.getChildren().clear();
4254             root.getChildren().addAll(itemsList);
4255         }
4256 
4257         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
4258         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4259 
4260         TreeTableColumn<String, String> col2 = new TreeTableColumn<>("Column 2");
4261         col2.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4262 
4263         tableView.getColumns().setAll(col, col2);
4264 
4265         TreeTableView.TreeTableViewSelectionModel<String> sm = tableView.getSelectionModel();
4266         sm.setSelectionMode(singleSelection ? SelectionMode.SINGLE : SelectionMode.MULTIPLE);
4267         sm.setCellSelectionEnabled(cellSelection);
4268 
4269         if (! updateItemsListBeforeSelectionModelChanges) {
4270             root.getChildren().clear();
4271             root.getChildren().addAll(itemsList);
4272         }
4273 
4274         StageLoader sl = new StageLoader(tableView);
4275 
4276         // test the initial state to ensure it is as we expect
4277         assertFalse(sm.isSelected(0));
4278         assertFalse(sm.isSelected(0, col));
4279         assertFalse(sm.isSelected(0, col2));
4280         assertEquals(0, sm.getSelectedIndices().size());
4281         assertEquals(0, sm.getSelectedItems().size());
4282         assertEquals(0, sm.getSelectedCells().size());
4283 
4284         final int startRow = 5;
4285         sm.clearSelection();
4286         sm.select(startRow, col);
4287         assertEquals(1, sm.getSelectedCells().size());
4288         assertEquals(startRow, sm.getSelectedCells().get(0).getRow());
4289         assertEquals(col, sm.getSelectedCells().get(0).getTableColumn());
4290         assertEquals(startRow, tableView.getFocusModel().getFocusedCell().getRow());
4291         assertEquals(col, tableView.getFocusModel().getFocusedCell().getTableColumn());
4292 
4293         keyboard.doKeyPress(moveUp ? KeyCode.UP : KeyCode.DOWN, KeyModifier.getShortcutKey());
4294         assertEquals(moveUp ? startRow-1 : startRow+1, tableView.getFocusModel().getFocusedCell().getRow());
4295         assertEquals(col, tableView.getFocusModel().getFocusedCell().getTableColumn());
4296 
4297         sl.dispose();
4298     }
4299 
4300     private int rt_39088_indices_event_count = 0;
4301     private int rt_39088_items_event_count = 0;
4302     @Test public void test_rt_39088() {
4303         ObservableList<TreeItem<String>> itemsList = FXCollections.observableArrayList();
4304         for (int i = 0; i < 4; i++) {
4305             itemsList.add(new TreeItem<>("Row " + i));
4306         }
4307 
4308         root.setExpanded(true);
4309         root.getChildren().setAll(itemsList);
4310 
4311         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
4312         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4313 
4314         tableView.getColumns().setAll(col);
4315 
4316         TreeTableView.TreeTableViewSelectionModel<String> sm = tableView.getSelectionModel();
4317         sm.setSelectionMode(SelectionMode.MULTIPLE);
4318         sm.setCellSelectionEnabled(false);
4319 
4320         ObservableList<Integer> indices = sm.getSelectedIndices();
4321         ObservableList<TreeItem<String>> items = sm.getSelectedItems();
4322 
4323         indices.addListener((ListChangeListener<Integer>) change -> rt_39088_indices_event_count++);
4324         items.addListener((ListChangeListener<TreeItem<String>>) change -> rt_39088_items_event_count++);
4325 
4326         StageLoader sl = new StageLoader(tableView);
4327 
4328         assertEquals(0, rt_39088_indices_event_count);
4329         assertEquals(0, rt_39088_items_event_count);
4330         assertEquals(0, indices.size());
4331         assertEquals(0, items.size());
4332 
4333         sm.select(3);
4334         assertEquals(1, rt_39088_indices_event_count);
4335         assertEquals(1, rt_39088_items_event_count);
4336         assertEquals(1, indices.size());
4337         assertEquals(1, items.size());
4338 
4339         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
4340         assertEquals(2, rt_39088_indices_event_count);
4341         assertEquals(2, rt_39088_items_event_count);
4342         assertEquals(2, indices.size());
4343         assertEquals(2, items.size());
4344 
4345         // this is where the test fails...
4346         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
4347         assertEquals(3, rt_39088_indices_event_count);
4348         assertEquals(3, rt_39088_items_event_count);
4349         assertEquals(3, indices.size());
4350         assertEquals(3, items.size());
4351 
4352         sl.dispose();
4353     }
4354 
4355     @Test public void test_rt_27709_singleSelection_cellSelection() {
4356         test_rt_27709(SelectionMode.SINGLE, true, false);
4357     }
4358 
4359     @Test public void test_rt_27709_multipleSelection_cellSelection() {
4360         test_rt_27709(SelectionMode.MULTIPLE, true, false);
4361     }
4362 
4363     @Test public void test_rt_27709_singleSelection_rowSelection() {
4364         test_rt_27709(SelectionMode.SINGLE, false, false);
4365     }
4366 
4367     @Test public void test_rt_27709_multipleSelection_rowSelection() {
4368         test_rt_27709(SelectionMode.MULTIPLE, false, false);
4369     }
4370 
4371     @Test public void test_rt_27709_singleSelection_cellSelection_resetSelection() {
4372         test_rt_27709(SelectionMode.SINGLE, true, true);
4373     }
4374 
4375     @Test public void test_rt_27709_multipleSelection_cellSelection_resetSelection() {
4376         test_rt_27709(SelectionMode.MULTIPLE, true, true);
4377     }
4378 
4379     @Test public void test_rt_27709_singleSelection_rowSelection_resetSelection() {
4380         test_rt_27709(SelectionMode.SINGLE, false, true);
4381     }
4382 
4383     @Test public void test_rt_27709_multipleSelection_rowSelection_resetSelection() {
4384         test_rt_27709(SelectionMode.MULTIPLE, false, true);
4385     }
4386 
4387     private void test_rt_27709(SelectionMode mode, boolean cellSelectionMode, boolean resetSelection) {
4388         root.getChildren().clear();
4389         for (int i = 0; i < 10; i++) {
4390             root.getChildren().add(new TreeItem<>("Row " + i));
4391         }
4392 
4393         root.setExpanded(true);
4394         tableView.setShowRoot(false);
4395 
4396         TreeTableColumn<String, String> col = new TreeTableColumn<>("Column");
4397         col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4398 
4399         tableView.getColumns().setAll(col);
4400 
4401         TreeTableView.TreeTableViewSelectionModel<String> sm = tableView.getSelectionModel();
4402         sm.setSelectionMode(mode);
4403         sm.setCellSelectionEnabled(cellSelectionMode);
4404 
4405         ObservableList<Integer> indices = sm.getSelectedIndices();
4406         ObservableList<TreeTablePosition<String,?>> cells = sm.getSelectedCells();
4407 
4408         StageLoader sl = new StageLoader(tableView);
4409 
4410         int expectedSize = mode == SelectionMode.SINGLE ? 1 : 10;
4411         int lookupIndex = mode == SelectionMode.SINGLE ? 0 : 9;
4412 
4413         sm.select(0, col);
4414         assertEquals(1, indices.size());
4415         assertEquals(1, cells.size());
4416 
4417         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
4418         assertEquals(expectedSize, indices.size());
4419         assertEquals(expectedSize, cells.size());
4420         assertEquals(9, (int) indices.get(lookupIndex));
4421         assertEquals(9, cells.get(lookupIndex).getRow());
4422 
4423         if (resetSelection) {
4424             sm.clearAndSelect(9, col);
4425             TreeTablePosition<?,?> anchor = TreeTableCellBehavior.getAnchor(tableView, null);
4426             assertEquals(9, anchor.getRow());
4427             assertEquals(col, anchor.getTableColumn());
4428         } else {
4429             expectedSize = 1;
4430         }
4431 
4432         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
4433         assertEquals(expectedSize, indices.size());
4434         assertEquals(expectedSize, cells.size());
4435         assertTrue(sm.isSelected(0, col));
4436 
4437         if (resetSelection) {
4438             sm.clearAndSelect(0, col);
4439 
4440             TreeTablePosition<?,?> anchor = TreeTableCellBehavior.getAnchor(tableView, null);
4441             assertEquals(0, anchor.getRow());
4442             assertEquals(col, anchor.getTableColumn());
4443         } else {
4444             expectedSize = mode == SelectionMode.SINGLE ? 1 : 10;
4445         }
4446 
4447         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
4448         assertEquals(expectedSize, indices.size());
4449         assertEquals(expectedSize, cells.size());
4450         assertTrue(sm.isSelected(9, col));
4451 
4452         sl.dispose();
4453     }
4454 
4455     @Test public void test_rt_18440_goLeft() {
4456         test_rt_18440(KeyCode.LEFT, 3, false, colIndex -> {
4457             keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
4458             return colIndex - 1;
4459         });
4460     }
4461 
4462     @Test public void test_rt_18440_goLeft_toEnd() {
4463         test_rt_18440(KeyCode.LEFT, 3, true, colIndex -> {
4464             keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
4465             return colIndex - 1;
4466         });
4467     }
4468 
4469     @Test public void test_rt_18440_goRight() {
4470         test_rt_18440(KeyCode.RIGHT, 0, false, colIndex -> {
4471             keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
4472             return colIndex + 1;
4473         });
4474     }
4475 
4476     @Test public void test_rt_18440_goRight_toEnd() {
4477         test_rt_18440(KeyCode.RIGHT, 0, true, colIndex -> {
4478             keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
4479             return colIndex + 1;
4480         });
4481     }
4482 
4483     private void test_rt_18440(KeyCode direction, int startColumn, boolean goToEnd, Function<Integer, Integer> r) {
4484         root.getChildren().clear();
4485         for (int i = 0; i < 10; i++) {
4486             root.getChildren().add(new TreeItem<>("Row " + i));
4487         }
4488 
4489         root.setExpanded(true);
4490         tableView.setShowRoot(false);
4491         tableView.setRoot(root);
4492 
4493         tableView.getColumns().clear();
4494         for (int i = 0; i < 4; i++) {
4495             TreeTableColumn<String, String> col = new TreeTableColumn<>("Column " + i);
4496             col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4497             tableView.getColumns().add(col);
4498         }
4499 
4500         TreeTableView.TreeTableViewFocusModel fm = tableView.getFocusModel();
4501         TreeTableView.TreeTableViewSelectionModel<String> sm = tableView.getSelectionModel();
4502         sm.setSelectionMode(SelectionMode.MULTIPLE);
4503         sm.setCellSelectionEnabled(true);
4504 
4505         ObservableList<Integer> indices = sm.getSelectedIndices();
4506         ObservableList<TreeItem<String>> items = sm.getSelectedItems();
4507 
4508         StageLoader sl = new StageLoader(tableView);
4509 
4510         assertEquals(0, indices.size());
4511         assertEquals(0, items.size());
4512 
4513         sm.select(0, tableView.getColumns().get(startColumn));
4514         assertEquals(0, sm.getSelectedIndex());
4515         assertEquals(tableView.getColumns().get(startColumn), sm.getSelectedCells().get(0).getTableColumn());
4516         assertEquals(0, fm.getFocusedIndex());
4517         assertEquals(tableView.getColumns().get(startColumn), fm.getFocusedCell().getTableColumn());
4518 
4519         int expectedColumn = r.apply(startColumn);
4520         assertEquals(0, sm.getSelectedIndex());
4521         assertEquals(tableView.getColumns().get(startColumn), sm.getSelectedCells().get(0).getTableColumn());
4522         assertEquals(0, fm.getFocusedIndex());
4523         assertEquals(tableView.getColumns().get(expectedColumn), fm.getFocusedCell().getTableColumn());
4524 
4525         expectedColumn = r.apply(expectedColumn);
4526         assertEquals(0, sm.getSelectedIndex());
4527         assertEquals(tableView.getColumns().get(startColumn), sm.getSelectedCells().get(0).getTableColumn());
4528         assertEquals(0, fm.getFocusedIndex());
4529         assertEquals(tableView.getColumns().get(expectedColumn), fm.getFocusedCell().getTableColumn());
4530 
4531         if (goToEnd) {
4532             expectedColumn = r.apply(expectedColumn);
4533             assertEquals(0, sm.getSelectedIndex());
4534             assertEquals(tableView.getColumns().get(startColumn), sm.getSelectedCells().get(0).getTableColumn());
4535             assertEquals(0, fm.getFocusedIndex());
4536             assertEquals(tableView.getColumns().get(expectedColumn), fm.getFocusedCell().getTableColumn());
4537         }
4538 
4539         expectedColumn = direction == KeyCode.RIGHT ? 3 : 0;
4540         keyboard.doKeyPress(direction, KeyModifier.SHIFT);
4541         assertEquals(0, sm.getSelectedIndex());
4542         assertEquals(debug(), 4, sm.getSelectedCells().size());
4543         assertEquals(0, fm.getFocusedIndex());
4544         assertEquals(tableView.getColumns().get(expectedColumn), fm.getFocusedCell().getTableColumn());
4545 
4546         sl.dispose();
4547     }
4548 
4549     @Test public void test_rt_24865_moveDownwards() {
4550         root.getChildren().clear();
4551         for (int i = 0; i < 100; i++) {
4552             root.getChildren().add(new TreeItem<>("Row " + i));
4553         }
4554 
4555         root.setExpanded(true);
4556         tableView.setShowRoot(false);
4557         tableView.setRoot(root);
4558 
4559         Toolkit.getToolkit().firePulse();
4560 
4561         ObservableList<Integer> indices = sm.getSelectedIndices();
4562 
4563         sm.select(0);
4564         assertTrue(isSelected(0));
4565         assertTrue(fm.isFocused(0));
4566         assertEquals(1, indices.size());
4567         assertEquals(0, ((TreeTablePosition) TreeTableCellBehavior.getAnchor(tableView, null)).getRow());
4568 
4569         keyboard.doDownArrowPress(KeyModifier.SHIFT);
4570         keyboard.doDownArrowPress(KeyModifier.SHIFT);
4571         keyboard.doDownArrowPress(KeyModifier.SHIFT);
4572         assertTrue(isSelected(0, 1, 2, 3));
4573         assertTrue(fm.isFocused(3));
4574         assertEquals(4, indices.size());
4575         assertEquals(0, ((TreeTablePosition)TreeTableCellBehavior.getAnchor(tableView, null)).getRow());
4576 
4577         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
4578         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
4579         keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
4580         assertTrue(isSelected(0, 1, 2, 3));
4581         assertTrue(isNotSelected(4, 5, 6, 7, 8, 9));
4582         assertTrue(fm.isFocused(6));
4583         assertEquals(4, indices.size());
4584         assertEquals(0, ((TreeTablePosition)TreeTableCellBehavior.getAnchor(tableView, null)).getRow());
4585 
4586         // main point of test: selection between the last index (3) and the focus
4587         // index (6) should now be true
4588         keyboard.doKeyPress(KeyCode.PAGE_DOWN, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
4589         final int selectedRowCount = indices.size();
4590         for (int i = 0; i < selectedRowCount; i++) {
4591             assertTrue(isSelected(i));
4592         }
4593         assertTrue(fm.isFocused(selectedRowCount - 1));
4594         assertEquals(0, ((TreeTablePosition)TreeTableCellBehavior.getAnchor(tableView, null)).getRow());
4595 
4596         keyboard.doDownArrowPress(KeyModifier.SHIFT);
4597         int newSelectedRowCount = selectedRowCount + 1;
4598         for (int i = 0; i < newSelectedRowCount; i++) {
4599             assertTrue(isSelected(i));
4600         }
4601         assertTrue(fm.isFocused(newSelectedRowCount - 1));
4602         assertEquals(0, ((TreeTablePosition)TreeTableCellBehavior.getAnchor(tableView, null)).getRow());
4603     }
4604 
4605     @Test public void test_rt_24865_moveUpwards() {
4606         root.getChildren().clear();
4607         for (int i = 0; i < 100; i++) {
4608             root.getChildren().add(new TreeItem<>("Row " + i));
4609         }
4610 
4611         root.setExpanded(true);
4612         tableView.setShowRoot(false);
4613         tableView.setRoot(root);
4614 
4615         Toolkit.getToolkit().firePulse();
4616 
4617         ObservableList<Integer> indices = sm.getSelectedIndices();
4618 
4619         sm.select(50);
4620         tableView.scrollTo(50);
4621 
4622         Toolkit.getToolkit().firePulse();
4623 
4624         assertTrue(isSelected(50));
4625         assertTrue(fm.isFocused(50));
4626         assertEquals(1, indices.size());
4627         assertEquals(50, ((TreeTablePosition)TreeTableCellBehavior.getAnchor(tableView, null)).getRow());
4628 
4629         keyboard.doUpArrowPress(KeyModifier.SHIFT);
4630         keyboard.doUpArrowPress(KeyModifier.SHIFT);
4631         keyboard.doUpArrowPress(KeyModifier.SHIFT);
4632         assertTrue(isSelected(50, 49, 48, 47));
4633         assertTrue(fm.isFocused(47));
4634         assertEquals(4, indices.size());
4635         assertEquals(50, ((TreeTablePosition)TreeTableCellBehavior.getAnchor(tableView, null)).getRow());
4636 
4637         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
4638         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
4639         keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
4640         assertTrue(isSelected(50, 49, 48, 47));
4641         assertTrue(isNotSelected(46, 45, 44, 43, 42, 41));
4642         assertTrue(fm.isFocused(44));
4643         assertEquals(4, indices.size());
4644         assertEquals(50, ((TreeTablePosition)TreeTableCellBehavior.getAnchor(tableView, null)).getRow());
4645 
4646         // main point of test: selection between the last index (47) and the focus
4647         // index (44) should now be true
4648         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.getShortcutKey(), KeyModifier.SHIFT);
4649         final int selectedRowCount = indices.size();
4650         for (int i = 0; i < selectedRowCount; i++) {
4651             assertTrue(isSelected(50 - i));
4652         }
4653         assertTrue(fm.isFocused(50 - selectedRowCount + 1));
4654         assertEquals(50, ((TreeTablePosition)TreeTableCellBehavior.getAnchor(tableView, null)).getRow());
4655 
4656         keyboard.doUpArrowPress(KeyModifier.SHIFT);
4657         int newSelectedRowCount = selectedRowCount + 1;
4658         for (int i = 0; i < newSelectedRowCount; i++) {
4659             assertTrue(isSelected(50 - i));
4660         }
4661         assertTrue(fm.isFocused(50 - newSelectedRowCount + 1));
4662         assertEquals(50, ((TreeTablePosition)TreeTableCellBehavior.getAnchor(tableView, null)).getRow());
4663     }
4664 
4665     @Test public void test_rt_39792_goLeft_goPastEnd() {
4666         test_rt_39792(3, colIndex -> {
4667             keyboard.doLeftArrowPress(KeyModifier.SHIFT);
4668             return colIndex - 1;
4669         });
4670     }
4671 
4672     @Test public void test_rt_39792_goRight_goPastEnd() {
4673         test_rt_39792(0, colIndex -> {
4674             keyboard.doRightArrowPress(KeyModifier.SHIFT);
4675             return colIndex + 1;
4676         });
4677     }
4678 
4679     private void test_rt_39792(int startColumn, Function<Integer, Integer> r) {
4680         root.getChildren().clear();
4681         for (int i = 0; i < 10; i++) {
4682             root.getChildren().add(new TreeItem<>("Row " + i));
4683         }
4684 
4685         root.setExpanded(true);
4686         tableView.setShowRoot(false);
4687         tableView.setRoot(root);
4688 
4689         tableView.getColumns().clear();
4690         for (int i = 0; i < 4; i++) {
4691             TreeTableColumn<String, String> col = new TreeTableColumn<>("Column " + i);
4692             col.setCellValueFactory(param -> new ReadOnlyStringWrapper(param.getValue().getValue()));
4693             tableView.getColumns().add(col);
4694         }
4695 
4696         TreeTableView.TreeTableViewSelectionModel<String> sm = tableView.getSelectionModel();
4697         sm.setSelectionMode(SelectionMode.MULTIPLE);
4698         sm.setCellSelectionEnabled(true);
4699 
4700         ObservableList<Integer> indices = sm.getSelectedIndices();
4701         ObservableList<TreeItem<String>> items = sm.getSelectedItems();
4702 
4703         StageLoader sl = new StageLoader(tableView);
4704 
4705         assertEquals(0, indices.size());
4706         assertEquals(0, items.size());
4707 
4708         sm.select(0, tableView.getColumns().get(startColumn));
4709         assertEquals(1, sm.getSelectedCells().size());
4710 
4711         int expectedColumn = r.apply(startColumn);
4712         assertEquals(2, sm.getSelectedCells().size());
4713 
4714         expectedColumn = r.apply(expectedColumn);
4715         assertEquals(3, sm.getSelectedCells().size());
4716 
4717         expectedColumn = r.apply(expectedColumn);
4718         assertEquals(4, sm.getSelectedCells().size());
4719 
4720         // this should not cause any issue, but it does - as noted in RT-39792
4721         /*expectedColumn = */r.apply(expectedColumn);
4722         assertEquals(4, sm.getSelectedCells().size());
4723 
4724         sl.dispose();
4725     }
4726 }