From 9e257321ab28a09a46469ec744820bf6d3b75d83 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Sat, 11 May 2024 13:02:50 +0200 Subject: [PATCH] Original sources, as-is --- app/src/main/java/expr/Add.java | 18 +++ app/src/main/java/expr/BinaryExpr.java | 37 +++++ app/src/main/java/expr/Div.java | 21 +++ app/src/main/java/expr/Environment.java | 6 + app/src/main/java/expr/Expr.java | 38 +++++ app/src/main/java/expr/ExprParser.java | 136 ++++++++++++++++++ app/src/main/java/expr/Mul.java | 18 +++ app/src/main/java/expr/Num.java | 21 +++ app/src/main/java/expr/Sub.java | 18 +++ app/src/main/java/expr/TestExpr.java | 30 ++++ app/src/main/java/expr/Variable.java | 18 +++ app/src/main/java/gui/BorderPanel.java | 13 ++ app/src/main/java/gui/ColoredLabel.java | 22 +++ app/src/main/java/gui/CurrentLabel.java | 10 ++ app/src/main/java/gui/Editor.java | 11 ++ app/src/main/java/gui/GridPanel.java | 13 ++ app/src/main/java/gui/RowLabels.java | 15 ++ app/src/main/java/gui/SheetPanel.java | 12 ++ app/src/main/java/gui/SlotLabel.java | 10 ++ app/src/main/java/gui/SlotLabels.java | 28 ++++ app/src/main/java/gui/StatusLabel.java | 16 +++ app/src/main/java/gui/StatusPanel.java | 12 ++ app/src/main/java/gui/XL.java | 49 +++++++ app/src/main/java/gui/XLCounter.java | 14 ++ app/src/main/java/gui/XLList.java | 40 ++++++ .../main/java/gui/menu/ClearAllMenuItem.java | 17 +++ app/src/main/java/gui/menu/ClearMenuItem.java | 17 +++ app/src/main/java/gui/menu/CloseMenuItem.java | 30 ++++ app/src/main/java/gui/menu/LoadMenuItem.java | 21 +++ app/src/main/java/gui/menu/NewMenuItem.java | 21 +++ app/src/main/java/gui/menu/OpenMenuItem.java | 45 ++++++ app/src/main/java/gui/menu/SaveMenuItem.java | 21 +++ app/src/main/java/gui/menu/WindowMenu.java | 26 ++++ .../main/java/gui/menu/WindowMenuItem.java | 21 +++ app/src/main/java/gui/menu/XLMenuBar.java | 24 ++++ app/src/main/java/util/Adjustment.java | 134 +++++++++++++++++ app/src/main/java/util/NumberAdjustment.java | 123 ++++++++++++++++ app/src/main/java/util/XLBufferedReader.java | 27 ++++ app/src/main/java/util/XLException.java | 8 ++ app/src/main/java/util/XLPrintStream.java | 25 ++++ 40 files changed, 1186 insertions(+) create mode 100644 app/src/main/java/expr/Add.java create mode 100644 app/src/main/java/expr/BinaryExpr.java create mode 100644 app/src/main/java/expr/Div.java create mode 100644 app/src/main/java/expr/Environment.java create mode 100644 app/src/main/java/expr/Expr.java create mode 100644 app/src/main/java/expr/ExprParser.java create mode 100644 app/src/main/java/expr/Mul.java create mode 100644 app/src/main/java/expr/Num.java create mode 100644 app/src/main/java/expr/Sub.java create mode 100644 app/src/main/java/expr/TestExpr.java create mode 100644 app/src/main/java/expr/Variable.java create mode 100644 app/src/main/java/gui/BorderPanel.java create mode 100644 app/src/main/java/gui/ColoredLabel.java create mode 100644 app/src/main/java/gui/CurrentLabel.java create mode 100644 app/src/main/java/gui/Editor.java create mode 100644 app/src/main/java/gui/GridPanel.java create mode 100644 app/src/main/java/gui/RowLabels.java create mode 100644 app/src/main/java/gui/SheetPanel.java create mode 100644 app/src/main/java/gui/SlotLabel.java create mode 100644 app/src/main/java/gui/SlotLabels.java create mode 100644 app/src/main/java/gui/StatusLabel.java create mode 100644 app/src/main/java/gui/StatusPanel.java create mode 100644 app/src/main/java/gui/XL.java create mode 100644 app/src/main/java/gui/XLCounter.java create mode 100644 app/src/main/java/gui/XLList.java create mode 100644 app/src/main/java/gui/menu/ClearAllMenuItem.java create mode 100644 app/src/main/java/gui/menu/ClearMenuItem.java create mode 100644 app/src/main/java/gui/menu/CloseMenuItem.java create mode 100644 app/src/main/java/gui/menu/LoadMenuItem.java create mode 100644 app/src/main/java/gui/menu/NewMenuItem.java create mode 100644 app/src/main/java/gui/menu/OpenMenuItem.java create mode 100644 app/src/main/java/gui/menu/SaveMenuItem.java create mode 100644 app/src/main/java/gui/menu/WindowMenu.java create mode 100644 app/src/main/java/gui/menu/WindowMenuItem.java create mode 100644 app/src/main/java/gui/menu/XLMenuBar.java create mode 100644 app/src/main/java/util/Adjustment.java create mode 100644 app/src/main/java/util/NumberAdjustment.java create mode 100644 app/src/main/java/util/XLBufferedReader.java create mode 100644 app/src/main/java/util/XLException.java create mode 100644 app/src/main/java/util/XLPrintStream.java diff --git a/app/src/main/java/expr/Add.java b/app/src/main/java/expr/Add.java new file mode 100644 index 0000000..8a68163 --- /dev/null +++ b/app/src/main/java/expr/Add.java @@ -0,0 +1,18 @@ +package xl.expr; + +class Add extends BinaryExpr { + + Add(Expr expr1, Expr expr2) { + super(expr1, expr2); + precedence1 = 0; + precedence2 = 0; + } + + public double op(double op1, double op2) { + return op1 + op2; + } + + protected String opString() { + return "+"; + } +} diff --git a/app/src/main/java/expr/BinaryExpr.java b/app/src/main/java/expr/BinaryExpr.java new file mode 100644 index 0000000..85c9989 --- /dev/null +++ b/app/src/main/java/expr/BinaryExpr.java @@ -0,0 +1,37 @@ +package xl.expr; + +abstract class BinaryExpr extends Expr { + + private Expr expr1; + private Expr expr2; + protected int precedence1; + protected int precedence2; + + protected BinaryExpr(Expr expr1, Expr expr2) { + this.expr1 = expr1; + this.expr2 = expr2; + } + + protected abstract double op(double op1, double op2); + + protected abstract String opString(); + + public String toString(int prec) { + StringBuilder builder = new StringBuilder(); + boolean parentheses = prec > precedence1; + if (parentheses) { + builder.append('('); + } + builder.append(expr1.toString(precedence1)); + builder.append(opString()); + builder.append(expr2.toString(precedence2)); + if (parentheses) { + builder.append(')'); + } + return builder.toString(); + } + + public double value(Environment env) { + return op(expr1.value(env), expr2.value(env)); + } +} diff --git a/app/src/main/java/expr/Div.java b/app/src/main/java/expr/Div.java new file mode 100644 index 0000000..e2b9def --- /dev/null +++ b/app/src/main/java/expr/Div.java @@ -0,0 +1,21 @@ +package xl.expr; + +import xl.util.XLException; + +class Div extends BinaryExpr { + + Div(Expr expr1, Expr expr2) { + super(expr1, expr2); + precedence1 = 1; + precedence2 = 2; + } + + public double op(double op1, double op2) { + if (op2 != 0) return op1 / op2; + else throw new XLException("division by zero"); + } + + protected String opString() { + return "/"; + } +} diff --git a/app/src/main/java/expr/Environment.java b/app/src/main/java/expr/Environment.java new file mode 100644 index 0000000..51a43b7 --- /dev/null +++ b/app/src/main/java/expr/Environment.java @@ -0,0 +1,6 @@ +package xl.expr; + +public interface Environment { + + public double value(String name); +} diff --git a/app/src/main/java/expr/Expr.java b/app/src/main/java/expr/Expr.java new file mode 100644 index 0000000..7715418 --- /dev/null +++ b/app/src/main/java/expr/Expr.java @@ -0,0 +1,38 @@ +package xl.expr; + +/** + * An Expr object represents a real valued expression that may contain variables. The + * value of a variable is obtained from an Environment object by specifying the name of + * the variable. + * + * @see Environment + * @author Lennart Andersson + */ +public abstract class Expr { + + /** + * The toString method returns a String representation of this + * expression without unnecessary parentheses. + * + * @return the String representation of this expression. + */ + public String toString() { + return toString(0); + } + + /* + * toString(prec) returns a string representation of this expression without + * unnecessary parentheses. The prec argument specifies the precedence level + * enclosing expression and is used to control the precedence of + * parentheses. + */ + public abstract String toString(int prec); + + /** + * The value method returns the value of this expression. + * + * @param env is the Environment containing the values of variables. + * @return the double value of this expression. + */ + public abstract double value(Environment env); +} diff --git a/app/src/main/java/expr/ExprParser.java b/app/src/main/java/expr/ExprParser.java new file mode 100644 index 0000000..f69465c --- /dev/null +++ b/app/src/main/java/expr/ExprParser.java @@ -0,0 +1,136 @@ +package xl.expr; + +import java.io.IOException; +import java.io.Reader; +import java.io.StreamTokenizer; +import java.io.StringReader; +import java.util.regex.Pattern; +import xl.util.XLException; + +/** + * An ExprParser object is a parser provides a factory method for building Expr + * objects from text representations of arithmetic expressions. The text containing the + * expression should adhere to the following grammar. + * + *
+ *
+ *
+ *
+ *    expr ::= term {addop term}
+ *    term ::= factor {mulop factor}
+ *    factor ::= number | variable | "(" expr ")"
+ *    addop ::= "+" | "-"
+ *    mulop ::= "*" | "/"
+ *
+ *
+ *
+ * 
+ * + * where number is an unsigned number according to StreamTokenizer and + * variable is a string of letters and digits. The first character must be a letter. + * + * @see Expr + * @see StreamTokenizer + * @author Lennart Andersson + */ +public class ExprParser { + + private int token; + private StreamTokenizer tokenizer; + + /** + * The build method returns an Expr representation of the expression + * provided by reader. + * + * @param reader a Reader provided the string to be parsed. + * @return an Expr representation of the string. + * @exception IOException if the reader does not deliver data. + * @exception ExprParserException if the reader input violates the grammar. + */ + public Expr build(Reader reader) throws IOException { + tokenizer = new StreamTokenizer(reader); + tokenizer.ordinaryChar('-'); + tokenizer.ordinaryChar('/'); + token = tokenizer.nextToken(); + Expr e = expr(); + if (token == StreamTokenizer.TT_EOF) return e; + else throw new XLException("trailing garbage"); + } + + /** + * The build method returns an Expr representation of the expression + * provided by the input string. + * + * @param input the String to be parsed. + * @return an Expr representation of the string. + * @exception IOException if the input does not deliver data. + * @exception XLException if the input violates the grammar. + */ + public Expr build(String input) throws IOException { + return build(new StringReader(input)); + } + + private Expr expr() throws IOException { + Expr result, term; + result = term(); + while (token == '+' || token == '-') { + int op = token; + token = tokenizer.nextToken(); + term = term(); + switch (op) { + case '+': + result = new Add(result, term); + break; + case '-': + result = new Sub(result, term); + break; + } + } + return result; + } + + private Expr factor() throws IOException { + Expr e; + switch (token) { + case '(': + token = tokenizer.nextToken(); + e = expr(); + if (token != ')') throw new XLException("expecting \")\", found: " + token); + token = tokenizer.nextToken(); + return e; + case StreamTokenizer.TT_NUMBER: + double x = tokenizer.nval; + token = tokenizer.nextToken(); + return new Num(x); + case StreamTokenizer.TT_WORD: + String address = tokenizer.sval.toUpperCase(); + if (!Pattern.matches("[A-Z][0-9]+", address)) + throw new XLException("illegal address: " + address); + token = tokenizer.nextToken(); + return new Variable(address); + case StreamTokenizer.TT_EOF: + throw new XLException("unexpected end of text"); + default: + throw new XLException("unexpected " + (char) token); + } + } + + private Expr term() throws IOException { + Expr result, factor; + result = factor(); + while (token == '*' || token == '/') { + int op = token; + token = tokenizer.nextToken(); + factor = factor(); + switch (op) { + case '*': + result = new Mul(result, factor); + break; + case '/': + result = new Div(result, factor); + break; + } + } + return result; + } +} diff --git a/app/src/main/java/expr/Mul.java b/app/src/main/java/expr/Mul.java new file mode 100644 index 0000000..2a5cffd --- /dev/null +++ b/app/src/main/java/expr/Mul.java @@ -0,0 +1,18 @@ +package xl.expr; + +class Mul extends BinaryExpr { + + Mul(Expr expr1, Expr expr2) { + super(expr1, expr2); + precedence1 = 1; + precedence2 = 1; + } + + public double op(double op1, double op2) { + return op1 * op2; + } + + protected String opString() { + return "*"; + } +} diff --git a/app/src/main/java/expr/Num.java b/app/src/main/java/expr/Num.java new file mode 100644 index 0000000..121b27f --- /dev/null +++ b/app/src/main/java/expr/Num.java @@ -0,0 +1,21 @@ +package xl.expr; + +import xl.util.NumberAdjustment; + +class Num extends Expr { + + private static NumberAdjustment adjustment = new NumberAdjustment(0, 2); + private double value; + + Num(double value) { + this.value = value; + } + + public String toString(int prec) { + return adjustment.right(value); + } + + public double value(Environment env) { + return value; + } +} diff --git a/app/src/main/java/expr/Sub.java b/app/src/main/java/expr/Sub.java new file mode 100644 index 0000000..7108153 --- /dev/null +++ b/app/src/main/java/expr/Sub.java @@ -0,0 +1,18 @@ +package xl.expr; + +class Sub extends BinaryExpr { + + Sub(Expr expr1, Expr expr2) { + super(expr1, expr2); + precedence1 = 0; + precedence2 = 1; + } + + public double op(double op1, double op2) { + return op1 - op2; + } + + protected String opString() { + return "-"; + } +} diff --git a/app/src/main/java/expr/TestExpr.java b/app/src/main/java/expr/TestExpr.java new file mode 100644 index 0000000..e5b6b1f --- /dev/null +++ b/app/src/main/java/expr/TestExpr.java @@ -0,0 +1,30 @@ +package xl.expr; + +import java.io.IOException; + +public class TestExpr { + + public static void main(String[] args) { + ExprParser parser = new ExprParser(); + try { + Expr expr = parser.build("1+2*3"); + System.out.println(expr); + System.out.println(expr.value(null)); + expr = parser.build("A3+A2*A1"); + Environment env = + new Environment() { + public double value(String name) { + if (name.equals("A3")) return 1; + if (name.equals("A2")) return 2; + if (name.equals("A1")) return 3; + System.out.println(name + " is undefined"); + return 0; + } + }; + System.out.println(expr); + System.out.println(expr.value(env)); + } catch (IOException e) { + System.err.println(e.getMessage()); + } + } +} diff --git a/app/src/main/java/expr/Variable.java b/app/src/main/java/expr/Variable.java new file mode 100644 index 0000000..b8d272f --- /dev/null +++ b/app/src/main/java/expr/Variable.java @@ -0,0 +1,18 @@ +package xl.expr; + +class Variable extends Expr { + + private String name; + + Variable(String name) { + this.name = name; + } + + public String toString(int prec) { + return name.toString(); + } + + public double value(Environment env) { + return env.value(name); + } +} diff --git a/app/src/main/java/gui/BorderPanel.java b/app/src/main/java/gui/BorderPanel.java new file mode 100644 index 0000000..002580d --- /dev/null +++ b/app/src/main/java/gui/BorderPanel.java @@ -0,0 +1,13 @@ +package xl.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import javax.swing.JPanel; + +public class BorderPanel extends JPanel { + + protected BorderPanel() { + super(new BorderLayout(2, 2)); + setBackground(Color.BLACK); + } +} diff --git a/app/src/main/java/gui/ColoredLabel.java b/app/src/main/java/gui/ColoredLabel.java new file mode 100644 index 0000000..408a33f --- /dev/null +++ b/app/src/main/java/gui/ColoredLabel.java @@ -0,0 +1,22 @@ +package xl.gui; + +import java.awt.Color; +import javax.swing.JLabel; +import javax.swing.SwingConstants; + +public class ColoredLabel extends JLabel { + + public ColoredLabel(String text) { + this(text, Color.WHITE, SwingConstants.LEFT); + } + + public ColoredLabel(String text, Color color) { + this(text, color, SwingConstants.LEFT); + } + + public ColoredLabel(String text, Color color, int alignment) { + super(text, alignment); + setBackground(color); + setOpaque(true); + } +} diff --git a/app/src/main/java/gui/CurrentLabel.java b/app/src/main/java/gui/CurrentLabel.java new file mode 100644 index 0000000..68a78e2 --- /dev/null +++ b/app/src/main/java/gui/CurrentLabel.java @@ -0,0 +1,10 @@ +package xl.gui; + +import java.awt.Color; + +public class CurrentLabel extends ColoredLabel { + + public CurrentLabel() { + super("A1", Color.WHITE); + } +} diff --git a/app/src/main/java/gui/Editor.java b/app/src/main/java/gui/Editor.java new file mode 100644 index 0000000..1004b4d --- /dev/null +++ b/app/src/main/java/gui/Editor.java @@ -0,0 +1,11 @@ +package xl.gui; + +import java.awt.Color; +import javax.swing.JTextField; + +public class Editor extends JTextField { + + public Editor() { + setBackground(Color.WHITE); + } +} diff --git a/app/src/main/java/gui/GridPanel.java b/app/src/main/java/gui/GridPanel.java new file mode 100644 index 0000000..a9ff152 --- /dev/null +++ b/app/src/main/java/gui/GridPanel.java @@ -0,0 +1,13 @@ +package xl.gui; + +import java.awt.Color; +import java.awt.GridLayout; +import javax.swing.JPanel; + +public class GridPanel extends JPanel { + + public GridPanel(int rows, int columns) { + super(new GridLayout(rows, columns, 2, 2)); + setBackground(Color.BLACK); + } +} diff --git a/app/src/main/java/gui/RowLabels.java b/app/src/main/java/gui/RowLabels.java new file mode 100644 index 0000000..a2b909f --- /dev/null +++ b/app/src/main/java/gui/RowLabels.java @@ -0,0 +1,15 @@ +package xl.gui; + +import static java.awt.Color.LIGHT_GRAY; +import static javax.swing.SwingConstants.RIGHT; + +class RowLabels extends GridPanel { + + RowLabels(int rows) { + super(rows + 1, 1); + add(new ColoredLabel("", LIGHT_GRAY, RIGHT)); + for (int i = 1; i <= rows; i++) { + add(new ColoredLabel(String.valueOf(i), LIGHT_GRAY, RIGHT)); + } + } +} diff --git a/app/src/main/java/gui/SheetPanel.java b/app/src/main/java/gui/SheetPanel.java new file mode 100644 index 0000000..74ca92d --- /dev/null +++ b/app/src/main/java/gui/SheetPanel.java @@ -0,0 +1,12 @@ +package xl.gui; + +import static java.awt.BorderLayout.CENTER; +import static java.awt.BorderLayout.WEST; + +public class SheetPanel extends BorderPanel { + + public SheetPanel(int rows, int columns) { + add(WEST, new RowLabels(rows)); + add(CENTER, new SlotLabels(rows, columns)); + } +} diff --git a/app/src/main/java/gui/SlotLabel.java b/app/src/main/java/gui/SlotLabel.java new file mode 100644 index 0000000..5807b19 --- /dev/null +++ b/app/src/main/java/gui/SlotLabel.java @@ -0,0 +1,10 @@ +package xl.gui; + +import java.awt.Color; + +public class SlotLabel extends ColoredLabel { + + public SlotLabel() { + super(" ", Color.WHITE, RIGHT); + } +} diff --git a/app/src/main/java/gui/SlotLabels.java b/app/src/main/java/gui/SlotLabels.java new file mode 100644 index 0000000..e1497d8 --- /dev/null +++ b/app/src/main/java/gui/SlotLabels.java @@ -0,0 +1,28 @@ +package xl.gui; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; +import javax.swing.SwingConstants; + +public class SlotLabels extends GridPanel { + + private List labelList; + + public SlotLabels(int rows, int cols) { + super(rows + 1, cols); + labelList = new ArrayList(rows * cols); + for (char ch = 'A'; ch < 'A' + cols; ch++) { + add(new ColoredLabel(Character.toString(ch), Color.LIGHT_GRAY, SwingConstants.CENTER)); + } + for (int row = 1; row <= rows; row++) { + for (char ch = 'A'; ch < 'A' + cols; ch++) { + SlotLabel label = new SlotLabel(); + add(label); + labelList.add(label); + } + } + SlotLabel firstLabel = labelList.get(0); + firstLabel.setBackground(Color.YELLOW); + } +} diff --git a/app/src/main/java/gui/StatusLabel.java b/app/src/main/java/gui/StatusLabel.java new file mode 100644 index 0000000..03389eb --- /dev/null +++ b/app/src/main/java/gui/StatusLabel.java @@ -0,0 +1,16 @@ +package xl.gui; + +import java.awt.Color; +import java.util.Observable; +import java.util.Observer; + +public class StatusLabel extends ColoredLabel implements Observer { + + public StatusLabel() { + super("", Color.WHITE); + } + + public void update(Observable observable, Object object) { + setText(""); + } +} diff --git a/app/src/main/java/gui/StatusPanel.java b/app/src/main/java/gui/StatusPanel.java new file mode 100644 index 0000000..a6087bf --- /dev/null +++ b/app/src/main/java/gui/StatusPanel.java @@ -0,0 +1,12 @@ +package xl.gui; + +import static java.awt.BorderLayout.CENTER; +import static java.awt.BorderLayout.WEST; + +public class StatusPanel extends BorderPanel { + + protected StatusPanel(StatusLabel statusLabel) { + add(WEST, new CurrentLabel()); + add(CENTER, statusLabel); + } +} diff --git a/app/src/main/java/gui/XL.java b/app/src/main/java/gui/XL.java new file mode 100644 index 0000000..d4c3e69 --- /dev/null +++ b/app/src/main/java/gui/XL.java @@ -0,0 +1,49 @@ +package xl.gui; + +import static java.awt.BorderLayout.CENTER; +import static java.awt.BorderLayout.NORTH; +import static java.awt.BorderLayout.SOUTH; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import xl.gui.menu.XLMenuBar; + +public class XL extends JFrame { + + private static final int ROWS = 10, COLUMNS = 8; + private XLCounter counter; + private StatusLabel statusLabel = new StatusLabel(); + private XLList xlList; + + public XL(XL oldXL) { + this(oldXL.xlList, oldXL.counter); + } + + public XL(XLList xlList, XLCounter counter) { + super("Untitled-" + counter); + this.xlList = xlList; + this.counter = counter; + xlList.add(this); + counter.increment(); + JPanel statusPanel = new StatusPanel(statusLabel); + JPanel sheetPanel = new SheetPanel(ROWS, COLUMNS); + Editor editor = new Editor(); + add(NORTH, statusPanel); + add(CENTER, editor); + add(SOUTH, sheetPanel); + setJMenuBar(new XLMenuBar(this, xlList, statusLabel)); + pack(); + setDefaultCloseOperation(EXIT_ON_CLOSE); + setResizable(false); + setVisible(true); + } + + public void rename(String title) { + setTitle(title); + xlList.setChanged(); + } + + public static void main(String[] args) { + new XL(new XLList(), new XLCounter()); + } +} diff --git a/app/src/main/java/gui/XLCounter.java b/app/src/main/java/gui/XLCounter.java new file mode 100644 index 0000000..7bcf68b --- /dev/null +++ b/app/src/main/java/gui/XLCounter.java @@ -0,0 +1,14 @@ +package xl.gui; + +public class XLCounter { + + private int counter; + + public void increment() { + counter++; + } + + public String toString() { + return Integer.toString(counter); + } +} diff --git a/app/src/main/java/gui/XLList.java b/app/src/main/java/gui/XLList.java new file mode 100644 index 0000000..7018072 --- /dev/null +++ b/app/src/main/java/gui/XLList.java @@ -0,0 +1,40 @@ +package xl.gui; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Observable; + +public class XLList extends Observable implements Iterable { + + private List list = new ArrayList(); + + public void add(XL xl) { + list.add(xl); + setChanged(); + notifyObservers(); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public Iterator iterator() { + return list.iterator(); + } + + public XL last() { + return list.get(list.size() - 1); + } + + public void remove(XL xl) { + list.remove(xl); + setChanged(); + notifyObservers(); + } + + public void setChanged() { + super.setChanged(); + notifyObservers(); + } +} diff --git a/app/src/main/java/gui/menu/ClearAllMenuItem.java b/app/src/main/java/gui/menu/ClearAllMenuItem.java new file mode 100644 index 0000000..dce2215 --- /dev/null +++ b/app/src/main/java/gui/menu/ClearAllMenuItem.java @@ -0,0 +1,17 @@ +package xl.gui.menu; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JMenuItem; + +class ClearAllMenuItem extends JMenuItem implements ActionListener { + + public ClearAllMenuItem() { + super("Clear all"); + addActionListener(this); + } + + public void actionPerformed(ActionEvent e) { + // TODO + } +} diff --git a/app/src/main/java/gui/menu/ClearMenuItem.java b/app/src/main/java/gui/menu/ClearMenuItem.java new file mode 100644 index 0000000..c1954f9 --- /dev/null +++ b/app/src/main/java/gui/menu/ClearMenuItem.java @@ -0,0 +1,17 @@ +package xl.gui.menu; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JMenuItem; + +class ClearMenuItem extends JMenuItem implements ActionListener { + + public ClearMenuItem() { + super("Clear"); + addActionListener(this); + } + + public void actionPerformed(ActionEvent e) { + // TODO + } +} diff --git a/app/src/main/java/gui/menu/CloseMenuItem.java b/app/src/main/java/gui/menu/CloseMenuItem.java new file mode 100644 index 0000000..4373217 --- /dev/null +++ b/app/src/main/java/gui/menu/CloseMenuItem.java @@ -0,0 +1,30 @@ +package xl.gui.menu; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JMenuItem; +import xl.gui.XL; +import xl.gui.XLList; + +class CloseMenuItem extends JMenuItem implements ActionListener { + + private XL xl; + private XLList xlList; + + public CloseMenuItem(XL xl, XLList xlList) { + super("Close"); + this.xl = xl; + this.xlList = xlList; + addActionListener(this); + } + + public void actionPerformed(ActionEvent event) { + xlList.remove(xl); + xl.dispose(); + if (xlList.isEmpty()) { + System.exit(0); + } else { + xlList.last().toFront(); + } + } +} diff --git a/app/src/main/java/gui/menu/LoadMenuItem.java b/app/src/main/java/gui/menu/LoadMenuItem.java new file mode 100644 index 0000000..c833104 --- /dev/null +++ b/app/src/main/java/gui/menu/LoadMenuItem.java @@ -0,0 +1,21 @@ +package xl.gui.menu; + +import java.io.FileNotFoundException; +import javax.swing.JFileChooser; +import xl.gui.StatusLabel; +import xl.gui.XL; + +class LoadMenuItem extends OpenMenuItem { + + public LoadMenuItem(XL xl, StatusLabel statusLabel) { + super(xl, statusLabel, "Load"); + } + + protected void action(String path) throws FileNotFoundException { + // TODO + } + + protected int openDialog(JFileChooser fileChooser) { + return fileChooser.showOpenDialog(xl); + } +} diff --git a/app/src/main/java/gui/menu/NewMenuItem.java b/app/src/main/java/gui/menu/NewMenuItem.java new file mode 100644 index 0000000..ae2aeb9 --- /dev/null +++ b/app/src/main/java/gui/menu/NewMenuItem.java @@ -0,0 +1,21 @@ +package xl.gui.menu; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JMenuItem; +import xl.gui.XL; + +class NewMenuItem extends JMenuItem implements ActionListener { + + private XL xl; + + public NewMenuItem(XL xl) { + super("New"); + this.xl = xl; + addActionListener(this); + } + + public void actionPerformed(ActionEvent event) { + new XL(xl); + } +} diff --git a/app/src/main/java/gui/menu/OpenMenuItem.java b/app/src/main/java/gui/menu/OpenMenuItem.java new file mode 100644 index 0000000..39c3f88 --- /dev/null +++ b/app/src/main/java/gui/menu/OpenMenuItem.java @@ -0,0 +1,45 @@ +package xl.gui.menu; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileNotFoundException; +import javax.swing.JFileChooser; +import javax.swing.JMenuItem; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileNameExtensionFilter; +import xl.gui.StatusLabel; +import xl.gui.XL; + +public abstract class OpenMenuItem extends JMenuItem implements ActionListener { + + protected StatusLabel statusLabel; + protected XL xl; + + protected OpenMenuItem(XL xl, StatusLabel statusLabel, String title) { + super(title); + this.xl = xl; + this.statusLabel = statusLabel; + addActionListener(this); + } + + protected abstract void action(String path) throws FileNotFoundException; + + public void actionPerformed(ActionEvent event) { + JFileChooser fileChooser = new JFileChooser("."); + FileFilter filter = new FileNameExtensionFilter("XL files", "xl"); + fileChooser.setFileFilter(filter); + int option = openDialog(fileChooser); + if (option == JFileChooser.APPROVE_OPTION) { + File file = fileChooser.getSelectedFile(); + try { + action(file.toString()); + xl.rename(file.getName()); + } catch (FileNotFoundException e) { + statusLabel.setText(e.getMessage()); + } + } + } + + protected abstract int openDialog(JFileChooser fileChooser); +} diff --git a/app/src/main/java/gui/menu/SaveMenuItem.java b/app/src/main/java/gui/menu/SaveMenuItem.java new file mode 100644 index 0000000..84b5807 --- /dev/null +++ b/app/src/main/java/gui/menu/SaveMenuItem.java @@ -0,0 +1,21 @@ +package xl.gui.menu; + +import java.io.FileNotFoundException; +import javax.swing.JFileChooser; +import xl.gui.StatusLabel; +import xl.gui.XL; + +class SaveMenuItem extends OpenMenuItem { + + public SaveMenuItem(XL xl, StatusLabel statusLabel) { + super(xl, statusLabel, "Save"); + } + + protected void action(String path) throws FileNotFoundException { + // TODO + } + + protected int openDialog(JFileChooser fileChooser) { + return fileChooser.showSaveDialog(xl); + } +} diff --git a/app/src/main/java/gui/menu/WindowMenu.java b/app/src/main/java/gui/menu/WindowMenu.java new file mode 100644 index 0000000..8b5073f --- /dev/null +++ b/app/src/main/java/gui/menu/WindowMenu.java @@ -0,0 +1,26 @@ +package xl.gui.menu; + +import java.util.Observable; +import java.util.Observer; +import javax.swing.JMenu; +import xl.gui.XL; +import xl.gui.XLList; + +public class WindowMenu extends JMenu implements Observer { + + private XLList xlList; + + public WindowMenu(XLList xlList) { + super("Window"); + this.xlList = xlList; + xlList.addObserver(this); + update(null, null); + } + + public void update(Observable observable, Object object) { + removeAll(); + for (XL xl : xlList) { + add(new WindowMenuItem(xl)); + } + } +} diff --git a/app/src/main/java/gui/menu/WindowMenuItem.java b/app/src/main/java/gui/menu/WindowMenuItem.java new file mode 100644 index 0000000..afa6d29 --- /dev/null +++ b/app/src/main/java/gui/menu/WindowMenuItem.java @@ -0,0 +1,21 @@ +package xl.gui.menu; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JMenuItem; +import xl.gui.XL; + +class WindowMenuItem extends JMenuItem implements ActionListener { + + private XL xl; + + public WindowMenuItem(XL xl) { + super(xl.getTitle()); + this.xl = xl; + addActionListener(this); + } + + public void actionPerformed(ActionEvent event) { + xl.toFront(); + } +} diff --git a/app/src/main/java/gui/menu/XLMenuBar.java b/app/src/main/java/gui/menu/XLMenuBar.java new file mode 100644 index 0000000..cbbf837 --- /dev/null +++ b/app/src/main/java/gui/menu/XLMenuBar.java @@ -0,0 +1,24 @@ +package xl.gui.menu; + +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import xl.gui.StatusLabel; +import xl.gui.XL; +import xl.gui.XLList; + +public class XLMenuBar extends JMenuBar { + + public XLMenuBar(XL xl, XLList xlList, StatusLabel statusLabel) { + JMenu file = new JMenu("File"); + JMenu edit = new JMenu("Edit"); + file.add(new SaveMenuItem(xl, statusLabel)); + file.add(new LoadMenuItem(xl, statusLabel)); + file.add(new NewMenuItem(xl)); + file.add(new CloseMenuItem(xl, xlList)); + edit.add(new ClearMenuItem()); + edit.add(new ClearAllMenuItem()); + add(file); + add(edit); + add(new WindowMenu(xlList)); + } +} diff --git a/app/src/main/java/util/Adjustment.java b/app/src/main/java/util/Adjustment.java new file mode 100644 index 0000000..c3e6003 --- /dev/null +++ b/app/src/main/java/util/Adjustment.java @@ -0,0 +1,134 @@ +package xl.util; + +/** + * Adjustment.java Created: Tue Oct 24 2005 + * + * @author Lennart Andersson + * @version 0.1 + */ +/** Adjustment is a class for adjusting string representations of values within a String. */ +public class Adjustment { + + private int width; + + /** + * Creates an adjustment. + * + * @param width is the number of positions for the result. If the width is insufficient extra + * positions are added. + */ + public Adjustment(int width) { + this.width = width; + } + + /** + * Returns a centered String. + * + * @param s is the string to adjust. + */ + public String center(String s) { + StringBuilder builder = new StringBuilder(width); + int fill = width - s.length(); + for (int i = 0; i < fill / 2; i++) { + builder.append(' '); + } + builder.append(s); + for (int i = 0; i < fill - fill / 2; i++) { + builder.append(' '); + } + return builder.toString(); + } + + /** + * Returns a left adjusted String. + * + * @param s is the string to adjust. + */ + public String left(String s) { + StringBuilder builder = new StringBuilder(width); + builder.append(s); + int fill = width - s.length(); + for (int i = 0; i < fill; i++) { + builder.append(' '); + } + return builder.toString(); + } + + /** + * Returns a right adjusted String. + * + * @param b is the value to adjust. + */ + public String right(boolean b) { + return right(String.valueOf(b)); + } + + /** + * Returns a right adjusted String. + * + * @param c is the value to adjust. + */ + public String right(char c) { + return right(String.valueOf(c)); + } + + /** + * Returns a right adjusted String. + * + * @param number is the value to adjust. + */ + public String right(double number) { + return right(String.valueOf(number)); + } + + /** + * Returns a right adjusted String. + * + * @param number is the value to adjust. + */ + public String right(float number) { + return right(String.valueOf(number)); + } + + /** + * Returns a right adjusted String. + * + * @param number is the value to adjust. + */ + public String right(int number) { + return right(String.valueOf(number)); + } + + /** + * Returns a right adjusted String. + * + * @param number is the value to adjust. + */ + public String right(long number) { + return right(String.valueOf(number)); + } + + /** + * Returns a right adjusted String. + * + * @param item is the value to adjust. + */ + public String right(Object item) { + return right(String.valueOf(item)); + } + + /** + * Returns a right adjusted String. + * + * @param s is the string to adjust. + */ + public String right(String s) { + StringBuilder builder = new StringBuilder(width); + int fill = width - s.length(); + for (int i = 0; i < fill; i++) { + builder.append(' '); + } + builder.append(s); + return builder.toString(); + } +} diff --git a/app/src/main/java/util/NumberAdjustment.java b/app/src/main/java/util/NumberAdjustment.java new file mode 100644 index 0000000..e77b721 --- /dev/null +++ b/app/src/main/java/util/NumberAdjustment.java @@ -0,0 +1,123 @@ +package xl.util; + +/** + * NumberAdjustment.java Created: Mon OTue 24 2005 + * + * @author Lennart Andersson + * @version 0.1 + */ +/** + * Adjustment is a class for adjusting string representations of numerical values within a String. + */ +public class NumberAdjustment extends Adjustment { + + private static final double log10 = Math.log(10.0); + private int decimals; + private int exponent; + + /** + * Creates an adjustment for numbers. + * + * @param width is the number of positions for the result. If the width is insufficient extra + * positions are added. + * @param decimals is the number of decimals in the result. + */ + public NumberAdjustment(int width, int decimals) { + super(width); + this.decimals = decimals; + } + + /** + * Creates an adjustment for numbers with an exponent field. + * + * @param width is the number of positions for the result. If the width is insufficient extra + * positions are added. + * @param decimals is the number of positions for the decimals. + * @param exponent is the number of positions for the exponent including the letter E. If the + * width is unsufficient extra positions are added. + */ + public NumberAdjustment(int width, int decimals, int exponent) { + this(width, decimals); + this.exponent = exponent; + } + + private StringBuilder fillZero(int exp) { + StringBuilder builder = new StringBuilder(); + int length = exponent; + if (exp < 0) { + builder.append('-'); + exp = -exp; + length = exponent - 1; + } + String s = String.valueOf(exp); + for (int i = s.length(); i < length; i++) { + builder.append('0'); + } + return builder.append(s); + } + + private StringBuilder format(double number) { + StringBuilder builder = new StringBuilder(); + long intpart = (long) number; + builder.append(intpart); + double fraction = number - intpart; + if (decimals > 0) { + builder.append('.'); + } + for (int i = 0; i < decimals; i++) { + fraction *= 10; + int d = (int) fraction; + builder.append((char) (d + '0')); + fraction = fraction - d; + } + return builder; + } + + /** + * Returns a right adjusted String. + * + * @param number is the value to adjust. + */ + public String right(double number) { + StringBuilder builder = new StringBuilder(); + boolean negative = number < 0; + if (negative) { + number = -number; + builder.append('-'); + } + if (exponent > 0) { + if (number == 0.0) return right(format(0.0) + "E" + fillZero(0)); + int exp = (int) Math.floor((Math.log(number) / log10)); + number /= Math.pow(10.0, exp); + number += 0.5 * Math.pow(10.0, -decimals); + if (number >= 10.0) { + number /= 10.0; + exp++; + } + builder.append(format(number)).append('E').append(fillZero(exp)); + } else { + number += 0.5 * Math.pow(10.0, -decimals); + builder.append(format(number)); + } + return right(builder.toString()); + } + + /** + * Returns a right adjusted String. + * + * @param number is the value to adjust. + */ + public String right(float number) { + return right((double) number); + } + + public static void main(String[] args) { + Adjustment adjustment = new NumberAdjustment(10, 2, 2); + System.out.println("0123456789"); + System.out.println(adjustment.right(-0.0000000000000000000000000)); + float value = (float) (1 / 3.0); + System.out.println(adjustment.right(value)); + adjustment = new Adjustment(12); + System.out.println(adjustment.right(value)); + } +} diff --git a/app/src/main/java/util/XLBufferedReader.java b/app/src/main/java/util/XLBufferedReader.java new file mode 100644 index 0000000..34ce774 --- /dev/null +++ b/app/src/main/java/util/XLBufferedReader.java @@ -0,0 +1,27 @@ +package xl.util; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.Map; + +// TODO move to another package +public class XLBufferedReader extends BufferedReader { + + public XLBufferedReader(String name) throws FileNotFoundException { + super(new FileReader(name)); + } + + // TODO Change Object to something appropriate + public void load(Map map) { + try { + while (ready()) { + String string = readLine(); + int i = string.indexOf('='); + // TODO + } + } catch (Exception e) { + throw new XLException(e.getMessage()); + } + } +} diff --git a/app/src/main/java/util/XLException.java b/app/src/main/java/util/XLException.java new file mode 100644 index 0000000..ef70535 --- /dev/null +++ b/app/src/main/java/util/XLException.java @@ -0,0 +1,8 @@ +package xl.util; + +public class XLException extends RuntimeException { + + public XLException(String message) { + super(message); + } +} diff --git a/app/src/main/java/util/XLPrintStream.java b/app/src/main/java/util/XLPrintStream.java new file mode 100644 index 0000000..8ff5525 --- /dev/null +++ b/app/src/main/java/util/XLPrintStream.java @@ -0,0 +1,25 @@ +package xl.util; + +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.util.Map.Entry; +import java.util.Set; + +// TODO move to another package +public class XLPrintStream extends PrintStream { + + public XLPrintStream(String fileName) throws FileNotFoundException { + super(fileName); + } + + // TODO Change Object to something appropriate + public void save(Set> set) { + for (Entry entry : set) { + print(entry.getKey()); + print('='); + println(entry.getValue()); + } + flush(); + close(); + } +}