C:\upload\java\Life\source\java\PopupWindow.java
/*******************************************************************
    Next is for pop up windows.
******************************************************************** */
 
import java.awt.*;
import java.awt.event.*;
 
final class PopupWindow implements ActionListener, 
                             Constants,     // Program constants, and
                             Strings, WindowListener        // Strings.
{

    private ScreenLocations screenLocations;
    private Frame  parentFrame;    // To what things are attached.
    private String windowName;  // What we call the window, title bar.

    private Dialog window;              // Displays the message & the buttons.
    private String buttonPressed;

/*******************************************************************
    Constructor follows:
******************************************************************** */

    PopupWindow(Frame parentFrame, ScreenLocations screenLocations, String windowName)
    {
        // Are there errors?  Next handles this:
        String errorString = ((parentFrame != null) && 
                              (screenLocations != null)) ? 
                             NULL_STRING : "parentFrame = " + parentFrame +
                             " screenLocations = " + screenLocations;
        if (!errorString.equals(NULL_STRING))
        {
            System.out.println("Error, null pointer, PopupWindow " 
                              + errorString);
            return;
        }
        // Our data is good.  Done with error handling.
        
        this.parentFrame = parentFrame;
        this.screenLocations = screenLocations;

        // More error handling.  We are very careful.
        if ((parentFrame == null) || (screenLocations == null))
        {
            System.out.println("Failure, PopupWindow, parentFrame = " + parentFrame +
                               " screenLocations = " + screenLocations + ". Fatal error.");
            System.exit(0);
        }        
        this.windowName = windowName;
        buttonPressed = INVALID_BUTTON;
    }

// Overidden methods from WindowListener interface:
// Only < windowClosing > matters:  user hit the "x" "close me" icon.
public void windowClosing(WindowEvent e)
{ 
   window.setVisible(false); // Time to get out. Continue.
   System.exit(0);           // Kill everything.
}
public void windowActivated(WindowEvent e)  {}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e)  {}
public void windowOpened(WindowEvent e)     {}
public void windowClosed(WindowEvent e)     {}

/*******************************************************************
    These windows must be ordered to go away when there are no 
    buttons, via < Dismiss() >, next.
******************************************************************** */ 
    protected void Dismiss()
    {
        window.setVisible(false);
    }

/*******************************************************************
   Utility routine < makeLabels > turns strings into a label array that 
   can be placed on a layout.
******************************************************************** */
    private Label [] makeLabels(String [] message)
    {
        int i;                  // Loop variable
        int len;                // Size of array we allocate.
        if (message != null)    // Always assume the calling routine may
        {                       // have given us garbage.
            len = message.length;
        }
        else
        {
            len = 0;    // We may return a null array.
        }
        Label [] ms = new Label[len];

        for (i = 0; i < len; i++)
        {
            ms[i] = new Label(message[i]);
        }
        return (ms);
    }

/*******************************************************************
   Utility routine < makeButtons > turns strings into a button array 
   that can be placed on a layout. These are used in the
   constructors, below, so placed above.
******************************************************************** */

    private Button [] makeButtons(String [] buttonNames)
    {
        int i;                      // Loop variable
        int len;                    // Size of array we allocate.
        if (buttonNames != null)    // Always assume the calling routine may
        {                           // have given us garbage.
            len = buttonNames.length;
            buttonPressed = buttonNames[0]; // Default button will be first.  If we
        }                                   // close via that "x" icon, this is chosen. 
        else
        {
            len = 0;    // We may return a null array.
        }

        Button [] buttons = new Button[len];

        for (i = 0; i < len; i++)
        {
            buttons[i] = new Button(buttonNames[i]);
        }
        return (buttons);
    }

