Search code examples
javalistviewjavafxpropertiesundo

JavaFX undo listview selection


I've got a ListView and I listen to the selectedItemProperty for when the user changes the selection.

In this listener I add an event to my UndoManager. When I try to undo the selection, the selectedItemProperty fires the ChangeListener and it will add an other event to the UndoManger and creating an infinit loop because it will add a ListViewSelectionChange to the UndoManger when it undoes something.

public class DeviceConfigurationController {

    @FXML private ListView<DeviceConfiguration> device_list;
    @FXML
    private void initialize() {
        device_list.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            UndoManager.add(new ListViewSelectionChange<>(oldValue, device_list));
        });
    }

    //redo/undo stuff
    @FXML
    private void undo() {
        UndoManager.undo(); //calls the last Change
    }
}

public class ListViewSelectionChange<T> implements Change {

    privateT lastValue;
    private T redoValue;
    ListView<T> listView;

    public ListViewSelectionChange(T lastValue, ListView<T> listView) {
        this.lastValue = lastValue;
        this.listView = listView;
    }

//gets called from the undomanager
    @Override
    public void undo() {
        redoValue = listView.getSelectionModel().getSelectedItem();
        listView.getSelectionModel().select(lastValue); //fires the selection listener again, thus adding a ListViewSelection to the UndoManager
    }
}

Does someone has any idea how to stop the listview from calling the listener?

Sebastian


Solution

  • You could add a simple flag to indicate if the listener should be fired:

    public class DeviceConfigurationController {
    
        @FXML private ListView<DeviceConfiguration> device_list;
        private boolean pauseListener;
    
        @FXML
        private void initialize() {
            device_list.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
                if(!pauseListener)
                   UndoManager.add(new ListViewSelectionChange<>(oldValue, device_list));
                }            
            });
        }
    
        @FXML
        private void undo() {
            pauseListener = true;
            UndoManager.undo();
            pauseListener = false;
        }
    }