From 3bc2117403bfbcd388163c4a02e32d8be88906dd Mon Sep 17 00:00:00 2001 From: dgelessus Date: Mon, 2 Sep 2024 16:39:48 +0200 Subject: [PATCH] Fix default simulation sometimes being saved into project files --- .../de/prob2/ui/project/machines/Machine.java | 4 ++ .../prob2/ui/simulation/SimulatorStage.java | 51 ++++++++++++------- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/prob2/ui/project/machines/Machine.java b/src/main/java/de/prob2/ui/project/machines/Machine.java index 0b592ea7f..b4807cdee 100644 --- a/src/main/java/de/prob2/ui/project/machines/Machine.java +++ b/src/main/java/de/prob2/ui/project/machines/Machine.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.FileTime; import java.util.ArrayList; import java.util.Collections; @@ -142,6 +143,9 @@ public Machine( this.validationTasks = new SimpleListProperty<>(this, "validationTasks", FXCollections.observableArrayList(validationTasks)); this.ltlPatterns = new SimpleListProperty<>(this, "ltlPatterns", FXCollections.observableArrayList(ltlPatterns)); this.simulations = new SimpleListProperty<>(this, "simulations", FXCollections.observableArrayList(simulations)); + // In previous versions, the default simulation was sometimes saved into the project file - remove it if it exists. + // TODO This should probably be moved into the old JSON format conversion code when we bump the project format version the next time + this.simulations.removeIf(simulationModel -> Paths.get("").equals(simulationModel.getPath())); this.visBVisualisation = new SimpleObjectProperty<>(this, "visBVisualisation", visBVisualisation); this.historyChartItems = new SimpleListProperty<>(this, "historyChartItems", FXCollections.observableArrayList(historyChartItems)); diff --git a/src/main/java/de/prob2/ui/simulation/SimulatorStage.java b/src/main/java/de/prob2/ui/simulation/SimulatorStage.java index 81f46b6f5..add11bfa0 100644 --- a/src/main/java/de/prob2/ui/simulation/SimulatorStage.java +++ b/src/main/java/de/prob2/ui/simulation/SimulatorStage.java @@ -58,6 +58,7 @@ import de.prob2.ui.verifications.CheckingStatusCell; import javafx.application.Platform; +import javafx.beans.InvalidationListener; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanExpression; import javafx.beans.property.BooleanProperty; @@ -349,6 +350,7 @@ protected void updateItem(final SimulationItem item, final boolean empty) { private final ObjectProperty lastSimulator; + private final InvalidationListener simulationModelsListener; private ChangeListener timeListener; @Inject @@ -381,6 +383,27 @@ public SimulatorStage( this.time = 0; this.timer = new Timer(true); stopActions.add(this::cancelTimer); + + this.simulationModelsListener = o -> { + Machine machine = currentProject.getCurrentMachine(); + // Show the simulation models saved for the machine, or the default simulation if none are saved. + if (machine.getSimulations().isEmpty()) { + cbSimulation.getItems().setAll(new SimulationModel(Paths.get(""))); + } else { + cbSimulation.getItems().setAll(machine.getSimulations()); + } + + // If the last selected simulation disappears, select a different one if possible. + // Note: it's important to check the selected index and not the selected item! + // When items are removed from the list, + // the selection model can get into a state where the selected index is -1, + // but the selected item is not null and still points to the last selected item. + // This may be a bug in JavaFX (last checked with JavaFX 22.0.2). + if (cbSimulation.getSelectionModel().getSelectedIndex() == -1 && !cbSimulation.getItems().isEmpty()) { + cbSimulation.getSelectionModel().selectFirst(); + } + }; + stageManager.loadFXML(this, "simulator_stage.fxml", this.getClass().getName()); } @@ -424,6 +447,9 @@ public void initialize() { )) ); + // The items list is set once here and then always updated in-place. + // setItems should never be called again after this. + cbSimulation.setItems(FXCollections.observableArrayList()); cbSimulation.getSelectionModel().selectedItemProperty().addListener((observable, from, to) -> { checkIfSimulationShouldBeSaved(); configurationPath.set(null); @@ -481,7 +507,7 @@ public void initialize() { configurationPath.set(null); simulationDiagramItems.getItems().clear(); simulationItems.itemsProperty().unbind(); - loadSimulationsFromMachine(to); + loadSimulationsFromMachine(from, to); }; currentProject.currentMachineProperty().addListener(machineChangeListener); machineChangeListener.changed(null, null, currentProject.getCurrentMachine()); @@ -721,17 +747,16 @@ private void checkMachine() { simulationItemHandler.handleMachine(cbSimulation.getSelectionModel().getSelectedItem()); } - public void loadSimulationsFromMachine(Machine machine) { - cbSimulation.itemsProperty().unbind(); + private void loadSimulationsFromMachine(Machine prevMachine, Machine machine) { + if (prevMachine != null) { + prevMachine.getSimulations().removeListener(this.simulationModelsListener); + } + cbSimulation.getItems().clear(); if (machine != null) { - cbSimulation.setItems(machine.getSimulations()); - if(cbSimulation.getItems().isEmpty()) { - cbSimulation.getItems().add(new SimulationModel(Paths.get(""))); - } + machine.getSimulations().addListener(this.simulationModelsListener); + this.simulationModelsListener.invalidated(null); cbSimulation.getSelectionModel().clearSelection(); cbSimulation.getSelectionModel().select(0); - } else { - cbSimulation.setItems(FXCollections.observableArrayList()); } } @@ -757,11 +782,6 @@ private void removeSimulation() { return; } currentProject.getCurrentMachine().getSimulations().remove(simulationModel); - if(cbSimulation.getItems().isEmpty()) { - cbSimulation.getItems().add(new SimulationModel(Paths.get(""))); - } - cbSimulation.getSelectionModel().clearSelection(); - cbSimulation.getSelectionModel().select(0); } private SimulationModelConfiguration buildSimulationModel() { @@ -830,9 +850,6 @@ private void saveSimulationAs() { if (currentMachine.getSimulations().contains(simulationModel)) { cbSimulation.getSelectionModel().select(simulationModel); } else { - if(previousPath.toString().isEmpty()) { - cbSimulation.getItems().remove(new SimulationModel(Paths.get(""))); - } currentMachine.getSimulations().add(simulationModel); cbSimulation.getSelectionModel().selectLast(); }