/*******************************************************************

    Notes: this object has six overloaded means of calling its main routine. 
    Sometimes the calling module wishes to display an array of strings, 
    sometimes a single string. Sometimes there is one button, sometimes 
    several buttons. The implementation should be "invisible" to the caller.

    And in the first two constructor there are no buttons, and the option
    of an array of strings or a single string.

    Note the liberal use of the utility routines < makeLabels > and
    < makeButtons >. These are below, and take an array of strings and
    turn them into an array of either:

        1) Labels holding said strings.
        2) Buttons with the given string as their name.

    The real dirty work takes place in routine 
    < utilityToSetUpPopupWindow >, which all four constructors call.
******************************************************************** */

    // First constructor for an array of messages and no buttons

    protected final void ShowMessage(String [] message)  // Display several strings
    {
        utilityToSetUpPopupWindow(makeLabels(message),     // Used by all constructors
                                  null);                   // No buttons.
    }    
    // A single string, no buttons:

    protected final void ShowMessage(String message)  // Display several strings
    {
        String [] labelStringArray = new String[1];
        labelStringArray[0] = message;

        utilityToSetUpPopupWindow(makeLabels(labelStringArray),    // Used by all constructors
                                  null);                           // No buttons.
 
    }
    // An array of labels and buttons:

    protected final void ShowMessage(String [] message, String [] buttonNames)  
                                        // Display several strings w/ several buttons
    {
        utilityToSetUpPopupWindow(makeLabels(message), makeButtons(buttonNames));   // Used by all constructors
    }
    // For an array of messages and a single button:

    protected final void ShowMessage(String [] message, String  buttonName)  // Display several strings
    {
        String [] StringArray = new String[1];
        StringArray[0] = buttonName;

        utilityToSetUpPopupWindow(makeLabels(message), makeButtons(StringArray));   // Used by all constructors
    }
    // For an a single message and an array of buttons:

    protected final void ShowMessage(String message, String [] buttonNames)  // Display several strings
    {
        String [] labelStringArray = new String[1];
        labelStringArray[0] = message;

        utilityToSetUpPopupWindow(makeLabels(labelStringArray), makeButtons(buttonNames));
        // Used by all constructors
    }
    // For an a single message and a single button:

    protected final void ShowMessage(String  message, String  buttonName)  // Display several strings
    {
        String [] StringArray = new String[1];
        StringArray[0] = buttonName;

        String [] labelStringArray = new String[1];
        labelStringArray[0] = message;

        utilityToSetUpPopupWindow(makeLabels(labelStringArray), makeButtons(StringArray));   // Used by all constructors
    }

/*******************************************************************
    Next sets up actual window that dispays the message. The real 
    dirty work lives in the next, which uses class < displayMessage >.
******************************************************************** */ 

    private final void utilityToSetUpPopupWindow(Label [] ms, Button [] buttons)
    {
        /* Why do we have the next boolean? Because of how Java works. 
           If the window is modal ("true" = "can't do anything until I
           am dismissed"), and there are no buttons, the Dialog can't
           be destroyed. It seems it must happen in the < actionPerformed >
           routine, and this is never called when there are no buttons.

           When there are no buttons, the calling program dismisses the
           Dialog via a call to routine < Dismiss >. Seems like a lot of
           bother, but that's how Java works. I tried a few books.
        */
        boolean buttonsExist = (buttons == null) ? false : true;

        window = new displayMessage(parentFrame, 
                                    windowName,       // Window's name.
                                    buttonsExist,     // Note above comment text.
                                    ms,               // Our array of labels 
                                    buttons);         // Our array of buttons.
        window.addWindowListener(this);

        window.pack();  // Get a sensible size.

        // Where do we go on the screen?

        window.setLocation(screenLocations.GetLocationOnScreen(window));
        window.setVisible(true);    // Show me.
    }

/* *********************************************************************
    Was the question answered (assuming there was one)? The next is the 
    interface by which this class communicates with the outside world.
   ********************************************************************* */
    protected final boolean ButtonPressed()
    {
    // Note that we initialized string  < buttonPressed > to the first in the list.
        
        return ( ! buttonPressed.equals(INVALID_BUTTON));
    }

/*******************************************************************
    Calling routine needs to know who was pressed, the next,
    < WhichButtonWasPressed() >, tells it.
******************************************************************** */ 

    protected final String WhichButtonWasPressed()
    {
        return buttonPressed;
    }

/*******************************************************************
    Routine < actionPerformed > follows. Null body; we don't use it.
******************************************************************** */

    public void actionPerformed (ActionEvent e) {} // Shouldn't be called.

