changeset 4845:9b8894841264

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/8.0/scrum/controls/jfx/rt
author jgiles
date Thu, 29 Aug 2013 15:58:24 +1200
parents 2fd809b11dfd 1d4565315819
children c52ac94b9d02 c661253e25cf
files
diffstat 10 files changed, 430 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/ListCellBehavior.java	Wed Aug 28 14:38:29 2013 -0700
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/ListCellBehavior.java	Thu Aug 29 15:58:24 2013 +1200
@@ -219,7 +219,8 @@
                 } else if (e.isShiftDown()) {
                     // we add all rows between the current focus and
                     // this row (inclusive) to the current selection.
-                    int focusIndex = getAnchor(listView);
+                    final int focusIndex = getAnchor(listView);
+                    final boolean asc = focusIndex < index;
 
                     // and then determine all row and columns which must be selected
                     int minRow = Math.min(focusIndex, index);
@@ -238,7 +239,16 @@
                             sm.clearSelection(selectedIndex);
                         }
                     }
-                    sm.selectRange(minRow, maxRow+1);
+
+                    // RT-21444: We need to put the range in in the correct
+                    // order or else the last selected row will not be the
+                    // last item in the selectedItems list of the selection
+                    // model,
+                    if (asc) {
+                        sm.selectRange(minRow, maxRow + 1);
+                    } else {
+                        sm.selectRange(maxRow, minRow - 1);
+                    }
 
                     // return selection back to the focus owner
                     fm.focus(index);
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java	Wed Aug 28 14:38:29 2013 -0700
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableCellBehaviorBase.java	Thu Aug 29 15:58:24 2013 +1200
@@ -240,7 +240,10 @@
                 } else if (e.isShiftDown()) {
                     // we add all cells/rows between the current selection focus and
                     // this cell/row (inclusive) to the current selection.
-                    TablePositionBase anchor = getAnchor(tableView, focusedCell);
+                    final TablePositionBase anchor = getAnchor(tableView, focusedCell);
+
+                    final int anchorRow = anchor.getRow();
+                    final boolean asc = anchorRow < row;
                     
                     // and then determine all row and columns which must be selected
                     int minRow = Math.min(anchor.getRow(), row);
@@ -269,8 +272,16 @@
                                 sm.clearSelection(selectedIndex);
                             }
                         }
-                        
-                        sm.selectRange(minRow, maxRow + 1);
+
+                        // RT-21444: We need to put the range in in the correct
+                        // order or else the last selected row will not be the
+                        // last item in the selectedItems list of the selection
+                        // model,
+                        if (asc) {
+                            sm.selectRange(minRow, maxRow + 1);
+                        } else {
+                            sm.selectRange(maxRow, minRow - 1);
+                        }
                     }
 
                     // This line of code below was disabled as a fix for RT-30394.
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehavior.java	Wed Aug 28 14:38:29 2013 -0700
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TableRowBehavior.java	Thu Aug 29 15:58:24 2013 +1200
@@ -76,10 +76,12 @@
                     // we add all rows between the current focus and
                     // this row (inclusive) to the current selection.
                     TablePositionBase anchor = TableCellBehavior.getAnchor(table, table.getFocusModel().getFocusedCell());
+                    final int anchorRow = anchor.getRow();
+                    final boolean asc = anchorRow < index;
 
                     // and then determine all row and columns which must be selected
-                    int minRow = Math.min(anchor.getRow(), index);
-                    int maxRow = Math.max(anchor.getRow(), index);
+                    int minRow = Math.min(anchorRow, index);
+                    int maxRow = Math.max(anchorRow, index);
 
                     // To prevent RT-32119, we make a copy of the selected indices
                     // list first, so that we are not iterating and modifying it
@@ -92,7 +94,15 @@
                         }
                     }
 
-                    sm.selectRange(minRow, maxRow + 1);
+                    // RT-21444: We need to put the range in in the correct
+                    // order or else the last selected row will not be the
+                    // last item in the selectedItems list of the selection
+                    // model,
+                    if (asc) {
+                        sm.selectRange(minRow, maxRow + 1);
+                    } else {
+                        sm.selectRange(maxRow, minRow - 1);
+                    }
                 } else {
                     sm.clearAndSelect(tableRow.getIndex());
                 }
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java	Wed Aug 28 14:38:29 2013 -0700
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java	Thu Aug 29 15:58:24 2013 +1200
@@ -232,6 +232,7 @@
                     // we add all rows between the current selection focus and
                     // this row (inclusive) to the current selection.
                     final int focusedIndex = getAnchor(treeView);
