/**
* Instances of this object class open a dialog with a simple calculator.
* The calculator includes a memory register, Tooltips for the keys, and error
* checking. It performs double precision calculations and includes square
* root and inverse functions. Other computations can be added easily.
* The code contains extensive comments.
* This class can be called via an Action from the menu or toolbar.
* Feel free to use this in your application!
*
* @author Michael Schmidt, 2006.
*/
//package mschmidt.komo;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class CalculatorMichaelSchmidt extends Dialog {
/*
* Initialize variables needed for this class.
*/
private Text displayText;
// The three calculator registers.
private String displayString = "0.";
private String memoryString = new String();
private String operatorString = new String();
// A variable to store the pending calculation
private char calcChar = ' ';
// Error strings
private final String ERROR_STRING = "Error: ";
private final String NAN_STRING = "Not a Number";
private final String LONG_STRING = "Number too long";
private final String INFINITY_STRING = "Infinity";
// A flag to check if display should be cleared on the next keystroke
private boolean clearDisplay = true;
// An ID constant for the copy to clipboard key
private static final int CLIPBOARD_ID = IDialogConstants.NO_TO_ALL_ID + 1;
public static void main(String[] a){
new CalculatorMichaelSchmidt(new Shell(new Display()));
}
/*
* Standard constructor to create the dialog.
* @param parentShell the Dialog shell
*/
public CalculatorMichaelSchmidt(final Shell parentShell) {
super(parentShell);
}
/*
* Create contents of the dialog, a display at the top and the various
* buttons. The Tooltip for each button explains its function.
* @param parent the composite
* @return Control the controls
*/
@Override
protected Control createDialogArea(final Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
final GridLayout calculatorGridLayout = new GridLayout();
calculatorGridLayout.marginRight = 5;
calculatorGridLayout.marginLeft = 5;
calculatorGridLayout.marginBottom = 5;
calculatorGridLayout.marginTop = 5;
calculatorGridLayout.marginWidth = 10;
calculatorGridLayout.marginHeight = 2;
calculatorGridLayout.numColumns = 4;
calculatorGridLayout.verticalSpacing = 2;
calculatorGridLayout.makeColumnsEqualWidth = true;
calculatorGridLayout.horizontalSpacing = 2;
container.setLayout(calculatorGridLayout);
// The display. Note that it has a limit of 30 characters,
// much greater than the length of a double-precision number.
displayText = new Text(container, SWT.RIGHT | SWT.BORDER);
displayText.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
displayText.setEditable(false);
displayText.setDoubleClickEnabled(false);
displayText.setTextLimit(30);
displayText.setText(displayString);
displayText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 4, 1));
final Button msButton = new Button(container, SWT.NONE);
msButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateMemory('S');
}
});
msButton.setToolTipText("Save value to Memory");
msButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
msButton.setText("MS");
final Button mcButton = new Button(container, SWT.NONE);
mcButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('D');
}
});
mcButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
mcButton.setToolTipText("Clear Memory");
mcButton.setText("MC");
final Button clearButton = new Button(container, SWT.NONE);
clearButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('C');
}
});
clearButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
clearButton.setToolTipText("Clear all Calculator Registers");
clearButton.setText("C");
final Button ceButton = new Button(container, SWT.NONE);
ceButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('E');
}
});
ceButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
ceButton.setToolTipText("Clear Entry");
ceButton.setText("CE");
final Button memAddButton = new Button(container, SWT.NONE);
memAddButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateMemory('+');
}
});
memAddButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
memAddButton.setToolTipText("Add value to Memory");
memAddButton.setText("M+");
final Button mrButton = new Button(container, SWT.NONE);
mrButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('R');
}
});
mrButton.setToolTipText("Recall value in Memory");
mrButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
mrButton.setText("MR");
final Button backButton = new Button(container, SWT.NONE);
backButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('B');
}
});
backButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
backButton.setToolTipText("Backspace");
backButton.setText("BACK");
final Button divideButton = new Button(container, SWT.NONE);
divideButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateCalc('/');
}
});
divideButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
divideButton.setToolTipText("Divide");
divideButton.setText("/");
final Button memSubtractButton = new Button(container, SWT.NONE);
memSubtractButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateMemory('-');
}
});
memSubtractButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
memSubtractButton.setToolTipText("Subtract value from Memory");
memSubtractButton.setText("M-");
final Button inverseButton = new Button(container, SWT.NONE);
inverseButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('I');
}
});
inverseButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
inverseButton.setToolTipText("Inverse of value");
inverseButton.setText("1/X");
final Button sqrtButton = new Button(container, SWT.NONE);
sqrtButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('Q');
}
});
sqrtButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
sqrtButton.setToolTipText("Square Root of value");
sqrtButton.setText("SQRT");
final Button multiplyButton = new Button(container, SWT.NONE);
multiplyButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateCalc('*');
}
});
multiplyButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
multiplyButton.setToolTipText("Multiply");
multiplyButton.setText("*");
final Button num7Button = new Button(container, SWT.NONE);
num7Button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('7');
}
});
num7Button.setToolTipText("Numeric Pad");
num7Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
num7Button.setText("7");
final Button num8Button = new Button(container, SWT.NONE);
num8Button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('8');
}
});
num8Button.setToolTipText("Numeric Pad");
num8Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
num8Button.setText("8");
final Button num9Button = new Button(container, SWT.NONE);
num9Button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('9');
}
});
num9Button.setToolTipText("Numeric Pad");
num9Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
num9Button.setText("9");
final Button SubtractButton = new Button(container, SWT.NONE);
SubtractButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateCalc('-');
}
});
SubtractButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
SubtractButton.setToolTipText("Subtract");
SubtractButton.setText("-");
final Button num4Button = new Button(container, SWT.NONE);
num4Button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('4');
}
});
num4Button.setToolTipText("Numeric Pad");
num4Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
num4Button.setText("4");
final Button num5Button = new Button(container, SWT.NONE);
num5Button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('5');
}
});
num5Button.setToolTipText("Numeric Pad");
num5Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
num5Button.setText("5");
final Button num6Button = new Button(container, SWT.NONE);
num6Button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('6');
}
});
num6Button.setToolTipText("Numeric Pad");
num6Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
num6Button.setText("6");
final Button AdditionButton = new Button(container, SWT.NONE);
AdditionButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateCalc('+');
}
});
AdditionButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
AdditionButton.setToolTipText("Add");
AdditionButton.setText("+");
final Button num1Button = new Button(container, SWT.NONE);
num1Button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('1');
}
});
num1Button.setCapture(true);
num1Button.setToolTipText("Numeric Pad");
num1Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
num1Button.setText("1");
final Button num2Button = new Button(container, SWT.NONE);
num2Button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('2');
}
});
num2Button.setToolTipText("Numeric Pad");
num2Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
num2Button.setText("2");
final Button num3Button = new Button(container, SWT.NONE);
num3Button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('3');
}
});
num3Button.setToolTipText("Numeric Pad");
num3Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
num3Button.setText("3");
final Button equalsButton = new Button(container, SWT.NONE);
equalsButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateCalc('=');
}
});
equalsButton.setToolTipText("Equals (get result)");
equalsButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 2));
equalsButton.setText("=");
final Button num0Button = new Button(container, SWT.NONE);
num0Button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('0');
}
});
num0Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
num0Button.setToolTipText("Numeric Pad");
num0Button.setText("0");
final Button decimalButton = new Button(container, SWT.NONE);
decimalButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('.');
}
});
decimalButton.setToolTipText("Numeric Pad");
decimalButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
decimalButton.setText(".");
final Button signButton = new Button(container, SWT.NONE);
signButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
updateDisplay('-');
}
});
signButton.setToolTipText("Change sign of value");
signButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
signButton.setText("+/-");
new Label(container, SWT.NONE);
//
return container;
}
/*
* Create contents of the button bar, including a button to copy the
* display to the system clipboard and a close button.
* @param parent
*/
@Override
protected void createButtonsForButtonBar(final Composite parent) {
createButton(parent, CLIPBOARD_ID, "Copy to Clipboard", false);
createButton(parent, IDialogConstants.CANCEL_ID,
IDialogConstants.CLOSE_LABEL, true);
}
/*
* Set the initial size of the dialog.
*/
@Override
protected Point getInitialSize() {
return new Point(260, 350);
}
/*
* Standard method to configure the shell.
*/
protected void configureShell(final Shell newShell) {
super.configureShell(newShell);
newShell.setText("Calculator");
// Include code here to set the window icon. The line here is a sample using the
// Eclipse plugin getImageDescriptor convenience method.
// newShell.setImage(KomoPlugin.getImageDescriptor(ApplicationImages.CALCULATOR_ICON).createImage());
}
/*
* (non-Javadoc)
* Method that copies contents of the display window to the clipboard when
* the Copy to Clipboard button is clicked.
* @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int)
*/
@Override
protected void buttonPressed(final int buttonID) {
if (buttonID == CLIPBOARD_ID) {
displayText.selectAll();
displayText.copy();
displayText.clearSelection();
} else {
super.buttonPressed(buttonID);
}
}
/*
* This method updates the display text based on user input.
*/
private void updateDisplay(final char keyPressed) {
char keyVal = keyPressed;
String tempString = new String();
boolean doClear = false;
if (!clearDisplay) {
tempString = displayString;
}
switch (keyVal) {
case 'B': // Backspace
if (tempString.length() < 2) {
tempString = "";
} else {
tempString = tempString.substring(0, tempString.length() - 1);
}
break;
case 'C': // Clear
tempString = "0.";
operatorString = "";
calcChar = ' ';
doClear = true;
break;
case 'D': // Clear Memory
memoryString = "";
break;
case 'E': // Clear Entry
tempString = "0.";
doClear = true;
break;
case 'I': // Inverse
tempString = doCalc(displayString, "", keyVal);
doClear = true;
break;
case 'Q': // Square Root
tempString = doCalc(displayString, "", keyVal);
doClear = true;
break;
case 'R': // Recall Memory to Display
tempString = memoryString;
doClear = true;
break;
case '-': // Change Sign
if (tempString.startsWith("-")) {
tempString = tempString.substring(1, tempString.length());
} else {
tempString = keyVal + tempString;
}
break;
case '.': // Can't have two decimal points.
if (tempString.indexOf(".") == -1 && tempString.length() < 29) {
tempString = tempString + keyVal;
}
break;
case '0': // Don't want 00 to be entered.
if (!tempString.equals("0") && tempString.length() < 29) {
tempString = tempString + keyVal;
}
break;
default: // Default case is for the digits 1 through 9.
if (tempString.length() < 29) {
tempString = tempString + keyVal;
}
break;
}
clearDisplay = doClear;
if (!displayString.equals(tempString)) {
displayString = tempString;
displayText.setText(displayString);
}
}
/*
* This method updates the value stored in memory.
* The value is cleared in the updateDisplay method.
*/
private void updateMemory(final char keyPressed) {
char keyVal = keyPressed;
String tempString = new String();
switch (keyVal) {
case 'S': // Save to Memory
tempString = trimString(displayString);
break;
case '+': // Add to Memory
if (memoryString.length() == 0) {
tempString = trimString(displayString);
} else {
tempString = doCalc(memoryString, displayString, '+');
}
break;
case '-': // Subtract from Memory
if (memoryString.length() == 0) {
if (displayString.startsWith("-")) {
tempString = displayString.substring(1, displayString.length());
tempString = trimString(tempString);
} else if (displayString.equals("0.0")
|| displayString.equals("0")
|| displayString.equals("0.")
|| displayString.equals("-0.0")) {
tempString = "0";
} else {
tempString = keyVal + displayString;
tempString = trimString(displayString);
}
} else {
tempString = doCalc(memoryString, displayString, '-');
}
break;
default: // Do nothing - this should never happen.
break;
}
// Do not save invalid entries to memory.
if (tempString.startsWith(ERROR_STRING)) {
if (!displayString.equals(tempString)) {
displayString = tempString;
displayText.setText(displayString);
}
} else {
memoryString = tempString;
}
clearDisplay = true;
}
/*
* This method converts the operator and display strings to double values
* and performs the calculation.
*/
private String doCalc(final String valAString, final String valBString,
final char opChar) {
String resultString = ERROR_STRING + NAN_STRING;
Double valA = 0.0;
Double valB = 0.0;
Double valAnswer = 0.0;
// Make sure register strings are numbers
if (valAString.length() > 0) {
try {
valA = Double.parseDouble(valAString);
} catch (NumberFormatException e) {
return resultString;
}
} else {
return resultString;
}
if (opChar != 'Q' && opChar != 'I') {
if (valBString.length() > 0) {
try {
valB = Double.parseDouble(valBString);
} catch (NumberFormatException e) {
return resultString;
}
} else {
return resultString;
}
}
switch (opChar) {
case 'Q': // Square Root
valAnswer = Math.sqrt(valA);
break;
case 'I': // Inverse
valB = 1.0;
valAnswer = valB/valA;
break;
case '+': // Addition
valAnswer = valA + valB;
break;
case '-': // Subtraction
valAnswer = valA - valB;
break;
case '/': // Division
valAnswer = valA/valB;
break;
case '*': // Multiplication
valAnswer = valA*valB;
break;
default: // Do nothing - this should never happen
break;
}
// Convert answer to string and format it before return.
resultString = valAnswer.toString();
resultString = trimString(resultString);
return resultString;
}
/*
* This method updates the operator and display strings, and the
* pending calculation flag.
*/
private void updateCalc(char keyPressed) {
char keyVal = keyPressed;
String tempString = displayString;
/*
* If there is no display value, the keystroke is deemed invalid and
* nothing is done.
*/
if (tempString.length() == 0) {
return;
}
/*
* If there is no operator value, only calculation key presses are
* considered valid. Check that the display value is valid and
* if so, move the display value to the operator. No calculation is done.
*/
if (operatorString.length() == 0) {
if (keyVal != '=') {
tempString = trimString(tempString);
if (tempString.startsWith(ERROR_STRING)) {
clearDisplay = true;
operatorString = "";
calcChar = ' ';
} else {
operatorString = tempString;
calcChar = keyVal;
clearDisplay = true;
}
}
return;
}
// There is an operator and a display value, so do the calculation.
displayString = doCalc(operatorString, tempString, calcChar);
/*
* If '=' was pressed or result was invalid, reset pending calculation
* flag and operator value. Otherwise, set new calculation flag so
* calculations can be chained.
*/
if (keyVal == '=' || displayString.startsWith(ERROR_STRING)) {
calcChar = ' ';
operatorString = "";
} else {
calcChar = keyVal;
operatorString = displayString;
}
// Set the clear display flag and show the result.
clearDisplay = true;
displayText.setText(displayString);
}
/*
* This method formats a string.
*/
private String trimString(final String newString) {
String tempString = newString;
// Value is not a number
if (tempString.equals("NaN")) {
tempString = ERROR_STRING + NAN_STRING;
return tempString;
}
// Value is infinity
if (tempString.equals("Infinity") || tempString.equals("-Infinity")) {
tempString = ERROR_STRING + INFINITY_STRING;
return tempString;
}
// Value is -0
if (tempString.equals(-0.0)) {
tempString = "0";
return tempString;
}
// Trim unnecessary trailing .0
if (tempString.endsWith(".0")) {
tempString = tempString.substring(0, tempString.length() - 2);
}
// String is too long to display
if (tempString.length() > 28) {
tempString = ERROR_STRING + LONG_STRING;
}
return tempString;
}
}
|