1
0
mirror of https://github.com/DanilaFe/abacus synced 2026-01-25 16:15:19 +00:00

Compare commits

..

10 Commits

5 changed files with 89 additions and 17 deletions

View File

@@ -5,10 +5,10 @@ Summer project for NWAPW.
Created by Arthur Drobot, Danila Fedorin and Riley Jones. Created by Arthur Drobot, Danila Fedorin and Riley Jones.
## Project Description ## Project Description
Abacus is a calculator built with extensibility and usability in mind. It provides a plugin interface, via Java, as Lua provides too difficult to link up to the Java core. The description of the internals of the project can be found on the wiki page. Abacus is a calculator built with extensibility and usability in mind. It provides a plugin interface, via Java, as Lua proves too difficult to link up to the Java core. The description of the internals of the project can be found on the wiki page.
## Current State ## Current State
Abacus is being built for the Northwest Advanced Programming Workshop, a 3 week program in which students work in treams to complete a single project, following principles of agile development. Because of its short timeframe, Abacus is not even close to completed state. Below is a list of the current features and problems. Abacus is being built for the Northwest Advanced Programming Workshop, a 3 week program in which students work in teams to complete a single project, following principles of agile development. Because of its short timeframe, Abacus is not even close to completed state. Below is a list of the current features and problems.
- [x] Basic number class - [x] Basic number class
- [x] Implementation of basic functions - [x] Implementation of basic functions
- [x] Implementation of `exp`, `ln`, `sqrt` using the basic functions and Taylor Series - [x] Implementation of `exp`, `ln`, `sqrt` using the basic functions and Taylor Series

View File