+                    final boolean asc = focusedIndex < index;
 
                     // and then determine all row and columns which must be selected
                     int minRow = Math.min(focusedIndex, index);
@@ -250,7 +251,16 @@
                             sm.clearSelection(selectedIndex);
                         }
                     }
-                    sm.selectRange(minRow, maxRow+1);
+
+                    // RT-21444: We need to put the range in in the correct
+                    // order or else the last selected row will not be the
+                    // last item in the selectedItems list of the selection
+                    // model,
+                    if (asc) {
+                        sm.selectRange(minRow, maxRow + 1);
+                    } else {
+                        sm.selectRange(maxRow, minRow - 1);
+                    }
 
                     fm.focus(index);
                 } else {
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java	Wed Aug 28 14:38:29 2013 -0700
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TreeTableRowBehavior.java	Thu Aug 29 15:58:24 2013 +1200
@@ -91,6 +91,8 @@
                     // we add all rows between the current focus and
                     // this row (inclusive) to the current selection.
                     TablePositionBase anchor = TreeTableCellBehavior.getAnchor(table, table.getFocusModel().getFocusedCell());
+                    final int anchorRow = anchor.getRow();
+                    final boolean asc = anchorRow < index;
 
                     // and then determine all row and columns which must be selected
                     int minRow = Math.min(anchor.getRow(), index);
@@ -107,7 +109,15 @@
                         }
                     }
 
-                    sm.selectRange(minRow, maxRow + 1);
+                    // RT-21444: We need to put the range in in the correct
+                    // order or else the last selected row will not be the
+                    // last item in the selectedItems list of the selection
+                    // model,
+                    if (asc) {
+                        sm.selectRange(minRow, maxRow + 1);
+                    } else {
+                        sm.selectRange(maxRow, minRow - 1);
+                    }
                 } else {
                     sm.clearAndSelect(treeTableRow.getIndex());
                 }
--- a/modules/controls/src/test/java/javafx/scene/control/ListViewMouseInputTest.java	Wed Aug 28 14:38:29 2013 -0700
+++ b/modules/controls/src/test/java/javafx/scene/control/ListViewMouseInputTest.java	Thu Aug 29 15:58:24 2013 +1200
@@ -199,4 +199,48 @@
         assertFalse(sm.isSelected(4));
         assertFalse(sm.isSelected(5));
     }
+
+    @Test public void test_rt21444_up() {
+        final int items = 8;
+        listView.getItems().clear();
+        for (int i = 1; i <= items; i++) {
+            listView.getItems().add("Row " + i);
+        }
+
+        final int selectRow = 3;
+
+        final MultipleSelectionModel sm = listView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 4", sm.getSelectedItem());
+
+        VirtualFlowTestUtils.clickOnRow(listView, selectRow - 1, KeyModifier.SHIFT);
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 3", sm.getSelectedItem());
+        assertEquals("Row 3", sm.getSelectedItems().get(0));
+    }
+
+    @Test public void test_rt21444_down() {
+        final int items = 8;
+        listView.getItems().clear();
+        for (int i = 1; i <= items; i++) {
+            listView.getItems().add("Row " + i);
+        }
+
+        final int selectRow = 3;
+
+        final MultipleSelectionModel sm = listView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 4", sm.getSelectedItem());
+
+        VirtualFlowTestUtils.clickOnRow(listView, selectRow + 1, KeyModifier.SHIFT);
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 5", sm.getSelectedItem());
+        assertEquals("Row 5", sm.getSelectedItems().get(1));
+    }
 }
--- a/modules/controls/src/test/java/javafx/scene/control/TableViewKeyInputTest.java	Wed Aug 28 14:38:29 2013 -0700
+++ b/modules/controls/src/test/java/javafx/scene/control/TableViewKeyInputTest.java	Thu Aug 29 15:58:24 2013 +1200
@@ -2103,4 +2103,46 @@
         assertNotSame(initialSelectionOwner, nextSelectionOwner);
         assertNotSame(newSelectionOwner, nextSelectionOwner);
     }
