Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8150636

InputMap: must cleanup internals on mappings.remove(...)

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 9
    • 9
    • javafx
    • 9-ea-104

      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 ... ;-)

            jgiles Jonathan Giles
            fastegal Jeanette Winzenburg
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: