001    /*
002     * Calculator GUI
003     *
004     * Developed for "Rethinking CS101", a project of Lynn Andrea Stein's AP Group.
005     * For more information, see <a href="http://www.ai.mit.edu/projects/cs101/">the
006     * CS101 homepage</a> or email <las@ai.mit.edu>.
007     *
008     * Copyright (C) 1996 Massachusetts Institute of Technology.
009     * Please do not redistribute without obtaining permission.
010     */
011    package calculator;
012    
013    import java.awt.*;
014    import java.awt.event.*;
015    import cs101.util.semaphore.IntBuffer;
016    
017    /**
018     * This is an implementation of the GUI for a basic four-function
019     * calculator.  It relies on a ButtonHandler (Runnable) to repeatedly
020     * call getButton() and consume the buttonIDs that the Calculator
021     * object produces.
022     *
023     * <P>This follows the interactive-control-loop design described in the
024     * early parts of 6.096 and as a part of the 
025     *      <a href="http://www.ai.mit.edu/projects/cs101/">
026     *                    Rethinking CS101
027     * </a> project of Lynn Andrea Stein's AP Group at the MIT
028     * Artificial Intelligence Laboratory.
029     *
030     * <P>Copyright (c) 1998 Massachusetts Institute of Technology
031     *
032     * @author:  Todd C. Parnell, tparnell@ai.mit.edu
033     * @author:  Emil Sit, sit@mit.edu
034     * @author:  Lynn Andrea Stein, las@ai.mit.edu
035     * @version: $Id: CalculatorGUI.java,v 1.1.1.1 2002/06/05 21:56:34 root Exp $
036     *
037     * @see calculator.ButtonHandler
038     * @see cs101.util.semaphore.IntBuffer
039     *
040     */
041    
042    public class CalculatorGUI extends Frame implements Calculator {
043    
044      /**
045       * The "screen" of the calculator.  Private -- do not use.
046       */
047      private TextField display;            
048        
049      /**
050       * Synchronized storage for put/getButton.  Private -- do not use.
051       * Note:  currently package visible becuase buttonBuf is used by an
052       * inner class.  This is a workaround for a bug in the JDK. (6 July 98)
053       */
054      /* private */ IntBuffer buttonBuf = new IntBuffer();  
055    
056      /**
057       * The Button components themselves.  Private -- do not use.
058       */
059      private Button[] Buttons = new Button[Calculator.LAST];
060    
061      // Set up the labels w/ static initializer (only need to do this once).
062      static {
063        for ( int i = 0; i < 10; i++ ) {
064          ButtonLabels[i] = String.valueOf( i );
065        }
066        ButtonLabels[Calculator.OP_DIV] = "/";
067        ButtonLabels[Calculator.OP_MUL] = "*";
068        ButtonLabels[Calculator.OP_ADD] = "+";
069        ButtonLabels[Calculator.OP_SUB] = "-";
070        ButtonLabels[Calculator.DOT]    = ".";
071        ButtonLabels[Calculator.EQUALS] = "=";
072        ButtonLabels[Calculator.CLEAR] = "clear";
073      }
074    
075      /**
076       * Initialize components and such at runtime.  Automagically called
077       * by the java runtime.  You should not use it. 
078       */
079      public CalculatorGUI() {
080        super("CS101 Calculator");
081    
082        this.setLayout( new GridLayout( 0, 1 ) );
083    
084        this.display = new TextField("");
085        this.display.setEditable( false );
086        this.display.setBackground( Color.white );
087        this.display.setForeground( Color.blue );
088        this.display.setFont( new Font("Monospaced", Font.BOLD, 24) );
089        this.display.setCursor( new Cursor(Cursor.HAND_CURSOR) );
090    
091        this.add( this.display );
092    
093        for ( int i = 0; i < Calculator.LAST; i++ ) {
094          this.Buttons[i] = new Button( Calculator.ButtonLabels[i] );
095          // Add the ActionListener for this button
096          this.Buttons[i].addActionListener(new ActionListener() {
097            public void actionPerformed(ActionEvent e) {
098              // Find out what button was pressed.  We cannot (unfortunately)
099              // simply use "i" here, so we do it the hard way.
100              String label = ((Button)e.getSource()).getLabel();
101              for ( int k = 0; k < Calculator.LAST; k++ ) {
102                if (Calculator.ButtonLabels[k].equals(label)) {
103                  CalculatorGUI.this.buttonBuf.putButton( k );
104                  break;      // only one match is possible
105                }
106              }
107            }
108          });
109        }
110        // Layout the keypad one row at a time.
111        Panel numberPad = new Panel();
112        numberPad.setBackground( Color.lightGray );
113        numberPad.setForeground( Color.black );
114        numberPad.setFont( new Font("Monospaced", Font.BOLD, 20) );
115        numberPad.setCursor( new Cursor(Cursor.HAND_CURSOR) );
116    
117        numberPad.setLayout( new GridLayout( 0, 4, 1, 1 ) );
118        numberPad.add( this.Buttons[7] );  // Row 1
119        numberPad.add( this.Buttons[8] );
120        numberPad.add( this.Buttons[9] );
121        numberPad.add( this.Buttons[Calculator.OP_DIV] );
122        numberPad.add( this.Buttons[4] );  // Row 2
123        numberPad.add( this.Buttons[5] );
124        numberPad.add( this.Buttons[6] );
125        numberPad.add( this.Buttons[Calculator.OP_MUL] );
126        numberPad.add( this.Buttons[1] );  // Row 3
127        numberPad.add( this.Buttons[2] );
128        numberPad.add( this.Buttons[3] );
129        numberPad.add( this.Buttons[Calculator.OP_ADD] );
130        numberPad.add( this.Buttons[0] );  // Row 4
131        numberPad.add( this.Buttons[Calculator.DOT] );
132        numberPad.add( this.Buttons[Calculator.EQUALS] );
133        numberPad.add( this.Buttons[Calculator.OP_SUB] );
134        numberPad.add( new Button("") );   // Row 5
135        numberPad.add( new Button("") );   
136        numberPad.add( new Button("") );   
137        numberPad.add( this.Buttons[Calculator.CLEAR] ); // --BIG button
138        this.add( numberPad );
139    
140        this.pack();      // Set the window size,
141        this.show();      // pop it up,
142        this.validate();  //
143        this.setResizable(false);  //
144    
145    
146        this.addWindowListener( new WindowAdapter() {
147          public void windowClosing( WindowEvent e) {
148            System.out.println("Exiting...");
149            CalculatorGUI.this.dispose();
150            System.exit(0);
151          }
152        });
153    
154      }
155    
156      /**
157       * Get the next Button pressed.  The return value will be an int
158       * between 0 and 9 (if the button was a number) or one of the
159       * Calculator constants.
160       *
161       * @return the next button to be handled.
162       */
163      public int getButton() {
164        return this.buttonBuf.getButton();
165      }
166    
167      /**
168       * Get the label for the given Button ID.  The argument 
169       * should be an int between 0 and 9 (if the button was 
170       * a number) or one of the Calculator constants, 
171       * otherwise the empty string ("") will be returned.
172       *
173       * @return the button label as a String.
174       */
175      public String getButtonLabel(int buttonID) {
176        if ((buttonID < 0) || (buttonID > Calculator.LAST)) {
177          return "";
178        } else { 
179          return ButtonLabels[buttonID];
180        }
181      }
182    
183      /**
184       * Get the text currently displayed on the Calculator.
185       *
186       * @return the text as a String.
187       */
188      public String getText() {
189        return this.display.getText();
190      }
191    
192    
193      /**
194       * Set the text currently displayed on the Calculator.
195       *
196       * @param newText the text to be displayed.
197       */
198      public void setText( String newText ) {
199        this.display.setText( newText );
200      }
201    }
202    
203    /* Comments:
204     *
205     * History:
206     *     $Log: CalculatorGUI.java,v $
207     *     Revision 1.1.1.1  2002/06/05 21:56:34  root
208     *     CS101 comes to Olin finally.
209     *
210     *     Revision 1.3  2000/05/01 06:25:19  mharder
211     *     Changed javadoc to agree with new cs101 packages.
212     *
213     *     Revision 1.2  2000/04/25 17:45:34  nathanw
214     *     Adapt to new cs101.* layout
215     *
216     *     Revision 1.1  1999/10/08 15:09:24  las
217     *     This pset replaces the old Calculator pset.  However, not everything
218     *     has been transferred.  At the moment, it's just java, doc, and index.
219     *     The rest are still in the repository under Calculator-Old.
220     *
221     *     Revision 1.6  1998/07/24 16:37:14  tparnell
222     *     Placate new javadoc behavior
223     *
224     *     Revision 1.5  1998/07/21 14:58:44  tparnell
225     *     javadoc fix
226     *
227     *     Revision 1.4  1998/07/07 14:22:00  tparnell
228     *     changed refrences to Frame.HAND_CURSOR to Cursor.HAND_CURSOR
229     *
230     *     Revision 1.3  1998/07/06 20:08:32  tparnell
231     *     removed some JDK1.0 code still present in file.  minor redesign of event
232     *     handling.  CalculatorGUI used to implement ActionListener and handled
233     *     events from the various buttons.  Now that work is done by an anonymous
234     *     inner class.
235     *
236     *     Revision 1.2  1998/06/05 05:19:29  craigh
237     *     added getButtonLabel() to Calculator interface.  Implemented the
238     *     method in CalculatorGUI, and made use of it in ButtonHandler.
239     *
240     *     Revision 1.1  1998/02/26 17:25:45  tparnell
241     *     Reconstruction from hard drive failure.  Everything appears intact.
242     *
243     *     Revision 1.3  1997/10/05 21:11:20  shong
244     *     Updated for fall97, to Java 1.1
245     *     changed GUI, using 1.1 Event Model
246     *
247     *     Revision 1.2  1997/07/16 14:15:21  tparnell
248     *     *** empty log message ***
249     *
250     *     Revision 1.2  1996/10/04 19:02:26  las
251     *     Fixed the location of the clear button so that it's not quite so
252     *     grotesque.  (I suppose that the right answer is a GridBagLayout....)
253     *
254     *     Revision 1.1  1996/10/04 16:20:21  las
255     *     Transformed Calculator into an application and made it a package.  See
256     *     STAFF_SETUP for which files are public.  To run, use Calculator.Main.
257     *
258     *     Specifics:
259     *         Added Main.java, which starts the calculator program (both
260     *     CalculatorGUI and ButtonHandler);
261     *         Made Calculator an interface;
262     *         Moved GUI implementation (previously in Calculator) to
263     *     CalculatorGUI.
264     *         Added clear button, which looks pretty gross right now.  (It can
265     *     be deleted in a single line, though.)
266     *
267     *     Revision 1.1.1.1  1996/07/18 17:26:12  sit
268     *     Import from summer 6.80s web tree
269     *
270     *
271     */
272