+
+    @Test public void test_rt21444_up() {
+        final int items = 8;
+        tableView.getItems().clear();
+        for (int i = 1; i <= items; i++) {
+            tableView.getItems().add("Row " + i);
+        }
+
+        final MultipleSelectionModel sm = tableView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(3);
+
+        assertEquals(3, sm.getSelectedIndex());
+        assertEquals("Row 4", sm.getSelectedItem());
+
+        keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);
+        Toolkit.getToolkit().firePulse();
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 3", sm.getSelectedItem());
+        assertEquals("Row 3", sm.getSelectedItems().get(0));
+    }
+
+    @Test public void test_rt21444_down() {
+        final int items = 8;
+        tableView.getItems().clear();
+        for (int i = 1; i <= items; i++) {
+            tableView.getItems().add("Row " + i);
+        }
+
+        final MultipleSelectionModel sm = tableView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(3);
+
+        assertEquals(3, sm.getSelectedIndex());
+        assertEquals("Row 4", sm.getSelectedItem());
+
+        keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);
+        Toolkit.getToolkit().firePulse();
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 5", sm.getSelectedItem());
+        assertEquals("Row 5", sm.getSelectedItems().get(1));
+    }
 }
--- a/modules/controls/src/test/java/javafx/scene/control/TableViewMouseInputTest.java	Wed Aug 28 14:38:29 2013 -0700
+++ b/modules/controls/src/test/java/javafx/scene/control/TableViewMouseInputTest.java	Thu Aug 29 15:58:24 2013 +1200
@@ -244,4 +244,92 @@
         assertTrue(sm.isSelected(4));
         assertTrue(sm.isSelected(5));
     }
+
+    @Test public void test_rt21444_up_cell() {
+        final int items = 8;
+        tableView.getItems().clear();
+        for (int i = 0; i < items; i++) {
+            tableView.getItems().add("Row " + i);
+        }
+
+        final int selectRow = 3;
+
+        final MultipleSelectionModel sm = tableView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 3", sm.getSelectedItem());
+
+        VirtualFlowTestUtils.clickOnRow(tableView, selectRow - 1, KeyModifier.SHIFT);
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 2", sm.getSelectedItem());
+        assertEquals("Row 2", sm.getSelectedItems().get(0));
+    }
+
+    @Test public void test_rt21444_down_cell() {
+        final int items = 8;
+        tableView.getItems().clear();
+        for (int i = 0; i < items; i++) {
+            tableView.getItems().add("Row " + i);
+        }
+
+        final int selectRow = 3;
+
+        final MultipleSelectionModel sm = tableView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 3", sm.getSelectedItem());
+
+        VirtualFlowTestUtils.clickOnRow(tableView, selectRow + 1, KeyModifier.SHIFT);
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 4", sm.getSelectedItem());
+        assertEquals("Row 4", sm.getSelectedItems().get(1));
+    }
+
+    @Test public void test_rt21444_up_row() {
+        final int items = 8;
+        tableView.getItems().clear();
+        for (int i = 0; i < items; i++) {
+            tableView.getItems().add("Row " + i);
+        }
+
+        final int selectRow = 3;
+
+        final MultipleSelectionModel sm = tableView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 3", sm.getSelectedItem());
+
+        VirtualFlowTestUtils.clickOnRow(tableView, selectRow - 1, true, KeyModifier.SHIFT);
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 2", sm.getSelectedItem());
+        assertEquals("Row 2", sm.getSelectedItems().get(0));
+    }
+
+    @Test public void test_rt21444_down_row() {
+        final int items = 8;
+        tableView.getItems().clear();
+        for (int i = 0; i < items; i++) {
+            tableView.getItems().add("Row " + i);
+        }
+
+        final int selectRow = 3;
+
+        final MultipleSelectionModel sm = tableView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 3", sm.getSelectedItem());
+
+        VirtualFlowTestUtils.clickOnRow(tableView, selectRow + 1, true, KeyModifier.SHIFT);
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 4", sm.getSelectedItem());
+        assertEquals("Row 4", sm.getSelectedItems().get(1));
+    }
 }
