JDK-8088686 : Tree selection: incorrect change notification of selectedItems
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: 8u60
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2015-03-26
  • Updated: 2018-09-05
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Description
Stumbled across a couple of issues. 

The example below is basically the same as RT-40010, with the added option to replace the selected child. To reproduce the variants of incorrect notification, run the example and notice the output.

Issue A: the type of event on removing all children is incorrect, we expect a replaced but get an added
- select a child, 
- press delete to remove all children: 
- root is selected and selectedItems fired single event (RT-40010 fixed)
- expected: the type of change must be replaced
- actual: the type of change is added

Issue B: no event fired on replacing the selectedItem
- press a several times to add children
- select the first child
- press r to replace the selected child
- selection moved to next child (arguable, but a different issue)
- expected: selectedItems must fire a replaced
- actual: selectedItems fire not at all

Issue C: incorrect number and type of events on shift-up/down
- press a several times to add children
- select any child
- press shift-up/down to move selection around
- expected (same as pressing up/down): a single event of type replaced (correct for up/down)
- actual: two events of type added

- A seems to be a variant of missing removed notification (already known/reported, but can't find it right now), 
- B might be a regression (more a wild guess because I don't remember seeing it before 8u60), 
- C looks like a mix of A and the implementation of alsoSelectNext/Prev in TreeViewBehaviour: it's a two-step algorithm that first clears the selection outside, then selects - thus producing two events

/**
 * still open:
 * - type of event on removeAll: only added for root, no removed for child
 * - replace selected item: no event at all
 * - shift-select: two added for the replacing child, no removed for old child 
 * 
 */
public class TreeViewSelection_40010 extends Application {

    @Override
    public void start(final Stage primaryStage) throws Exception {
        final VBox box = new VBox();
        final Scene scene = new Scene(box);
        primaryStage.setScene(scene);
        final TreeView<String> treeView = getTreeView();
        box.getChildren().add(treeView);
        primaryStage.show();

        // remove all children 
        scene.getAccelerators().put(new KeyCodeCombination(KeyCode.DELETE), () -> {
            treeView.getRoot().getChildren().removeIf(item -> true);
        });
        // replace selected
        scene.getAccelerators().put(new KeyCodeCombination(KeyCode.R), () -> {
            TreeItem<?> old = treeView.getSelectionModel().getSelectedItem();
            int childIndex = treeView.getRoot().getChildren().indexOf(old);
            if (childIndex < 0) return;
            treeView.getRoot().getChildren().set(childIndex, createTreeChild());
        });
        // add child
        scene.getAccelerators().put(new KeyCodeCombination(KeyCode.A), () -> {
            treeView.getRoot().getChildren().add(createTreeChild());
        });
        // print selectedItems
        scene.getAccelerators().put(new KeyCodeCombination(KeyCode.G), () -> {
            final MultipleSelectionModel<TreeItem<String>> selectionModel = treeView.getSelectionModel();
            System.out.println(selectionModel.getSelectedItems());
        });
    }

    private TreeView<String> getTreeView() {
        final TreeItem<String> root = createTreeItem("root ");
        root.getChildren().add(createTreeChild());

        final TreeView<String> treeView = new TreeView<String>(root);
        root.setExpanded(true);
//        treeView.setSelectionModel(new SimpleTreeSelectionModel<>(treeView));
        treeView.getSelectionModel().select(root);
        treeView.getSelectionModel().getSelectedItems().addListener((final Change<? extends TreeItem<String>> c) -> {
            System.out.println("--- change on selectedItems: " + c);
//            FXUtils.prettyPrint(c);
        });
        return treeView;
    }

    private int count;
    private TreeItem<String> createTreeChild() {
        return createTreeItem("child ");
    }
    private TreeItem<String> createTreeItem(String text) {
//        return new TreeItemX<>(text + count++);
        return new TreeItem<>(text + count++);
    }
    public static void main(final String[] args) {
        launch(args);
    }
}