CalculatorMichaelSchmidt.java Source code

Java tutorial

Introduction

Here is the source code for CalculatorMichaelSchmidt.java

Source

/**
 * 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;
    }

}