mirror of
https://github.com/DanilaFe/abacus
synced 2026-01-25 08:05:19 +00:00
Compare commits
19 Commits
plugin-add
...
gradle-mod
| Author | SHA1 | Date | |
|---|---|---|---|
| d861444d13 | |||
| eac2a9ed6b | |||
| 31c61fdf95 | |||
| 8f251d2d13 | |||
| 99ffd51a43 | |||
| 00c51c62fd | |||
| 400ed6e70a | |||
|
|
5902ba8c5c | ||
|
|
efdc4af31b | ||
| 2e0b1201a3 | |||
|
|
d94edaa33f | ||
|
|
1e6cf08ec2 | ||
| 7c378b401a | |||
|
|
fee9f091fd | ||
|
|
4226df72f5 | ||
|
|
1f0e6a7ce4 | ||
|
|
efe76a6fdc | ||
|
|
ca6d8d2ba2 | ||
|
|
1d6957c4d9 |
28
build.gradle
28
build.gradle
@@ -1,21 +1,13 @@
|
|||||||
plugins {
|
subprojects {
|
||||||
id 'java'
|
|
||||||
id 'application'
|
|
||||||
id 'org.jetbrains.kotlin.jvm' version '1.1.3'
|
|
||||||
}
|
|
||||||
apply plugin: 'java'
|
|
||||||
apply plugin: 'application'
|
|
||||||
|
|
||||||
repositories {
|
apply plugin: 'java'
|
||||||
mavenCentral()
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:1.1.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile 'com.moandjiezana.toml:toml4j:0.7.1'
|
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8"
|
|
||||||
testCompile 'junit:junit:4.12'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define the main class for the application
|
|
||||||
mainClassName = 'org.nwapw.abacus.Abacus'
|
|
||||||
|
|
||||||
|
|||||||
8
core/build.gradle
Normal file
8
core/build.gradle
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version '1.1.3'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile 'com.moandjiezana.toml:toml4j:0.7.1'
|
||||||
|
testCompile 'junit:junit:4.12'
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.nwapw.abacus;
|
package org.nwapw.abacus;
|
||||||
|
|
||||||
import org.nwapw.abacus.config.Configuration;
|
import org.nwapw.abacus.config.Configuration;
|
||||||
import org.nwapw.abacus.fx.AbacusApplication;
|
|
||||||
import org.nwapw.abacus.number.NumberInterface;
|
import org.nwapw.abacus.number.NumberInterface;
|
||||||
import org.nwapw.abacus.parsing.LexerTokenizer;
|
import org.nwapw.abacus.parsing.LexerTokenizer;
|
||||||
import org.nwapw.abacus.parsing.ShuntingYardParser;
|
import org.nwapw.abacus.parsing.ShuntingYardParser;
|
||||||
@@ -61,10 +60,6 @@ public class Abacus {
|
|||||||
pluginManager.addListener(lexerTokenizer);
|
pluginManager.addListener(lexerTokenizer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
AbacusApplication.launch(AbacusApplication.class, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current tree builder.
|
* Gets the current tree builder.
|
||||||
*
|
*
|
||||||
@@ -519,6 +519,144 @@ public class StandardPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The arcsine function (return type in radians).
|
||||||
|
*/
|
||||||
|
public final Function functionArcsin = new Function() {
|
||||||
|
@Override
|
||||||
|
protected boolean matchesParams(NumberInterface[] params) {
|
||||||
|
return params.length == 1
|
||||||
|
&& FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NumberInterface applyInternal(NumberInterface[] params) {
|
||||||
|
if(FUNCTION_ABS.apply(params[0]).compareTo(new NaiveNumber(0.8).promoteTo(params[0].getClass())) >= 0){
|
||||||
|
NumberInterface[] newParams = {FUNCTION_SQRT.apply(fromInt(params[0].getClass(), 1).subtract(params[0].multiply(params[0])))};
|
||||||
|
return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2))
|
||||||
|
.subtract(applyInternal(newParams)).multiply(fromInt(params[0].getClass(), params[0].signum()));
|
||||||
|
}
|
||||||
|
NumberInterface currentTerm = params[0], sum = currentTerm,
|
||||||
|
multiplier = currentTerm.multiply(currentTerm), summandBound = sum.getMaxError().multiply(fromInt(sum.getClass(), 1).subtract(multiplier)),
|
||||||
|
power = currentTerm, coefficient = fromInt(params[0].getClass(), 1);
|
||||||
|
int exponent = 1;
|
||||||
|
while(FUNCTION_ABS.apply(currentTerm).compareTo(summandBound) > 0){
|
||||||
|
exponent += 2;
|
||||||
|
power = power.multiply(multiplier);
|
||||||
|
coefficient = coefficient.multiply(fromInt(params[0].getClass(), exponent-2))
|
||||||
|
.divide(fromInt(params[0].getClass(), exponent - 1));
|
||||||
|
currentTerm = power.multiply(coefficient).divide(fromInt(power.getClass(), exponent));
|
||||||
|
sum = sum.add(currentTerm);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The arccosine function.
|
||||||
|
*/
|
||||||
|
public final Function functionArccos = new Function() {
|
||||||
|
@Override
|
||||||
|
protected boolean matchesParams(NumberInterface[] params) {
|
||||||
|
return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NumberInterface applyInternal(NumberInterface[] params) {
|
||||||
|
return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2))
|
||||||
|
.subtract(functionArcsin.apply(params));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The arccosecant function.
|
||||||
|
*/
|
||||||
|
public final Function functionArccsc = new Function() {
|
||||||
|
@Override
|
||||||
|
protected boolean matchesParams(NumberInterface[] params) {
|
||||||
|
return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NumberInterface applyInternal(NumberInterface[] params) {
|
||||||
|
NumberInterface[] reciprocalParamArr = {fromInt(params[0].getClass(), 1).divide(params[0])};
|
||||||
|
return functionArcsin.apply(reciprocalParamArr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The arcsecant function.
|
||||||
|
*/
|
||||||
|
public final Function functionArcsec = new Function() {
|
||||||
|
@Override
|
||||||
|
protected boolean matchesParams(NumberInterface[] params) {
|
||||||
|
return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NumberInterface applyInternal(NumberInterface[] params) {
|
||||||
|
NumberInterface[] reciprocalParamArr = {fromInt(params[0].getClass(), 1).divide(params[0])};
|
||||||
|
return functionArccos.apply(reciprocalParamArr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The arctangent function.
|
||||||
|
*/
|
||||||
|
public final Function functionArctan = new Function() {
|
||||||
|
@Override
|
||||||
|
protected boolean matchesParams(NumberInterface[] params) {
|
||||||
|
return params.length == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NumberInterface applyInternal(NumberInterface[] params) {
|
||||||
|
if(params[0].signum() == -1){
|
||||||
|
NumberInterface[] negatedParams = {params[0].negate()};
|
||||||
|
return applyInternal(negatedParams).negate();
|
||||||
|
}
|
||||||
|
if(params[0].compareTo(fromInt(params[0].getClass(), 1)) > 0){
|
||||||
|
NumberInterface[] reciprocalParams = {fromInt(params[0].getClass(), 1).divide(params[0])};
|
||||||
|
return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2))
|
||||||
|
.subtract(applyInternal(reciprocalParams));
|
||||||
|
}
|
||||||
|
if(params[0].compareTo(fromInt(params[0].getClass(), 1)) == 0){
|
||||||
|
return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 4));
|
||||||
|
}
|
||||||
|
if(params[0].compareTo(new NaiveNumber(0.9).promoteTo(params[0].getClass())) >= 0){
|
||||||
|
NumberInterface[] newParams = {params[0].multiply(fromInt(params[0].getClass(),2 ))
|
||||||
|
.divide(fromInt(params[0].getClass(), 1).subtract(params[0].multiply(params[0])))};
|
||||||
|
return applyInternal(newParams).divide(fromInt(params[0].getClass(), 2));
|
||||||
|
}
|
||||||
|
NumberInterface currentPower = params[0], currentTerm = currentPower, sum = currentTerm,
|
||||||
|
maxError = params[0].getMaxError(), multiplier = currentPower.multiply(currentPower).negate();
|
||||||
|
int n = 1;
|
||||||
|
while(FUNCTION_ABS.apply(currentTerm).compareTo(maxError) > 0){
|
||||||
|
n += 2;
|
||||||
|
currentPower = currentPower.multiply(multiplier);
|
||||||
|
currentTerm = currentPower.divide(fromInt(currentPower.getClass(), n));
|
||||||
|
sum = sum.add(currentTerm);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The arccotangent function. Range: (0, pi).
|
||||||
|
*/
|
||||||
|
public final Function functionArccot = new Function() {
|
||||||
|
@Override
|
||||||
|
protected boolean matchesParams(NumberInterface[] params) {
|
||||||
|
return params.length == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NumberInterface applyInternal(NumberInterface[] params) {
|
||||||
|
return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2))
|
||||||
|
.subtract(functionArctan.apply(params));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public StandardPlugin(PluginManager manager) {
|
public StandardPlugin(PluginManager manager) {
|
||||||
super(manager);
|
super(manager);
|
||||||
}
|
}
|
||||||
@@ -633,6 +771,7 @@ public class StandardPlugin extends Plugin {
|
|||||||
registerFunction("exp", FUNCTION_EXP);
|
registerFunction("exp", FUNCTION_EXP);
|
||||||
registerFunction("ln", FUNCTION_LN);
|
registerFunction("ln", FUNCTION_LN);
|
||||||
registerFunction("sqrt", FUNCTION_SQRT);
|
registerFunction("sqrt", FUNCTION_SQRT);
|
||||||
|
|
||||||
registerFunction("sin", functionSin);
|
registerFunction("sin", functionSin);
|
||||||
registerFunction("cos", functionCos);
|
registerFunction("cos", functionCos);
|
||||||
registerFunction("tan", functionTan);
|
registerFunction("tan", functionTan);
|
||||||
@@ -640,6 +779,13 @@ public class StandardPlugin extends Plugin {
|
|||||||
registerFunction("csc", functionCsc);
|
registerFunction("csc", functionCsc);
|
||||||
registerFunction("cot", functionCot);
|
registerFunction("cot", functionCot);
|
||||||
|
|
||||||
|
registerFunction("arcsin", functionArcsin);
|
||||||
|
registerFunction("arccos", functionArccos);
|
||||||
|
registerFunction("arctan", functionArctan);
|
||||||
|
registerFunction("arcsec", functionArcsec);
|
||||||
|
registerFunction("arccsc", functionArccsc);
|
||||||
|
registerFunction("arccot", functionArccot);
|
||||||
|
|
||||||
registerFunction("random_int", FUNCTION_RAND_INT);
|
registerFunction("random_int", FUNCTION_RAND_INT);
|
||||||
|
|
||||||
registerDocumentation(new Documentation("abs", "Absolute Value", "Finds the distance " +
|
registerDocumentation(new Documentation("abs", "Absolute Value", "Finds the distance " +
|
||||||
@@ -655,27 +801,40 @@ public class StandardPlugin extends Plugin {
|
|||||||
"the power that e has to be brought to to be equal to the number.\n\n" +
|
"the power that e has to be brought to to be equal to the number.\n\n" +
|
||||||
"Example: ln(2.718) -> 1", DocumentationType.FUNCTION));
|
"Example: ln(2.718) -> 1", DocumentationType.FUNCTION));
|
||||||
registerDocumentation(new Documentation("sqrt", "Square Root", "Finds the square root " +
|
registerDocumentation(new Documentation("sqrt", "Square Root", "Finds the square root " +
|
||||||
"of the number.", "A square root a of a number is defined such that a times a is equal " +
|
"of the number.", "A square root a of a number is defined as the non-negative a such that a times a is equal " +
|
||||||
"to that number.\n\n" +
|
"to that number.\n\n" +
|
||||||
"Example: sqrt(4) -> 2", DocumentationType.FUNCTION));
|
"Example: sqrt(4) -> 2", DocumentationType.FUNCTION));
|
||||||
registerDocumentation(new Documentation("sin", "Sine", "Computes the sine of the given angle, " +
|
registerDocumentation(new Documentation("sin", "Sine", "Computes the sine of the given angle, " +
|
||||||
"in radians.", "", DocumentationType.FUNCTION));
|
"in radians.", "Example: sin(pi/6) -> 0.5", DocumentationType.FUNCTION));
|
||||||
registerDocumentation(new Documentation("cos", "Cosine", "Computes the cosine of the given angle, " +
|
registerDocumentation(new Documentation("cos", "Cosine", "Computes the cosine of the given angle, " +
|
||||||
"in radians.", "", DocumentationType.FUNCTION));
|
"in radians.", "Example: cos(pi/6) -> 0.866... (the exact result is sqrt(3)/2)", DocumentationType.FUNCTION));
|
||||||
registerDocumentation(new Documentation("tan", "Tangent", "Computes the tangent of the given angle, " +
|
registerDocumentation(new Documentation("tan", "Tangent", "Computes the tangent of the given angle, " +
|
||||||
"in radians.", "", DocumentationType.FUNCTION));
|
"in radians.", "Example: tan(pi/6) -> 0.577... (the exact result is 1/sqrt(3))", DocumentationType.FUNCTION));
|
||||||
registerDocumentation(new Documentation("sec", "Secant", "Computes the secant of the given angle, " +
|
registerDocumentation(new Documentation("sec", "Secant", "Computes the secant of the given angle, " +
|
||||||
"in radians.", "", DocumentationType.FUNCTION));
|
"in radians.", "Example: sec(pi/6) -> 1.154... (the exact result is 2/sqrt(3))", DocumentationType.FUNCTION));
|
||||||
registerDocumentation(new Documentation("csc", "Cosecant", "Computes the cosecant of the given angle, " +
|
registerDocumentation(new Documentation("csc", "Cosecant", "Computes the cosecant of the given angle, " +
|
||||||
"in radians.", "", DocumentationType.FUNCTION));
|
"in radians.", "Example: csc(pi/6) -> 2", DocumentationType.FUNCTION));
|
||||||
registerDocumentation(new Documentation("cot", "Cotangent", "Computes the cotangent of the given angle, " +
|
registerDocumentation(new Documentation("cot", "Cotangent", "Computes the cotangent of the given angle, " +
|
||||||
"in radians.", "", DocumentationType.FUNCTION));
|
"in radians.", "Example: cot(pi/6) -> 1.732... (the exact result is sqrt(3))", DocumentationType.FUNCTION));
|
||||||
registerDocumentation(new Documentation("random_int", "Random Integer", "Generates a random integer [0, n].",
|
registerDocumentation(new Documentation("random_int", "Random Integer", "Generates a random integer [0, n].",
|
||||||
"Generates a pseudorandom number using the standard JVM random mechanism, keeping it less than or " +
|
"Generates a pseudorandom number using the standard JVM random mechanism, keeping it less than or " +
|
||||||
"equal to the given number.\n\n" +
|
"equal to the given number.\n\n" +
|
||||||
"Example: random_int(5) -> 4\n" +
|
"Example: random_int(5) -> 4\n" +
|
||||||
"random_int(5) -> 3\n" +
|
"random_int(5) -> 3\n" +
|
||||||
"random_int(5) -> 3\n", DocumentationType.FUNCTION));
|
"random_int(5) -> 3\n", DocumentationType.FUNCTION));
|
||||||
|
registerDocumentation(new Documentation("arcsin", "Arcsine", "Computes the arcsine of x. (The result is in radians.)",
|
||||||
|
"Example: arcsin(0.5) -> 0.523... (the exact result is pi/6)", DocumentationType.FUNCTION));
|
||||||
|
registerDocumentation(new Documentation("arccos", "Arccosine", "Computes the arccosine of x. (The result is in radians.)",
|
||||||
|
"Example: arccos(0.5) -> 1.047... (the exact result is pi/3)", DocumentationType.FUNCTION));
|
||||||
|
registerDocumentation(new Documentation("arctan", "Arctangent", "Computes the arctangent of x. (The result is in radians.)",
|
||||||
|
"Example: arctan(1) -> 0.785... (the exact result is pi/4)", DocumentationType.FUNCTION));
|
||||||
|
registerDocumentation(new Documentation("arcsec", "Arcsecant", "Computes the arcsecant of x. (The result is in radians.)",
|
||||||
|
"Example: arcsec(2) -> 1.047... (the exact result is pi/3)", DocumentationType.FUNCTION));
|
||||||
|
registerDocumentation(new Documentation("arccsc", "Arccosecant", "Computes the arcscosecant of x. (The result is in radians.)",
|
||||||
|
"Example: arccsc(2) -> 0.523... (the exact result is pi/6)", DocumentationType.FUNCTION));
|
||||||
|
registerDocumentation(new Documentation("arccot", "Arccotangent", "Computes the arccotangent of x. (The result is in radians," +
|
||||||
|
" in the range (0, pi).)",
|
||||||
|
"Example: arccot(0) -> 1.570... (the exact result is pi/2)", DocumentationType.FUNCTION));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
10
fx/build.gradle
Normal file
10
fx/build.gradle
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version '1.1.3'
|
||||||
|
}
|
||||||
|
apply plugin: 'application'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':core')
|
||||||
|
}
|
||||||
|
|
||||||
|
mainClassName = 'org.nwapw.abacus.fx.AbacusApplication'
|
||||||
@@ -33,4 +33,9 @@ public class AbacusApplication extends Application {
|
|||||||
super.stop();
|
super.stop();
|
||||||
controller.performStop();
|
controller.performStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
launch(args);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
rootProject.name = 'abacus'
|
rootProject.name = 'abacus'
|
||||||
|
include 'core', 'fx'
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
package org.nwapw.abacus.window;
|
|
||||||
|
|
||||||
import org.nwapw.abacus.tree.TreeNode;
|
|
||||||
|
|
||||||
import javax.swing.table.AbstractTableModel;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A table model to store data about the history of inputs
|
|
||||||
* in the calculator.
|
|
||||||
*/
|
|
||||||
public class HistoryTableModel extends AbstractTableModel {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static array used to get the column names.
|
|
||||||
*/
|
|
||||||
public static final String[] COLUMN_NAMES = {
|
|
||||||
"Input",
|
|
||||||
"Parsed Input",
|
|
||||||
"Output"
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static array used to get the class of each column.
|
|
||||||
*/
|
|
||||||
public static final Class[] CLASS_TYPES = {
|
|
||||||
String.class,
|
|
||||||
TreeNode.class,
|
|
||||||
String.class
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* The list of entries.
|
|
||||||
*/
|
|
||||||
List<HistoryEntry> entries;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new empty history table model
|
|
||||||
*/
|
|
||||||
public HistoryTableModel() {
|
|
||||||
entries = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an entry to the model.
|
|
||||||
*
|
|
||||||
* @param entry the entry to add.
|
|
||||||
*/
|
|
||||||
public void addEntry(HistoryEntry entry) {
|
|
||||||
entries.add(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getRowCount() {
|
|
||||||
return entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColumnCount() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnName(int columnIndex) {
|
|
||||||
return COLUMN_NAMES[columnIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getColumnClass(int columnIndex) {
|
|
||||||
return CLASS_TYPES[columnIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
|
||||||
return entries.get(rowIndex).nthValue(columnIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class used specifically to hold data about
|
|
||||||
* the previous entries into the calculator.
|
|
||||||
*/
|
|
||||||
public static class HistoryEntry {
|
|
||||||
public String input;
|
|
||||||
public TreeNode parsedInput;
|
|
||||||
public String output;
|
|
||||||
|
|
||||||
public HistoryEntry(String input, TreeNode parsedInput, String output) {
|
|
||||||
this.input = input;
|
|
||||||
this.parsedInput = parsedInput;
|
|
||||||
this.output = output;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object nthValue(int n) {
|
|
||||||
if (n == 0) return input;
|
|
||||||
if (n == 1) return parsedInput;
|
|
||||||
if (n == 2) return output;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,255 +0,0 @@
|
|||||||
package org.nwapw.abacus.window;
|
|
||||||
|
|
||||||
import org.nwapw.abacus.Abacus;
|
|
||||||
import org.nwapw.abacus.number.NumberInterface;
|
|
||||||
import org.nwapw.abacus.tree.TreeNode;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.datatransfer.StringSelection;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main UI window for the calculator.
|
|
||||||
*/
|
|
||||||
public class Window extends JFrame {
|
|
||||||
|
|
||||||
private static final String CALC_STRING = "Calculate";
|
|
||||||
private static final String SYNTAX_ERR_STRING = "Syntax Error";
|
|
||||||
private static final String EVAL_ERR_STRING = "Evaluation Error";
|
|
||||||
private static final String NUMBER_SYSTEM_LABEL = "Number Type:";
|
|
||||||
private static final String FUNCTION_LABEL = "Functions:";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of Strings to which the "calculate" button's text
|
|
||||||
* changes. For instance, in the graph tab, the name will
|
|
||||||
* be "Graph" and not "Calculate".
|
|
||||||
*/
|
|
||||||
private static final String[] BUTTON_NAMES = {
|
|
||||||
CALC_STRING,
|
|
||||||
CALC_STRING
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of booleans that determine whether the input
|
|
||||||
* field and the input button are enabled at a particular
|
|
||||||
* index.
|
|
||||||
*/
|
|
||||||
private static boolean[] INPUT_ENABLED = {
|
|
||||||
true,
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The instance of the Abacus class, used
|
|
||||||
* for interaction with plugins and configuration.
|
|
||||||
*/
|
|
||||||
private Abacus abacus;
|
|
||||||
/**
|
|
||||||
* The last output by the calculator.
|
|
||||||
*/
|
|
||||||
private String lastOutput;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The tabbed pane that separates calculator contexts.
|
|
||||||
*/
|
|
||||||
private JTabbedPane pane;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The panel where the output occurs.
|
|
||||||
*/
|
|
||||||
private JPanel calculationPanel;
|
|
||||||
/**
|
|
||||||
* The text area reserved for the last output.
|
|
||||||
*/
|
|
||||||
private JTextArea lastOutputArea;
|
|
||||||
/**
|
|
||||||
* The table used for storing history results.
|
|
||||||
*/
|
|
||||||
private JTable historyTable;
|
|
||||||
/**
|
|
||||||
* The table model used for managing history.
|
|
||||||
*/
|
|
||||||
private HistoryTableModel historyModel;
|
|
||||||
/**
|
|
||||||
* The scroll pane for the history area.
|
|
||||||
*/
|
|
||||||
private JScrollPane historyScroll;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The panel where the input occurs.
|
|
||||||
*/
|
|
||||||
private JPanel inputPanel;
|
|
||||||
/**
|
|
||||||
* The input text field.
|
|
||||||
*/
|
|
||||||
private JTextField inputField;
|
|
||||||
/**
|
|
||||||
* The "submit" button.
|
|
||||||
*/
|
|
||||||
private JButton inputEnterButton;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The side panel for separate configuration.
|
|
||||||
*/
|
|
||||||
private JPanel settingsPanel;
|
|
||||||
/**
|
|
||||||
* Panel for elements relating to number
|
|
||||||
* system selection.
|
|
||||||
*/
|
|
||||||
private JPanel numberSystemPanel;
|
|
||||||
/**
|
|
||||||
* The possible list of number systems.
|
|
||||||
*/
|
|
||||||
private JComboBox<String> numberSystemList;
|
|
||||||
/**
|
|
||||||
* The panel for elements relating to
|
|
||||||
* function selection.
|
|
||||||
*/
|
|
||||||
private JPanel functionSelectPanel;
|
|
||||||
/**
|
|
||||||
* The list of functions available to the user.
|
|
||||||
*/
|
|
||||||
private JComboBox<String> functionList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action listener that causes the input to be evaluated.
|
|
||||||
*/
|
|
||||||
private ActionListener evaluateListener = (event) -> {
|
|
||||||
TreeNode parsedExpression = abacus.parseString(inputField.getText());
|
|
||||||
if (parsedExpression == null) {
|
|
||||||
lastOutputArea.setText(SYNTAX_ERR_STRING);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NumberInterface numberInterface = abacus.evaluateTree(parsedExpression);
|
|
||||||
if (numberInterface == null) {
|
|
||||||
lastOutputArea.setText(EVAL_ERR_STRING);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastOutput = numberInterface.toString();
|
|
||||||
historyModel.addEntry(new HistoryTableModel.HistoryEntry(inputField.getText(), parsedExpression, lastOutput));
|
|
||||||
historyTable.invalidate();
|
|
||||||
lastOutputArea.setText(lastOutput);
|
|
||||||
inputField.setText("");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of listeners that tell the input button how to behave
|
|
||||||
* at a given input tab.
|
|
||||||
*/
|
|
||||||
private ActionListener[] listeners = {
|
|
||||||
evaluateListener,
|
|
||||||
null
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new window with the given manager.
|
|
||||||
*
|
|
||||||
* @param abacus the calculator instance to interact with other components.
|
|
||||||
*/
|
|
||||||
public Window(Abacus abacus) {
|
|
||||||
this();
|
|
||||||
this.abacus = abacus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new window.
|
|
||||||
*/
|
|
||||||
private Window() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
lastOutput = "";
|
|
||||||
|
|
||||||
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
|
||||||
setSize(320, 480);
|
|
||||||
|
|
||||||
inputField = new JTextField();
|
|
||||||
inputEnterButton = new JButton(CALC_STRING);
|
|
||||||
|
|
||||||
inputPanel = new JPanel();
|
|
||||||
inputPanel.setLayout(new BorderLayout());
|
|
||||||
inputPanel.add(inputField, BorderLayout.CENTER);
|
|
||||||
inputPanel.add(inputEnterButton, BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
historyModel = new HistoryTableModel();
|
|
||||||
historyTable = new JTable(historyModel);
|
|
||||||
historyScroll = new JScrollPane(historyTable);
|
|
||||||
lastOutputArea = new JTextArea(lastOutput);
|
|
||||||
lastOutputArea.setEditable(false);
|
|
||||||
|
|
||||||
calculationPanel = new JPanel();
|
|
||||||
calculationPanel.setLayout(new BorderLayout());
|
|
||||||
calculationPanel.add(historyScroll, BorderLayout.CENTER);
|
|
||||||
calculationPanel.add(lastOutputArea, BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
numberSystemList = new JComboBox<>();
|
|
||||||
|
|
||||||
numberSystemPanel = new JPanel();
|
|
||||||
numberSystemPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
|
||||||
numberSystemPanel.setLayout(new FlowLayout());
|
|
||||||
numberSystemPanel.add(new JLabel(NUMBER_SYSTEM_LABEL));
|
|
||||||
numberSystemPanel.add(numberSystemList);
|
|
||||||
numberSystemPanel.setMaximumSize(numberSystemPanel.getPreferredSize());
|
|
||||||
|
|
||||||
functionList = new JComboBox<>();
|
|
||||||
|
|
||||||
functionSelectPanel = new JPanel();
|
|
||||||
functionSelectPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
|
||||||
functionSelectPanel.setLayout(new FlowLayout());
|
|
||||||
functionSelectPanel.add(new JLabel(FUNCTION_LABEL));
|
|
||||||
functionSelectPanel.add(functionList);
|
|
||||||
functionSelectPanel.setMaximumSize(functionSelectPanel.getPreferredSize());
|
|
||||||
|
|
||||||
settingsPanel = new JPanel();
|
|
||||||
settingsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
|
||||||
settingsPanel.setLayout(new BoxLayout(settingsPanel, BoxLayout.PAGE_AXIS));
|
|
||||||
settingsPanel.add(numberSystemPanel);
|
|
||||||
settingsPanel.add(functionSelectPanel);
|
|
||||||
|
|
||||||
pane = new JTabbedPane();
|
|
||||||
pane.add("Calculator", calculationPanel);
|
|
||||||
pane.add("Settings", settingsPanel);
|
|
||||||
pane.addChangeListener(e -> {
|
|
||||||
int selectionIndex = pane.getSelectedIndex();
|
|
||||||
boolean enabled = INPUT_ENABLED[selectionIndex];
|
|
||||||
ActionListener listener = listeners[selectionIndex];
|
|
||||||
inputEnterButton.setText(BUTTON_NAMES[selectionIndex]);
|
|
||||||
inputField.setEnabled(enabled);
|
|
||||||
inputEnterButton.setEnabled(enabled);
|
|
||||||
|
|
||||||
for (ActionListener removingListener : inputEnterButton.getActionListeners()) {
|
|
||||||
inputEnterButton.removeActionListener(removingListener);
|
|
||||||
inputField.removeActionListener(removingListener);
|
|
||||||
}
|
|
||||||
if (listener != null) {
|
|
||||||
inputEnterButton.addActionListener(listener);
|
|
||||||
inputField.addActionListener(listener);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(pane, BorderLayout.CENTER);
|
|
||||||
add(inputPanel, BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
inputEnterButton.addActionListener(evaluateListener);
|
|
||||||
inputField.addActionListener(evaluateListener);
|
|
||||||
historyTable.addMouseListener(new MouseAdapter() {
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e) {
|
|
||||||
Point clickPoint = e.getPoint();
|
|
||||||
if (e.getClickCount() == 2) {
|
|
||||||
int row = historyTable.rowAtPoint(clickPoint);
|
|
||||||
int column = historyTable.columnAtPoint(clickPoint);
|
|
||||||
String toCopy = historyTable.getValueAt(row, column).toString();
|
|
||||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(toCopy), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setVisible(boolean b) {
|
|
||||||
super.setVisible(b);
|
|
||||||
if (b) inputField.requestFocusInWindow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user