--- a/modules/controls/src/test/java/javafx/scene/control/TreeTableViewMouseInputTest.java	Wed Aug 28 14:38:29 2013 -0700
+++ b/modules/controls/src/test/java/javafx/scene/control/TreeTableViewMouseInputTest.java	Thu Aug 29 15:58:24 2013 +1200
@@ -62,8 +62,6 @@
     private TreeTableView.TreeTableViewSelectionModel<String> sm;
     private TreeTableView.TreeTableViewFocusModel<String> fm;
     
-    private KeyEventFirer keyboard;
-    
     private StageLoader stageLoader;
     
     private final TreeTableColumn<String, String> col0 = new TreeTableColumn<String, String>("col0");
@@ -71,23 +69,38 @@
     private final TreeTableColumn<String, String> col2 = new TreeTableColumn<String, String>("col2");
     private final TreeTableColumn<String, String> col3 = new TreeTableColumn<String, String>("col3");
     private final TreeTableColumn<String, String> col4 = new TreeTableColumn<String, String>("col4");
-    
-    private final TreeItem<String> root = new TreeItem<String>("Root");                     // 0
-        private final TreeItem<String> child1 = new TreeItem<String>("Child 1");            // 1
-        private final TreeItem<String> child2 = new TreeItem<String>("Child 2");            // 2
-        private final TreeItem<String> child3 = new TreeItem<String>("Child 3");            // 3
-            private final TreeItem<String> subchild1 = new TreeItem<String>("Subchild 1");  // 4
-            private final TreeItem<String> subchild2 = new TreeItem<String>("Subchild 2");  // 5
-            private final TreeItem<String> subchild3 = new TreeItem<String>("Subchild 3");  // 6
-        private final TreeItem<String> child4 = new TreeItem<String>("Child 4");            // 7
-        private final TreeItem<String> child5 = new TreeItem<String>("Child 5");            // 8
-        private final TreeItem<String> child6 = new TreeItem<String>("Child 6");            // 9
-        private final TreeItem<String> child7 = new TreeItem<String>("Child 7");            // 10
-        private final TreeItem<String> child8 = new TreeItem<String>("Child 8");            // 11
-        private final TreeItem<String> child9 = new TreeItem<String>("Child 9");            // 12
-        private final TreeItem<String> child10 = new TreeItem<String>("Child 10");          // 13
-    
+
+    private TreeItem<String> root;                  // 0
+    private TreeItem<String> child1;            // 1
+    private TreeItem<String> child2;            // 2
+    private TreeItem<String> child3;            // 3
+    private TreeItem<String> subchild1;     // 4
+    private TreeItem<String> subchild2;     // 5
+    private TreeItem<String> subchild3;     // 6
+    private TreeItem<String> child4;            // 7
+    private TreeItem<String> child5;            // 8
+    private TreeItem<String> child6;            // 9
+    private TreeItem<String> child7;            // 10
+    private TreeItem<String> child8;            // 11
+    private TreeItem<String> child9;            // 12
+    private TreeItem<String> child10;           // 13
+
     @Before public void setup() {
+        root = new TreeItem<String>("Root");             // 0
+        child1 = new TreeItem<String>("Child 1");        // 1
+        child2 = new TreeItem<String>("Child 2");        // 2
+        child3 = new TreeItem<String>("Child 3");        // 3
+        subchild1 = new TreeItem<String>("Subchild 1");  // 4
+        subchild2 = new TreeItem<String>("Subchild 2");  // 5
+        subchild3 = new TreeItem<String>("Subchild 3");  // 6
+        child4 = new TreeItem<String>("Child 4");        // 7
+        child5 = new TreeItem<String>("Child 5");        // 8
+        child6 = new TreeItem<String>("Child 6");        // 9
+        child7 = new TreeItem<String>("Child 7");        // 10
+        child8 = new TreeItem<String>("Child 8");        // 11
+        child9 = new TreeItem<String>("Child 9");        // 12
+        child10 = new TreeItem<String>("Child 10");      // 13
+
         // reset tree structure
         root.getChildren().clear();
         root.setExpanded(true);
@@ -126,8 +139,6 @@
         
         sm.clearAndSelect(0);
         
-        keyboard = new KeyEventFirer(tableView);
-        
         stageLoader = new StageLoader(tableView);
         stageLoader.getStage().show();
     }