@@ -24,6 +24,19 @@ import java.util.Set;
*/ */
public class AbacusController implements PluginListener { public class AbacusController implements PluginListener {
/**
* The title for the apply alert dialog.
*/
private static final String APPLY_MSG_TITLE = "\"Apply\" Needed";
/**
* The text for the header of the apply alert dialog.
*/
private static final String APPLY_MSG_HEADER = "The settings have not been applied.";
/**
* The text for the dialog that is shown if settings haven't been applied.
*/
private static final String APPLY_MSG_TEXT = "You have made changes to the configuration, however, you haven't pressed \"Apply\". " +
"The changes to the configuration will not be present in the calculator until \"Apply\" is pressed.";
/** /**
* Constant string that is displayed if the text could not be lexed or parsed. * Constant string that is displayed if the text could not be lexed or parsed.
*/ */
@@ -33,6 +46,12 @@ public class AbacusController implements PluginListener {
*/ */
private static final String ERR_EVAL = "Evaluation Error"; private static final String ERR_EVAL = "Evaluation Error";
@FXML
private TabPane coreTabPane;
@FXML
private Tab calculateTab;
@FXML
private Tab settingsTab;
@FXML @FXML
private TableView<HistoryModel> historyTable; private TableView<HistoryModel> historyTable;
@FXML @FXML
@@ -69,8 +88,35 @@ public class AbacusController implements PluginListener {
*/ */
private ObservableList<ToggleablePlugin> enabledPlugins; private ObservableList<ToggleablePlugin> enabledPlugins;
/**
* The abacus instance used for changing the plugin configuration.
*/
private Abacus abacus; private Abacus abacus;
/**
* Boolean which represents whether changes were made to the configuration.
*/
private boolean changesMade;
/**
* Whether an alert about changes to the configuration was already shown.
*/
private boolean reloadAlertShown;
/**
* The alert shown when a press to "apply" is needed.
*/
private Alert reloadAlert;
/**
* Alerts the user if the changes they made
* have not yet been applied.
*/
private void alertIfApplyNeeded(boolean ignorePrevious){
if(changesMade && (!reloadAlertShown || ignorePrevious)) {
reloadAlertShown = true;
reloadAlert.showAndWait();
}
}
@FXML @FXML
public void initialize(){ public void initialize(){
Callback<TableColumn<HistoryModel, String>, TableCell<HistoryModel, String>> cellFactory = Callback<TableColumn<HistoryModel, String>, TableCell<HistoryModel, String>> cellFactory =
@@ -92,6 +138,7 @@ public class AbacusController implements PluginListener {
historyTable.setItems(historyData); historyTable.setItems(historyData);
numberImplementationOptions = FXCollections.observableArrayList(); numberImplementationOptions = FXCollections.observableArrayList();
numberImplementationBox.setItems(numberImplementationOptions); numberImplementationBox.setItems(numberImplementationOptions);
numberImplementationBox.getSelectionModel().selectedIndexProperty().addListener(e -> changesMade = true);
historyTable.getSelectionModel().setCellSelectionEnabled(true); historyTable.getSelectionModel().setCellSelectionEnabled(true);
enabledPlugins = FXCollections.observableArrayList(); enabledPlugins = FXCollections.observableArrayList();
enabledPluginView.setItems(enabledPlugins); enabledPluginView.setItems(enabledPlugins);
@@ -102,10 +149,21 @@ public class AbacusController implements PluginListener {
parsedColumn.setCellValueFactory(cell -> cell.getValue().parsedProperty()); parsedColumn.setCellValueFactory(cell -> cell.getValue().parsedProperty());
outputColumn.setCellFactory(cellFactory); outputColumn.setCellFactory(cellFactory);
outputColumn.setCellValueFactory(cell -> cell.getValue().outputProperty()); outputColumn.setCellValueFactory(cell -> cell.getValue().outputProperty());
coreTabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
if(oldValue.equals(settingsTab)) alertIfApplyNeeded(true);
});
abacus = new Abacus(); abacus = new Abacus();
abacus.getPluginManager().addListener(this); abacus.getPluginManager().addListener(this);
abacus.getPluginManager().reload(); abacus.getPluginManager().reload();
changesMade = false;
reloadAlertShown = false;
reloadAlert = new Alert(Alert.AlertType.WARNING);
reloadAlert.setTitle(APPLY_MSG_TITLE);
reloadAlert.setHeaderText(APPLY_MSG_HEADER);
reloadAlert.setContentText(APPLY_MSG_TEXT);
} }
@FXML @FXML
@@ -131,13 +189,16 @@ public class AbacusController implements PluginListener {
} }
@FXML @FXML
private void performReload(){ private void performSaveAndReload(){
Configuration configuration = abacus.getConfiguration(); performSave();
Set<String> disabledPlugins = configuration.getDisabledPlugins(); performReload();
disabledPlugins.clear(); changesMade = false;
for(ToggleablePlugin pluginEntry : enabledPlugins){ reloadAlertShown = false;
if(!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName());
} }
@FXML
private void performReload(){
alertIfApplyNeeded(true);
abacus.getPluginManager().reload(); abacus.getPluginManager().reload();
} }
@@ -145,7 +206,14 @@ public class AbacusController implements PluginListener {
private void performSave(){ private void performSave(){
Configuration configuration = abacus.getConfiguration(); Configuration configuration = abacus.getConfiguration();
configuration.setNumberImplementation(numberImplementationBox.getSelectionModel().getSelectedItem()); configuration.setNumberImplementation(numberImplementationBox.getSelectionModel().getSelectedItem());
Set<String> disabledPlugins = configuration.getDisabledPlugins();
disabledPlugins.clear();
for(ToggleablePlugin pluginEntry : enabledPlugins){
if(!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName());
}
configuration.saveTo(Abacus.CONFIG_FILE); configuration.saveTo(Abacus.CONFIG_FILE);
changesMade = false;
reloadAlertShown = false;
} }
@Override @Override
@@ -158,7 +226,9 @@ public class AbacusController implements PluginListener {
numberImplementationBox.getSelectionModel().select(toSelect); numberImplementationBox.getSelectionModel().select(toSelect);
for(Class<?> pluginClass : abacus.getPluginManager().getLoadedPluginClasses()){ for(Class<?> pluginClass : abacus.getPluginManager().getLoadedPluginClasses()){
String fullName = pluginClass.getName(); String fullName = pluginClass.getName();
enabledPlugins.add(new ToggleablePlugin(!disabledPlugins.contains(fullName), fullName)); ToggleablePlugin plugin = new ToggleablePlugin(!disabledPlugins.contains(fullName), fullName);
plugin.enabledProperty().addListener(e -> changesMade = true);
enabledPlugins.add(plugin);
} }
} }

View File

@@ -89,7 +89,7 @@ public class ShuntingYardParser implements Parser<Match<TokenType>>, PluginListe
if (!(otherMatchType == TokenType.OP || otherMatchType == TokenType.FUNCTION)) break; if (!(otherMatchType == TokenType.OP || otherMatchType == TokenType.FUNCTION)) break;
if (otherMatchType == TokenType.OP) { if (otherMatchType == TokenType.OP) {
int otherPrecedence = precedenceMap.get(match.getContent()); int otherPrecedence = precedenceMap.get(otherMatch.getContent());
if (otherPrecedence < precedence || if (otherPrecedence < precedence ||
(associativity == OperatorAssociativity.RIGHT && otherPrecedence == precedence)) { (associativity == OperatorAssociativity.RIGHT && otherPrecedence == precedence)) {
break; break;

View File

@@ -222,7 +222,7 @@ public class StandardPlugin extends Plugin {
} else { } else {
param = param.multiply(new NaiveNumber(2).promoteTo(param.getClass())); param = param.multiply(new NaiveNumber(2).promoteTo(param.getClass()));
powersOf2--; powersOf2--;
if (param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() != 1) { if (param.subtract(NaiveNumber.ONE.promoteTo(param.getClass())).signum() != -1) {
break; break;
//No infinite loop for you. //No infinite loop for you.
} }

View File

@@ -7,12 +7,13 @@
<?import javafx.scene.text.Text?> <?import javafx.scene.text.Text?>
<?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.FlowPane?>
<BorderPane xmlns="http://javafx.com/javafx" <BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml" xmlns:fx="http://javafx.com/fxml"
fx:controller="org.nwapw.abacus.fx.AbacusController"> fx:controller="org.nwapw.abacus.fx.AbacusController">
<center> <center>
<TabPane> <TabPane fx:id="coreTabPane">
<Tab text="Calculator" closable="false"> <Tab fx:id="calculateTab" text="Calculator" closable="false">
<BorderPane> <BorderPane>
<center> <center>
<TableView fx:id="historyTable"> <TableView fx:id="historyTable">
@@ -41,7 +42,7 @@
</bottom> </bottom>
</BorderPane> </BorderPane>
</Tab> </Tab>
<Tab text="Settings" closable="false"> <Tab fx:id="settingsTab" text="Settings" closable="false">
<GridPane hgap="10" vgap="10"> <GridPane hgap="10" vgap="10">
<padding><Insets left="10" right="10" top="10" bottom="10"/></padding> <padding><Insets left="10" right="10" top="10" bottom="10"/></padding>
<Label text="Number Implementation" GridPane.columnIndex="0" GridPane.rowIndex="0"/> <Label text="Number Implementation" GridPane.columnIndex="0" GridPane.rowIndex="0"/>
@@ -49,10 +50,11 @@
<ListView fx:id="enabledPluginView" <ListView fx:id="enabledPluginView"
GridPane.rowIndex="1" GridPane.columnIndex="0" GridPane.rowIndex="1" GridPane.columnIndex="0"
GridPane.columnSpan="2" maxHeight="100"/> GridPane.columnSpan="2" maxHeight="100"/>
<HBox GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="2" spacing="10"> <FlowPane GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="2" hgap="10" vgap="10">
<Button text="Apply" onAction="#performSave"/> <Button text="Apply" onAction="#performSave"/>
<Button text="Reload" onAction="#performReload"/> <Button text="Reload Plugins" onAction="#performReload"/>
</HBox> <Button text="Apply and Reload" onAction="#performSaveAndReload"/>
</FlowPane>
</GridPane> </GridPane>
</Tab> </Tab>
</TabPane> </TabPane>