The use-case is to replace the behavior of a concrete skin, see http://stackoverflow.com/q/35156039/203657 My expectation is that oldBehavior.dispose() removes all mappings installed by the oldBehavior. Actually it doesn't, the mappings still interfer. Tracked down to InputMap not cleaning up its internal invers mappings.
Below is an example to reproduce, run and
- click into the circle and see output "initial"
- press button to to remove the initial mapping from the map and install a new InputMap with a new mapping
- click into the circle
- expected: output "replaced"
- actual: output "initial"
Note that inputMap dispose cleans up as expected, but that's not what a behavior wants to do: as per code-comment, it only wants to remove the mappings that were installed by itself.
The example:
public class InputMapCleanupBug extends Application {
private Parent getContent() {
Shape shape = new Circle(200, 200, 100);
InputMap<Shape> inputMap = new InputMap<>(shape);
inputMap.getMappings().add(new InputMap.MouseMapping(MouseEvent.MOUSE_PRESSED, this::initial));
Button replace = new Button("Replace InputMap");
replace.setOnAction(e -> {
// dispose cleans up
// that's not what a Behavior want's to do in its dispose
// as per code comment, it wants to remove only the mappings that were
// installed by the behavior
// inputMap.dispose();
// clearing the mappings doesn't cleans up
inputMap.getMappings().clear();
InputMap<Shape> replaced = new InputMap<>(shape);
replaced.getMappings().add(new InputMap.MouseMapping(MouseEvent.MOUSE_PRESSED, this::replaced));
});
BorderPane pane = new BorderPane(shape);
pane.setBottom(replace);
return pane;
}
public void initial(MouseEvent e) {
System.out.println("initial");
}
public void replaced(MouseEvent e) {
System.out.println("replaced");
}
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(getContent(), 500, 500));
//primaryStage.setTitle(FXUtils.version());
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Yeah, I'm aware that all is internal api and that there's a TODO marker in removeMapping ... ;-)
Below is an example to reproduce, run and
- click into the circle and see output "initial"
- press button to to remove the initial mapping from the map and install a new InputMap with a new mapping
- click into the circle
- expected: output "replaced"
- actual: output "initial"
Note that inputMap dispose cleans up as expected, but that's not what a behavior wants to do: as per code-comment, it only wants to remove the mappings that were installed by itself.
The example:
public class InputMapCleanupBug extends Application {
private Parent getContent() {
Shape shape = new Circle(200, 200, 100);
InputMap<Shape> inputMap = new InputMap<>(shape);
inputMap.getMappings().add(new InputMap.MouseMapping(MouseEvent.MOUSE_PRESSED, this::initial));
Button replace = new Button("Replace InputMap");
replace.setOnAction(e -> {
// dispose cleans up
// that's not what a Behavior want's to do in its dispose
// as per code comment, it wants to remove only the mappings that were
// installed by the behavior
// inputMap.dispose();
// clearing the mappings doesn't cleans up
inputMap.getMappings().clear();
InputMap<Shape> replaced = new InputMap<>(shape);
replaced.getMappings().add(new InputMap.MouseMapping(MouseEvent.MOUSE_PRESSED, this::replaced));
});
BorderPane pane = new BorderPane(shape);
pane.setBottom(replace);
return pane;
}
public void initial(MouseEvent e) {
System.out.println("initial");
}
public void replaced(MouseEvent e) {
System.out.println("replaced");
}
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(getContent(), 500, 500));
//primaryStage.setTitle(FXUtils.version());
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Yeah, I'm aware that all is internal api and that there's a TODO marker in removeMapping ... ;-)