001    /*
002     * Calculator GUI
003     *
004     * Developed for "Rethinking CS101", a project of Lynn Andrea Stein's.
005     * For more information, see <a href="http://www.cs101.org/">the
006     * CS101 homepage</a> or email <las@olin.edu>.
007     *
008     * Copyright (C) 1996 Massachusetts Institute of Technology.
009     * Please do not redistribute without obtaining permission.
010     */
011    package calculator;
012    import java.awt.*;
013    import java.awt.event.*;
014    import cs101.util.semaphore.IntBuffer;
015    
016    /**
017     * This is an implementation of the GUI for a basic four-function
018     * calculator.  It relies on a ButtonHandler (Runnable) to repeatedly
019     * call getButton() and consume the buttonIDs that the Calculator
020     * object produces. <p>
021     *
022     * This follows the interactive-control-loop design described in the
023     * early parts of PI and as a part of the 
024     *      <a href="http://www.cs101.org/">
025     *                    Rethinking CS101
026     * </a> project of Lynn Andrea Stein's AP Group at Olin College.
027     * <p>
028     *
029     *
030     * @see ButtonHandler
031     * @see cs101.util.semaphore.IntBuffer
032     *
033     */
034    
035    public class CalculatorGUI extends Frame implements ActionListener, Calculator {
036    
037       /**
038        * The "screen" of the calculator.  Private -- do not use.
039        */
040        private TextField display;            
041        
042        /**
043        * Synchronized storage for put/getButton.  Private -- do not use.
044        */
045        private IntBuffer buttonBuf = new IntBuffer();  
046    
047       /**
048        * The Button components themselves.  Private -- do not use.
049        */
050        private Button[] Buttons      = new Button[Calculator.LAST];
051    
052        // Set up the labels w/ static initializer (only need to do this once).
053        static {
054            for ( int i = 0; i < 10; i++ ) {
055                ButtonLabels[i] = String.valueOf( i );
056            }
057            ButtonLabels[Calculator.OP_DIV] = "/";
058            ButtonLabels[Calculator.OP_MUL] = "*";
059            ButtonLabels[Calculator.OP_ADD] = "+";
060            ButtonLabels[Calculator.OP_SUB] = "-";
061            ButtonLabels[Calculator.DOT]    = ".";
062            ButtonLabels[Calculator.EQUALS] = "=";
063            ButtonLabels[Calculator.CLEAR] = "clear";
064        }
065    
066       /**
067        * Initialize components and such at runtime.  Automagically called
068        * by the java runtime.  You should not use it. 
069        */
070        public CalculatorGUI() {
071                    super("CS101 Calculator");
072    
073                    this.setLayout( new GridLayout( 0, 1 ) );
074    
075                    this.display = new TextField("");
076                    this.display.setEditable( false );
077                    this.display.setBackground( Color.white );
078                    this.display.setForeground( Color.blue );
079                    this.display.setFont( new Font("Monospaced", Font.BOLD, 24) );
080                    this.display.setCursor( new Cursor(HAND_CURSOR) );
081    
082                    this.add( this.display );
083    
084                    for ( int i = 0; i < Calculator.LAST; i++ ) {
085                        this.Buttons[i] = new Button( Calculator.ButtonLabels[i] );
086                        this.Buttons[i].addActionListener(this);
087                    }
088                    // Layout the keypad one row at a time.
089                    Panel numberPad = new Panel();
090                    numberPad.setBackground( Color.lightGray );
091                    numberPad.setForeground( Color.black );
092                    numberPad.setFont( new Font("Monospaced", Font.BOLD, 20) );
093                    numberPad.setCursor( new Cursor(HAND_CURSOR) );
094    
095                    numberPad.setLayout( new GridLayout( 0, 4, 1, 1 ) );
096                    numberPad.add( this.Buttons[7] );  // Row 1
097                    numberPad.add( this.Buttons[8] );
098                    numberPad.add( this.Buttons[9] );
099                    numberPad.add( this.Buttons[Calculator.OP_DIV] );
100                    numberPad.add( this.Buttons[4] );  // Row 2
101                    numberPad.add( this.Buttons[5] );
102                    numberPad.add( this.Buttons[6] );
103                    numberPad.add( this.Buttons[Calculator.OP_MUL] );
104                    numberPad.add( this.Buttons[1] );  // Row 3
105                    numberPad.add( this.Buttons[2] );
106                    numberPad.add( this.Buttons[3] );
107                    numberPad.add( this.Buttons[Calculator.OP_ADD] );
108                    numberPad.add( this.Buttons[0] );  // Row 4
109                    numberPad.add( this.Buttons[Calculator.DOT] );
110                    numberPad.add( this.Buttons[Calculator.EQUALS] );
111                    numberPad.add( this.Buttons[Calculator.OP_SUB] );
112                    numberPad.add( new Button("") );   // Row 5
113                    numberPad.add( new Button("") );   
114                    numberPad.add( new Button("") );   
115                    numberPad.add( this.Buttons[Calculator.CLEAR] ); // --BIG button
116                    this.add( numberPad );
117    
118                    this.pack();      // Set the window size,
119                    this.show();      // pop it up,
120                    this.validate();  //
121                    this.setResizable(false);  //
122    
123    
124                    this.addWindowListener( new WindowAdapter() {
125                      public void windowClosing( WindowEvent e) {
126                        System.out.println("Exiting...");
127                        CalculatorGUI.this.dispose();
128                        System.exit(0);
129                      }
130                    });
131    
132    
133                    //  Java 1.1 Event Model: To handle WINDOW_CLOSING event,
134                    //  i.e., cleanly kill this application, either need (1) the
135                    //  above event listener implemented as an anonymous inner
136                    //  class OR (2) the following line and the
137                    //  'processWindowEvent' method for low-level event handling,
138    
139                    this.enableEvents(AWTEvent.WINDOW_EVENT_MASK);
140        }
141    
142       /**
143        * Handle WINDOW_CLOSING event, i.e., cleanly kill this
144        * application.  Automagically called by the java runtime.  You
145        * should not use it.
146        *
147        * Other window events are passed to the superclass (default) event
148        * handling.
149        */
150        public void processWindowEvent( WindowEvent e ) {
151            if (e.getID() == WindowEvent.WINDOW_CLOSING) {
152                System.out.println("Exiting...");
153                this.dispose();
154                System.exit(0);
155            } else {
156                super.processWindowEvent(e);
157            }
158        }
159    
160       /**
161        * Handle button pushes by making them available to getButton.
162        * Automagically called by the java runtime.  You should not use it. 
163        */
164        public void actionPerformed( ActionEvent e ) {
165          /*
166            private String whichButton = new String(
167                                                    e.getActionCommand() );
168    
169                                                    */
170            // Java 1.1 Event Model: If no action command string is
171            // explicitly set, 'getActionCommand' returns the button label.
172            
173            for ( int i = 0; i < Calculator.LAST; i++ ) {           
174                if ( (e.getActionCommand()).equals( ButtonLabels[i] )) {
175                    buttonBuf.putButton( i );
176                    break;  // exit the for loop as soon as we have a match.
177                }
178            }
179        }
180        
181       /**
182        * Get the next Button pressed.  The return value will be an int
183        * between 0 and 9 (if the button was a number) or one of the
184        * Calculator constants.
185        *
186        * @return the next button to be handled.
187        */
188        public int getButton() {
189            return this.buttonBuf.getButton();
190        }
191    
192       /**
193        * Get the text currently displayed on the Calculator.
194        *
195        * @return the text as a String.
196        */
197        public String getText() {
198            return this.display.getText();
199        }
200    
201    
202       /**
203        * Set the text currently displayed on the Calculator.
204        *
205        * @param newText the text to be displayed.
206        */
207        public void setText( String newText ) {
208            this.display.setText( newText );
209        }
210    }
211    
212    /* Comments:
213     *
214     * History:
215     *     $Log: CalculatorGUI.java,v $
216     *     Revision 1.2  2004/03/26 21:04:11  gus
217     *     take ownership
218     *
219     *     Revision 1.1  2003/07/10 21:14:43  jon
220     *     Initial commit of spring03 calculator source.
221     *
222     *     Revision 1.1.1.1  2002/06/05 21:56:24  root
223     *     CS101 comes to Olin finally.
224     *
225     *     Revision 1.3  1997/10/05 21:11:20  shong
226     *     Updated for fall97, to Java 1.1
227     *     changed GUI, using 1.1 Event Model
228     *
229     *     Revision 1.2  1997/07/16 14:15:21  tparnell
230     *     *** empty log message ***
231     *
232     *     Revision 1.2  1996/10/04 19:02:26  las
233     *     Fixed the location of the clear button so that it's not quite so
234     *     grotesque.  (I suppose that the right answer is a GridBagLayout....)
235     *
236     *     Revision 1.1  1996/10/04 16:20:21  las
237     *     Transformed Calculator into an application and made it a package.  See
238     *     STAFF_SETUP for which files are public.  To run, use Calculator.Main.
239     *
240     *     Specifics:
241     *         Added Main.java, which starts the calculator program (both
242     *     CalculatorGUI and ButtonHandler);
243     *         Made Calculator an interface;
244     *         Moved GUI implementation (previously in Calculator) to
245     *     CalculatorGUI.
246     *         Added clear button, which looks pretty gross right now.  (It can
247     *     be deleted in a single line, though.)
248     *
249     *     Revision 1.1.1.1  1996/07/18 17:26:12  sit
250     *     Import from summer 6.80s web tree
251     *
252     *
253     */
254    
255