Apendice B -Full Source Code Listings

Embed Size (px)

DESCRIPTION

Apendice B -Full Source Code Listings

Citation preview

  • A P P E N D I X B

    Full Source CodeListings

    A P P E N D I X B

    Full Source CodeListings

    A P P E N D I X B

    Full Source CodeListings

  • Here you will find the full source code listings for the calculator application.The source files include the javadoc comments that are used to generate thecalculator application API documentation. The javadoc comments weremostly omitted in the books sessions. The packages are listed alphabetically,and the source files are listed alphabetically under their respective packages.

    Package com.wkndjava.calculatorThe com.wkndjava.calculator package contains only one classCalculator.

    Class Calculator/*

    * Calculator

    * The Calculator application

    */

    package com.wkndjava.calculator;

    import com.wkndjava.calculator.event.*;

    import com.wkndjava.calculator.exception.*;

    import com.wkndjava.calculator.gui.*;

    import java.awt.*;

    3

  • import java.awt.event.*;

    import java.applet.Applet;

    import java.io.*;

    import javax.swing.*;

    import javax.swing.event.*;

    import javax.swing.colorchooser.ColorSelectionModel;

    /**

    * The main class for the Calculator application.

    * Run this main class from the command line to start up the

    * Calculator application. If the Calculator should be run as

    * an applet, run

    * {@link com.wkndjava.calculator.gui.CalculatorApplet

    * CalculatorApplet}

    * instead.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class Calculator implements CalculatorKeypadListener,

    ActionListener {

    private CalculatorViewer view;

    private CalculatorHelper helper;

    private boolean needNewNumber = false;

    private int mode;

    /** Indicates Calculator is running in application mode */

    public final static int APPLICATION = 1;

    /** Indicates Calculator is running in applet mode */

    public final static int APPLET = 2;

    /**

    4 Learn Java In a Weekend

  • * Constructs a new Calculator object that

    * uses the given CalculatorViewer as its

    * view. This constructor method loads the color

    * preferences if it is being run as an application.

    * If the CalculatorViewer is an instance of

    * java.awt.Frame, it is considered to be an

    * application. If the CalculatorViewer

    * is an instance of java.applet.Applet,

    * it is considered to be an applet.

    *

    * @param ui A CalculatorViewer that will be

    * used as the view for the Calculator application.

    *

    * @throws CalculatorException if the given

    * CalculatorViewer object is not an applet

    * or a frame.

    */

    public Calculator(CalculatorViewer ui)

    throws CalculatorException {

    view = ui;

    helper = new CalculatorHelper();

    view.addCalculatorKeypadListener(this);

    view.addMenuActionListener(this);

    if (view instanceof Frame) {

    ((Frame)view).setVisible(true);

    mode = APPLICATION;

    //load saved colors

    System.out.println(Loading saved colors...);

    try {

    FileInputStream colorPrefs

    APPENDIX B Full Source Code Listings 5

  • = new FileInputStream(colors.pref);

    ObjectInputStream colorIn

    = new ObjectInputStream(colorPrefs);

    DigitalDisplay display = view.getDigitalDisplay();

    display.setBackground(

    (Color) colorIn.readObject());

    display.setUnlitColor(

    (Color) colorIn.readObject());

    display.setForeground(

    (Color) colorIn.readObject());

    colorIn.close();

    } catch (FileNotFoundException fnfe) {

    System.out.println(

    No saved preferences... using defaults);

    } catch (Exception e) {

    //quit if any exceptions occur

    System.out.println(

    Error occurred... using default colors);

    }

    }

    else if (view instanceof Applet) {

    mode = APPLET;

    }

    else throw new CalculatorException(CalculatorViewer

    + must be an instance of either Frame or Applet);

    System.out.println(The calculator is being started in

    + (mode == APPLET ? applet : application)

    + mode);

    }

    6 Learn Java In a Weekend

  • /**

    * The main method for the Calculator application. This

    * method is called if the Calculator is run as an

    * application

    * @param args The application does not accept command

    * line arguments

    */

    public static void main(String args[]) {

    try {

    new Calculator(new CalculatorView());

    } catch (CalculatorException e) {

    System.out.println(CalculatorException:

    + e.getMessage());

    }

    }

    /**

    * Implemented to handle CalculatorKeypadEvents

    *

    * @param event The CalculatorKeypadEvent object

    */

    public void calculatorKeyPressed(CalculatorKeypadEvent event) {

    CalculatorModel model;

    String key = event.getKey();

    if (CalculatorKeypadEvent.isNumerical(key)) {

    if (needNewNumber) {

    view.setDisplayValue(0.0);

    needNewNumber = false;

    APPENDIX B Full Source Code Listings 7

  • }view.appendDisplayDigit(Integer.parseInt(key));

    }

    else if (key.equals(CalculatorKeypadEvent.DECIMAL)) {

    view.appendDisplayDecimal();

    }

    else if (CalculatorKeypadEvent.isOperational(key)) {

    helper.setOperand(view.getDisplayValue());

    helper.setOp(key);

    model = helper.getCalculatorModel();

    view.setDisplayValue(model.getCurrentDisplayValue());

    needNewNumber = !key.equals(

    CalculatorKeypadEvent.SIGN);

    }

    else if (key.equals(CalculatorKeypadEvent.EQUALS)) {

    if (!needNewNumber) {

    helper.setOperand(view.getDisplayValue());

    }

    model = helper.performOperation();

    view.setDisplayValue(model.getCurrentDisplayValue());

    needNewNumber = true;

    }

    else if (key.equals(CalculatorKeypadEvent.C)) {

    model = helper.clear();

    view.setDisplayValue(model.getCurrentDisplayValue());

    }

    else if (key.equals(CalculatorKeypadEvent.AC)) {

    model = helper.clearAll();

    view.setDisplayValue(model.getCurrentDisplayValue());

    }

    8 Learn Java In a Weekend

  • else if (key.equals(CalculatorKeypadEvent.MS)) {

    helper.setOperand(view.getDisplayValue());

    model = helper.memSwap();

    view.setDisplayValue(model.getCurrentDisplayValue());

    }

    else if (key.equals(CalculatorKeypadEvent.MR)) {

    helper.setOperand(view.getDisplayValue());

    model = helper.memRecall();

    view.setDisplayValue(model.getCurrentDisplayValue());

    }

    else if (key.equals(CalculatorKeypadEvent.MC)) {

    helper.setOperand(view.getDisplayValue());

    model = helper.memClear();

    view.setDisplayValue(model.getCurrentDisplayValue());

    }

    else if (key.equals(CalculatorKeypadEvent.MADD)) {

    helper.setOperand(view.getDisplayValue());

    model = helper.memAdd();

    view.setDisplayValue(model.getCurrentDisplayValue());

    }

    else if (key.equals(CalculatorKeypadEvent.MSUBTRACT)) {

    helper.setOperand(view.getDisplayValue());

    model = helper.memSubtract();

    view.setDisplayValue(model.getCurrentDisplayValue());

    }

    view.updateAuditTrail(helper.getAuditTrail());

    }

    /**

    * Implemented to handle CalculatorMenu events.

    APPENDIX B Full Source Code Listings 9

  • ** @param even The java.awt.event.ActionEvent

    * objectthat is triggered by selecting a

    * CalculatorMenu item.

    */

    public void actionPerformed(ActionEvent event) {

    //these events should come from the views menu

    if (event.getSource() instanceof JMenuItem) {

    String selection

    = ((JMenuItem)event.getSource()).getText();

    if (selection.equals(CalculatorMenu.FILE_EXIT)) {

    System.exit(0);

    }

    else if (selection.equals(

    CalculatorMenu.VIEW_AUDIT_TRAIL)) {

    view.showAuditTrail(helper.getAuditTrail());

    }

    else if (selection.equals(

    CalculatorMenu.VIEW_COLOR_BACKGROUND)) {

    DigitalDisplay display = view.getDigitalDisplay();

    ColorUpdater colorUpd = new Calculator.ColorUpdater(

    ColorUpdater.BG, display.getBackground());

    colorUpd.updateColor();

    }

    else if (selection.equals(

    CalculatorMenu.VIEW_COLOR_UNLIT)) {

    DigitalDisplay display = view.getDigitalDisplay();

    10 Learn Java In a Weekend

  • ColorUpdater colorUpd

    = new Calculator.ColorUpdater(

    ColorUpdater.UNLIT, display.getUnlitColor());

    colorUpd.updateColor();

    }

    else if (selection.equals(

    CalculatorMenu.VIEW_COLOR_LIT)) {

    DigitalDisplay display = view.getDigitalDisplay();

    ColorUpdater colorUpd

    = new Calculator.ColorUpdater(

    ColorUpdater.LIT, display.getForeground());

    colorUpd.updateColor();

    }

    else if (selection.equals(

    CalculatorMenu.FILE_SAVE_AUDIT_TRAIL)) {

    StringBuffer at = new StringBuffer(

    helper.getAuditTrail());

    String nl = System.getProperty(line.separator);

    int nlIndex, place = 0;

    while ( (nlIndex

    = at.toString().indexOf(\n, place)) != -1) {

    at.replace(nlIndex, nlIndex + 1, nl);

    place = nlIndex + nl.length();

    }

    try {

    FileWriter writer

    = new FileWriter(audittrail.txt);

    writer.write(at.toString());

    writer.close();

    view.showInfo(

    APPENDIX B Full Source Code Listings 11

  • Saved audit trail as audittrail.txt);

    } catch (IOException e) {

    System.out.println(

    Unable to save audit trail:

    + e.getMessage());

    view.showInfo(Unable to save audit trail);

    }

    }

    else if (selection.equals(

    CalculatorMenu.FILE_SAVE_COLORS)) {

    System.out.println(Saving color preferences...);

    try {

    DigitalDisplay display

    = view.getDigitalDisplay();

    FileOutputStream cp

    = new FileOutputStream(colors.pref);

    ObjectOutputStream colorOut

    = new ObjectOutputStream(cp);

    colorOut.writeObject(display.getBackground());

    colorOut.writeObject(display.getUnlitColor());

    colorOut.writeObject(display.getForeground());

    colorOut.flush();

    colorOut.close();

    view.showInfo(

    Color preferences saved successfully);

    } catch (Exception e) {

    System.out.println(

    Unable to save color preferences:

    + e.getMessage());

    view.showInfo(

    12 Learn Java In a Weekend

  • Unable to save color preferences);

    }

    }

    }

    }

    private Color getUserColor(Color initial) {

    Color newColor;

    JColorChooser pal = new JColorChooser(initial);

    pal.setVisible(true);

    JDialog colorDialog = JColorChooser.createDialog(

    (Component)view, Choose a Color, true,

    pal, null, null);

    colorDialog.setVisible(true);

    colorDialog.dispose();

    return Color.green;

    }

    private class ColorUpdater

    implements ChangeListener, ActionListener {

    private final static int BG = 0;

    private final static int UNLIT = 1;

    private final static int LIT = 2;

    private int type;

    private Color initialColor;

    private JColorChooser chooser;

    private DigitalDisplay display;

    private ColorUpdater(int whichColor, Color initial) {

    type = whichColor;

    APPENDIX B Full Source Code Listings 13

  • initialColor = new Color(initial.getRGB());

    chooser = new JColorChooser(initialColor);

    chooser.getSelectionModel().addChangeListener(this);

    display = view.getDigitalDisplay();

    }

    public void updateColor() {

    JDialog colorDialog

    = JColorChooser.createDialog((Component)view,

    Choose a color, true, chooser, null, this);

    colorDialog.setVisible(true);

    colorDialog.dispose();

    }

    /* cancel listener for color chooser */

    public void actionPerformed(ActionEvent e) {

    updateDisplayColor(initialColor);

    }

    /* listens for color choser updates */

    public void stateChanged(ChangeEvent e) {

    if (e.getSource() instance ofColorSelectionModel) {

    ColorSelectionModel csm

    = (ColorSelectionModel)e.getSource();

    updateDisplayColor(csm.getSelectedColor());

    }

    }

    private void updateDisplayColor(Color newColor) {

    switch(type) {

    14 Learn Java In a Weekend

  • case BG:

    display.setBackground(newColor);

    break;

    case UNLIT:

    display.setUnlitColor(newColor);

    break;

    case LIT:

    display.setForeground(newColor);

    }

    }

    }

    }

    package.html

    Contains the Calculator application main file

    Package com.wkndjava.calculator.eventThe com.wkndjava.calculator.event package contains event classes andinterfaces for the calculator application.

    Class CalculatorKeyMap/*

    * CalculatorKeyMap.java

    * Maps KeyEvent keys to CalculatorKeypadEvent keys

    */

    package com.wkndjava.calculator.event;

    APPENDIX B Full Source Code Listings 15

  • import java.awt.event.KeyEvent;

    /**

    * Maps java.awt.event.KeyEvent keys to

    * CalculatorKeypadEvent keys.

    * This class conatains only static fields and methods and

    * cannot be instantiated. The CalculatorKeypad

    * component uses this map to map keyboard-generated events

    * to the CalculatorKeypadEvent keys to facilitate

    * application event handling.

    * java.awt.event.KeyEvents are captured and

    * mapped to corresponding CalculatorKeypadEvents,

    * which are fired instead of the keyboard-generated events.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class CalculatorKeyMap {

    /**

    * Signifies that a java.awt.event.KeyEvent is

    * unknown to the Calculator application and cannot be mapped

    */

    public final static String UNKNOWN = ?;

    //cannot be instantiated

    private CalculatorKeyMap() {}

    /**

    * Maps the given java.awt.event.KeyEvent to its

    16 Learn Java In a Weekend

  • * CalculatorKeypadEvent counterpart

    *

    * @param The java.awt.event.KeyEvent to map

    *

    * @return a

    * {@link CalculatorKeypadEvent

    * CalculatorKeypadEvent}

    * constant, which corresponds to the

    * java.awt.event.KeyEvent

    */

    public static String map(KeyEvent ke) {

    switch(ke.getKeyCode()) {

    case KeyEvent.VK_0:

    case KeyEvent.VK_NUMPAD0:

    return CalculatorKeypadEvent.CK0;

    case KeyEvent.VK_1:

    case KeyEvent.VK_NUMPAD1:

    return CalculatorKeypadEvent.CK1;

    case KeyEvent.VK_2:

    case KeyEvent.VK_NUMPAD2:

    return CalculatorKeypadEvent.CK2;

    case KeyEvent.VK_3:

    case KeyEvent.VK_NUMPAD3:

    return CalculatorKeypadEvent.CK3;

    case KeyEvent.VK_4:

    case KeyEvent.VK_NUMPAD4:

    return CalculatorKeypadEvent.CK4;

    case KeyEvent.VK_5:

    case KeyEvent.VK_NUMPAD5:

    return CalculatorKeypadEvent.CK5;

    APPENDIX B Full Source Code Listings 17

  • case KeyEvent.VK_6:

    case KeyEvent.VK_NUMPAD6:

    return CalculatorKeypadEvent.CK6;

    case KeyEvent.VK_7:

    case KeyEvent.VK_NUMPAD7:

    return CalculatorKeypadEvent.CK7;

    case KeyEvent.VK_8:

    case KeyEvent.VK_NUMPAD8:

    return CalculatorKeypadEvent.CK8;

    case KeyEvent.VK_9:

    case KeyEvent.VK_NUMPAD9:

    return CalculatorKeypadEvent.CK9;

    case KeyEvent.VK_DECIMAL:

    case KeyEvent.VK_PERIOD:

    return CalculatorKeypadEvent.DECIMAL;

    case KeyEvent.VK_ADD:

    return CalculatorKeypadEvent.ADD;

    case KeyEvent.VK_SUBTRACT:

    if (ke.getModifiers() == KeyEvent.ALT_MASK) {

    return CalculatorKeypadEvent.SIGN;

    }

    else {

    return CalculatorKeypadEvent.SUBTRACT;

    }

    case KeyEvent.VK_MULTIPLY:

    return CalculatorKeypadEvent.MULTIPLY;

    case KeyEvent.VK_DIVIDE:

    return CalculatorKeypadEvent.DIVIDE;

    case KeyEvent.VK_ENTER:

    case KeyEvent.VK_EQUALS:

    18 Learn Java In a Weekend

  • return CalculatorKeypadEvent.EQUALS;

    case KeyEvent.VK_DELETE:

    if (ke.getModifiers() == KeyEvent.ALT_MASK) {

    return CalculatorKeypadEvent.AC;

    }

    else {

    return CalculatorKeypadEvent.C;

    }

    case KeyEvent.VK_F2:

    return CalculatorKeypadEvent.POW;

    case KeyEvent.VK_F3:

    return CalculatorKeypadEvent.SQRT;

    case KeyEvent.VK_F4:

    return CalculatorKeypadEvent.MS;

    case KeyEvent.VK_F5:

    return CalculatorKeypadEvent.MR;

    case KeyEvent.VK_F6:

    return CalculatorKeypadEvent.MC;

    case KeyEvent.VK_F7:

    return CalculatorKeypadEvent.MADD;

    case KeyEvent.VK_F8:

    return CalculatorKeypadEvent.MSUBTRACT;

    default:

    return UNKNOWN;

    }

    }

    }

    APPENDIX B Full Source Code Listings 19

  • Class CalculatorKeypadEvent/*

    * CalculatorKeypadEvent.java

    */

    package com.wkndjava.calculator.event;

    import java.util.EventObject;

    import javax.swing.JButton;

    /**

    * Encapsulates events fired by the CalculatorKeypad

    * component.This event class contains constants that represent

    * the labels of the CalculatorKeypad buttons. It

    * also has methods for obtaining more specific information

    * about a particular CalculatorKeypadEvent

    * instance.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class CalculatorKeypadEvent extends EventObject {

    /** The key for the Memory Recall operation */

    public final static String MR = MR;

    /** The key for the Memory Clear operation */

    public final static String MC = MC;

    /** The key for the Memory Add operation */

    public final static String MADD = M+;

    /** The key for the Memory Subtract operation */

    20 Learn Java In a Weekend

  • public final static String MSUBTRACT = M-;

    /** The key for the Memory Swap operation */

    public final static String MS = MS;

    /** The key for the Square Root operation */

    public final static String SQRT = SQRT;

    /** The key for the Clear operation */

    public final static String C = C;

    /** The key for the All Clear operation */

    public final static String AC = AC;

    /** The key for the Power operation */

    public final static String POW = POW;

    /** The key for the Divide operation */

    public final static String DIVIDE = String.valueOf((char)247);

    /** The key for the Multiply operation */

    public final static String MULTIPLY

    = String.valueOf((char)215);

    /** The key for the Subtract operation */

    public final static String SUBTRACT = -;

    /** The key for the Number 7 */

    public final static String CK7 = 7;

    /** The key for the Number 8 */

    public final static String CK8 = 8;

    /** The key for the Number 9 */

    public final static String CK9 = 9;

    /** The key for the Sign operation */

    public final static String SIGN = String.valueOf((char)177);

    /** The key for the Number 4 */

    public final static String CK4 = 4;

    APPENDIX B Full Source Code Listings 21

  • /** The key for the Number 5 */

    public final static String CK5 = 5;

    /** The key for the Number 6 */

    public final static String CK6 = 6;

    /** The key for the Add operation */

    public final static String ADD = +;

    /** The key for the Number 1 */

    public final static String CK1 = 1;

    /** The key for the Number 2 */

    public final static String CK2 = 2;

    /** The key for the Number 3 */

    public final static String CK3 = 3;

    /** The key for the Equals operation */

    public final static String EQUALS = =;

    /** The key for the Number 0 */

    public final static String CK0 = 0;

    /** The key for the Decimal Point */

    public final static String DECIMAL = .;

    /** Stores the key value for this

    * CalculatorKeypadEvent.

    */

    private String key;

    /**

    * Constructs a new CalculatorKeypadEvent

    * object, with the given source object and key.

    *

    * @param source The object that fired this

    * CalculatorKeypadEvent

    22 Learn Java In a Weekend

  • * @param keyString The key that is associated with this

    * event. One of the static constant key value strings

    * should be passed in here.

    */

    public CalculatorKeypadEvent(Object source, String keyString) {

    super(source);

    key = keyString;

    }

    /**

    * Gets the key associated with this

    * CalculatorKeypadEvent. The returned key

    * can be compared to the static key value strings

    * defined in this class.

    *

    * @return A String value that represents the

    * CalculatorKeypad

    * key that fired this CalculatorKeypadEvent

    */

    public String getKey() {

    return key;

    }

    /**

    * Returns true if given key represents a

    * numerical key. This method attempts to parse the

    * keyValue argument to an integer using the

    * Integer.parseInt(int) method.

    * If it is successful, the key is numerical and this

    * method returns true, else it returns

    APPENDIX B Full Source Code Listings 23

  • * false.

    *

    * @param keyValue The String key value to check

    *

    * @return true if the given key represents

    * a numerical key.

    */

    public static boolean isNumerical(String keyValue) {

    try {

    Integer.parseInt(keyValue);

    return true;

    } catch (NumberFormatException nfe) {

    return false;

    }

    }

    /**

    * Returns true if the given key represents

    * an operational key. The key is considered to be an

    * operational key if it is equal to one of the

    * following constants:

    *

    * {@link #ADD ADD}

    * {@link #SUBTRACT SUBTRACT}

    * {@link #MULTIPLY MULTIPLY}

    * {@link #DIVIDE DIVIDE}

    * {@link #SQRT SQRT}

    * {@link #POW POW}

    * {@link #SIGN SIGN}

    *

    *

    24 Learn Java In a Weekend

  • * @param keyValue The String key value to check

    *

    * @return true if the given key represents

    * an operational key

    */

    public static boolean isOperational(String keyValue) {

    if (keyValue.equals(ADD) || keyValue.equals(SUBTRACT)

    || keyValue.equals(MULTIPLY) || keyValue.equals(DIVIDE)

    || keyValue.equals(SQRT) || keyValue.equals(POW)

    || keyValue.equals(SIGN) ) {

    return true;

    }

    return false;

    }

    /**

    * Returns true if the given key represents

    * a memory operational key. The key is considered to be

    * an operational key if it is equal to one of the

    * following constants:

    *

    * {@link #MADD MADD}

    * {@link #MC MC}

    * {@link #MR MR}

    * {@link #MS MS}

    * {@link #MSUBTRACT MSUBTRACT}

    *

    *

    * @param keyValue The String key value to check

    *

    APPENDIX B Full Source Code Listings 25

  • * @return true if the given key represents

    * a memory operational key

    */

    public static boolean isMemOperational(String keyValue) {

    if (keyValue.equals(MADD) || keyValue.equals(MC)

    || keyValue.equals(MR) || keyValue.equals(MS)

    || keyValue.equals(MSUBTRACT)) {

    return true;

    }

    return false;

    }

    /**

    * Indicates if the current operator is binary or unary.

    * The operation is considered binary if it operates on two

    * operands, or unary if it operates on only one operand.

    *

    * @return true if the current operator is binary.

    */

    public static boolean isOpBinary(String op) {

    return op.equals(ADD) || op.equals(SUBTRACT)

    || op.equals(MULTIPLY)

    || op.equals(DIVIDE) || op.equals(POW);

    }

    }

    26 Learn Java In a Weekend

  • Interface CalculatorKeypadListener/*

    * CalculatorKeypadListener.java

    */

    package com.wkndjava.calculator.event;

    /**

    * This interface contains methods that are associated with

    * CalculatorKeypadEvents. Any class that is

    * interested in registering as a listener for these types of

    * events should implement this interface.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public interface CalculatorKeypadListener extends

    java.util.EventListener {

    /**

    * This method is called to notify

    * CalculatorKeypadListeners of a

    * CalculatorKeypadEvent.

    * CalculatorKeypadEvents are typically

    * triggered by a user pressing the

    * CalculatorKeypad buttons.

    */

    public void calculatorKeyPressed(CalculatorKeypadEvent event);

    }

    APPENDIX B Full Source Code Listings 27

  • package.html

    Contains event classes and interfaces for the Calculator

    application

    Package com.wkndjava.calculator.exceptionThe com.wkndjava.calculator.exception package contains exceptionclasses for the calculator application.

    Exception CalculatorException/*

    * CalculatorException

    */

    package com.wkndjava.calculator.exception;

    /**

    * A generic Exception for the Calculator application.

    */

    public class CalculatorException extends java.lang.Exception {

    /**

    * Constructs a CalculatorException with

    * the default message.

    */

    public CalculatorException() {

    this(Calculator Exception);

    }

    28 Learn Java In a Weekend

  • /**

    * Constructs a CalculatorException with

    * the given message.

    *

    * @param msg A message that explains this exception

    */

    public CalculatorException(String msg) {

    super(msg);

    }

    }

    Exception DigitalDisplayOverflowException/*

    * DigitalDisplayOverflowException

    */

    package com.wkndjava.calculator.exception;

    /**

    * An exception that indicates that a DigitalDisplay cannot

    * display a number due to the size of the number exceeding

    * the displays display capacity. The

    * {@link com.wkndjava.calculator.gui.DigitalDisplay

    * DigitalDisplay} component throws this exception

    * if it cannot display a particular number for any other

    * reason, such as NaN, or infinity.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class DigitalDisplayOverflowException extends Exception {

    APPENDIX B Full Source Code Listings 29

  • /**

    * Constructs a DigitalDisplayOverflowException

    * with the default message.

    */

    public DigitalDisplayOverflowException() {

    this(DigitalDisplay Overflow Exception);

    }

    /**

    * Constructs a DigitalDisplayOverflowException

    * with the given message.

    *

    * @param msg a message that explains this exception

    */

    public DigitalDisplayOverflowException(String msg) {

    super(msg);

    }

    }

    package.html

    Contains exceptions for the Calculator application

    Package com.wkndjava.calculator.guiThe com.wkndjava.calculator.gui package contains GUI classes and theassociated helper classes that are responsible for the calculators graphicaluser interface.

    30 Learn Java In a Weekend

  • Class AuditTrailView/*

    * AuditTrailView

    * A dialog window for viewing the calculators audit trail

    */

    package com.wkndjava.calculator.gui;

    import java.awt.*;

    import javax.swing.*;

    /**

    * A dialog window for viewing the Calculators audit trail.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class AuditTrailView extends JDialog {

    private JTextArea trail;

    public AuditTrailView(Frame owner, String atText) {

    super(owner, Audit Trail Viewer);

    trail = new JTextArea(atText, 25, 45);

    trail.setFont(new Font(Monospaced, Font.PLAIN, 10));

    trail.setEditable(false);

    JScrollPane scrollPane = new JScrollPane(trail);

    APPENDIX B Full Source Code Listings 31

  • getContentPane().add(scrollPane, BorderLayout.CENTER);

    setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);

    pack();

    }

    /**

    * Sets the audit trail text.

    *

    * @param atText The audit trail text to display

    */

    public void setText(String atText) {

    trail.setText(atText);

    }

    /**

    * Gets the currently displayed audit trail text.

    *

    * @return The currently displayed audit trail text.

    */

    public String getText() {

    return trail.getText();

    }

    }

    Class CalculatorApplet/*

    * CalculatorApplet.java

    * Runs the Calculator as an applet

    32 Learn Java In a Weekend

  • */

    package com.wkndjava.calculator.gui;

    import com.wkndjava.calculator.Calculator;

    import com.wkndjava.calculator.event.*;

    import com.wkndjava.calculator.exception.*;

    import javax.swing.*;

    import java.awt.*;

    import java.awt.event.*;

    /**

    * The view for the Calculator application when it is running

    * in applet mode. Include this class in the

    * tag of an HTML document to run the Calculator as an applet. To

    * run the Calculator as an application, run

    * {@link com.wkndjava.calculator.Calculator

    * com.wkndjava.calculator.Calculator} instead.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class CalculatorApplet extends JApplet

    implements CalculatorViewer {

    private DigitalDisplay display;

    private CalculatorKeypad keypad;

    private CalculatorMenu menu;

    private AuditTrailView auditTrailViewer;

    APPENDIX B Full Source Code Listings 33

  • /**

    * Overrides the javax.swing.JApplet method to

    * initialize the Calculator applet.

    */

    public void init() {

    Container content = getContentPane();

    menu = new CalculatorMenu(Calculator.APPLET);

    setJMenuBar(menu);

    display = new DigitalDisplay(9, 0.0, true,

    new Color(88, 207, 233),

    new Color(30, 189, 223), Color.black);

    content.add(display, BorderLayout.NORTH);

    keypad = new CalculatorKeypad();

    content.add(keypad, BorderLayout.CENTER);

    try {

    Calculator controller = new Calculator(this);

    } catch (CalculatorException e) {

    e.printStackTrace();

    System.out.println(CalculatorException:

    + e.getMessage());

    showStatus(e.getMessage());

    }

    }

    public void setDisplayValue(double value) {

    34 Learn Java In a Weekend

  • try {

    display.setDoubleValue(value);

    } catch (DigitalDisplayOverflowException e) {

    System.out.println(DigitalDisplayOverflow:

    + e.getMessage());

    } finally {

    display.updateDisplay();

    }

    }

    public double getDisplayValue() {

    return display.getDoubleValue();

    }

    public void appendDisplayDigit(int appendInt) {

    display.appendDigit(appendInt);

    }

    public void appendDisplayDecimal() {

    display.appendDecimal();

    }

    public void addCalculatorKeypadListener(

    CalculatorKeypadListener ckl) {

    keypad.addCalculatorKeypadListener(ckl);

    }

    public void addMenuActionListener(ActionListener al) {

    menu.addMenuActionListener(al);

    }

    APPENDIX B Full Source Code Listings 35

  • public void showAuditTrail(String atText) {

    if (auditTrailViewer == null) {

    auditTrailViewer = new AuditTrailView(new JFrame(),

    atText);

    }

    else {

    auditTrailViewer.setText(atText);

    }

    auditTrailViewer.setVisible(true);

    }

    public void updateAuditTrail(String atText) {

    if (auditTrailViewer != null

    && auditTrailViewer.isVisible()) {

    auditTrailViewer.setText(atText);

    }

    }

    public DigitalDisplay getDigitalDisplay() {

    return display;

    }

    public void showInfo(String message) {

    JOptionPane.showMessageDialog(this, message);

    }

    }

    36 Learn Java In a Weekend

  • Class CalculatorHelper/*

    * CalculatorHelper

    * A class that performs mathematical functions for a Calculator

    * program.

    */

    package com.wkndjava.calculator.gui;

    import com.wkndjava.calculator.event.*;

    /**

    * Performs mathematical functions and maintains the

    * CalculatorModel component for the Calculator

    * application.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class CalculatorHelper {

    private CalculatorModel calcModel;

    private StringBuffer auditTrail;

    private boolean opPerformed;

    private int decimalPos;

    /**

    * Constructs a new CalculatorHelper object with

    * the default decimal point alignment for the audit trail.

    */

    APPENDIX B Full Source Code Listings 37

  • public CalculatorHelper() {

    this(20);

    }

    /**

    * Constructs a new CalculatorHelper object with

    * the given decimal point alignment for the audit trail.

    *

    * @param decimalAlignmentPos The character position for the

    * decimal point alignment for the audit trail. All numbers

    * printed in the audit trail

    * will be aligned by their decimal points at this position.

    */

    public CalculatorHelper(int decimalAlignmentPos) {

    calcModel = new CalculatorModel();

    auditTrail = new StringBuffer();

    decimalPos = decimalAlignmentPos;

    }

    private CalculatorModel performUnaryOperation(String op) {

    double value;

    if (op.equals(CalculatorKeypadEvent.SIGN)) {

    value = sign();

    }

    else if (op.equals(CalculatorKeypadEvent.SQRT)) {

    value = sqrt();

    }

    else {

    return calcModel;

    }

    38 Learn Java In a Weekend

  • auditTrail.append(align([ + op

    + + calcModel.getCurrentDisplayValue()

    + ]) + \n);

    calcModel.setCurrentDisplayValue(value);

    setOperand(value);

    return calcModel;

    }

    /**

    * Performs the current operation on the current operands.

    *

    * @return The affected CalculatorModel object

    */

    public CalculatorModel performOperation() {

    double value;

    if (CalculatorKeypadEvent.isOpBinary(

    calcModel.getCurrentOp())) {

    auditTrail.append(align(calcModel.getCurrentOp() +

    + calcModel.getOperand2()) + \n);

    }

    else if (!calcModel.getCurrentOp().equals(

    CalculatorModel.NONE)) {

    auditTrail.append(calcModel.getCurrentOp() + \n);

    }

    String op = calcModel.getCurrentOp();

    if (op.equals(CalculatorKeypadEvent.ADD)) {

    value = add();

    }

    APPENDIX B Full Source Code Listings 39

  • else if (op.equals(CalculatorKeypadEvent.SUBTRACT)) {

    value = subtract();

    }

    else if (op.equals(CalculatorKeypadEvent.MULTIPLY)) {

    value = multiply();

    }

    else if (op.equals(CalculatorKeypadEvent.DIVIDE)) {

    value = divide();

    }

    else if (op.equals(CalculatorKeypadEvent.POW)) {

    value = pow();

    }

    else if (op.equals(CalculatorKeypadEvent.SQRT)) {

    value = sqrt();

    }

    else if (op.equals(CalculatorKeypadEvent.SIGN)) {

    value = sign();

    }

    else {

    value = calcModel.getCurrentDisplayValue();

    calcModel.setOperand1(value);

    calcModel.setOperand2(0.0);

    }

    calcModel.setCurrentDisplayValue(value);

    //makes the currently displayed value ready for another op

    calcModel.setOperand1(value);

    opPerformed = true;

    auditTrail.append(

    =============================================\n

    40 Learn Java In a Weekend

  • + align(String.valueOf(value)) + \n);

    return calcModel;

    }

    /**

    * Returns the CalculatorModel that this

    * CalculatorHelper is operating on.

    *

    * @return The CalculatorModel object.

    */

    public CalculatorModel getCalculatorModel() {

    return calcModel;

    }

    /**

    * Sets an operand to the given double value.

    * Follows specific rules to determine whether to set the

    * first or the second operand. In general, if the first

    * operand is already set, it sets the second operand.

    *

    * @param value The number to set to the operand.

    *

    * @return The affected CalculatorModel object.

    */

    public CalculatorModel setOperand(double value) {

    if (CalculatorKeypadEvent.isOpBinary(

    calcModel.getCurrentOp())

    && !opPerformed) {

    calcModel.setOperand2(value);

    }

    APPENDIX B Full Source Code Listings 41

  • else {

    auditTrail.append(\n

    + align(String.valueOf(value)) + \n);

    calcModel.setOperand1(value);

    calcModel.setOperand2(0.0);

    calcModel.setCurrentOp(CalculatorModel.NONE);

    }

    calcModel.setCurrentDisplayValue(value);

    return calcModel;

    }

    /**

    * Sets the operation to the given operation. Automatically

    * performs the operation if it is unary.

    *

    * @param op The operation to set. Should equal one of the

    * operational

    * {@link com.wkndjava.calculator.event.CalculatorKeypadEvent

    * CalculatorKeypadEvent} constants.

    *

    * @see com.wkndjava.calculator.event.* CalculatorKeypadEvent#isOperational(String)

    */

    public CalculatorModel setOp(String op) {

    //automatically perform unary operations

    if (!CalculatorKeypadEvent.isOpBinary(op)) {

    return performUnaryOperation(op);

    }

    if (opPerformed == false

    && !calcModel.getCurrentOp().equals(

    42 Learn Java In a Weekend

  • CalculatorModel.NONE)) {

    performOperation();

    }

    opPerformed = false;

    calcModel.setCurrentOp(op);

    return calcModel;

    }

    /**

    * Performs the Memory Add operation by adding the current

    * number to the number in memory, storing the result back

    * in memory.

    *

    * @return The affected CalculatorModel object

    */

    public CalculatorModel memAdd() {

    calcModel.setMem(calcModel.getMem()

    + calcModel.getCurrentDisplayValue());

    return calcModel;

    }

    /**

    * Performs the Memory Subtract operation by subtracting

    * the current number from the number in memory, storing

    * the result back in memory.

    *

    * @return The affected CalculatorModel object

    */

    public CalculatorModel memSubtract() {

    calcModel.setMem(calcModel.getMem()

    APPENDIX B Full Source Code Listings 43

  • - calcModel.getCurrentDisplayValue());

    return calcModel;

    }

    /**

    * Performs the Memory Recall operation by displaying the

    * number currently in memory

    *

    * @return The affected CalculatorModel object

    */

    public CalculatorModel memRecall() {

    setOperand(calcModel.getMem());

    return calcModel;

    }

    /**

    * Performs the Memory Swap function by swapping the currently

    * displayed number with the number in memory.

    *

    * @return the affected CalculatorModel object

    */

    public CalculatorModel memSwap() {

    double swapVal = calcModel.getMem();

    calcModel.setMem(calcModel.getCurrentDisplayValue());

    setOperand(swapVal);

    return calcModel;

    }

    /**

    * Performs the Memory Clear operation by setting the memory

    44 Learn Java In a Weekend

  • * value to 0.0

    *

    * @return The affected CalculatorModel object

    */

    public CalculatorModel memClear() {

    calcModel.setMem(0.0);

    return calcModel;

    }

    /**

    * Clears the current operand.

    *

    * @return The affected CalculatorModel object

    */

    public CalculatorModel clear() {

    //clears second operand if binary operation in progress

    setOperand(0.0);

    return calcModel;

    }

    /**

    * Clears everything except the memory value

    *

    * @return The affected CalculatorModel object

    */

    public CalculatorModel clearAll() {

    calcModel.setOperand1(0.0);

    calcModel.setOperand2(0.0);

    calcModel.setCurrentDisplayValue(0.0);

    calcModel.setCurrentOp(CalculatorModel.NONE);

    APPENDIX B Full Source Code Listings 45

  • opPerformed = false;

    return calcModel;

    }

    /**

    * Returns the audit trail that is built as operand are set

    * and operations are performed.

    */

    public String getAuditTrail() {

    return auditTrail.toString();

    }

    private String align(String decimalString) {

    String aligned = decimalString;

    int currDecPos = aligned.lastIndexOf(.);

    for (int pos = currDecPos; pos < decimalPos; pos++) {

    aligned = + aligned;

    }

    return aligned;

    }

    private double add() {

    return calcModel.getOperand1() + calcModel.getOperand2();

    }

    private double subtract() {

    return calcModel.getOperand1() - calcModel.getOperand2();

    }

    private double multiply() {

    46 Learn Java In a Weekend

  • return calcModel.getOperand1() * calcModel.getOperand2();

    }

    private double divide() {

    return calcModel.getOperand1() / calcModel.getOperand2();

    }

    private double pow() {

    return Math.pow(calcModel.getOperand1(),

    calcModel.getOperand2());

    }

    private double sqrt() {

    return Math.sqrt(calcModel.getCurrentDisplayValue());

    }

    private double sign() {

    return calcModel.getCurrentDisplayValue() * -1;

    }

    }

    Class CalculatorKeypad/*

    * CalculatorKeypad

    * A JPanel subclass that contains a set of buttons for a

    * calculator

    */

    package com.wkndjava.calculator.gui;

    APPENDIX B Full Source Code Listings 47

  • import com.wkndjava.calculator.event.*;

    import java.awt.*;

    import java.awt.event.*;

    import javax.swing.*;

    import java.util.*;

    /**

    * A subclass of javax.swing.JPanel that contains a

    * set of buttons for the Calculator application.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class CalculatorKeypad extends JPanel {

    private JButton[] buttons;

    private Vector listeners;

    /**

    * Constructs the CalculatorKeypad component.

    */

    public CalculatorKeypad() {

    super();

    GridBagLayout gbl = new GridBagLayout();

    GridBagConstraints gbc = new GridBagConstraints();

    gbc.fill = GridBagConstraints.BOTH;

    gbc.weightx = gbc.weighty = 1.0;

    gbc.ipadx = gbc.ipady = 5;

    48 Learn Java In a Weekend

  • // bLabels is an array of button labels in add order

    String[] bLabels = { CalculatorKeypadEvent.MR,

    CalculatorKeypadEvent.MC,

    CalculatorKeypadEvent.MADD,

    CalculatorKeypadEvent.MSUBTRACT,

    CalculatorKeypadEvent.MS,

    CalculatorKeypadEvent.SQRT,

    CalculatorKeypadEvent.C,

    CalculatorKeypadEvent.AC,

    CalculatorKeypadEvent.POW,

    CalculatorKeypadEvent.DIVIDE,

    CalculatorKeypadEvent.MULTIPLY,

    CalculatorKeypadEvent.SUBTRACT,

    CalculatorKeypadEvent.CK7,

    CalculatorKeypadEvent.CK8,

    CalculatorKeypadEvent.CK9,

    CalculatorKeypadEvent.SIGN,

    CalculatorKeypadEvent.CK4,

    CalculatorKeypadEvent.CK5,

    CalculatorKeypadEvent.CK6,

    CalculatorKeypadEvent.ADD,

    CalculatorKeypadEvent.CK1,

    CalculatorKeypadEvent.CK2,

    CalculatorKeypadEvent.CK3,

    CalculatorKeypadEvent.EQUALS,

    CalculatorKeypadEvent.CK0,

    CalculatorKeypadEvent.DECIMAL };

    //there are four columns of buttons

    int cols = 4;

    APPENDIX B Full Source Code Listings 49

  • //build the Button array and add to Panel

    buttons = new JButton[bLabels.length];

    setLayout(gbl);

    ActionEventHandler actionListener

    = new ActionEventHandler();

    KeyEventListener keyListener = new KeyEventListener();

    for (int b = 0; b < buttons.length; b++) {

    buttons[b] = new JButton(bLabels[b]);

    //set different constraints

    if (bLabels[b].equals(=)) {

    // = spans two rows

    gbc.gridheight = 2;

    gbc.gridwidth = GridBagConstraints.REMAINDER;

    }

    else if (bLabels[b].equals(0)) {

    // 0 spans two cols

    gbc.gridy = 6;

    gbc.gridx = 0;

    gbc.gridwidth = 2;

    gbc.gridheight = 1;

    }

    else if (bLabels[b].equals(3)) {

    gbc.gridheight = 1;

    gbc.gridwidth = GridBagConstraints.RELATIVE;

    }

    else if ((b + 1) % cols == 0) {

    gbc.gridheight = 1;

    //end a row

    50 Learn Java In a Weekend

  • gbc.gridwidth = GridBagConstraints.REMAINDER;

    }

    else {

    // for the . button to be next to the 0

    gbc.gridx = GridBagConstraints.RELATIVE;

    gbc.gridheight = 1;

    gbc.gridwidth = 1;

    }

    //set the constraints and add it to the panel

    buttons[b].setFont(

    new Font(Helvetica, Font.BOLD, 14));

    gbl.setConstraints(buttons[b], gbc);

    buttons[b].addActionListener(actionListener);

    buttons[b].addKeyListener(keyListener);

    add(buttons[b]);

    listeners = new Vector();

    }

    }

    private class ActionEventHandler implements ActionListener {

    public void actionPerformed(ActionEvent event) {

    CalculatorKeypadEvent cke

    = new CalculatorKeypadEvent(event.getSource(),

    ((JButton)event.getSource()).getText());

    Iterator i = listeners.iterator();

    CalculatorKeypadListener ckl;

    while(i.hasNext()) {

    ckl = (CalculatorKeypadListener)i.next();

    APPENDIX B Full Source Code Listings 51

  • ckl.calculatorKeyPressed(cke);

    }

    }

    }

    private class KeyEventListener extends KeyAdapter {

    public void keyPressed(KeyEvent event) {

    String key = CalculatorKeyMap.map(event);

    if (key != CalculatorKeyMap.UNKNOWN) {

    CalculatorKeypadEvent cke

    = new CalculatorKeypadEvent(

    event.getSource(), key);

    Iterator i = listeners.iterator();

    CalculatorKeypadListener ckl;

    while (i.hasNext()) {

    ckl = (CalculatorKeypadListener)i.next();

    ckl.calculatorKeyPressed(cke);

    }

    }

    }

    }

    /**

    * Registers a CalculatorKeypadListener to listen

    * to events that this CalculatorKeypad triggers.

    *

    * @param The CalculatorKeypadListener

    * to register.

    */

    public void addCalculatorKeypadListener(

    52 Learn Java In a Weekend

  • CalculatorKeypadListener ckl) {

    if (ckl == null) return;

    listeners.add(ckl);

    }

    /**

    * Returns an array of CalculatorKeypadListener

    * objects that are registered.

    *

    * @return an array of registered

    * CalculatorKeypadListeners

    */

    public CalculatorKeypadListener[] getCalculatorKeypadListeners() {

    return (CalculatorKeypadListener[]) listeners.toArray();

    }

    }

    Class CalculatorMenu/*

    * CalculatorMenu

    * The menu for the Calculator program

    */

    package com.wkndjava.calculator.gui;

    import com.wkndjava.calculator.Calculator;

    import com.wkndjava.calculator.gui.*;

    APPENDIX B Full Source Code Listings 53

  • import javax.swing.*;

    import java.awt.event.*;

    import java.util.*;

    /**

    * The menu for the Calculator application. To handle events fired

    * by this menu, register an ActionListener by calling

    * the {@link #addMenuActionListener(ActionListener)

    * addMenuActionListener()}

    * method. Then compare the source

    * (a javax.swing.JMenuItem object) text to one of the

    * static constants to determine which action to perform.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class CalculatorMenu extends JMenuBar {

    private int appType;

    private Vector menuItems;

    //static constants represent menu items

    /** Represents the File->Exit menu option */

    public final static String FILE_EXIT = Exit;

    /** Represents the File->Save Audit Trail menu option */

    public final static String FILE_SAVE_AUDIT_TRAIL

    = Save Audit Trail;

    /** Represents the File->Save Colors menu option */

    public final static String FILE_SAVE_COLORS

    = Save Color Preferences;

    /** Represents the View->Audit Trail menu option */

    public final static String VIEW_AUDIT_TRAIL = Audit Trail;

    54 Learn Java In a Weekend

  • /** Represents the View->Color Background menu option */

    public final static String VIEW_COLOR_BACKGROUND

    = Background Color;

    /** Represents the View->Color Unlit menu option */

    public final static String VIEW_COLOR_UNLIT = Unlit Color;

    /** Represents the View->Color Lit menu option */

    public final static String VIEW_COLOR_LIT = Lit Color;

    /**

    * Constructs a CalculatorMenu object with the

    * given calculator mode.

    *

    * @param type The type is either

    * {@link com.wkndjava.calculator.Calculator#APPLICATION

    * Calculator.APPLICATION}

    * or

    * {@link com.wkndjava.calculator.Calculator#APPLET

    * Calculator.APPLET}

    * and determines whether or not file operations are enabled

    */

    public CalculatorMenu(int type) {

    super();

    switch (type) {

    case Calculator.APPLICATION:

    case Calculator.APPLET:

    appType = type;

    break;

    default:

    appType = Calculator.APPLET;

    APPENDIX B Full Source Code Listings 55

  • }populateMenu();

    }

    private void populateMenu() {

    menuItems = new Vector();

    // File menu

    JMenu file = new JMenu(File);

    if (appType == Calculator.APPLET) {

    file.setEnabled(false);

    }

    JMenuItem fileSaveAt

    = new JMenuItem(FILE_SAVE_AUDIT_TRAIL);

    menuItems.add(fileSaveAt);

    file.add(fileSaveAt);

    JMenuItem fileSaveColors = new JMenuItem(FILE_SAVE_COLORS);

    menuItems.add(fileSaveColors);

    file.add(fileSaveColors);

    file.addSeparator();

    JMenuItem fileExit = new JMenuItem(FILE_EXIT);

    menuItems.add(fileExit);

    file.add(fileExit);

    add(file);

    //view menu

    56 Learn Java In a Weekend

  • JMenu view = new JMenu(View);

    JMenuItem viewAt = new JMenuItem(VIEW_AUDIT_TRAIL);

    menuItems.add(viewAt);

    view.add(viewAt);

    //color submenu

    JMenu colors = new JMenu(Color);

    JMenuItem bkgColor = new JMenuItem(VIEW_COLOR_BACKGROUND);

    menuItems.add(bkgColor);

    colors.add(bkgColor);

    JMenuItem unlitColor = new JMenuItem(VIEW_COLOR_UNLIT);

    menuItems.add(unlitColor);

    colors.add(unlitColor);

    JMenuItem litColor = new JMenuItem(VIEW_COLOR_LIT);

    menuItems.add(litColor);

    colors.add(litColor);

    view.add(colors);

    add(view);

    }

    /**

    * Registers an ActionListener to listen to the

    * events that are fired by this CalculatorMenus

    * JMenuItems.

    *

    * @param listener The ActionListener to register.

    */

    public void addMenuActionListener(ActionListener listener)

    APPENDIX B Full Source Code Listings 57

  • {Iterator itemIter = menuItems.iterator();

    while (itemIter.hasNext()) {

    ((JMenuItem)itemIter.next()).addActionListener(

    listener);

    }

    }

    }

    Class CalculatorModel/*

    * CalculatorModel

    * Encapsulates the data model used by the Calculator Application

    */

    package com.wkndjava.calculator.gui;

    import com.wkndjava.calculator.event.*;

    /**

    * Encapsulates the data model used by the Calculator application.

    * Contains methods for getting and setting operands, operations,

    * display values, and memory operations.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class CalculatorModel {

    58 Learn Java In a Weekend

  • private double operand1;

    private double operand2;

    /* Stores the value associated with a calculators memory */

    private double mem;

    /* The current operand that appears in the display */

    private double currentDisplayValue;

    /* Represents operation to be performed on the operands */

    private String currentOp;

    /** Constant that indicates there is no current operation. */

    public final static String NONE = ?;

    /**

    * Constructs a new CalculatorModel object.

    *

    * @param maxDigits The maximum number of displayable digits

    */

    public CalculatorModel() {

    currentOp = CalculatorModel.NONE;

    }

    /**

    * Sets operand 1, which is the first operand in binary

    * operations.

    *

    * @param value The value to set operand 1 to.

    */

    public void setOperand1(double value) {

    operand1 = value;

    currentDisplayValue = operand1;

    }

    APPENDIX B Full Source Code Listings 59

  • /**

    * Returns the value currently set to operand 1.

    *

    * @return The value of operand 1.

    */

    public double getOperand1() {

    return operand1;

    }

    /**

    * Sets operand 2, which is the second operand in binary

    * operations.

    *

    * @param value The value to set operand 2 to.

    */

    public void setOperand2(double value) {

    operand2 = value;

    currentDisplayValue = operand2;

    }

    /**

    * Returns the value currently set to operand 2.

    *

    * @return The value of operand 2.

    */

    public double getOperand2() {

    return operand2;

    }

    /**

    60 Learn Java In a Weekend

  • * Sets the memory value.

    *

    * @param value the value to set to memory

    */

    public void setMem(double value) {

    mem = value;

    }

    /**

    * Returns the memory value.

    *

    * @return The value currently stored in memory

    */

    public double getMem() {

    return mem;

    }

    /**

    * Sets the currently displayed number

    *

    * @param value The number to set.

    */

    public void setCurrentDisplayValue(double value) {

    currentDisplayValue = value;

    }

    /**

    * Returns the currently displayed number.

    *

    * @return the current display value.

    APPENDIX B Full Source Code Listings 61

  • */

    public double getCurrentDisplayValue() {

    return currentDisplayValue;

    }

    /**

    * Sets the operation.

    *

    * @param op The operation to set. This value should be one of

    * the

    * {@link com.wkndjava.calculator.event.CalculatorKeypadEvent

    * CalculatorKeypadEvent} operation constants.

    *

    * @see com.wkndjava.calculator.event.CalculatorKeypadEvent* #isOperational(String)

    */

    public void setCurrentOp(String op) {

    if (op.equals(CalculatorKeypadEvent.ADD)

    || op.equals(CalculatorKeypadEvent.SUBTRACT)

    || op.equals(CalculatorKeypadEvent.MULTIPLY)

    || op.equals(CalculatorKeypadEvent.DIVIDE)

    || op.equals(CalculatorKeypadEvent.POW)) {

    currentOp = op;

    }

    else {

    currentOp = CalculatorModel.NONE;

    }

    }

    /**

    62 Learn Java In a Weekend

  • * Gets the current operator.

    *

    * @return the current operator

    */

    public String getCurrentOp() {

    return currentOp;

    }

    public String toString() {

    String s = operand1 = + operand1

    + operand2 = + operand2

    + currentOp = + currentOp

    + currentDisplayValue = + currentDisplayValue

    + mem = + mem;

    return s;

    }

    }

    Class CalculatorView/*

    * CalculatorView

    * Encapsulates the Calculator GUI

    */

    package com.wkndjava.calculator.gui;

    import com.wkndjava.calculator.event.*;

    import com.wkndjava.calculator.exception.*;

    import com.wkndjava.calculator.Calculator;

    APPENDIX B Full Source Code Listings 63

  • import java.awt.*;

    import java.awt.event.*;

    import javax.swing.*;

    /**

    * The view for the Calculator when it is running in application

    * mode.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class CalculatorView extends JFrame

    implements CalculatorViewer {

    private CalculatorMenu menu;

    private DigitalDisplay display;

    private CalculatorKeypad keypad;

    private AuditTrailView auditTrailViewer;

    public CalculatorView() {

    super(Java Calculator);

    menu = new CalculatorMenu(Calculator.APPLICATION);

    setJMenuBar(menu);

    Container content = getContentPane();

    display = new DigitalDisplay(9, 0.0, true,

    new Color(88, 207, 233),

    new Color(30, 189, 223), Color.black);

    content.add(display, BorderLayout.NORTH);

    64 Learn Java In a Weekend

  • keypad = new CalculatorKeypad();

    content.add(keypad, BorderLayout.CENTER);

    setDefaultCloseOperation(EXIT_ON_CLOSE);

    setResizable(false);

    pack();

    }

    public void setDisplayValue(double value) {

    try {

    display.setDoubleValue(value);

    } catch (DigitalDisplayOverflowException e) {

    System.out.println(DigitalDisplayOverflow:

    + e.getMessage());

    } finally {

    display.updateDisplay();

    }

    }

    public double getDisplayValue() {

    return display.getDoubleValue();

    }

    public void appendDisplayDigit(int appendInt) {

    display.appendDigit(appendInt);

    }

    public void appendDisplayDecimal() {

    display.appendDecimal();

    APPENDIX B Full Source Code Listings 65

  • }public void addCalculatorKeypadListener(

    CalculatorKeypadListener ckl) {

    keypad.addCalculatorKeypadListener(ckl);

    }

    public void addMenuActionListener(ActionListener al) {

    menu.addMenuActionListener(al);

    }

    public void showAuditTrail(String atText) {

    if (auditTrailViewer == null) {

    auditTrailViewer = new AuditTrailView(this, atText);

    }

    else {

    auditTrailViewer.setText(atText);

    }

    auditTrailViewer.setVisible(true);

    }

    public void updateAuditTrail(String atText) {

    if (auditTrailViewer != null

    && auditTrailViewer.isVisible()) {

    auditTrailViewer.setText(atText);

    }

    }

    public DigitalDisplay getDigitalDisplay() {

    return display;

    66 Learn Java In a Weekend

  • }public void showInfo(String message) {

    JOptionPane.showMessageDialog(this, message);

    }

    }

    Interface CalculatorViewer/*

    * CalculatorViewer

    * An interface for Calculator Viewers

    */

    package com.wkndjava.calculator.gui;

    import com.wkndjava.calculator.event.*;

    import java.awt.Color;

    import java.awt.event.*;

    /**

    * An interface for classes that act as a view for the Calculator.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public interface CalculatorViewer {

    APPENDIX B Full Source Code Listings 67

  • /**

    * Sets the display value to the given number.

    *

    * @param value The number to display

    */

    public void setDisplayValue(double value);

    /**

    * Gets the currently displayed number.

    *

    * @return The currently displayed number

    */

    public double getDisplayValue();

    /**

    * Appends a digit to the currently displayed number.

    *

    * @param appendInt The digit to append.

    */

    public void appendDisplayDigit(int appendInt);

    /**

    * Appends a decimal point to the currently displayed number

    * if there isnt a decimal there already.

    */

    public void appendDisplayDecimal();

    /**

    * Registers a CalculatorKeypadListener to listen

    * for CalculatorKeypadEvents.

    68 Learn Java In a Weekend

  • ** @param ckl A CalculatorKeypadListener

    */

    public void addCalculatorKeypadListener(

    CalculatorKeypadListener ckl);

    /**

    * Registers a ActionListener to listen for

    * CalculatorMenu events.

    *

    * @param al An ActionListener

    */

    public void addMenuActionListener(ActionListener al);

    /**

    * Displays the given audit trail text.

    *

    * @param atText The audit trail text to display

    */

    public void showAuditTrail(String atText);

    /**

    * Updates the displayed audit trail text, assuming that

    * the audit trail is already being displayed.

    *

    * @param atText The audit trail text (in full).

    */

    public void updateAuditTrail(String atText);

    /**

    APPENDIX B Full Source Code Listings 69

  • * Returns the DigitalDisplay object that is

    * used for displaying numbers.

    *

    * @return The DigitalDisplay object

    */

    public DigitalDisplay getDigitalDisplay();

    /**

    * Displays a message for the user to see

    *

    * @param message The message to display.

    */

    public void showInfo(String message);

    }

    Class DigitalDisplay/*

    * DigitalDisplay

    * A lightweight component that graphically represents a liquid

    * crystal digital display.

    */

    package com.wkndjava.calculator.gui;

    import com.wkndjava.calculator.exception.*;

    import java.awt.*;

    import javax.swing.*;

    import java.text.DecimalFormat;

    70 Learn Java In a Weekend

  • import javax.swing.border.*;

    /**

    * Uses multiple LiquidCrystalDigits and an

    * optional LiquidCrystalNegative component to

    * display a number.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class DigitalDisplay extends JPanel {

    /** The LiquidCrystalDigit objects that make up this

    * DigitalDisplay */

    protected LiquidCrystalDigit[] lcdDigits;

    /** An optional LiquidCrystalNegative component */

    protected LiquidCrystalNegative lcdNegative;

    /** The color for all of the unlit pieces */

    protected Color offColor;

    /** The decimal formatter inner helper class */

    protected DigitalDisplayFormat digitalFormat;

    /**

    * Constructs a DigitalDisplay using the given

    * number of LiquidCrystalDigit digits.

    * The LiquidCrystalNegative component is not

    * used.

    *

    * @param digits The number if LiquidCrystalDigits

    * to use

    APPENDIX B Full Source Code Listings 71

  • */

    public DigitalDisplay(int digits) {

    this (digits, 0.0);

    }

    /**

    * Constructs a DigitalDisplay using the given

    * number of LiquidCrystalDigit digits and

    * initializing the displayed number to the given number.

    * The LiquidCrystalNegative component is not

    * used.

    *

    * @param digits The number if

    * LiquidCrystalDigits to use @param number

    * The initial number to display

    */

    public DigitalDisplay(int digits, double number) {

    this (digits, number, false);

    }

    /**

    * Constructs a DigitalDisplay using the given

    * number of LiquidCrystalDigit digits and

    * initializing the displayed number to the given number.

    * The LiquidCrystalNegative component is used

    * if the second argument is true

    *

    * @param digits The number if LiquidCrystalDigits

    * to use

    * @param number The initial number to display

    72 Learn Java In a Weekend

  • * @param useNegative true to use a

    * LiquidCrystalNegative component, or

    * false to omit it.

    */

    public DigitalDisplay(int digits, double number,

    boolean useNegative) {

    this(digits, number, useNegative,

    Color.black, new Color(0, 80, 0), Color.green);

    }

    /**

    * Constructs a DigitalDisplay using the given

    * number of LiquidCrystalDigit digits and

    * initializing the displayed number to the given number.

    * The LiquidCrystalNegative component is used

    * if the second argument is true. The colors

    * are set to the given colors

    *

    * @param digits The number if LiquidCrystalDigits

    * to use

    * @param number The initial number to display

    * @param useNegative true to use a

    * LiquidCrystalNegative component, or

    * false to omit it.

    * @param bg The background color

    * @param unlit The unlit color

    * @param lit The lit (foreground) color

    */

    public DigitalDisplay(int digits, double number,

    boolean useNegative, Color bg, Color unlit,

    APPENDIX B Full Source Code Listings 73

  • Color lit) {

    lcdDigits = new LiquidCrystalDigit[digits];

    digitalFormat = new DigitalDisplayFormat();

    setBackground(bg);

    setForeground(lit);

    offColor = unlit;

    setLayout(new GridLayout(1, 0, 0, 0));

    if (useNegative) {

    lcdNegative = new LiquidCrystalNegative(false,

    bg, unlit, lit);

    add(lcdNegative);

    }

    for (int d = 0; d < lcdDigits.length; d++) {

    lcdDigits[d] = new LiquidCrystalDigit(0,

    bg, unlit, lit);

    add(lcdDigits[d]);

    }

    setBorder(BorderFactory.createBevelBorder(

    BevelBorder.LOWERED));

    digitalFormat.parseAndSetValue(number);

    updateDisplay();

    }

    /**

    * Returns the number of LiquidCrystalDigit

    * components

    * that this DigitalDisplay uses.

    74 Learn Java In a Weekend

  • */

    public int getNumDigits() {

    return lcdDigits.length;

    }

    /**

    * Returns the String value of the current number. Any

    * negative signs

    * and/or decimal points are omitted.

    *

    * @return The String value of the current number.

    */

    public String getValue() {

    return digitalFormat.value.toString();

    }

    /**

    * Sets the display value to the given double.

    * Calling this method does not repaint the new number.

    * To display this number, you should call

    * {@link #updateDisplay() updateDisplay()}

    *

    * @param dValue The number to display

    *

    * @throws DigitalDisplayOverflowException if the given

    * number is too

    * large to be displayed by this DigitalDisplay

    *

    * @see #updateDisplay()

    */

    APPENDIX B Full Source Code Listings 75

  • public void setDoubleValue(double dValue) throws

    DigitalDisplayOverflowException {

    DigitalDisplayOverflowException de

    = digitalFormat.parseAndSetValue(dValue);

    String strValue = digitalFormat.value.toString();

    if (de != null) {

    throw de;

    }

    }

    /**

    * Returns the current number

    *

    * @return The current number

    */

    public double getDoubleValue() {

    return digitalFormat.getDoubleValue();

    }

    /**

    * Updates the display by repainting the graphics to render

    * the current number.

    */

    protected void updateDisplay() {

    for (int d = 0; d < lcdDigits.length; d++) {

    lcdDigits[d].setDigit(digitalFormat.getIntAt(d));

    lcdDigits[d].setDecimalPoint(

    digitalFormat.decimalIndex == d);

    }

    repaint();

    76 Learn Java In a Weekend

  • }/**

    * Appends a digit to the end of the current number

    * and updates the display.

    */

    public void appendDigit(int appendInt) {

    digitalFormat.tryAppend(appendInt);

    updateDisplay();

    }

    /**

    * Appends a decimal point (if there isnt one there already)

    * to the end of the current number and updates the display.

    */

    public void appendDecimal() {

    if( digitalFormat.decimalIndex

    == DigitalDisplayFormat.NO_DECIMAL) {

    digitalFormat.decimalIndex

    = lcdDigits.length - 1;

    updateDisplay();

    }

    }

    /**

    * Overrides the javax.swing.JComponent method

    * to set the background color as well as the background

    * colors for all of the LiquidCrystalComponents

    * that this DigitalDisplay may contain.

    */

    APPENDIX B Full Source Code Listings 77

  • public void setBackground(Color bg) {

    super.setBackground(bg);

    if (lcdDigits != null) {

    for (int c=0; c < lcdDigits.length; c++) {

    if (lcdDigits[c] != null) {

    lcdDigits[c].setBackground(bg);

    }

    }

    if (lcdNegative != null) {

    lcdNegative.setBackground(bg);

    }

    }

    }

    /**

    * Sets the unlit color for this DigitalDisplay

    * and also sets the unlit color for all of the

    * LiquidCrystalComponents that it may contain.

    */

    public void setUnlitColor(Color unlit) {

    offColor = unlit;

    if (lcdDigits != null) {

    for (int c=0; c < lcdDigits.length; c++) {

    if (lcdDigits[c] != null) {

    lcdDigits[c].setUnlitColor(unlit);

    }

    }

    }

    if (lcdNegative != null) {

    lcdNegative.setUnlitColor(unlit);

    78 Learn Java In a Weekend

  • }repaint();

    }

    /**

    * Returns the unlit color.

    *

    * @return The unlit Color

    */

    public Color getUnlitColor() {

    return offColor;

    }

    /**

    * Sets the foreground (lit) color for this

    * DigitalDisplay and also the lit color for

    * all of the LiquidCrystalComponents that

    * it may contain.

    */

    public void setForeground(Color lit) {

    super.setForeground(lit);

    if (lcdDigits != null) {

    for (int c=0; c < lcdDigits.length; c++) {

    if (lcdDigits[c] != null) {

    lcdDigits[c].setForeground(lit);

    }

    }

    }

    if (lcdNegative != null) {

    lcdNegative.setForeground(lit);

    APPENDIX B Full Source Code Listings 79

  • }}

    /* An inner class that handles the formatting of the

    * numbers for displaying them. */

    private class DigitalDisplayFormat {

    /* The formatter for decimal numbers */

    private DecimalFormat formatter;

    /* The formatted string representation of

    * the displayed number */

    private StringBuffer value;

    /* An instance of the DigitalDisplayForamat inner class */

    private boolean negative;

    /* Indicates the index for the digit that precedes the

    * decimal point */

    private int decimalIndex;

    /* Indicates there is no decimal point */

    private final static int NO_DECIMAL = -2;

    /* Largest possible value that can be displayed */

    private double largestValue;

    private DigitalDisplayFormat() {

    formatter = new DecimalFormat();

    formatter.setMaximumFractionDigits(lcdDigits.length);

    formatter.setMinimumFractionDigits(0);

    formatter.setMinimumIntegerDigits(1);

    formatter.setDecimalSeparatorAlwaysShown(false);

    formatter.setGroupingUsed(false);

    80 Learn Java In a Weekend

  • StringBuffer large = new StringBuffer();

    for (int d = 0; d < lcdDigits.length; d++) {

    large.append(9);

    }

    largestValue = Double.parseDouble(large.toString());

    }

    private DigitalDisplayOverflowException parseAndSetValue(

    double number) {

    if (Double.isNaN(number)) {

    setNegative(false);

    decimalIndex = NO_DECIMAL;

    value = new StringBuffer(getErrorString());

    return new DigitalDisplayOverflowException(

    Value is not defined);

    }

    setNegative(number < 0);

    number = Math.abs(number);

    if (number > largestValue) {

    setNegative(false);

    decimalIndex = NO_DECIMAL;

    value = new StringBuffer(getErrorString());

    return new DigitalDisplayOverflowException(

    Double value + number

    + cannot be displayed with + getNumDigits()

    + digits);

    }

    value = new StringBuffer(formatter.format(number));

    //strip decimal point (but remember where it is)

    APPENDIX B Full Source Code Listings 81

  • decimalIndex = value.toString().indexOf(.) - 1;

    if (decimalIndex != NO_DECIMAL) {

    value.deleteCharAt(decimalIndex + 1);

    }

    //ensure length is equal to number of lcd digits

    if (value.length() > lcdDigits.length) {

    while (value.length() > lcdDigits.length + 1) {

    value.deleteCharAt(value.length() - 1);

    }

    //round off the extra stuff

    double roundMe

    = Double.parseDouble(value.toString()) / 10.0;

    String rounded

    = formatter.format(Math.rint(roundMe));

    value = new StringBuffer(rounded);

    }

    while (value.length() < lcdDigits.length) {

    value.insert(0, );

    if (decimalIndex != NO_DECIMAL) {

    decimalIndex++;

    }

    }

    return null;

    }

    private void tryAppend(int number) {

    if (value.toString() != getErrorString()

    && getDoubleValue() == 0.0

    82 Learn Java In a Weekend

  • && decimalIndex == NO_DECIMAL) {

    value.setCharAt(

    value.toString().indexOf(0), );

    }

    if (value.toString().trim().length()

    < getNumDigits()) {

    value.deleteCharAt(0);

    value.append(number);

    if (decimalIndex != NO_DECIMAL) {

    decimalIndex--;

    }

    }

    }

    private void setNegative(boolean isNegative) {

    negative = isNegative;

    if (lcdNegative != null) {

    lcdNegative.setNegative(isNegative);

    }

    }

    private String getErrorString() {

    String errorString = ;

    for (int d = 0; d < lcdDigits.length - 1; d++) {

    errorString += ;

    }

    errorString += E;

    return errorString;

    }

    APPENDIX B Full Source Code Listings 83

  • private double getDoubleValue() {

    StringBuffer parseValue

    = new StringBuffer(value.toString());

    if (parseValue.toString().equals(getErrorString()))

    return 0.0;

    if (decimalIndex != NO_DECIMAL) {

    parseValue.insert(decimalIndex + 1, .);

    }

    double dValue = Double.parseDouble(

    parseValue.toString().trim());

    if (negative) dValue *= -1;

    return dValue;

    }

    private int getIntAt(int index) {

    String charStrVal = + value.charAt(index);

    if (charStrVal.equals( )) {

    return LiquidCrystalDigit.EMPTY;

    }

    else if (charStrVal.equals(E)) {

    return LiquidCrystalDigit.E;

    }

    return Integer.parseInt(charStrVal);

    }

    }

    }

    84 Learn Java In a Weekend

  • Class LiquidCrystalComponent/*

    * LiquidCrystalComponent

    * An abstract class that defines functionality that is common

    * for all components that use a Liquid Crystal Display look.

    */

    package com.wkndjava.calculator.gui;

    import java.awt.*;

    /**

    * Abstract super class for components that have a liquid crystal

    * display. A liquid crystal display breaks up its display into

    * pieces that are either lit or unlit (on or off). Collectively

    * all of the pieces that are available are capable of displaying

    * all images that are possible for a particular liquid crystal

    * component. A subset of the pieces are lit to display one

    * of the specific possible images. The idea is similar to a

    * digital watch. The appropriate bars of each digit are lit up

    * to display a specific number, while the other bars remain unlit.

    * A liquid crystal display has a background color, a foreground

    * color, and also an unlit color. The unlit color is used to

    * graphically represent the pieces of the image that are not lit

    * in a particular image display.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    APPENDIX B Full Source Code Listings 85

  • public abstract class LiquidCrystalComponent extends Component {

    /** Pieces of the pattern that are either on

    * (true) or off (false) */

    protected boolean[] litPattern;

    /** color for unlit pieces, (foreground color is on) */

    protected Color offColor;

    /**

    * Constructs a new LiquidCrystalComponent using

    * the default colors

    */

    protected LiquidCrystalComponent() {

    this(Color.black, new Color(0, 80, 0), Color.green);

    }

    /**

    * Constructs a new LiquidCrystalComponent with

    * the given set of colors

    *

    * @param bg The background color

    * @param unlit The unlit color

    * @param lit The lit color (foreground color)

    */

    protected LiquidCrystalComponent(Color bg, Color unlit,

    Color lit) {

    super();

    setBackground(bg);

    setUnlitColor(unlit);

    setForeground(lit);

    86 Learn Java In a Weekend

  • }/**

    * Sets the color used for unlit pieces

    *

    * @param unlit The unlit color

    */

    public void setUnlitColor(Color unlit) {

    offColor = unlit;

    }

    /**

    * Returns the color used for unlit pieces

    *

    * @return The color used for unlit pieces

    */

    public Color getUnlitColor() {

    return offColor;

    }

    /**

    * Sets the lit pattern for this Liquid CrystalComponent by

    * setting the litPattern elements to either true or false.

    */

    protected abstract void buildLitPattern();

    /**

    * Lights this LiquidCrystalComponent using the given pattern.

    * pattern is an array whose values correspond to litPattern

    * elements that should be lit (set to true).

    APPENDIX B Full Source Code Listings 87

  • ** @param pattern The values of this array are the subscripts

    * of the litPattern[] array that should be lit.

    */

    protected void lightPattern(int[] pattern) {

    for (int b = 0; b < pattern.length; b++) {

    litPattern[pattern[b]] = true;

    }

    }

    /**

    * Sets all of this LiquidCrystalComponents pieces to unlit

    */

    protected void clearPattern() {

    for (int b = 0; b < litPattern.length; b++) {

    litPattern[b] = false;

    }

    }

    /**

    * Returns the color for the pattern pieces indicated by the

    * given litPattern index. The returned color is either the

    * lit or unlit color.

    *

    * @param patternIndex The index of the

    * litPattern[] array

    */

    protected Color getPieceColor(int patternIndex) {

    if (litPattern[patternIndex]) return getForeground();

    return offColor;

    88 Learn Java In a Weekend

  • }/**

    * Overrides the method inherited from

    * java.awt.Component

    */

    public Dimension getMinimumSize() {

    return new Dimension(22, 55);

    }

    /**

    * Overrides the method inherited from

    * java.awt.Component

    */

    public Dimension getPreferredSize() {

    return getMinimumSize();

    }

    }

    Class LiquidCrystalDigit/*

    * LiquidCrystalDigit

    * A lightweight component that represents an LCD digit.

    */

    package com.wkndjava.calculator.gui;

    import java.awt.*;

    APPENDIX B Full Source Code Listings 89

  • /**

    * A lightweight 8-piece liquid crystal digit component. Seven

    * pieces are used for the digit and the other piece is used for

    * the decimal point. The seven bars make the following pattern:

    *

    * -

    * | |

    * -

    * | |

    * _ .

    *

    * The individual pieces are lit to represent the numbers

    * 0 through 9

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    public class LiquidCrystalDigit extends LiquidCrystalComponent {

    /** The constant that represents the empty display

    * (no bars lit) */

    public final static char EMPTY = ;

    /** A constant that represents the error code E */

    public final static int E = 99;

    /** The currently displayed digit */

    protected int digit;

    /** Indicates whether the decimal point is on or off */

    protected boolean decimalPoint;

    /**

    90 Learn Java In a Weekend

  • * Constructs a LiquidCrystalDigit that is

    * initially empty (does not have any bars lit, and thus

    * does not display any number)

    */

    public LiquidCrystalDigit() {

    this(EMPTY);

    }

    /**

    * Constructs a LiquidCrystalDigit that is

    * initialized to display the given digit

    *

    * @param digitToDisplay Possible values:

    *

    * A single-digit int ranging from 0 to 9

    * {@link #EMPTY EMPTY}

    * {@link #E E}

    *

    */

    public LiquidCrystalDigit(int digitToDisplay) {

    super();

    litPattern = new boolean[8];

    setDigit(digitToDisplay);

    }

    /**

    * Constructs a LiquidCrystalDigit that is

    * initialized to display the given digit and uses the given

    * colors.

    *

    APPENDIX B Full Source Code Listings 91

  • * @param digitToDisplay Possible values:

    *

    * A single-digit int ranging from 0 to 9

    * {@link #EMPTY EMPTY}

    * {@link #E E}

    *

    * @param bg The background color

    * @param unlit The unlit color

    * @param lit The lit (foreground) color

    */

    public LiquidCrystalDigit(int digitToDisplay,

    Color bg, Color unlit, Color lit) {

    super(bg, unlit, lit);

    litPattern = new boolean[8];

    setDigit(digitToDisplay);

    }

    /**

    * Sets the digit for this LiquidCrystalDigit to

    * display

    * @param digitToDisplay Possible values:

    *

    * A single-digit int ranging from 0 to 9

    * {@link #EMPTY EMPTY}

    * {@link #E E}

    *

    */

    public void setDigit(int digitToDisplay) {

    digit = isDigitValid(digitToDisplay) ? digitToDisplay : E;

    buildLitPattern();

    92 Learn Java In a Weekend

  • repaint();

    }

    /**

    * Returns the currently displayed digit

    *

    * @param The currently displayed digit

    */

    public int getDigit() {

    return digit;

    }

    /**

    * Turns the decimal point on or off

    *

    * @param on true to turn the decimal point on, or

    * false to turn the decimal point off

    */

    public void setDecimalPoint(boolean on) {

    decimalPoint = on;

    buildLitPattern();

    repaint();

    }

    /**

    * Returns a boolean value indicating whether

    * the decimal point is on or off

    *

    * @return true if the decimal point is on, or

    * false if the decimal point is off

    APPENDIX B Full Source Code Listings 93

  • */

    public boolean hasDecimalPoint() {

    return decimalPoint;

    }

    /**

    * Used to determine if a given digit is displayable by this

    * LiquidCrystalDigit component.

    *

    * @param digitChar Valid if equal to one of the following:

    *

    * A single-digit int ranging from 0 to 9

    * {@link #EMPTY EMPTY}

    * {@link #E E}

    *

    */

    public boolean isDigitValid(int digitChar) {

    if ( (digit >= 0 && digit

  • clearPattern();

    switch (digit) {

    case 0:

    lightPattern( new int[] { 0, 1, 2, 4, 5, 6 } );

    break;

    case 1:

    lightPattern( new int[] { 2, 5 } );

    break;

    case 2:

    lightPattern( new int[] { 0, 2, 3, 4, 6 } );

    break;

    case 3:

    lightPattern( new int[] { 0, 2, 3, 5, 6 } );

    break;

    case 4:

    lightPattern( new int[] { 1, 2, 3, 5 } );

    break;

    case 5:

    lightPattern( new int[] { 0, 1, 3, 5, 6} );

    break;

    case 6:

    lightPattern( new int[] { 0, 1, 3, 4, 5, 6 } );

    break;

    case 7:

    lightPattern( new int[] { 0, 2, 5 } );

    break;

    case 8:

    lightPattern( new int[] { 0, 1, 2, 3, 4, 5, 6 } );

    break;

    case 9:

    APPENDIX B Full Source Code Listings 95

  • lightPattern( new int[] { 0, 1, 2, 3, 5, 6 } );

    break;

    case E:

    lightPattern( new int[] { 0, 1, 3, 4, 6 } );

    break;

    case EMPTY:

    default:

    return;

    }

    litPattern[7] = decimalPoint;

    }

    /**

    * Overrides the java.awt.Component method to

    * draw the pieces that graphically represent the digit

    */

    public void paint(Graphics g) {

    g.setColor(getBackground());

    g.fillRect(0, 0, getWidth(), getHeight());

    g.setColor(getPieceColor(0));

    g.fillRect(5, 5, 11, 3);

    g.setColor(getPieceColor(1));

    g.fillRect(2, 8, 3, 18);

    g.setColor(getPieceColor(2));

    g.fillRect(16, 8, 3, 18);

    g.setColor(getPieceColor(3));

    g.fillRect(5, 26, 11, 3);

    g.setColor(getPieceColor(4));

    g.fillRect(2, 29, 3, 18);

    g.setColor(getPieceColor(5));

    96 Learn Java In a Weekend

  • g.fillRect(16, 29, 3, 18);

    g.setColor(getPieceColor(6));

    g.fillRect(5, 47, 11, 3);

    g.setColor(getPieceColor(7));

    g.fillRect(20, 47, 3, 3);

    }

    }

    Class LiquidCrystalNegative/*

    * LiquidCrystalNegative

    * A liquidCrystalComponent that represents a negative sign.

    */

    package com.wkndjava.calculator.gui;

    import java.awt.*;

    /**

    * A single-piece

    * LiquidCyrstalComponent that represents a negative

    * sign. This component graphically renders a single negative-sign

    * piece, that should be used in conjunction with

    * LiquidCrystalDigits to represent a negative

    * number.

    *

    * @author Joseph P Russell

    * @version 1.00

    */

    APPENDIX B Full Source Code Listings 97

  • public class LiquidCrystalNegative extends LiquidCrystalComponent {

    /** true if the negative sign should be lit */

    protected boolean negative;

    /** constructs a new LiquidCrystalNegative that is initially

    * unlit */

    public LiquidCrystalNegative() {

    this (false);

    }

    /**

    * Constructs a new LiquidCrystalNegative that is either

    * lit or unlit.

    *

    * @param isNegative true to light the negative

    * sign, or false to leave it unlit.

    */

    public LiquidCrystalNegative(boolean isNegative) {

    super();

    litPattern = new boolean[1];

    negative = isNegative;

    buildLitPattern();

    }

    /**

    * Constructs a new LiquidCrystalNegative that is either

    * lit or unlit and uses the given colors.

    *

    * @param isNegative true to light the negative

    98 Learn Java In a Weekend

  • * sign, or false to leave it unlit.

    * @param bg The background color

    * @param unlit The unlit color

    * @param lit The lit (foreground) color

    */

    public LiquidCrystalNegative(boolean isNegative,

    Color bg, Color unlit, Color lit) {

    super(bg, unlit, lit);

    litPattern = new boolean[1];

    negative = isNegative;

    buildLitPattern();

    }

    /**

    * Sets the negative sign to either lit or unlit

    *

    * @param isNegative true to light the negative

    * sign, or false for unlit.

    */

    public void setNegative(boolean isNegative) {

    negative = isNegative;

    buildLitPattern();

    repaint();

    }

    /**

    * Indicates whether the negative sign is lit or unlit

    *

    * @return true if the negative sign is lit, or

    * false if it is unlit.

    APPENDIX B Full Source Code Listings 99

  • */

    public boolean isNegative() {

    return negative;

    }

    /**

    * Sets the negative sign to lit or unlit, depending on the

    * value of negative.

    */

    public void buildLitPattern() {

    clearPattern();

    if (negative) {

    litPattern[0] = true;

    }

    }

    /**

    * Overrides method in java.awt.Component to

    * graphically represent the negative sign.

    */

    public void paint(Graphics g) {

    g.setColor(getBackground());

    g.fillRect(0, 0, getWidth(), getHeight());

    g.setColor(getPieceColor(0));

    g.fillRect(5, 26, 11, 3);

    }

    }

    100 Learn Java In a Weekend

  • package.html

    Contains the GUI pieces and associated helper classes for the

    Calculator application

    APPENDIX B Full Source Code Listings 101