Simple calculator example, initial version

A simple calculator example with a Swing user interface.

Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
diff --git a/org.eclipse.example.calc/.classpath b/org.eclipse.example.calc/.classpath
new file mode 100644
index 0000000..18d70f0
--- /dev/null
+++ b/org.eclipse.example.calc/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.example.calc/.gitignore b/org.eclipse.example.calc/.gitignore
new file mode 100644
index 0000000..934e0e0
--- /dev/null
+++ b/org.eclipse.example.calc/.gitignore
@@ -0,0 +1,2 @@
+/bin
+/target
diff --git a/org.eclipse.example.calc/.project b/org.eclipse.example.calc/.project
new file mode 100644
index 0000000..05f7dc5
--- /dev/null
+++ b/org.eclipse.example.calc/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.example.calc</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.example.calc/.settings/org.eclipse.core.resources.prefs b/org.eclipse.example.calc/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..3f5bf67
--- /dev/null
+++ b/org.eclipse.example.calc/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Fri Feb 25 01:31:16 CET 2011
+eclipse.preferences.version=1
+encoding//src/org/eclipse/example/calc/internal/operations/Square.java=UTF-8
diff --git a/org.eclipse.example.calc/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.example.calc/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..e0d7ca8
--- /dev/null
+++ b/org.eclipse.example.calc/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Thu Feb 24 22:46:12 CET 2011
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/org.eclipse.example.calc/Calculator.launch b/org.eclipse.example.calc/Calculator.launch
new file mode 100644
index 0000000..d3f8131
--- /dev/null
+++ b/org.eclipse.example.calc/Calculator.launch
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/ui/Calculator.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
+<mapEntry key="[run]" value="org.eclipse.jdt.launching.localJavaApplication"/>
+</mapAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.example.calc.internal.ui.Calculator"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.example.calc"/>
+</launchConfiguration>
diff --git a/org.eclipse.example.calc/src/org/eclipse/example/calc/BinaryOperation.java b/org.eclipse.example.calc/src/org/eclipse/example/calc/BinaryOperation.java
new file mode 100644
index 0000000..5e0348e
--- /dev/null
+++ b/org.eclipse.example.calc/src/org/eclipse/example/calc/BinaryOperation.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.example.calc;
+
+/**
+ * Binary operation interface
+ */
+public interface BinaryOperation extends Operation {
+	/**
+	 * @param arg1 first parameter
+	 * @param arg2 second parameter
+	 * @return result of binary operation
+	 */
+	public float perform(float arg1, float arg2);
+}
diff --git a/org.eclipse.example.calc/src/org/eclipse/example/calc/Operation.java b/org.eclipse.example.calc/src/org/eclipse/example/calc/Operation.java
new file mode 100644
index 0000000..68cb046
--- /dev/null
+++ b/org.eclipse.example.calc/src/org/eclipse/example/calc/Operation.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.example.calc;
+
+public interface Operation {
+	/**
+	 * @return name of the operation
+	 */
+	public String getName();
+}
diff --git a/org.eclipse.example.calc/src/org/eclipse/example/calc/Operations.java b/org.eclipse.example.calc/src/org/eclipse/example/calc/Operations.java
new file mode 100644
index 0000000..af57361
--- /dev/null
+++ b/org.eclipse.example.calc/src/org/eclipse/example/calc/Operations.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.example.calc;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class to register operations
+ */
+public class Operations {
+	public static final Operations INSTANCE = new Operations();
+
+	private final Map<String, Operation> commands = new HashMap<String, Operation>();
+
+	public void register(Operation op) {
+		assert (commands.get(op.getName()) == null);
+		commands.put(op.getName(), op);
+	}
+
+	public void reset() {
+		commands.clear();
+	}
+
+	public Operation getOperation(String name) {
+		return commands.get(name);
+	}
+
+	public int size() {
+		return commands.size();
+	}
+
+	public String getOperationName(int i) {
+		String keys[] = new String[commands.keySet().size()];
+		(commands.keySet()).toArray(keys);
+		Arrays.sort(keys);
+		return keys[i];
+	}
+}
diff --git a/org.eclipse.example.calc/src/org/eclipse/example/calc/UnaryOperation.java b/org.eclipse.example.calc/src/org/eclipse/example/calc/UnaryOperation.java
new file mode 100644
index 0000000..04db3fe
--- /dev/null
+++ b/org.eclipse.example.calc/src/org/eclipse/example/calc/UnaryOperation.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.example.calc;
+
+/**
+ * Unary operation
+ */
+public interface UnaryOperation extends Operation {
+	/**
+	 * @param arg1 parameter
+	 * @return result of binary operation
+	 */
+	public float perform(float arg1);
+}
diff --git a/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/AbstractOperation.java b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/AbstractOperation.java
new file mode 100644
index 0000000..9fa00c3
--- /dev/null
+++ b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/AbstractOperation.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.example.calc.internal.operations;
+
+import org.eclipse.example.calc.Operation;
+import org.eclipse.example.calc.Operations;
+
+/**
+ * Abstract operation caring for book-keeping
+ */
+public abstract class AbstractOperation implements Operation {
+	AbstractOperation() {
+		Operations.INSTANCE.register(this);
+	}
+}
diff --git a/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Equals.java b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Equals.java
new file mode 100644
index 0000000..4907684
--- /dev/null
+++ b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Equals.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.example.calc.internal.operations;
+
+import org.eclipse.example.calc.Operation;
+
+/**
+ * Equals operation to trigger binary operations
+ */
+public class Equals extends AbstractOperation implements Operation {
+	
+	@Override
+	public String getName() {
+		return "=";
+	}
+
+}
diff --git a/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Minus.java b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Minus.java
new file mode 100644
index 0000000..5eec406
--- /dev/null
+++ b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Minus.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.example.calc.internal.operations;
+
+import org.eclipse.example.calc.BinaryOperation;
+
+/**
+ * Binary minus operation
+ */
+public class Minus extends AbstractOperation implements BinaryOperation {
+
+	@Override
+	public float perform(float arg1, float arg2) {
+		return arg1 - arg2;
+	}
+
+	@Override
+	public String getName() {
+		return "-";
+	}
+
+}
diff --git a/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Plus.java b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Plus.java
new file mode 100644
index 0000000..3ea65d5
--- /dev/null
+++ b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Plus.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.example.calc.internal.operations;
+
+import org.eclipse.example.calc.BinaryOperation;
+
+/**
+ * Binary plus operation
+ */
+public class Plus extends AbstractOperation implements BinaryOperation {
+
+	@Override
+	public float perform(float arg1, float arg2) {
+		return arg1 + arg2;
+	}
+
+	@Override
+	public String getName() {
+		return "+";
+	}
+
+}
diff --git a/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Square.java b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Square.java
new file mode 100644
index 0000000..53d45fe
--- /dev/null
+++ b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/operations/Square.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.example.calc.internal.operations;
+
+import org.eclipse.example.calc.UnaryOperation;
+
+/**
+ * Square operation
+ */
+public class Square extends AbstractOperation implements UnaryOperation {
+
+	@Override
+	public String getName() {
+		return "x²";
+	}
+
+	@Override
+	public float perform(float arg1) {
+		return arg1 * arg1;
+	}
+
+}
diff --git a/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/ui/Calculator.java b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/ui/Calculator.java
new file mode 100644
index 0000000..db032da
--- /dev/null
+++ b/org.eclipse.example.calc/src/org/eclipse/example/calc/internal/ui/Calculator.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Matthias Sohn <matthias.sohn@sap.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.example.calc.internal.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.TitledBorder;
+
+import org.eclipse.example.calc.BinaryOperation;
+import org.eclipse.example.calc.Operation;
+import org.eclipse.example.calc.Operations;
+import org.eclipse.example.calc.UnaryOperation;
+import org.eclipse.example.calc.internal.operations.Equals;
+import org.eclipse.example.calc.internal.operations.Minus;
+import org.eclipse.example.calc.internal.operations.Plus;
+import org.eclipse.example.calc.internal.operations.Square;
+
+/*
+ * A simple calculator featuring a Swing UI.
+ */
+public class Calculator extends JFrame implements ActionListener {
+	private static final long serialVersionUID = 1L;
+
+	private String cmd;
+	private boolean clearDisplay;
+	private float value;
+
+	private JTextField display;
+	private JPanel buttonsPanel;
+	private JPanel numberButtonsPanel;
+	private JPanel cmdButtonsPanel;
+	private JButton numberButtons[];
+	private JButton cmdButtons[];
+
+	public static void main(String args[]) {
+		new Calculator().setVisible(true);
+	}
+
+	public Calculator() {
+		setupOperations();
+		setupGUI();
+	}
+
+	private void setupOperations() {
+		new Equals();
+		new Minus();
+		new Plus();
+		new Square();
+	}
+
+	private void setupGUI() {
+		setTitle("Simple Calculator");
+		Container c = getContentPane();
+		c.setLayout(new BorderLayout());
+
+		setupDisplay(c);
+		setupButtonsPanel(c);
+		setupNumberButtons();
+		setupCommandButtons();
+
+		pack();
+	}
+
+	private void setupDisplay(Container c) {
+		display = new JTextField("0");
+		display.setHorizontalAlignment(JTextField.TRAILING);
+		c.add(display, BorderLayout.NORTH);
+		// initially clear the display
+		clearDisplay = true;
+	}
+
+	private void setupButtonsPanel(Container c) {
+		buttonsPanel = new JPanel();
+		buttonsPanel.setLayout(new GridLayout(2, 1));
+		c.add(buttonsPanel);
+	}
+
+	private void setupNumberButtons() {
+		numberButtonsPanel = new JPanel();
+		numberButtonsPanel.setLayout(new GridLayout(3, 4));
+		buttonsPanel.add(numberButtonsPanel, BorderLayout.CENTER);
+		numberButtons = new JButton[11];
+
+		for (int i = 0; i < numberButtons.length - 1; i++) {
+			addNumberButton(i, Integer.valueOf(i).toString());
+		}
+		addNumberButton(10, ".");
+	}
+
+	private void addNumberButton(int i, String name) {
+		numberButtons[i] = new JButton();
+		numberButtons[i].setText(name);
+		numberButtons[i].addActionListener(this);
+		numberButtonsPanel.add(numberButtons[i]);
+	}
+
+	private void setupCommandButtons() {
+		// command buttons
+		cmdButtonsPanel = new JPanel();
+		cmdButtonsPanel.setLayout(new GridLayout(1, 0));
+		buttonsPanel.add(cmdButtonsPanel, BorderLayout.CENTER);
+		TitledBorder title = BorderFactory.createTitledBorder("Operations");
+		cmdButtonsPanel.setBorder(title);
+		cmdButtons = new JButton[Operations.INSTANCE.size()];
+
+		// make the buttons, set ActionListener and add to panel
+		for (int i = 0; i < cmdButtons.length; i++) {
+			addCommandButton(i);
+		}
+	}
+
+	private void addCommandButton(int i) {
+		cmdButtons[i] = new JButton();
+		cmdButtons[i].setText(Operations.INSTANCE.getOperationName(i));
+		cmdButtons[i].addActionListener(this);
+		cmdButtonsPanel.add(cmdButtons[i]);
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		String str = e.getActionCommand();
+		if (isCommand(str)) {
+			calculate(str);
+		} else {
+			char digit = (str.toCharArray())[0];
+			if (Character.isDigit(digit) || digit == '.') {
+				if (clearDisplay) {
+					// save current value and clear the display
+					value = Float.parseFloat(display.getText());
+					display.setText("");
+					clearDisplay = false;
+				}
+
+				// add new digit to display
+				display.setText(display.getText() + digit);
+			}
+		}
+	}
+
+	private boolean isCommand(String name) {
+		return (Operations.INSTANCE.getOperation(name) != null);
+	}
+
+	private void calculate(String cmdName) {
+		float curValue;
+		float newValue = 0;
+
+		// get current value of display
+		curValue = Float.parseFloat(display.getText());
+
+		if (cmd == null || cmd.equals("")) {
+			// if no command was saved previously, save this one and clear
+			cmd = cmdName;
+			clearDisplay = true;
+		} else {
+			// perform the saved command
+			Operation op = Operations.INSTANCE.getOperation(cmd);
+			assert (op != null);
+			if (op instanceof BinaryOperation) {
+				BinaryOperation bop = (BinaryOperation) op;
+				newValue = bop.perform(value, curValue);
+			} else if (op instanceof UnaryOperation) {
+				UnaryOperation uop = (UnaryOperation) op;
+				newValue = uop.perform(curValue);
+			}
+
+			// display the result and order to clear
+			display.setText("" + newValue);
+			clearDisplay = true;
+
+			if (cmdName.equals("=")) {
+				// do not save = command
+				cmd = null;
+			} else {
+				// save other commands
+				cmd = cmdName;
+			}
+		}
+
+	}
+}