1 /* 2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.scene.control; 27 28 import static org.junit.Assert.assertEquals; 29 import static org.junit.Assert.assertFalse; 30 import static org.junit.Assert.assertNotNull; 31 import static org.junit.Assert.assertNull; 32 import static org.junit.Assert.assertSame; 33 import static org.junit.Assert.assertTrue; 34 import static org.junit.Assert.fail; 35 36 import java.util.*; 37 38 import com.sun.javafx.scene.control.infrastructure.StageLoader; 39 import javafx.collections.FXCollections; 40 import javafx.collections.ListChangeListener; 41 import javafx.collections.ObservableList; 42 import javafx.scene.control.ListView.ListViewFocusModel; 43 import javafx.scene.control.TableView.TableViewFocusModel; 44 import javafx.scene.control.TableView.TableViewSelectionModel; 45 import javafx.scene.control.TreeTableView.TreeTableViewFocusModel; 46 import javafx.scene.control.TreeTableView.TreeTableViewSelectionModel; 47 import javafx.scene.control.TreeView.TreeViewFocusModel; 48 49 import org.junit.After; 50 import org.junit.AfterClass; 51 import org.junit.Assert; 52 import org.junit.Before; 53 import org.junit.Ignore; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 import org.junit.runners.Parameterized; 57 import org.junit.runners.Parameterized.Parameters; 58 59 import com.sun.javafx.scene.control.infrastructure.VirtualFlowTestUtils; 60 61 /** 62 * Unit tests for the SelectionModel abstract class used by ListView 63 * and TreeView. This unit test attempts to test all known implementations, and 64 * as such contains some conditional logic to handle the various controls as 65 * simply as possible. 66 */ 67 @RunWith(Parameterized.class) 68 public class MultipleSelectionModelImplTest { 69 70 private MultipleSelectionModel model; 71 private FocusModel focusModel; 72 73 private Class<? extends MultipleSelectionModel> modelClass; 74 private Control currentControl; 75 76 // ListView 77 private ListView<String> listView; 78 79 // ListView model data 80 private static ObservableList<String> defaultData = FXCollections.<String>observableArrayList(); 81 private static ObservableList<String> data = FXCollections.<String>observableArrayList(); 82 private static final String ROW_1_VALUE = "Row 1"; 83 private static final String ROW_2_VALUE = "Row 2"; 84 private static final String ROW_3_VALUE = "Long Row 3"; 85 private static final String ROW_5_VALUE = "Row 5"; 86 private static final String ROW_20_VALUE = "Row 20"; 87 88 // TreeView 89 private TreeView treeView; 90 private TreeItem<String> root; 91 private TreeItem<String> ROW_2_TREE_VALUE; 92 private TreeItem<String> ROW_5_TREE_VALUE; 93 94 // TreeTableView 95 private TreeTableView treeTableView; 96 97 // TableView 98 private TableView tableView; 99 100 @Parameters public static Collection implementations() { 101 return Arrays.asList(new Object[][] { 102 { ListView.ListViewBitSetSelectionModel.class }, 103 { TreeView.TreeViewBitSetSelectionModel.class }, 104 { TableView.TableViewArrayListSelectionModel.class }, 105 { TreeTableView.TreeTableViewArrayListSelectionModel.class }, 106 }); 107 } 108 109 public MultipleSelectionModelImplTest(Class<? extends MultipleSelectionModel> modelClass) { 110 this.modelClass = modelClass; 111 } 112 113 @AfterClass public static void tearDownClass() throws Exception { } 114 115 @Before public void setUp() { 116 // ListView init 117 defaultData.setAll(ROW_1_VALUE, ROW_2_VALUE, ROW_3_VALUE, "Row 4", ROW_5_VALUE, "Row 6", 118 "Row 7", "Row 8", "Row 9", "Row 10", "Row 11", "Row 12", "Row 13", 119 "Row 14", "Row 15", "Row 16", "Row 17", "Row 18", "Row 19", ROW_20_VALUE); 120 121 data.setAll(defaultData); 122 listView = new ListView<>(data); 123 // --- ListView init 124 125 // TreeView init 126 root = new TreeItem<>(ROW_1_VALUE); 127 root.setExpanded(true); 128 for (int i = 1; i < data.size(); i++) { 129 root.getChildren().add(new TreeItem<>(data.get(i))); 130 } 131 ROW_2_TREE_VALUE = root.getChildren().get(0); 132 ROW_5_TREE_VALUE = root.getChildren().get(3); 133 134 treeView = new TreeView(root); 135 // --- TreeView init 136 137 // TreeTableView init 138 treeTableView = new TreeTableView(root); 139 // --- TreeView init 140 141 // TableView init 142 tableView = new TableView(); 143 tableView.setItems(data); 144 // --- TableView init 145 146 try { 147 // reset the data model 148 data = FXCollections.<String>observableArrayList(); 149 data.setAll(defaultData); 150 151 // we create a new SelectionModel per test to ensure it is always back 152 // at the default settings 153 if (modelClass.equals(ListView.ListViewBitSetSelectionModel.class)) { 154 // recreate the selection model 155 model = modelClass.getConstructor(ListView.class).newInstance(listView); 156 listView.setSelectionModel((MultipleSelectionModel<String>)model); 157 158 // create a new focus model 159 focusModel = new ListViewFocusModel(listView); 160 listView.setFocusModel(focusModel); 161 currentControl = listView; 162 } else if (modelClass.equals(TreeView.TreeViewBitSetSelectionModel.class)) { 163 model = modelClass.getConstructor(TreeView.class).newInstance(treeView); 164 treeView.setSelectionModel((MultipleSelectionModel<String>)model); 165 focusModel = treeView.getFocusModel(); 166 167 // create a new focus model 168 focusModel = new TreeViewFocusModel(treeView); 169 treeView.setFocusModel(focusModel); 170 currentControl = treeView; 171 } else if (TableViewSelectionModel.class.isAssignableFrom(modelClass)) { 172 // recreate the selection model 173 model = modelClass.getConstructor(TableView.class).newInstance(tableView); 174 tableView.setSelectionModel((TableViewSelectionModel) model); 175 176 // create a new focus model 177 focusModel = new TableViewFocusModel(tableView); 178 tableView.setFocusModel((TableViewFocusModel) focusModel); 179 currentControl = tableView; 180 } else if (TreeTableViewSelectionModel.class.isAssignableFrom(modelClass)) { 181 // recreate the selection model 182 model = modelClass.getConstructor(TreeTableView.class).newInstance(treeTableView); 183 treeTableView.setSelectionModel((TreeTableViewSelectionModel) model); 184 185 // create a new focus model 186 focusModel = new TreeTableViewFocusModel(treeTableView); 187 treeTableView.setFocusModel((TreeTableViewFocusModel) focusModel); 188 currentControl = treeTableView; 189 } 190 191 // ensure the selection mode is set to multiple 192 model.setSelectionMode(SelectionMode.MULTIPLE); 193 } catch (Exception ex) { 194 ex.printStackTrace(); 195 } 196 } 197 198 @After public void tearDown() { 199 model = null; 200 } 201 202 private Object getValue(Object item) { 203 if (item instanceof TreeItem) { 204 return ((TreeItem)item).getValue(); 205 } 206 return item; 207 } 208 209 private String indices(MultipleSelectionModel sm) { 210 return "Selected Indices: " + sm.getSelectedIndices(); 211 } 212 213 private String items(MultipleSelectionModel sm) { 214 return "Selected Items: " + sm.getSelectedItems(); 215 } 216 217 private MultipleSelectionModel msModel() { 218 return model; 219 } 220 221 private boolean isTree() { 222 return model instanceof TreeView.TreeViewBitSetSelectionModel || 223 model instanceof TreeTableView.TreeTableViewArrayListSelectionModel; 224 } 225 226 private void ensureInEmptyState() { 227 assertEquals(-1, model.getSelectedIndex()); 228 assertNull(model.getSelectedItem()); 229 230 if (focusModel != null) { 231 assertEquals(-1, focusModel.getFocusedIndex()); 232 assertNull(focusModel.getFocusedItem()); 233 } 234 235 assertNotNull(msModel().getSelectedIndices()); 236 assertNotNull(msModel().getSelectedItems()); 237 assertEquals(0, msModel().getSelectedIndices().size()); 238 assertEquals(0, msModel().getSelectedItems().size()); 239 } 240 241 @Test public void ensureInDefaultState() { 242 assertEquals(-1, model.getSelectedIndex()); 243 assertNull(model.getSelectedItem()); 244 245 if (focusModel != null) { 246 assertEquals(0, focusModel.getFocusedIndex()); 247 assertNotNull(focusModel.getFocusedItem()); 248 } 249 250 assertNotNull(msModel().getSelectedIndices()); 251 assertNotNull(msModel().getSelectedItems()); 252 assertEquals(0, msModel().getSelectedIndices().size()); 253 assertEquals(0, msModel().getSelectedItems().size()); 254 } 255 256 @Test public void selectValidIndex() { 257 int index = 4; 258 model.clearSelection(); 259 model.select(index); 260 261 assertEquals(index, model.getSelectedIndex()); 262 assertNotNull(model.getSelectedItem()); 263 assertEquals(ROW_5_VALUE, getValue(model.getSelectedItem())); 264 265 if (focusModel != null) { 266 assertEquals(index, focusModel.getFocusedIndex()); 267 assertNotNull(focusModel.getFocusedItem()); 268 assertEquals(ROW_5_VALUE, getValue(focusModel.getFocusedItem())); 269 } 270 271 assertNotNull(msModel().getSelectedIndices()); 272 assertNotNull(msModel().getSelectedItems()); 273 assertEquals(1, msModel().getSelectedIndices().size()); 274 assertEquals(index, msModel().getSelectedIndices().get(0)); 275 assertEquals(1, msModel().getSelectedItems().size()); 276 assertEquals(ROW_5_VALUE, getValue(msModel().getSelectedItems().get(0))); 277 } 278 279 @Test public void testSelectAllWithSingleSelection() { 280 msModel().setSelectionMode(SelectionMode.SINGLE); 281 msModel().selectAll(); 282 ensureInDefaultState(); 283 } 284 285 @Test public void testSelectAllWithMultipleSelection() { 286 msModel().clearSelection(); 287 msModel().selectAll(); 288 289 assertEquals(19, model.getSelectedIndex()); 290 assertNotNull(model.getSelectedItem()); 291 assertEquals(ROW_20_VALUE, getValue(model.getSelectedItem())); 292 assertEquals(19, focusModel.getFocusedIndex()); 293 assertNotNull(focusModel.getFocusedItem()); 294 assertEquals(ROW_20_VALUE, getValue(focusModel.getFocusedItem())); 295 assertNotNull(msModel().getSelectedIndices()); 296 assertNotNull(msModel().getSelectedItems()); 297 assertEquals(20, msModel().getSelectedIndices().size()); 298 assertEquals(20, msModel().getSelectedItems().size()); 299 } 300 301 @Test public void clearAllSelection() { 302 msModel().selectAll(); 303 model.clearSelection(); 304 ensureInEmptyState(); 305 } 306 307 @Test public void clearPartialSelectionWithSingleSelection() { 308 model.clearSelection(); 309 assertFalse(model.isSelected(5)); 310 model.select(5); 311 assertTrue(model.isSelected(5)); 312 model.clearSelection(5); 313 assertFalse(model.isSelected(5)); 314 315 assertEquals(0, msModel().getSelectedIndices().size()); 316 assertEquals(0, msModel().getSelectedItems().size()); 317 } 318 319 @Test public void clearPartialSelectionWithMultipleSelection() { 320 msModel().setSelectionMode(SelectionMode.MULTIPLE); 321 msModel().selectAll(); 322 model.clearSelection(5); 323 324 assertTrue(model.isSelected(4)); 325 assertFalse(model.isSelected(5)); 326 assertTrue(model.isSelected(6)); 327 } 328 329 @Test public void testSelectedIndicesObservableListIsEmpty() { 330 assertTrue(msModel().getSelectedIndices().isEmpty()); 331 } 332 333 @Test public void testSelectedIndicesIteratorIsNotNull() { 334 assertNotNull(msModel().getSelectedIndices().iterator()); 335 } 336 337 @Test public void testSelectedIndicesIteratorHasNoNext() { 338 assertFalse(msModel().getSelectedIndices().iterator().hasNext()); 339 } 340 341 @Test public void testSelectedIndicesIteratorWorksWithSingleSelection() { 342 msModel().clearSelection(); 343 model.select(5); 344 345 Iterator<Integer> it = msModel().getSelectedIndices().iterator(); 346 assertEquals(5, (int) it.next()); 347 assertFalse(it.hasNext()); 348 } 349 350 @Test public void testSelectedIndicesIteratorWorksWithMultipleSelection() { 351 msModel().clearSelection(); 352 msModel().setSelectionMode(SelectionMode.MULTIPLE); 353 msModel().selectIndices(1, 2, 5); 354 355 Iterator<Integer> it = msModel().getSelectedIndices().iterator(); 356 assertEquals(indices(msModel()), 1, (int) it.next()); 357 assertEquals(indices(msModel()), 2, (int) it.next()); 358 assertEquals(indices(msModel()), 5, (int) it.next()); 359 assertFalse(it.hasNext()); 360 } 361 362 @Test public void testSelectedIndicesContains() { 363 model.select(5); 364 assertTrue(msModel().getSelectedIndices().contains(5)); 365 } 366 367 @Test public void testSelectedItemsObservableListIsEmpty() { 368 assertTrue(msModel().getSelectedItems().isEmpty()); 369 } 370 371 @Test public void testSelectedItemsIndexOf() { 372 msModel().clearSelection(); 373 if (isTree()) { 374 model.select(ROW_2_TREE_VALUE); 375 assertEquals(1, msModel().getSelectedItems().size()); 376 assertEquals(0, msModel().getSelectedItems().indexOf(ROW_2_TREE_VALUE)); 377 } else { 378 model.select(ROW_2_VALUE); 379 assertEquals(1, msModel().getSelectedItems().size()); 380 assertEquals(0, msModel().getSelectedItems().indexOf(ROW_2_VALUE)); 381 } 382 } 383 384 @Test public void testSelectedItemsIteratorIsNotNull() { 385 assertNotNull(msModel().getSelectedIndices().iterator()); 386 } 387 388 @Test public void testSelectedItemsLastIndexOf() { 389 msModel().clearSelection(); 390 if (isTree()) { 391 model.select(ROW_2_TREE_VALUE); 392 assertEquals(1, msModel().getSelectedItems().size()); 393 assertEquals(0, msModel().getSelectedItems().lastIndexOf(ROW_2_TREE_VALUE)); 394 } else { 395 model.select(ROW_2_VALUE); 396 assertEquals(1, msModel().getSelectedItems().size()); 397 assertEquals(0, msModel().getSelectedItems().lastIndexOf(ROW_2_VALUE)); 398 } 399 } 400 401 @Test public void testSelectedItemsContains() { 402 model.select(5); 403 assertTrue(msModel().getSelectedIndices().contains(5)); 404 } 405 406 @Test public void testSingleSelectionMode() { 407 msModel().clearSelection(); 408 msModel().setSelectionMode(SelectionMode.SINGLE); 409 assertTrue(model.isEmpty()); 410 411 model.select(5); 412 assertTrue(model.isSelected(5)); 413 414 model.select(10); 415 assertTrue(model.isSelected(10)); 416 assertFalse(model.isSelected(5)); 417 418 assertEquals(1, msModel().getSelectedIndices().size()); 419 assertEquals(1, msModel().getSelectedItems().size()); 420 } 421 422 @Test public void testMultipleSelectionMode() { 423 msModel().clearSelection(); 424 msModel().setSelectionMode(SelectionMode.MULTIPLE); 425 assertTrue(model.isEmpty()); 426 427 model.select(5); 428 assertTrue(model.isSelected(5)); 429 430 model.select(10); 431 assertTrue(model.isSelected(10)); 432 assertTrue(model.isSelected(5)); 433 assertEquals(2, msModel().getSelectedIndices().size()); 434 assertEquals(2, msModel().getSelectedItems().size()); 435 } 436 437 @Test public void testChangeSelectionMode() { 438 msModel().clearSelection(); 439 msModel().setSelectionMode(SelectionMode.MULTIPLE); 440 msModel().selectIndices(5, 10, 15); 441 assertEquals(indices(msModel()), 3, msModel().getSelectedIndices().size()); 442 assertEquals(3, msModel().getSelectedItems().size()); 443 assertTrue(model.isSelected(5)); 444 assertTrue(model.isSelected(10)); 445 assertTrue(model.isSelected(15)); 446 447 msModel().setSelectionMode(SelectionMode.SINGLE); 448 assertEquals(1, msModel().getSelectedIndices().size()); 449 assertEquals(1, msModel().getSelectedItems().size()); 450 assertFalse(indices(msModel()), model.isSelected(5)); 451 assertFalse(indices(msModel()), model.isSelected(10)); 452 assertTrue(indices(msModel()), model.isSelected(15)); 453 } 454 455 // @Test public void testSelectNullObject() { 456 // model.select(null); 457 // } 458 459 @Test public void testSelectRange() { 460 // should select all indices starting at 5, and finishing just before 461 // the 10th item 462 msModel().clearSelection(); 463 msModel().setSelectionMode(SelectionMode.MULTIPLE); 464 msModel().selectRange(5, 10); 465 assertEquals(indices(msModel()), 5, msModel().getSelectedIndices().size()); 466 assertEquals(5, msModel().getSelectedItems().size()); 467 assertFalse(model.isSelected(4)); 468 assertTrue(model.isSelected(5)); 469 assertTrue(model.isSelected(6)); 470 assertTrue(model.isSelected(7)); 471 assertTrue(model.isSelected(8)); 472 assertTrue(model.isSelected(9)); 473 assertFalse(model.isSelected(10)); 474 } 475 476 @Test public void testDeselectionFromASelectionRange() { 477 msModel().setSelectionMode(SelectionMode.MULTIPLE); 478 msModel().selectRange(2, 10); 479 model.clearSelection(5); 480 assertTrue(indices(msModel()), model.isSelected(4)); 481 assertFalse(indices(msModel()), model.isSelected(5)); 482 assertTrue(indices(msModel()), model.isSelected(6)); 483 } 484 485 @Test public void testAccurateItemSelection() { 486 msModel().clearSelection(); 487 msModel().setSelectionMode(SelectionMode.MULTIPLE); 488 msModel().selectRange(2, 5); 489 ObservableList selectedItems = msModel().getSelectedItems(); 490 assertEquals(3, selectedItems.size()); 491 492 if (isTree()) { 493 assertFalse(selectedItems.contains(root.getChildren().get(0))); 494 assertTrue(selectedItems.contains(root.getChildren().get(1))); 495 assertTrue(selectedItems.contains(root.getChildren().get(2))); 496 assertTrue(selectedItems.contains(root.getChildren().get(3))); 497 assertFalse(selectedItems.contains(root.getChildren().get(4))); 498 } else { 499 assertFalse(selectedItems.contains(data.get(1))); 500 assertTrue(selectedItems.contains(data.get(2))); 501 assertTrue(selectedItems.contains(data.get(3))); 502 assertTrue(selectedItems.contains(data.get(4))); 503 assertFalse(selectedItems.contains(data.get(5))); 504 } 505 } 506 507 @Test public void ensureSelectedIndexAndItemIsAlwaysTheLastSelectionWithSelect() { 508 msModel().setSelectionMode(SelectionMode.MULTIPLE); 509 model.select(3); 510 assertEquals(3, model.getSelectedIndex()); 511 if (isTree()) { 512 assertEquals(root.getChildren().get(2), model.getSelectedItem()); 513 } else { 514 assertEquals(data.get(3), model.getSelectedItem()); 515 } 516 517 model.select(1); 518 assertEquals(1, model.getSelectedIndex()); 519 if (isTree()) { 520 assertEquals(root.getChildren().get(0), model.getSelectedItem()); 521 } else { 522 assertEquals(data.get(1), model.getSelectedItem()); 523 } 524 525 model.select(5); 526 assertEquals(5, model.getSelectedIndex()); 527 if (isTree()) { 528 assertEquals(root.getChildren().get(4), model.getSelectedItem()); 529 } else { 530 assertEquals(data.get(5), model.getSelectedItem()); 531 } 532 533 model.select(1); 534 assertEquals(1, model.getSelectedIndex()); 535 if (isTree()) { 536 assertEquals(root.getChildren().get(0), model.getSelectedItem()); 537 } else { 538 assertEquals(data.get(1), model.getSelectedItem()); 539 } 540 } 541 542 @Test public void ensureSelectedIndexAndItemIsAlwaysTheLastSelectionWithMultipleSelect() { 543 msModel().setSelectionMode(SelectionMode.MULTIPLE); 544 msModel().selectIndices(3,4,5); 545 assertEquals(5, model.getSelectedIndex()); 546 547 if (isTree()) { 548 assertEquals(root.getChildren().get(4), model.getSelectedItem()); 549 } else { 550 assertEquals(data.get(5), model.getSelectedItem()); 551 } 552 553 model.select(1); 554 assertEquals(1, model.getSelectedIndex()); 555 556 if (isTree()) { 557 assertEquals(root.getChildren().get(0), model.getSelectedItem()); 558 } else { 559 assertEquals(data.get(1), model.getSelectedItem()); 560 } 561 562 msModel().selectIndices(8,7,6); 563 assertEquals(6, model.getSelectedIndex()); 564 if (isTree()) { 565 assertEquals(root.getChildren().get(5), model.getSelectedItem()); 566 } else { 567 assertEquals(data.get(6), model.getSelectedItem()); 568 } 569 } 570 571 @Test public void ensureSelectedIndexAndItemIsAlwaysTheLastSelectionWithSelectRange() { 572 msModel().setSelectionMode(SelectionMode.MULTIPLE); 573 msModel().selectRange(3,10); 574 assertEquals(9, model.getSelectedIndex()); 575 if (isTree()) { 576 assertEquals(root.getChildren().get(8), model.getSelectedItem()); 577 } else { 578 assertEquals(data.get(9), model.getSelectedItem()); 579 } 580 581 model.select(1); 582 assertEquals(1, model.getSelectedIndex()); 583 if (isTree()) { 584 assertEquals(root.getChildren().get(0), model.getSelectedItem()); 585 } else { 586 assertEquals(data.get(1), model.getSelectedItem()); 587 } 588 589 msModel().selectRange(6, 8); 590 assertEquals(7, model.getSelectedIndex()); 591 if (isTree()) { 592 assertEquals(root.getChildren().get(6), model.getSelectedItem()); 593 } else { 594 assertEquals(data.get(7), model.getSelectedItem()); 595 } 596 } 597 598 @Test public void testMultipleSelectionWithEmptyArray() { 599 msModel().clearSelection(); 600 msModel().setSelectionMode(SelectionMode.MULTIPLE); 601 msModel().selectIndices(3,new int[] { }); 602 assertEquals(3, model.getSelectedIndex()); 603 assertEquals(1, msModel().getSelectedIndices().size()); 604 assertEquals(1, msModel().getSelectedItems().size()); 605 606 if (isTree()) { 607 assertEquals(root.getChildren().get(2), model.getSelectedItem()); 608 } else { 609 assertEquals(data.get(3), model.getSelectedItem()); 610 } 611 } 612 613 @Test public void selectOnlyValidIndicesInSingleSelection() { 614 msModel().setSelectionMode(SelectionMode.SINGLE); 615 msModel().selectIndices(750397, 3, 709709375, 4, 8597998, 47929); 616 assertEquals(4, model.getSelectedIndex()); 617 assertFalse(model.isSelected(3)); 618 assertTrue(model.isSelected(4)); 619 assertEquals(1, msModel().getSelectedIndices().size()); 620 assertEquals(1, msModel().getSelectedItems().size()); 621 622 if (isTree()) { 623 assertEquals(root.getChildren().get(3), model.getSelectedItem()); 624 } else { 625 assertEquals(data.get(4), model.getSelectedItem()); 626 } 627 } 628 629 @Test public void selectOnlyValidIndicesInMultipleSelection() { 630 msModel().setSelectionMode(SelectionMode.MULTIPLE); 631 model.clearSelection(); 632 msModel().selectIndices(750397, 3, 709709375, 4, 8597998, 47929); 633 assertEquals(4, model.getSelectedIndex()); 634 assertTrue(model.isSelected(3)); 635 assertTrue(model.isSelected(4)); 636 assertEquals(2, msModel().getSelectedIndices().size()); 637 assertEquals(2, msModel().getSelectedItems().size()); 638 639 if (isTree()) { 640 assertEquals(root.getChildren().get(3), model.getSelectedItem()); 641 } else { 642 assertEquals(data.get(4), model.getSelectedItem()); 643 } 644 } 645 646 @Test public void testNullArrayInMultipleSelection() { 647 msModel().clearSelection(); 648 msModel().setSelectionMode(SelectionMode.MULTIPLE); 649 msModel().selectIndices(-20, null); 650 assertEquals(-1, model.getSelectedIndex()); 651 assertNull(model.getSelectedItem()); 652 assertEquals(indices(msModel()), 0, msModel().getSelectedIndices().size()); 653 assertEquals(items(msModel()), 0, msModel().getSelectedItems().size()); 654 } 655 656 @Test public void testMultipleSelectionWithInvalidIndices() { 657 msModel().clearSelection(); 658 msModel().setSelectionMode(SelectionMode.MULTIPLE); 659 msModel().selectIndices(-20, 23505, 78125); 660 assertEquals(-1, model.getSelectedIndex()); 661 assertNull(model.getSelectedItem()); 662 assertEquals(indices(msModel()), 0, msModel().getSelectedIndices().size()); 663 assertEquals(items(msModel()), 0, msModel().getSelectedItems().size()); 664 } 665 666 @Test public void testInvalidSelection() { 667 msModel().clearSelection(); 668 msModel().setSelectionMode(SelectionMode.SINGLE); 669 msModel().selectIndices(-20, null); 670 assertEquals(-1, model.getSelectedIndex()); 671 assertNull(model.getSelectedItem()); 672 assertEquals(indices(msModel()), 0, msModel().getSelectedIndices().size()); 673 assertEquals(items(msModel()), 0, msModel().getSelectedItems().size()); 674 } 675 676 @Test public void ensureSwappedSelectRangeWorks() { 677 // first test a valid range - there should be 6 selected items 678 model.clearSelection(); 679 model.setSelectionMode(SelectionMode.MULTIPLE); 680 model.selectRange(3, 10); 681 assertEquals(indices(model), 7, model.getSelectedIndices().size()); 682 assertEquals(9, model.getSelectedIndex()); 683 if (isTree()) { 684 assertEquals(root.getChildren().get(8), model.getSelectedItem()); 685 } else { 686 assertEquals(data.get(9), model.getSelectedItem()); 687 } 688 689 model.clearSelection(); 690 691 // we should select the range from 10 - 4 inclusive 692 model.selectRange(10, 3); 693 assertEquals(7, model.getSelectedIndices().size()); 694 assertEquals(indices(model), 4, model.getSelectedIndex()); 695 if (isTree()) { 696 assertEquals(root.getChildren().get(3), model.getSelectedItem()); 697 } else { 698 assertEquals(data.get(4), model.getSelectedItem()); 699 } 700 } 701 702 @Test public void testInvalidSelectRange() { 703 msModel().clearSelection(); 704 msModel().setSelectionMode(SelectionMode.MULTIPLE); 705 msModel().selectRange(200, 220); 706 assertEquals(-1, model.getSelectedIndex()); 707 assertEquals(null, model.getSelectedItem()); 708 assertEquals(indices(msModel()), 0, msModel().getSelectedIndices().size()); 709 assertEquals(items(msModel()), 0, msModel().getSelectedItems().size()); 710 } 711 712 @Test public void testEmptySelectRange() { 713 msModel().clearSelection(); 714 msModel().setSelectionMode(SelectionMode.MULTIPLE); 715 msModel().selectRange(10, 10); 716 assertEquals(-1, model.getSelectedIndex()); 717 assertEquals(null, model.getSelectedItem()); 718 assertEquals(indices(msModel()), 0, msModel().getSelectedIndices().size()); 719 assertEquals(items(msModel()), 0, msModel().getSelectedItems().size()); 720 } 721 722 @Test public void testNegativeSelectRange() { 723 msModel().clearSelection(); 724 msModel().setSelectionMode(SelectionMode.MULTIPLE); 725 msModel().selectRange(-10, -1); 726 assertEquals(-1, model.getSelectedIndex()); 727 assertEquals(null, model.getSelectedItem()); 728 assertEquals(indices(msModel()), 0, msModel().getSelectedIndices().size()); 729 assertEquals(items(msModel()), 0, msModel().getSelectedItems().size()); 730 } 731 732 @Test(expected=IllegalArgumentException.class) 733 public void testNullListViewInSelectionModel() { 734 new ListView.ListViewBitSetSelectionModel(null); 735 } 736 737 @Test(expected=IllegalArgumentException.class) 738 public void testNullTreeViewInSelectionModel() { 739 new TreeView.TreeViewBitSetSelectionModel(null); 740 } 741 742 @Test public void selectAllInEmptySingleSelectionMode() { 743 model.clearSelection(); 744 msModel().setSelectionMode(SelectionMode.SINGLE); 745 assertTrue(model.isEmpty()); 746 msModel().selectAll(); 747 assertTrue(model.isEmpty()); 748 } 749 750 @Test public void selectAllInSingleSelectionModeWithSelectedRow() { 751 msModel().setSelectionMode(SelectionMode.SINGLE); 752 model.clearSelection(); 753 assertTrue(model.isEmpty()); 754 model.select(3); 755 msModel().selectAll(); 756 assertTrue(model.isSelected(3)); 757 assertEquals(1, msModel().getSelectedIndices().size()); 758 } 759 760 @Test public void selectionModePropertyHasReferenceToBean() { 761 assertSame(model, model.selectionModeProperty().getBean()); 762 } 763 764 @Test public void selectionModePropertyHasName() { 765 assertSame("selectionMode", model.selectionModeProperty().getName()); 766 } 767 768 @Ignore("Not yet implemented in TreeView and TableView") 769 @Test public void testSelectionChangesWhenItemIsInsertedAtStartOfModel() { 770 /* Select the fourth item, and insert a new item at the start of the 771 * data model. The end result should be that the fourth item should NOT 772 * be selected, and the fifth item SHOULD be selected. 773 */ 774 model.select(3); 775 assertTrue(model.isSelected(3)); 776 data.add(0, "Inserted String"); 777 assertFalse(model.isSelected(3)); 778 assertTrue(model.isSelected(4)); 779 } 780 781 private int rt_28615_row_1_hit_count = 0; 782 private int rt_28615_row_2_hit_count = 0; 783 @Test public void test_rt_28615() { 784 model.clearSelection(); 785 msModel().setSelectionMode(SelectionMode.MULTIPLE); 786 787 msModel().getSelectedItems().addListener((ListChangeListener.Change change) -> { 788 while (change.next()) { 789 if (change.wasAdded()) { 790 for (Object item : change.getAddedSubList()) { 791 if (isTree()) { 792 if (root.equals(item)) { 793 rt_28615_row_1_hit_count++; 794 } else if (ROW_2_TREE_VALUE.equals(item)) { 795 rt_28615_row_2_hit_count++; 796 } 797 } else { 798 if (ROW_1_VALUE.equals(item)) { 799 rt_28615_row_1_hit_count++; 800 } else if (ROW_2_VALUE.equals(item)) { 801 rt_28615_row_2_hit_count++; 802 } 803 } 804 } 805 } 806 } 807 }); 808 809 assertEquals(0, rt_28615_row_1_hit_count); 810 assertEquals(0, rt_28615_row_2_hit_count); 811 812 msModel().select(0); 813 assertEquals(1, rt_28615_row_1_hit_count); 814 assertEquals(0, rt_28615_row_2_hit_count); 815 816 msModel().select(1); 817 assertEquals(1, rt_28615_row_1_hit_count); 818 assertEquals(1, rt_28615_row_2_hit_count); 819 } 820 821 private int rt_29860_size_count = 0; 822 @Test public void test_rt_29860_add() { 823 model.clearSelection(); 824 msModel().setSelectionMode(SelectionMode.MULTIPLE); 825 826 msModel().getSelectedIndices().addListener((ListChangeListener.Change change) -> { 827 while (change.next()) { 828 if (change.wasAdded()) { 829 rt_29860_size_count += change.getAddedSize(); 830 } 831 } 832 }); 833 834 assertEquals(0, rt_29860_size_count); 835 836 // 0,1,2,3 are all selected. The bug is not that the msModel().getSelectedIndices() 837 // list is wrong (it isn't - it's correct). The bug is that the addedSize 838 // reported in the callback above is incorrect. 839 msModel().selectIndices(0, 1, 2, 3); 840 assertEquals(msModel().getSelectedIndices().toString(), 4, rt_29860_size_count); 841 rt_29860_size_count = 0; 842 843 msModel().selectIndices(0,1,2,3,4); 844 assertEquals(msModel().getSelectedIndices().toString(), 1, rt_29860_size_count); // only 4 was selected 845 rt_29860_size_count = 0; 846 847 msModel().selectIndices(6,7,8); 848 assertEquals(3, rt_29860_size_count); // 6,7,8 was selected 849 } 850 851 @Test public void test_rt_29821() { 852 msModel().setSelectionMode(SelectionMode.MULTIPLE); 853 854 IndexedCell cell_3 = VirtualFlowTestUtils.getCell(currentControl, 3); 855 assertNotNull(cell_3); 856 assertFalse(cell_3.isSelected()); 857 858 msModel().clearSelection(); 859 msModel().select(3); 860 assertTrue(cell_3.isSelected()); 861 assertEquals(1, msModel().getSelectedIndices().size()); 862 863 // in multiple selection passing in select(null) is a no-op. In single 864 // selection (tested elsewhere), this would result in a clearSelection() 865 // call 866 msModel().select(null); 867 assertTrue(msModel().isSelected(3)); 868 assertTrue(cell_3.isSelected()); 869 } 870 871 private int rt_32411_add_count = 0; 872 private int rt_32411_remove_count = 0; 873 @Test public void test_rt_32411_selectedItems() { 874 model.clearSelection(); 875 876 model.getSelectedItems().addListener((ListChangeListener.Change change) -> { 877 while (change.next()) { 878 rt_32411_remove_count += change.getRemovedSize(); 879 rt_32411_add_count += change.getAddedSize(); 880 } 881 }); 882 883 // reset fields 884 rt_32411_add_count = 0; 885 rt_32411_remove_count = 0; 886 887 // select a row - no problems here 888 model.select(2); 889 assertEquals(1, rt_32411_add_count); 890 assertEquals(0, rt_32411_remove_count); 891 892 // clear and select a new row. We should receive a remove event followed 893 // by an added event - but this bug shows we don't get the remove event. 894 model.clearAndSelect(4); 895 assertEquals(2, rt_32411_add_count); 896 assertEquals(1, rt_32411_remove_count); 897 } 898 899 @Test public void test_rt_32411_selectedIndices() { 900 model.clearSelection(); 901 902 model.getSelectedIndices().addListener((ListChangeListener.Change change) -> { 903 while (change.next()) { 904 rt_32411_remove_count += change.getRemovedSize(); 905 rt_32411_add_count += change.getAddedSize(); 906 } 907 }); 908 909 // reset fields 910 rt_32411_add_count = 0; 911 rt_32411_remove_count = 0; 912 913 // select a row - no problems here 914 model.select(2); 915 assertEquals(1, rt_32411_add_count); 916 assertEquals(0, rt_32411_remove_count); 917 918 // clear and select a new row. We should receive a remove event followed 919 // by an added event - but this bug shows we don't get the remove event. 920 model.clearAndSelect(4); 921 assertEquals(2, rt_32411_add_count); 922 assertEquals(1, rt_32411_remove_count); 923 } 924 925 private int rt32618_count = 0; 926 @Test public void test_rt32618_multipleSelection() { 927 model.selectedItemProperty().addListener((ov, t, t1) -> rt32618_count++); 928 929 assertEquals(0, rt32618_count); 930 931 model.select(1); 932 assertEquals(1, rt32618_count); 933 assertEquals(ROW_2_VALUE, getValue(model.getSelectedItem())); 934 935 model.clearAndSelect(2); 936 assertEquals(2, rt32618_count); 937 assertEquals(ROW_3_VALUE, getValue(model.getSelectedItem())); 938 } 939 940 @Test public void test_rt33324_selectedIndices() { 941 // pre-select item 0 942 model.select(0); 943 944 // install listener 945 model.getSelectedIndices().addListener((ListChangeListener.Change change) -> { 946 while (change.next()) { 947 assertTrue(change.wasRemoved()); 948 assertTrue(change.wasAdded()); 949 assertTrue(change.wasReplaced()); 950 951 assertFalse(change.wasPermutated()); 952 } 953 }); 954 955 // change selection to index 1. This should result in a change event 956 // being fired where wasAdded() is true, wasRemoved() is true, but most 957 // importantly, wasReplaced() is true 958 model.clearAndSelect(1); 959 } 960 961 @Test public void test_rt33324_selectedItems() { 962 // pre-select item 0 963 model.select(0); 964 965 // install listener 966 model.getSelectedItems().addListener((ListChangeListener.Change change) -> { 967 while (change.next()) { 968 assertTrue(change.wasRemoved()); 969 assertTrue(change.wasAdded()); 970 assertTrue(change.wasReplaced()); 971 972 assertFalse(change.wasPermutated()); 973 } 974 }); 975 976 // change selection to index 1. This should result in a change event 977 // being fired where wasAdded() is true, wasRemoved() is true, but most 978 // importantly, wasReplaced() is true 979 model.clearAndSelect(1); 980 } 981 982 @Test public void test_rt33324_selectedCells() { 983 if (! (msModel() instanceof TableViewSelectionModel)) { 984 return; 985 } 986 987 TableViewSelectionModel tableSM = (TableViewSelectionModel) msModel(); 988 989 // pre-select item 0 990 tableSM.select(0); 991 992 // install listener 993 tableSM.getSelectedCells().addListener((ListChangeListener.Change change) -> { 994 while (change.next()) { 995 assertTrue(change.wasRemoved()); 996 assertTrue(change.wasAdded()); 997 assertTrue(change.wasReplaced()); 998 999 assertFalse(change.wasPermutated()); 1000 } 1001 }); 1002 1003 // change selection to index 1. This should result in a change event 1004 // being fired where wasAdded() is true, wasRemoved() is true, but most 1005 // importantly, wasReplaced() is true 1006 tableSM.clearAndSelect(1); 1007 } 1008 1009 @Test public void test_rt35624_selectedIndices_downwards() { 1010 model.clearSelection(); 1011 model.select(2); 1012 1013 msModel().getSelectedIndices().addListener((ListChangeListener.Change change) -> { 1014 while (change.next()) { 1015 // we expect two items in the added list: 3 and 4, as index 1016 // 2 has previously been selected 1017 Assert.assertEquals(2, change.getAddedSize()); 1018 Assert.assertEquals(FXCollections.observableArrayList(3, 4), change.getAddedSubList()); 1019 } 1020 1021 // In the actual list, we expect three items: 2, 3 and 4 1022 Assert.assertEquals(3, change.getList().size()); 1023 Assert.assertEquals(FXCollections.observableArrayList(2, 3, 4), change.getList()); 1024 }); 1025 1026 model.selectIndices(2, 3, 4); 1027 } 1028 1029 @Test public void test_rt35624_selectedIndices_upwards() { 1030 model.clearSelection(); 1031 model.select(4); 1032 1033 msModel().getSelectedIndices().addListener(((ListChangeListener.Change change) -> { 1034 while (change.next()) { 1035 // we expect two items in the added list: 3 and 2, as index 1036 // 4 has previously been selected 1037 assertEquals(2, change.getAddedSize()); 1038 assertEquals(FXCollections.observableArrayList(2, 3), change.getAddedSubList()); 1039 } 1040 1041 // In the actual list, we expect three items: 2, 3 and 4 1042 assertEquals(3, change.getList().size()); 1043 assertEquals(FXCollections.observableArrayList(2, 3, 4), change.getList()); 1044 })); 1045 1046 model.selectIndices(4, 3, 2); 1047 } 1048 1049 @Test public void test_rt35624_selectedItems_downwards() { 1050 model.clearSelection(); 1051 model.select(2); 1052 1053 msModel().getSelectedItems().addListener(((ListChangeListener.Change change) -> { 1054 while (change.next()) { 1055 // we expect two items in the added list: the items in index 1056 // 3 and 4, as index 2 has previously been selected 1057 assertEquals(2, change.getAddedSize()); 1058 1059 if (isTree()) { 1060 assertEquals(FXCollections.observableArrayList( 1061 root.getChildren().get(2), 1062 root.getChildren().get(3) 1063 ), change.getAddedSubList()); 1064 } else { 1065 assertEquals(FXCollections.observableArrayList( 1066 data.get(3), 1067 data.get(4) 1068 ), change.getAddedSubList()); 1069 } 1070 } 1071 1072 // In the actual list, we expect three items: the values at index 1073 // 2, 3 and 4 1074 assertEquals(3, change.getList().size()); 1075 1076 if (isTree()) { 1077 assertEquals(FXCollections.observableArrayList( 1078 root.getChildren().get(1), 1079 root.getChildren().get(2), 1080 root.getChildren().get(3) 1081 ), change.getList()); 1082 } else { 1083 assertEquals(FXCollections.observableArrayList( 1084 data.get(2), 1085 data.get(3), 1086 data.get(4) 1087 ), change.getList()); 1088 } 1089 })); 1090 1091 model.selectIndices(2, 3, 4); 1092 } 1093 1094 @Test public void test_rt35624_selectedItems_upwards() { 1095 model.clearSelection(); 1096 model.select(4); 1097 1098 msModel().getSelectedItems().addListener(((ListChangeListener.Change change) -> { 1099 while (change.next()) { 1100 // we expect two items in the added list: the items in index 1101 // 2 and 3, as index 4 has previously been selected 1102 assertEquals(2, change.getAddedSize()); 1103 1104 if (isTree()) { 1105 assertEquals(FXCollections.observableArrayList( 1106 root.getChildren().get(1), 1107 root.getChildren().get(2) 1108 ), change.getAddedSubList()); 1109 } else { 1110 assertEquals(FXCollections.observableArrayList( 1111 data.get(2), 1112 data.get(3) 1113 ), change.getAddedSubList()); 1114 } 1115 } 1116 1117 // In the actual list, we expect three items: the values at index 1118 // 2, 3 and 4 1119 assertEquals(3, change.getList().size()); 1120 1121 if (isTree()) { 1122 assertEquals(FXCollections.observableArrayList( 1123 root.getChildren().get(1), 1124 root.getChildren().get(2), 1125 root.getChildren().get(3) 1126 ), change.getList()); 1127 } else { 1128 assertEquals(FXCollections.observableArrayList( 1129 data.get(2), 1130 data.get(3), 1131 data.get(4) 1132 ), change.getList()); 1133 } 1134 })); 1135 1136 model.selectIndices(4, 3, 2); 1137 } 1138 1139 @Test public void test_rt39548_positiveValue_outOfRange() { 1140 // for this test we want there to be no data in the controls 1141 clearModelData(); 1142 1143 model.clearAndSelect(10); 1144 } 1145 1146 @Test public void test_rt39548_negativeValue() { 1147 // for this test we want there to be no data in the controls 1148 clearModelData(); 1149 1150 model.clearAndSelect(-1); 1151 } 1152 1153 @Ignore 1154 @Test public void test_rt38884_invalidChange() { 1155 model.select(3); 1156 int removedSize = model.getSelectedItems().size(); 1157 ListChangeListener l = (ListChangeListener.Change c) -> { 1158 c.next(); 1159 assertEquals(removedSize, c.getRemovedSize()); 1160 }; 1161 model.getSelectedItems().addListener(l); 1162 clearModelData(); 1163 } 1164 1165 private void clearModelData() { 1166 listView.getItems().clear(); 1167 tableView.getItems().clear(); 1168 treeView.setRoot(null); 1169 treeTableView.setRoot(null); 1170 } 1171 1172 @Test public void test_rt40804() { 1173 final Thread.UncaughtExceptionHandler exceptionHandler = Thread.currentThread().getUncaughtExceptionHandler(); 1174 Thread.currentThread().setUncaughtExceptionHandler((t, e) -> { 1175 e.printStackTrace(); 1176 fail("We don't expect any exceptions in this test!"); 1177 }); 1178 1179 StageLoader sl = new StageLoader(currentControl); 1180 model.setSelectionMode(SelectionMode.MULTIPLE); 1181 model.select(0); 1182 model.select(1); 1183 model.clearSelection(); 1184 model.select(3); // this is where the test failed 1185 1186 sl.dispose(); 1187 1188 // reset the exception handler 1189 Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler); 1190 } 1191 }