diff --git a/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt b/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt index 661e92b..3acf465 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt @@ -63,13 +63,13 @@ class Abacus(val configuration: Configuration) { * Reloads the Abacus core. */ fun reload(){ - pluginManager.reload() - with(mutableContext) { - numberImplementation = pluginManager.numberImplementationFor(configuration.numberImplementation) - ?: StandardPlugin.IMPLEMENTATION_NAIVE + with(mutableContext){ clearVariables() clearDefinitions() } + pluginManager.reload() + mutableContext.numberImplementation = pluginManager.numberImplementationFor(configuration.numberImplementation) + ?: StandardPlugin.IMPLEMENTATION_NAIVE } /** * Merges the current context with the provided one, updating diff --git a/fx/src/main/java/org/nwapw/abacus/fx/AbacusApplication.java b/fx/src/main/java/org/nwapw/abacus/fx/AbacusApplication.java index 92a4b3f..5445898 100644 --- a/fx/src/main/java/org/nwapw/abacus/fx/AbacusApplication.java +++ b/fx/src/main/java/org/nwapw/abacus/fx/AbacusApplication.java @@ -26,7 +26,7 @@ public class AbacusApplication extends Application { FXMLLoader loader = new FXMLLoader(getClass().getResource("/abacus.fxml")); Parent parent = loader.load(); controller = loader.getController(); - Scene mainScene = new Scene(parent, 320, 480); + Scene mainScene = new Scene(parent, 420, 520); primaryStage.setScene(mainScene); primaryStage.setTitle("Abacus"); primaryStage.show(); diff --git a/fx/src/main/java/org/nwapw/abacus/fx/AbacusController.java b/fx/src/main/java/org/nwapw/abacus/fx/AbacusController.java index 903225a..a208466 100644 --- a/fx/src/main/java/org/nwapw/abacus/fx/AbacusController.java +++ b/fx/src/main/java/org/nwapw/abacus/fx/AbacusController.java @@ -8,6 +8,7 @@ import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.control.cell.CheckBoxListCell; import javafx.scene.text.Text; +import javafx.stage.FileChooser; import javafx.util.Callback; import javafx.util.StringConverter; import org.nwapw.abacus.Abacus; @@ -23,9 +24,12 @@ import org.nwapw.abacus.EvaluationResult; import org.nwapw.abacus.tree.nodes.TreeNode; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; +import java.util.Scanner; import java.util.Set; import java.util.stream.Collectors; @@ -69,6 +73,7 @@ public class AbacusController implements PluginListener { * Constant string that is displayed if the calculations are interrupted by an exception. */ private static final String ERR_EXCEPTION = "Exception Thrown"; + private static final String ERR_DEFINITION = "Definition Error"; @FXML private TabPane coreTabPane; @FXML @@ -103,6 +108,8 @@ public class AbacusController implements PluginListener { private ListView functionListView; @FXML private TextField functionListSearchField; + @FXML + private ListView definitionFilesView; /** * The list of history entries, created by the users. @@ -128,6 +135,10 @@ public class AbacusController implements PluginListener { * The filtered list displayed to the user. */ private FilteredList functionFilter; + /** + * The list of definition files to be loaded. + */ + private ObservableList definitionFiles; /** * The abacus instance used for changing the plugin configuration. @@ -251,6 +262,9 @@ public class AbacusController implements PluginListener { if (oldValue.equals(settingsTab)) alertIfApplyNeeded(true); }); + definitionFiles = FXCollections.observableArrayList(); + definitionFilesView.setItems(definitionFiles); + abacus = new Abacus(new ExtendedConfiguration(CONFIG_FILE)); PluginManager abacusPluginManager = abacus.getPluginManager(); abacusPluginManager.addListener(this); @@ -304,6 +318,23 @@ public class AbacusController implements PluginListener { reloadAlertShown = false; } + private void loadDefinitionFile(String fileName){ + File definitionFile = new File(fileName); + if(!definitionFile.exists()) return; + try { + FileReader fileReader = new FileReader(definitionFile); + Scanner scanner = new Scanner(fileReader); + while(scanner.hasNext()){ + EvaluationResult result = abacus.evaluateTree(abacus.parseString(scanner.nextLine())); + abacus.applyToContext(result.getResultingContext()); + } + } catch (AbacusException abacusError) { + outputText.setText(ERR_DEFINITION + "(" + abacusError.getMessage() + ")"); + } catch (RuntimeException runtime) { + outputText.setText(ERR_DEFINITION + "(" + ERR_EXCEPTION + ")"); + } catch (FileNotFoundException ignored) {} + } + @FXML public void performScan() { PluginManager abacusPluginManager = abacus.getPluginManager(); @@ -325,23 +356,44 @@ public class AbacusController implements PluginListener { @FXML public void performSave() { - Configuration configuration = abacus.getConfiguration(); + ExtendedConfiguration configuration = (ExtendedConfiguration) abacus.getConfiguration(); configuration.setNumberImplementation(numberImplementationBox.getSelectionModel().getSelectedItem()); Set disabledPlugins = configuration.getDisabledPlugins(); disabledPlugins.clear(); for (ToggleablePlugin pluginEntry : enabledPlugins) { if (!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName()); } + Set abacusDefinitionFiles = configuration.getDefinitionFiles(); + abacusDefinitionFiles.clear(); + abacusDefinitionFiles.addAll(definitionFiles); if (computationLimitField.getText().matches("\\d*(\\.\\d+)?") && computationLimitField.getText().length() != 0) - ((ExtendedConfiguration) configuration).setComputationDelay(Double.parseDouble(computationLimitField.getText())); - ((ExtendedConfiguration) configuration).saveTo(CONFIG_FILE); + configuration.setComputationDelay(Double.parseDouble(computationLimitField.getText())); + configuration.saveTo(CONFIG_FILE); changesMade = false; reloadAlertShown = false; } + @FXML + public void performAddDefinitionFile(){ + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("Add definition file"); + File selectedFile = fileChooser.showOpenDialog(null); + if(selectedFile == null) return; + String absolutePath = selectedFile.getAbsolutePath(); + if(!definitionFiles.contains(absolutePath)) definitionFiles.add(absolutePath); + changesMade = true; + } + + @FXML + public void performRemoveDefinitionFile(){ + String selectedItem = definitionFilesView.getSelectionModel().getSelectedItem(); + if(selectedItem != null) definitionFiles.remove(selectedItem); + changesMade = true; + } + @Override public void onLoad(PluginManager manager) { - Configuration configuration = abacus.getConfiguration(); + ExtendedConfiguration configuration = (ExtendedConfiguration) abacus.getConfiguration(); Set disabledPlugins = configuration.getDisabledPlugins(); numberImplementationOptions.addAll(abacus.getPluginManager().getAllNumberImplementations()); String actualImplementation = configuration.getNumberImplementation(); @@ -367,6 +419,10 @@ public class AbacusController implements PluginListener { return documentationInstance; }).collect(Collectors.toCollection(ArrayList::new))); functionList.sort(Comparator.comparing(Documentation::getCodeName)); + definitionFiles.addAll(configuration.getDefinitionFiles()); + for(String file : definitionFiles){ + loadDefinitionFile(file); + } } @Override @@ -374,6 +430,7 @@ public class AbacusController implements PluginListener { functionList.clear(); enabledPlugins.clear(); numberImplementationOptions.clear(); + definitionFiles.clear(); } } diff --git a/fx/src/main/kotlin/org/nwapw/abacus/fx/ExtendedConfiguration.kt b/fx/src/main/kotlin/org/nwapw/abacus/fx/ExtendedConfiguration.kt index 1cfaf87..edb6782 100644 --- a/fx/src/main/kotlin/org/nwapw/abacus/fx/ExtendedConfiguration.kt +++ b/fx/src/main/kotlin/org/nwapw/abacus/fx/ExtendedConfiguration.kt @@ -17,8 +17,9 @@ import java.io.File * @param disabledPlugins the list of plugins that should be disabled, same as [Configuration.disabledPlugins] */ class ExtendedConfiguration(var computationDelay: Double = 0.0, - implementation: String = "", - disabledPlugins: Array = emptyArray()) + definitionFiles: Array = emptyArray(), + implementation: String = "", + disabledPlugins: Array = emptyArray()) : Configuration(implementation, disabledPlugins) { companion object { @@ -27,6 +28,7 @@ class ExtendedConfiguration(var computationDelay: Double = 0.0, */ val DEFAULT_TOML_STRING = """ computationDelay=0.0 + definitionFiles=[] implementation="naive" disabledPlugins=[] """ @@ -40,6 +42,11 @@ class ExtendedConfiguration(var computationDelay: Double = 0.0, val DEFAULT_TOML_WRITER = TomlWriter() } + /** + * The set of files that definitions should be loaded from. + */ + val definitionFiles: MutableSet = mutableSetOf(*definitionFiles) + /** * Constructs a new configuration from a file on disk. * @param tomlFile the file from disk to load. @@ -59,6 +66,8 @@ class ExtendedConfiguration(var computationDelay: Double = 0.0, numberImplementation = config.numberImplementation disabledPlugins.clear() disabledPlugins.addAll(config.disabledPlugins) + definitionFiles.clear() + definitionFiles.addAll(config.definitionFiles) } /** diff --git a/fx/src/main/resources/abacus.fxml b/fx/src/main/resources/abacus.fxml index 816c775..6125735 100644 --- a/fx/src/main/resources/abacus.fxml +++ b/fx/src/main/resources/abacus.fxml @@ -47,17 +47,33 @@