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