diff --git a/src/main/java/org/nwapw/abacus/config/Configuration.java b/src/main/java/org/nwapw/abacus/config/Configuration.java index 2b68236..1bc7aa2 100644 --- a/src/main/java/org/nwapw/abacus/config/Configuration.java +++ b/src/main/java/org/nwapw/abacus/config/Configuration.java @@ -30,6 +30,10 @@ public class Configuration { */ private static final TomlWriter TOML_WRITER = new TomlWriter(); + /** + * The computation delay for which the thread can run without interruption. + */ + private double computationDelay = 0; /** * The implementation of the number that should be used. */ @@ -51,10 +55,12 @@ public class Configuration { /** * Creates a new configuration with the given values. * + * @param computationDelay the delay before the computation gets killed. * @param numberImplementation the number implementation, like "naive" or "precise" * @param disabledPlugins the list of disabled plugins. */ - public Configuration(String numberImplementation, String[] disabledPlugins) { + public Configuration(double computationDelay, String numberImplementation, String[] disabledPlugins) { + this.computationDelay = computationDelay; this.numberImplementation = numberImplementation; this.disabledPlugins.addAll(Arrays.asList(disabledPlugins)); } @@ -75,6 +81,7 @@ public class Configuration { * @param otherConfiguration the configuration to copy from. */ public void copyFrom(Configuration otherConfiguration) { + this.computationDelay = otherConfiguration.computationDelay; this.numberImplementation = otherConfiguration.numberImplementation; this.disabledPlugins.addAll(otherConfiguration.disabledPlugins); } @@ -130,4 +137,23 @@ public class Configuration { return disabledPlugins; } + + /** + * Gets the computation delay specified in the configuration. + * + * @return the computaton delay. + */ + public double getComputationDelay() { + return computationDelay; + } + + /** + * Sets the computation delay. + * + * @param computationDelay the new computation delay. + */ + public void setComputationDelay(double computationDelay) { + this.computationDelay = computationDelay; + } + } diff --git a/src/main/java/org/nwapw/abacus/fx/AbacusApplication.java b/src/main/java/org/nwapw/abacus/fx/AbacusApplication.java index 82d31fb..e02ed8e 100644 --- a/src/main/java/org/nwapw/abacus/fx/AbacusApplication.java +++ b/src/main/java/org/nwapw/abacus/fx/AbacusApplication.java @@ -12,13 +12,25 @@ import javafx.stage.Stage; */ public class AbacusApplication extends Application { + /** + * The controller currently managing the application. + */ + private AbacusController controller; + @Override public void start(Stage primaryStage) throws Exception { - Parent parent = FXMLLoader.load(getClass().getResource("/abacus.fxml")); + FXMLLoader loader = new FXMLLoader(getClass().getResource("/abacus.fxml")); + Parent parent = loader.load(); + controller = loader.getController(); Scene mainScene = new Scene(parent, 320, 480); primaryStage.setScene(mainScene); primaryStage.setTitle("Abacus"); primaryStage.show(); } + @Override + public void stop() throws Exception { + super.stop(); + controller.performStop(); + } } diff --git a/src/main/java/org/nwapw/abacus/fx/AbacusController.java b/src/main/java/org/nwapw/abacus/fx/AbacusController.java index 06b10ac..2bdb5ef 100644 --- a/src/main/java/org/nwapw/abacus/fx/AbacusController.java +++ b/src/main/java/org/nwapw/abacus/fx/AbacusController.java @@ -1,6 +1,8 @@ package org.nwapw.abacus.fx; import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; @@ -89,6 +91,8 @@ public class AbacusController implements PluginListener { private ComboBox numberImplementationBox; @FXML private ListView enabledPluginView; + @FXML + private TextField computationLimitField; /** * The list of history entries, created by the users. @@ -124,6 +128,17 @@ public class AbacusController implements PluginListener { * The alert shown when a press to "apply" is needed. */ private Alert reloadAlert; + /** + * The runnable that takes care of killing computations that take too long. + */ + private final Runnable TIMER_RUNNABLE = () -> { + try { + Configuration abacusConfig = abacus.getConfiguration(); + if(abacusConfig.getComputationDelay() == 0) return; + Thread.sleep((long) (abacusConfig.getComputationDelay() * 1000)); + performStop(); + } catch (InterruptedException e) { } + }; /** * The runnable used to perform the calculation. */ @@ -161,6 +176,10 @@ public class AbacusController implements PluginListener { }); } }; + /** + * The thread that is waiting to pause the calculation. + */ + private Thread computationLimitThread; /** * The thread in which the computation runs. */ @@ -224,6 +243,15 @@ public class AbacusController implements PluginListener { } abacusPluginManager.reload(); + computationLimitField.setText(Double.toString(abacus.getConfiguration().getComputationDelay())); + computationLimitField.textProperty().addListener((observable, oldValue, newValue) -> { + if(!newValue.matches("(\\d+(\\.\\d*)?)?")) { + computationLimitField.setText(oldValue); + } else { + changesMade = true; + } + }); + changesMade = false; reloadAlertShown = false; @@ -234,21 +262,29 @@ public class AbacusController implements PluginListener { } @FXML - private void performCalculation() { + public void performCalculation() { inputButton.setDisable(true); stopButton.setDisable(false); calculationThread = new Thread(CALCULATION_RUNNABLE); calculationThread.start(); + computationLimitThread = new Thread(TIMER_RUNNABLE); + computationLimitThread.start(); } @FXML - private void performStop(){ - if(calculationThread != null) + public void performStop(){ + if(calculationThread != null) { calculationThread.interrupt(); + calculationThread = null; + } + if(computationLimitThread != null){ + computationLimitThread.interrupt(); + computationLimitThread = null; + } } @FXML - private void performSaveAndReload() { + public void performSaveAndReload() { performSave(); performReload(); changesMade = false; @@ -256,13 +292,13 @@ public class AbacusController implements PluginListener { } @FXML - private void performReload() { + public void performReload() { alertIfApplyNeeded(true); abacus.getPluginManager().reload(); } @FXML - private void performSave() { + public void performSave() { Configuration configuration = abacus.getConfiguration(); configuration.setNumberImplementation(numberImplementationBox.getSelectionModel().getSelectedItem()); Set disabledPlugins = configuration.getDisabledPlugins(); @@ -270,6 +306,8 @@ public class AbacusController implements PluginListener { for (ToggleablePlugin pluginEntry : enabledPlugins) { if (!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName()); } + if(computationLimitField.getText().matches("\\d*(\\.\\d+)?") && computationLimitField.getText().length() != 0) + configuration.setComputationDelay(Double.parseDouble(computationLimitField.getText())); configuration.saveTo(CONFIG_FILE); changesMade = false; reloadAlertShown = false; @@ -296,4 +334,5 @@ public class AbacusController implements PluginListener { enabledPlugins.clear(); numberImplementationOptions.clear(); } + } diff --git a/src/main/resources/abacus.fxml b/src/main/resources/abacus.fxml index 495c654..495187c 100644 --- a/src/main/resources/abacus.fxml +++ b/src/main/resources/abacus.fxml @@ -50,7 +50,9 @@ - + +