/*******************************************************************
Next is to display things.
******************************************************************** */  

    public class displayMessage extends Dialog implements ActionListener, Constants
    {
        private Frame parentFrame;
        
        // Constructor:

        displayMessage(Frame parentFrame, 
                       String title,
                       boolean modal, 
                       Label [] message,
                       Button [] buttons)
        {
            super(parentFrame, title, modal);
            this.parentFrame = parentFrame;

            int i; // Loop variable.
 
            // Set up the layout. Grid bag layouts are tedious, but they are effective.
           
            GridBagLayout gridbag = new GridBagLayout();
            setBackground(Color.gray);
            GridBagConstraints constraints = new GridBagConstraints();
            setLayout(gridbag);

            setFont(STANDARD_FONT);

            /* Take care of adding buttons & setting up their action
               listeners, but only if there *are* buttons.
            */
            if (buttons != null)
            {
                Cursor ourCursor = new Cursor(Cursor.HAND_CURSOR); // What cursor we use.
                for (i = 0; i < buttons.length; i++)
                {
                    add(buttons[i]);
                    buttons[i].addActionListener(this);
                    buttons[i].setCursor(ourCursor);
                }
            }

            // Now for the tedious setting of the Grid Bag Layout.
            // We try to make this as painless as possible.

            // First: the label < message >.

            if (message != null)
            {
            /* The parameter < buttons > may be null. We 
                need to account for the size of the board. 
            
               Otherwise we get "used null pointer" problems. If buttons is non-null,
               we eat all columns (see setting of GridBagLayout below); note
               this routine sets Buttons across, Labels down. If buttons is
            */
                int len = (buttons == null) ? 1 : buttons.length;

                for (i = 0; i < message.length; i++)
                {
                    add(message[i]);
                    buildConstraints(constraints, 0,      // Column one
                                                  i,      // Row *i* -- note
                                                  len,    // Eat all columns 
                                                          // Note parameter < len >.
                                                  1,      // Eats one row, and ...
                                                  0,      // all columns -- gets 0
                                                  100 / (message.length + 1),
                                                  SMALL_PADDING,
                                                  SMALL_PADDING);
                    constraints.fill = GridBagConstraints.HORIZONTAL;
                    gridbag.setConstraints(message[i], constraints);
               }
            }

                // Second: the buttons. Note labels went down, and the buttons
                // go across, in one row.

            if (buttons != null)    // If we have no buttons, do nothing.
            {
            /* The parameter < buttons > may be null. We need to 
               account for the size of the board.
            
               Otherwise we may get "used null pointer" problems.
            */
                int len = (message == null) ? 1 : message.length + 1;

                /* The "+ 1" (distinction from how < len > was 
                   defined above in case of Labels) is because 
                   Labels go down, and this routine sets buttons 
                   across. If we have labels, we want the buttons
                   one row down from bottom of labels.
                */
                for (i = 0; i < buttons.length; i++)
                {
                    buildConstraints(constraints, i,      // Column i
                                                  len,    // Note defined above:
                                                          // last row, or only row.
                                                  1,      // Eats one column
                                                  1,      // Eats one row, and ...
                                                  1,      // one colum
                                                  100 / (len + 1),
                                                  SMALL_PADDING,
                                                  SMALL_PADDING);
                    constraints.fill = GridBagConstraints.HORIZONTAL;
                    gridbag.setConstraints(buttons[i], constraints);
                }
            }       // End "if (buttons != null)" clause
        }           // End < displayMessage > constructor.
        
/*******************************************************************
        Next is the standard Insets method
******************************************************************** */

        public Insets getInsets()
        {
            return new Insets(DEFAULT_INSET, DEFAULT_INSET, DEFAULT_INSET, DEFAULT_INSET);
        }
        
/*******************************************************************
        Next is the actionPerformed method. It only gets the 
        button name.
******************************************************************** */        
        
        public void actionPerformed (ActionEvent e)
        {
            if (e.getSource() instanceof Button)
            {
                // Who was pressed?

                buttonPressed = ((Button) e.getSource()).getLabel();

                setVisible(false);  // Done. Get out.
            }
        }

/*******************************************************************
        Next is the standard GridBagConstraints method
******************************************************************** */

        void buildConstraints(GridBagConstraints gbc, 
                                int gx, 
                                int gy, 
                                int gw, 
                                int gh, 
                                int wx, 
                                int wy,
                                int padx,
                                int pady)
        {
            gbc.gridx       = gx;
            gbc.gridy       = gy;
            gbc.gridwidth   = gw;
            gbc.gridheight  = gh;
            gbc.weightx     = wx;
            gbc.weighty     = wy;
            gbc.ipadx       = padx;
            gbc.ipady       = pady;
        }
    }       // End public class displayMessage
}           // End class PopupWindow