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/java/org/nwapw/abacus/number/NumberInterface.java b/src/main/java/org/nwapw/abacus/number/NumberInterface.java index e997c7a..83007c2 100755 --- a/src/main/java/org/nwapw/abacus/number/NumberInterface.java +++ b/src/main/java/org/nwapw/abacus/number/NumberInterface.java @@ -173,7 +173,7 @@ public abstract class NumberInterface { /** * Returns the least integer greater than or equal to the number. * - * @return the least integer >= the number, if int can hold the value. + * @return the least integer greater or equal to the number, if int can hold the value. */ protected abstract NumberInterface ceilingInternal(); @@ -201,7 +201,7 @@ public abstract class NumberInterface { * Also, checks if the thread has been interrupted, and if so, throws * an exception. * - * @return the greatest int greater than or equal to the number. + * @return the greatest int smaller than or equal to the number. */ public final NumberInterface floor(){ checkInterrupted(); diff --git a/src/main/java/org/nwapw/abacus/plugin/Plugin.java b/src/main/java/org/nwapw/abacus/plugin/Plugin.java index b569dea..7a78764 100644 --- a/src/main/java/org/nwapw/abacus/plugin/Plugin.java +++ b/src/main/java/org/nwapw/abacus/plugin/Plugin.java @@ -17,18 +17,6 @@ import java.util.Set; */ public abstract class Plugin { - /** - * A hash map of functions mapped to their string names. - */ - private Map functions; - /** - * A hash map of operators mapped to their string names. - */ - private Map operators; - /** - * The map of the number implementations this plugin provides. - */ - private Map numberImplementations; /** * The plugin manager in which to search for functions * not inside this package, @@ -49,69 +37,9 @@ public abstract class Plugin { */ public Plugin(PluginManager manager) { this.manager = manager; - functions = new HashMap<>(); - operators = new HashMap<>(); - numberImplementations = new HashMap<>(); enabled = false; } - /** - * Gets the list of functions provided by this plugin. - * - * @return the list of registered functions. - */ - public final Set providedFunctions() { - return functions.keySet(); - } - - /** - * Gets the list of functions provided by this plugin. - * - * @return the list of registered functions. - */ - public final Set providedOperators() { - return operators.keySet(); - } - - /** - * Gets the list of number implementations provided by this plugin. - * - * @return the list of registered number implementations. - */ - public final Set providedNumberImplementations() { - return numberImplementations.keySet(); - } - - /** - * Gets a function under the given function name. - * - * @param functionName the name of the function to get - * @return the function, or null if this plugin doesn't provide it. - */ - public final Function getFunction(String functionName) { - return functions.get(functionName); - } - - /** - * Gets an operator under the given operator name. - * - * @param operatorName the name of the operator to get. - * @return the operator, or null if this plugin doesn't provide it. - */ - public final Operator getOperator(String operatorName) { - return operators.get(operatorName); - } - - /** - * Gets the number implementation under the given name. - * - * @param name the name of the number implementation to look up. - * @return the number implementation associated with that name, or null if the plugin doesn't provide it. - */ - public final NumberImplementation getNumberImplementation(String name) { - return numberImplementations.get(name); - } - /** * Enables the function, loading the necessary instances * of functions. @@ -129,8 +57,6 @@ public abstract class Plugin { public final void disable() { if (!enabled) return; onDisable(); - functions.clear(); - operators.clear(); enabled = false; } @@ -142,7 +68,7 @@ public abstract class Plugin { * @param toRegister the function implementation. */ protected final void registerFunction(String name, Function toRegister) { - functions.put(name, toRegister); + manager.registerFunction(name, toRegister); } /** @@ -154,7 +80,7 @@ public abstract class Plugin { * @param operator the operator to register. */ protected final void registerOperator(String name, Operator operator) { - operators.put(name, operator); + manager.registerOperator(name, operator); } /** @@ -165,7 +91,7 @@ public abstract class Plugin { * @param implementation the actual implementation class to register. */ protected final void registerNumberImplementation(String name, NumberImplementation implementation) { - numberImplementations.put(name, implementation); + manager.registerNumberImplementation(name, implementation); } /** @@ -213,7 +139,7 @@ public abstract class Plugin { * @param forClass the class to which to find the pi instance. * @return the pi value for the given class. */ - protected final NumberInterface getPi(Class forClass) { + protected final NumberInterface piFor(Class forClass) { return manager.piFor(forClass); } diff --git a/src/main/java/org/nwapw/abacus/plugin/PluginManager.java b/src/main/java/org/nwapw/abacus/plugin/PluginManager.java index b1e5143..e40b481 100644 --- a/src/main/java/org/nwapw/abacus/plugin/PluginManager.java +++ b/src/main/java/org/nwapw/abacus/plugin/PluginManager.java @@ -23,20 +23,17 @@ public class PluginManager { */ private Set plugins; /** - * List of functions that have been cached, - * that is, found in a plugin and returned. + * The map of functions registered by the plugins. */ - private Map cachedFunctions; + private Map registeredFunctions; /** - * List of operators that have been cached, - * that is, found in a plugin and returned. + * The map of operators registered by the plugins */ - private Map cachedOperators; + private Map registeredOperators; /** - * The list of number implementations that have - * been cached, that is, found in a plugin and returned. + * The map of number implementations registered by the plugins. */ - private Map cachedNumberImplementations; + private Map registeredNumberImplementations; /** * The list of number implementations that have been * found by their implementation class. @@ -46,18 +43,6 @@ public class PluginManager { * The pi values for each implementation class that have already been computer. */ private Map, NumberInterface> cachedPi; - /** - * List of all functions loaded by the plugins. - */ - private Set allFunctions; - /** - * List of all operators loaded by the plugins. - */ - private Set allOperators; - /** - * List of all the number implementations loaded by the plugins. - */ - private Set allNumberImplementations; /** * The list of plugin listeners attached to this instance. */ @@ -77,79 +62,66 @@ public class PluginManager { this.abacus = abacus; loadedPluginClasses = new HashSet<>(); plugins = new HashSet<>(); - cachedFunctions = new HashMap<>(); - cachedOperators = new HashMap<>(); - cachedNumberImplementations = new HashMap<>(); + registeredFunctions = new HashMap<>(); + registeredOperators = new HashMap<>(); + registeredNumberImplementations = new HashMap<>(); cachedInterfaceImplementations = new HashMap<>(); cachedPi = new HashMap<>(); - allFunctions = new HashSet<>(); - allOperators = new HashSet<>(); - allNumberImplementations = new HashSet<>(); listeners = new HashSet<>(); } /** - * Searches the plugin list for a certain value, retrieving the Plugin's - * list of items of the type using the setFunction and getting the value - * of it is available via getFunction. If the value is contained - * in the cache, it returns the cached value instead. - * - * @param plugins the plugin list to search. - * @param cache the cache to use - * @param setFunction the function to retrieve a set of available T's from the plugin - * @param getFunction the function to get the T value under the given name - * @param name the name to search for - * @param the type of element being search - * @param the type of key that the cache is indexed by. - * @return the retrieved element, or null if it was not found. + * Registers a function under the given name. + * @param name the name of the function. + * @param function the function to register. */ - private static T searchCached(Collection plugins, Map cache, - java.util.function.Function> setFunction, - java.util.function.BiFunction getFunction, - K name) { - if (cache.containsKey(name)) return cache.get(name); - - T loadedValue = null; - for (Plugin plugin : plugins) { - if (setFunction.apply(plugin).contains(name)) { - loadedValue = getFunction.apply(plugin, name); - break; - } - } - - cache.put(name, loadedValue); - return loadedValue; + public void registerFunction(String name, Function function){ + registeredFunctions.put(name, function); } /** - * Gets a function under the given name. - * - * @param name the name of the function - * @return the function under the given name. - */ - public Function functionFor(String name) { - return searchCached(plugins, cachedFunctions, Plugin::providedFunctions, Plugin::getFunction, name); - } - - /** - * Gets an operator under the given name. - * + * Registers an operator under the given name. * @param name the name of the operator. - * @return the operator under the given name. + * @param operator the operator to register. */ - public Operator operatorFor(String name) { - return searchCached(plugins, cachedOperators, Plugin::providedOperators, Plugin::getOperator, name); + public void registerOperator(String name, Operator operator){ + registeredOperators.put(name, operator); } /** - * Gets the number implementation under the given name. - * - * @param name the name of the implementation. - * @return the implementation. + * Registers a number implementation under the given name. + * @param name the name of the number implementation. + * @param implementation the number implementation to register. */ - public NumberImplementation numberImplementationFor(String name) { - return searchCached(plugins, cachedNumberImplementations, Plugin::providedNumberImplementations, - Plugin::getNumberImplementation, name); + public void registerNumberImplementation(String name, NumberImplementation implementation){ + registeredNumberImplementations.put(name, implementation); + } + + /** + * Gets the function registered under the given name. + * @param name the name of the function. + * @return the function, or null if it was not found. + */ + public Function functionFor(String name){ + return registeredFunctions.get(name); + } + + /** + * Gets the operator registered under the given name. + * @param name the name of the operator. + * @return the operator, or null if it was not found. + */ + public Operator operatorFor(String name){ + return registeredOperators.get(name); + } + + /** + * Gets the number implementation registered under the given name. + * @param name the name of the number implementation. + * @return the number implementation, or null if it was not found. + */ + public NumberImplementation numberImplementationFor(String name){ + return registeredNumberImplementations.get(name); } /** @@ -161,14 +133,11 @@ public class PluginManager { public NumberImplementation interfaceImplementationFor(Class name) { if (cachedInterfaceImplementations.containsKey(name)) return cachedInterfaceImplementations.get(name); NumberImplementation toReturn = null; - outside: - for (Plugin plugin : plugins) { - for (String implementationName : plugin.providedNumberImplementations()) { - NumberImplementation implementation = plugin.getNumberImplementation(implementationName); - if (implementation.getImplementation().equals(name)) { - toReturn = implementation; - break outside; - } + for(String key : registeredNumberImplementations.keySet()){ + NumberImplementation implementation = registeredNumberImplementations.get(key); + if(implementation.getImplementation() == name) { + toReturn = implementation; + break; } } cachedInterfaceImplementations.put(name, toReturn); @@ -227,12 +196,6 @@ public class PluginManager { if (disabledPlugins.contains(plugin.getClass().getName())) continue; plugin.enable(); } - for (Plugin plugin : plugins) { - if (disabledPlugins.contains(plugin.getClass().getName())) continue; - allFunctions.addAll(plugin.providedFunctions()); - allOperators.addAll(plugin.providedOperators()); - allNumberImplementations.addAll(plugin.providedNumberImplementations()); - } listeners.forEach(e -> e.onLoad(this)); } @@ -246,14 +209,8 @@ public class PluginManager { if (disabledPlugins.contains(plugin.getClass().getName())) continue; plugin.disable(); } - cachedFunctions.clear(); - cachedOperators.clear(); - cachedNumberImplementations.clear(); cachedInterfaceImplementations.clear(); cachedPi.clear(); - allFunctions.clear(); - allOperators.clear(); - allNumberImplementations.clear(); listeners.forEach(e -> e.onUnload(this)); } @@ -271,7 +228,7 @@ public class PluginManager { * @return the set of all functions that were loaded. */ public Set getAllFunctions() { - return allFunctions; + return registeredFunctions.keySet(); } /** @@ -280,7 +237,7 @@ public class PluginManager { * @return the set of all operators that were loaded. */ public Set getAllOperators() { - return allOperators; + return registeredOperators.keySet(); } /** @@ -289,7 +246,7 @@ public class PluginManager { * @return the set of all implementations that were loaded. */ public Set getAllNumberImplementations() { - return allNumberImplementations; + return registeredNumberImplementations.keySet(); } /** diff --git a/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java b/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java index e085e07..4d8aea2 100755 --- a/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java @@ -371,7 +371,7 @@ public class StandardPlugin extends Plugin { @Override protected NumberInterface applyInternal(NumberInterface[] params) { - NumberInterface pi = getPi(params[0].getClass()); + NumberInterface pi = piFor(params[0].getClass()); NumberInterface twoPi = pi.multiply(fromInt(pi.getClass(), 2)); NumberInterface theta = getSmallAngle(params[0], pi); //System.out.println(theta); @@ -395,7 +395,7 @@ public class StandardPlugin extends Plugin { @Override protected NumberInterface applyInternal(NumberInterface[] params) { - return functionSin.apply(getPi(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) + return functionSin.apply(piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) .subtract(params[0])); } }; 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 @@ - + +