@@ -135,6 +146,7 @@
     @After public void tearDown() {
         tableView.getSkin().dispose();
         stageLoader.dispose();
+        sm = null;
     }
     
     /***************************************************************************
@@ -302,4 +314,92 @@
         assertTrue(sm.isSelected(4));
         assertTrue(sm.isSelected(5));
     }
+
+    @Test public void test_rt21444_up_cell() {
+        final int items = 8;
+        root.getChildren().clear();
+        for (int i = 0; i < items; i++) {
+            root.getChildren().add(new TreeItem<>("Row " + i));
+        }
+
+        final int selectRow = 3;
+
+        tableView.setShowRoot(false);
+        final MultipleSelectionModel<TreeItem<String>> sm = tableView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 3", sm.getSelectedItem().getValue());
+
+        VirtualFlowTestUtils.clickOnRow(tableView, selectRow - 1, KeyModifier.SHIFT);
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 2", sm.getSelectedItem().getValue());
+        assertEquals("Row 2", sm.getSelectedItems().get(1).getValue());
+    }
+
+    @Test public void test_rt21444_down_cell() {
+        final int items = 8;
+        root.getChildren().clear();
+        for (int i = 0; i < items; i++) {
+            root.getChildren().add(new TreeItem<>("Row " + i));
+        }
+
+        final int selectRow = 3;
+
+        tableView.setShowRoot(false);
+        final MultipleSelectionModel<TreeItem<String>> sm = tableView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 3", sm.getSelectedItem().getValue());
+
+        VirtualFlowTestUtils.clickOnRow(tableView, selectRow + 1, KeyModifier.SHIFT);
+        assertEquals("Row 4", sm.getSelectedItem().getValue());
+    }
+
+    @Test public void test_rt21444_up_row() {
+        final int items = 8;
+        root.getChildren().clear();
+        for (int i = 0; i < items; i++) {
+            root.getChildren().add(new TreeItem<>("Row " + i));
+        }
+
+        final int selectRow = 3;
+
+        tableView.setShowRoot(false);
+        final MultipleSelectionModel<TreeItem<String>> sm = tableView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 3", sm.getSelectedItem().getValue());
+
+        VirtualFlowTestUtils.clickOnRow(tableView, selectRow - 1, true, KeyModifier.SHIFT);
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 2", sm.getSelectedItem().getValue());
+        assertEquals("Row 2", sm.getSelectedItems().get(1).getValue());
+    }
+
+    @Test public void test_rt21444_down_row() {
+        final int items = 8;
+        root.getChildren().clear();
+        for (int i = 0; i < items; i++) {
+            root.getChildren().add(new TreeItem<>("Row " + i));
+        }
+
+        final int selectRow = 3;
+
+        tableView.setShowRoot(false);
+        final MultipleSelectionModel<TreeItem<String>> sm = tableView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 3", sm.getSelectedItem().getValue());
+
+        VirtualFlowTestUtils.clickOnRow(tableView, selectRow + 1, true, KeyModifier.SHIFT);
+        assertEquals("Row 4", sm.getSelectedItem().getValue());
+    }
 }
--- a/modules/controls/src/test/java/javafx/scene/control/TreeViewMouseInputTest.java	Wed Aug 28 14:38:29 2013 -0700
+++ b/modules/controls/src/test/java/javafx/scene/control/TreeViewMouseInputTest.java	Thu Aug 29 15:58:24 2013 +1200
@@ -60,22 +60,37 @@
     private KeyEventFirer keyboard;
     private StageLoader stageLoader;
     
-    private final TreeItem<String> root = new TreeItem<String>("Root");                     // 0
-        private final TreeItem<String> child1 = new TreeItem<String>("Child 1");            // 1
-        private final TreeItem<String> child2 = new TreeItem<String>("Child 2");            // 2
-        private final TreeItem<String> child3 = new TreeItem<String>("Child 3");            // 3
-            private final TreeItem<String> subchild1 = new TreeItem<String>("Subchild 1");  // 4
-            private final TreeItem<String> subchild2 = new TreeItem<String>("Subchild 2");  // 5
-            private final TreeItem<String> subchild3 = new TreeItem<String>("Subchild 3");  // 6
-        private final TreeItem<String> child4 = new TreeItem<String>("Child 4");            // 7
-        private final TreeItem<String> child5 = new TreeItem<String>("Child 5");            // 8
-        private final TreeItem<String> child6 = new TreeItem<String>("Child 6");            // 9
-        private final TreeItem<String> child7 = new TreeItem<String>("Child 7");            // 10
-        private final TreeItem<String> child8 = new TreeItem<String>("Child 8");            // 11
-        private final TreeItem<String> child9 = new TreeItem<String>("Child 9");            // 12
-        private final TreeItem<String> child10 = new TreeItem<String>("Child 10");          // 13
+    private TreeItem<String> root;                  // 0
+        private TreeItem<String> child1;            // 1
+        private TreeItem<String> child2;            // 2
+        private TreeItem<String> child3;            // 3
+            private TreeItem<String> subchild1;     // 4
+            private TreeItem<String> subchild2;     // 5
+            private TreeItem<String> subchild3;     // 6
+        private TreeItem<String> child4;            // 7
+        private TreeItem<String> child5;            // 8
+        private TreeItem<String> child6;            // 9
+        private TreeItem<String> child7;            // 10
+        private TreeItem<String> child8;            // 11
+        private TreeItem<String> child9;            // 12
+        private TreeItem<String> child10;           // 13
 
     @Before public void setup() {
+        root = new TreeItem<String>("Root");             // 0
+        child1 = new TreeItem<String>("Child 1");        // 1
+        child2 = new TreeItem<String>("Child 2");        // 2
+        child3 = new TreeItem<String>("Child 3");        // 3
+        subchild1 = new TreeItem<String>("Subchild 1");  // 4
+        subchild2 = new TreeItem<String>("Subchild 2");  // 5
+        subchild3 = new TreeItem<String>("Subchild 3");  // 6
+        child4 = new TreeItem<String>("Child 4");        // 7
+        child5 = new TreeItem<String>("Child 5");        // 8
+        child6 = new TreeItem<String>("Child 6");        // 9
+        child7 = new TreeItem<String>("Child 7");        // 10
+        child8 = new TreeItem<String>("Child 8");        // 11
+        child9 = new TreeItem<String>("Child 9");        // 12
+        child10 = new TreeItem<String>("Child 10");      // 13
+
         // reset tree structure
         root.getChildren().clear();
         root.setExpanded(true);
@@ -251,4 +266,50 @@
         assertFalse(sm.isSelected(4));
         assertFalse(sm.isSelected(5));
     }
+
+    @Test public void test_rt21444_up() {
+        final int items = 8;
+        root.getChildren().clear();
+        for (int i = 0; i < items; i++) {
+            root.getChildren().add(new TreeItem<>("Row " + i));
+        }
+
+        final int selectRow = 3;
+
+        treeView.setShowRoot(false);
+        final MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 3", sm.getSelectedItem().getValue());
+
+        VirtualFlowTestUtils.clickOnRow(treeView, selectRow - 1, KeyModifier.SHIFT);
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 2", sm.getSelectedItem().getValue());
+        assertEquals("Row 2", sm.getSelectedItems().get(0).getValue());
+    }
+
+    @Test public void test_rt21444_down() {
+        final int items = 8;
+        root.getChildren().clear();
+        for (int i = 0; i < items; i++) {
+            root.getChildren().add(new TreeItem<>("Row " + i));
+        }
+
+        final int selectRow = 3;
+
+        treeView.setShowRoot(false);
+        final MultipleSelectionModel<TreeItem<String>> sm = treeView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(selectRow);
+
+        assertEquals(selectRow, sm.getSelectedIndex());
+        assertEquals("Row 3", sm.getSelectedItem().getValue());
+
+        VirtualFlowTestUtils.clickOnRow(treeView, selectRow + 1, KeyModifier.SHIFT);
+        assertEquals(2, sm.getSelectedItems().size());
+        assertEquals("Row 4", sm.getSelectedItem().getValue());
+        assertEquals("Row 4", sm.getSelectedItems().get(1).getValue());
+    }
 }