/*
 * @(#)DisplayPanel.java    2.3.4   6 February 2005
 *
 * Copyright 2004
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.gui;

import edu.neu.ccs.*;
import edu.neu.ccs.codec.*;
import edu.neu.ccs.util.*;
import java.awt.*;
import java.util.Vector;
import javax.swing.*;

/**
 * <P>A <CODE>{@link Displayable Displayable}</CODE> is a
 * <CODE>{@link JPanel JPanel}</CODE> that recursively propagates 
 * <CODE>Displayable</CODE> method calls 
 * only to contained components 
 * that are also <CODE>Displayable</CODE>.</P>
 *
 * <P>This class is the base class for all panel-style containers
 * provided by the JPT.</P>
 *
 * <p>As of the 2.3.3, methods have been provided that permit a
 * <code>DisplayPanel</code> to <i>self-actualize</i>, that is,
 * to install inself in a window and open that window.</p>
 *
 * <p>The various <i>frame</i> methods install this panel into a
 * <code>JPTFrame</code> which is an extension of the Java class
 * <code>JFrame</code>.</p>
 *
 * <p>The various methods that have <i>dialog</i> in their name 
 * install this panel into a <code>GeneralDialog</code> which is
 * an extension of the Java class <code>JDialog</code>.</p>
 *
 * <p>Since no component should be installed in more than one
 * frame or dialog, the user should take care to call at most
 * one of the above methods and do this at most once while an
 * object is alive.  To support this rule and to ensure that
 * the panel is installed in a window at construction, we
 * recommend the following convention.</p>
 *
 * <p><i>Convention:</i> If you choose to call a <i>frame</i> or
 * <i>dialog</i> method, do this either as the last line in a
 * constructor or soon after the constructor returns.</p>
 * 
 * <p>Since the methods that install a <code>DisplayPanel</code>
 * in a frame or dialog return that window, the caller may save
 * the window reference and later close and reopen the window if
 * desired.</p>
 *
 * @author  Richard Rasala
 * @author  Jeff Raab
 * @version 2.3.4
 * @since   1.0
 * @see Displayable
 */
public class DisplayPanel
    extends JPanel 
    implements Displayable,
               MalformedDataListener,
               JPTConstants 
{
    /** Bound property name for the codec property. */
    public static final String CODEC = "codec";

    /** Background color before alert status was entered. */
    protected Color background = SystemColor.control;
    
    /** Identifier for codec used by this panel. */
    protected String codec = CodecUtilities.getDefaultCodec();
    
    //////////////////
    // Constructors //
    //////////////////

    /**
     * Constructs a panel with the default layout manager 
     * for a <CODE>{@link JPanel JPanel}</CODE>.
     */
    public DisplayPanel() {
        super();
    }
    
    /**
     * Constructs a panel with the default layout manager 
     * for a <CODE>{@link JPanel JPanel}</CODE>
     * and the given double-buffering strategy.
     *
     * @param isDoubleBuffered whether or not the panel
     *      makes use of double-buffering
     */
    public DisplayPanel(boolean isDoubleBuffered) {
        super(isDoubleBuffered);
    }
    
    /**
     * Constructs a panel with the given layout manager.
     *
     * @param layout the desired layout manager
     */
    public DisplayPanel(LayoutManager layout) {
        super(layout);
    }

    /**
     * Constructs a panel with the given layout manager
     * and the given double-buffering strategy.
     *
     * @param layout the desired layout manager
     * @param isDoubleBuffered whether or not the panel
     *      makes use of double-buffering
     */
    public DisplayPanel(
        LayoutManager layout, 
        boolean isDoubleBuffered) 
    {
        super(layout, isDoubleBuffered);
    }

    /////////////////
    // Displayable //
    /////////////////

    /**
     * <P>Sets the view states for 
     * <CODE>Displayable</CODE> objects in the container
     * to the data encoded in the given <CODE>String</CODE>.</P>
     * 
     * <P>If the given encoded data is <CODE>null</CODE>,
     * the view states are not changed.</P>
     * 
     * </P>If the given encoded data is not <CODE>null</CODE>,
     * the data is decoded into its component data elements
     * and the view state for each of as many 
     * <CODE>Displayable</CODE> objects as possible
     * is set to the state encapsulated in the corresponding
     * data element.
     *
     * If the encoded data contains more data elements
     * than there are <CODE>Displayable</CODE> objects in the panel,
     * the extraneous data elements are ignored.
     *
     * If the encoded data contains fewer data elements
     * than there are <CODE>Displayable</CODE> objects in the panel,
     * the view states are not changed for objects that
     * do not have a corresponding data element.</P>
     *
     * @param data the encoded <CODE>String</CODE> data
     * @see #getViewState()
     * @see Displayable
     */
    public void setViewState(String data) {
        if (data == null)
            return;
    
        // decode the data and bail if null
        String[] decoded = CodecUtilities.decode(data);
        if (decoded == null)
            return;
        
        // set the view state of as many displayed objects 
        // as possible from the data
        //
        // do not change view states of objects for which
        // no data is provided
        for (int i = 0, pos = 0; i < getComponentCount(); i++) {
            Component c = getComponent(i);

            if (c instanceof Displayable) {
                Displayable d = (Displayable)c;

                if ((decoded != null) && (pos < decoded.length))
                    d.setViewState(decoded[pos++]);
            }
        }

        // notify listeners of property change
        firePropertyChange(
            VIEW_STATE, 
            null, 
            data);
    }
    
    /**
     * Returns the view states 
     * for objects in the container
     * as an encoded <CODE>String</CODE>.
     *
     * The encoded data is constructed by collecting an array
     * containing the view states for each of the
     * <CODE>Displayable</CODE> objects in the container
     * and encoding it using the CODEC whose identifier
     * is stored by this panel.
     *
     * @see #setViewState(String)
     * @see Displayable
     */
    public String getViewState() {
        
        // extract and store the values from each of the subdisplays
        Vector temp = new Vector();
        for (int i = 0; i < getComponentCount(); i++) {
            Component c = getComponent(i);
            
            if (c instanceof Displayable) {
                Displayable d = (Displayable)c;
                temp.add(d.getViewState());
            }
        }
        
        // build an array of Strings from the extracted values
        String[] data = null;
        if (temp.size() > 0) {
            data = new String[temp.size()];
            for (int i = 0; i < temp.size(); i++)
                data[i] = (String)temp.get(i);
        }

        // return the encoded representation of the data Strings
        return CodecUtilities.encode(data, codec);
    }
    
    /**
     * Sets the default view states for objects in the collection 
     * to the data encoded in the given <CODE>String</CODE>.
     *
     * <P>If the given encoded data is <CODE>null</CODE>,
     * the default view states are not changed.</P>
     * 
     * </P>If the given encoded data is not <CODE>null</CODE>,
     * the data is decoded into its component data elements
     * and the default view state for each of as many 
     * <CODE>Displayable</CODE> objects as possible
     * is set to the state encapsulated in the corresponding
     * data element.
     *
     * If the encoded data contains more data elements
     * than there are <CODE>Displayable</CODE> objects in the panel,
     * the extraneous data elements are ignored.
     *
     * If the encoded data contains fewer data elements
     * than there are <CODE>Displayable</CODE> objects in the panel,
     * the default view states are not changed for objects that
     * do not have a corresponding data element.</P>
     *
     * @see #reset()
     * @see Displayable
     * @param data the desired default <CODE>String</CODE> data
     */
    public void setDefaultViewState(String data) {
        String[] decoded = CodecUtilities.decode(data);
    
        // set the default view state of as many displayed objects 
        // as possible from the data
        //
        // do not change default view states of objects for which
        // no data is provided
        for (int i = 0, pos = 0; i < getComponentCount(); i++) {
            Component c = getComponent(i);

            if (c instanceof Displayable) {
                Displayable d = (Displayable)c;

                if ((decoded != null) && (pos < decoded.length))
                    d.setDefaultViewState(decoded[pos++]);
            }
        }

        // notify listeners of property change
        firePropertyChange(
            DEFAULT_VIEW_STATE, 
            null, 
            data);
    }
    
    /**
     * Returns the default view states 
     * for objects in the collection 
     * as an encoded <CODE>String</CODE>.
     *
     * The encoded data is constructed by collecting an array
     * containing the default view states for each of the
     * <CODE>Displayable</CODE> objects in the container
     * and encoding it using the CODEC whose identifier
     * is stored by this panel.
     *
     * @see #setDefaultViewState(String)
     * @see #reset()
     */
    public String getDefaultViewState() {
        String[] defaultStates = null;
        Vector v = new Vector();
    
        // get the default view state of 
        // the contained displayable objects
        for (int i = 0, pos = 0; i < getComponentCount(); i++) {
            Component c = getComponent(i);

            if (c instanceof Displayable) {
                Displayable d = (Displayable)c;
                v.add(d.getDefaultViewState());
            }
        }
        
        // cast the stored states to strings
        if (v.size() > 0) {
            Object[] statesArray = v.toArray();
            defaultStates = new String[statesArray.length];
            for (int i = 0; i < statesArray.length; i++)
                defaultStates[i] = (String)statesArray[i];
        }
        
        // return the encoded representation
        return CodecUtilities.encode(defaultStates);
    }

    /**
     * Enables or disables the panel, 
     * and recursively enables or disables its contents, 
     * based on the given value.
     *
     * @param isEnabled whether or not this panel is to be enabled
     * @see Displayable
     */
    public void setEnabled(boolean isEnabled) {
        for (int i = 0; i < getComponentCount(); i++)
            getComponent(i).setEnabled(isEnabled);
        
        super.setEnabled(isEnabled);
    }
    
    /**
     * Recursively resets any <CODE>Displayable</CODE> objects
     * held in the panel.
     *
     * @see #setDefaultViewState(String)
     * @see Displayable
     */
    public void reset() {
        for (int i = 0; i < getComponentCount(); i++) {
            Component c = getComponent(i);
            
            if (c instanceof Displayable) {
                Displayable d = (Displayable)c;
                d.reset();
            }
        }
    }
    
    ///////////////////////////
    // MalformedDataListener //
    ///////////////////////////
    
    /**
     * Handles a malformed data event 
     * generated by a fragile input component 
     * by alerting the user 
     * through a change to the background color of the panel.
     *
     * @param evt the malformed data event
     * @see MalformedDataListener
     */
    public void dataMalformed(MalformedDataEvent evt) {
        if (evt.isAlertOn())
            startAlert(evt);
        else
            endAlert(evt);    
    }

    /**
     * Turns on alert status for this component
     * and its children that are also <CODE>AlertListener</CODE>s.
     *
     * @param evt the alert event
     * @see AlertListener
     */
    public void startAlert(AlertEvent evt) {
        background = getBackground();
        setBackground(SystemColor.textHighlight);

        // recurse on other appropriate components in the container
        for (int i = 0; i < getComponentCount(); i++) {
            Component c = getComponent(i);
            
            if (c instanceof AlertListener) {
                AlertListener a = (AlertListener)c;
                a.startAlert(evt);
            }
        }
    }

    /**
     * Turns off alert status for this component
     * and its children that are also <CODE>AlertListener</CODE>s.
     *
     * @param evt the alert event
     * @see AlertListener
     */
    public void endAlert(AlertEvent evt) {
        setBackground(background);

        // recurse on other appropriate components in the container
        for (int i = 0; i < getComponentCount(); i++) {
            Component c = getComponent(i);
            
            if (c instanceof AlertListener) {
                AlertListener a = (AlertListener)c;
                a.endAlert(evt);
            }
        }
    }

    ////////////////
    // Public API //
    ////////////////

    /**
     * Adds the specified component to the end of this container.
     *
     * @param c the component to be added
     * @return the component argument
     * @see #add(Component, int)
     * @see #add(Component, Object)
     * @see #add(Component, Object, int)
     * @see #add(String, Component)
     * @see #remove(Component)
     * @see #remove(int)
     * @see #removeAll()
     */
    public Component add(Component c) {
        return add(c, -1);
    }
    
    /**
     * Adds the specified component to this container 
     * at the given position.
     *
     * @param c the component to be added
     * @param index the position at which to insert the component,
     *      or -1 to insert the component at the end.
     * @return the component argument
     * @see #add(Component)
     * @see #add(Component, Object)
     * @see #add(Component, Object, int)
     * @see #add(String, Component)
     * @see #remove(Component)
     * @see #remove(int)
     * @see #removeAll()
     */
    public Component add(Component c, int index) {
        super.add(c, index);

        // store the new object on display and add it to the
        // visualization
        if ((c != null) && (c instanceof Fragile)) {
            Fragile f = (Fragile)c;
            f.addMalformedDataListener(this);
        }
    
        // update the visualization
        revalidate();
                
        // return the component argument
        return c;
    }

    /**
     * Adds the specified component to the end of this container. 
     *
     * Also notifies the layout manager 
     * to add the component to this container's layout 
     * using the given constraints object.
     *
     * @param c the component to be added
     * @param constraints an object expressing layout constraints 
     *      for this component
     * @see #add(Component)
     * @see #add(Component, int)
     * @see #add(Component, Object, int)
     * @see #add(String, Component)
     * @see #remove(Component)
     * @see #remove(int)
     * @see #removeAll()
     */
    public void add(Component c, Object constraints) {
        super.add(c, constraints);

        // store the new object on display and add it to the
        // visualization
        if ((c != null) && (c instanceof Fragile)) {
            Fragile f = (Fragile)c;
            f.addMalformedDataListener(this);
        }
    
        // update the visualization
        revalidate();
    }

    /**
     * Adds the specified component at the given position. 
     * 
     * Also notifies the layout manager 
     * to add the component to this container's layout 
     * using the specified constraints object.
     *
     * @param c the component to be added
     * @param constraints an object expressing layout constraints 
     *      for this component
     * @param index the position at which to insert the component,
     *      or -1 to insert the component at the end.
     * @see #add(Component)
     * @see #add(Component, int)
     * @see #add(Component, Object)
     * @see #add(String, Component)
     * @see #remove(Component)
     * @see #remove(int)
     * @see #removeAll()
     */
    public void add(Component c, Object constraints, int index) {
        super.add(c, constraints, index);

        // store the new object on display and add it to the
        // visualization
        if ((c != null) && (c instanceof Fragile)) {
            Fragile f = (Fragile)c;
            f.addMalformedDataListener(this);
        }
    
        // update the visualization
        revalidate();
    }

    /**
     * Adds the given component to this container. 
     *
     * It is strongly advised to use the 1.1 method, 
     * <CODE>{@link #add(Component, Object)
     *               add(Component, Object)}</CODE>,
     * in place of this method.
     *
     * @param name the name of the component to be added
     * @param c the component to be added
     * @return the component argument
     * @see #add(Component)
     * @see #add(Component, int)
     * @see #add(Component, Object)
     * @see #add(Component, Object, int)
     * @see #remove(Component)
     * @see #remove(int)
     * @see #removeAll()
     */
    public Component add(String name, Component c) {
        super.add(name, c);

        // store the new object on display and add it to the
        // visualization
        if ((c != null) && (c instanceof Fragile)) {
            Fragile f = (Fragile)c;
            f.addMalformedDataListener(this);
        }
        
        // update the visualization
        revalidate();
        
        // return the component argument
        return c;
    }

    /**
     * Add the given object to this <CODE>DisplayPanel</CODE>
     * at the next available position
     * after applying the transformation of the method
     * <CODE>makeComponent</CODE>.
     *
     * @param  object the object to be transformed and added to the panel
     * @return the component obtained by transforming the object
     * @see #addObject(Object, int)
     * @see #addObject(Object, Object)
     * @see #addObject(Object, Object, int)
     * @see #makeComponent(Object)
     * @since 2.2
     */
    public Component addObject(Object object) {
        Component component = makeComponent(object);
        
        if (component != null)
            add(component);
        
        return component;
    }
    
    /**
     * Add the given object to this <CODE>DisplayPanel</CODE>
     * at the given index position
     * after applying the transformation of the method
     * <CODE>makeComponent</CODE>.
     *
     * @param  object the object to be transformed and added to the panel
     * @param  index the position at which to add the component
     * @return the component obtained by transforming the object
     * @see #addObject(Object)
     * @see #addObject(Object, Object)
     * @see #addObject(Object, Object, int)
     * @see #makeComponent(Object)
     * @since 2.2
     */
    public Component addObject(Object object, int index) {
        Component component = makeComponent(object);
        
        if (component != null)
            add(component, index);
        
        return component;
    }
    
    /**
     * Add the given object to this <CODE>DisplayPanel</CODE>
     * with the specified constaints
     * at the next appropriate position
     * after applying the transformation of the method
     * <CODE>makeComponent</CODE>.
     *
     * @param  object the object to be transformed and added to the panel
     * @param  constraints an object expressing layout constraints for the component
     * @return the component obtained by transforming the object
     * @see #addObject(Object)
     * @see #addObject(Object, int)
     * @see #addObject(Object, Object, int)
     * @see #makeComponent(Object)
     * @since 2.2
     */
    public Component addObject(Object object, Object constraints) {
        Component component = makeComponent(object);
        
        if (component != null)
            add(component, constraints);
        
        return component;
    }
    
    /**
     * Add the given object to this <CODE>DisplayPanel</CODE>
     * at the given index position
     * after applying the transformation of the method
     * <CODE>makeComponent</CODE>.
     *
     * @param  object the object to be transformed and added to the panel
     * @param  constraints an object expressing layout constraints for the component
     * @param  index the position at which to add the component
     * @return the component obtained by transforming the object
     * @see #addObject(Object)
     * @see #addObject(Object, int)
     * @see #addObject(Object, Object)
     * @see #makeComponent(Object)
     * @since 2.2
     */
    public Component addObject(Object object, Object constraints, int index) {
        Component component = makeComponent(object);
        
        if (component != null)
            add(component, constraints, index);
        
        return component;
    }
    
    /**
     * By default, this method will return the
     * <CODE>Component</CODE> constructed using
     * <CODE>ComponentFactory.makeComponent</CODE>.
     *
     * @param  object the object to be transformed
     * @return the component obtained by transforming the object
     * @see ComponentFactory#makeComponent(Object)
     * @since 2.2
     */
    public Component makeComponent(Object o) {
        return ComponentFactory.makeComponent(o);
    }
    
    /**
     * Removes the given component from this container.
     *
     * @param c the component to be removed
     * @see #add(Component)
     * @see #add(Component, int)
     * @see #add(Component, Object)
     * @see #add(Component, Object, int)
     * @see #add(String, Component)
     * @see #remove(int)
     * @see #removeAll()
     */
    public void remove(Component c) {
        super.remove(c);

        // remove the listener for this object if necessary
        if ((c != null) && (c instanceof Fragile)) {
            Fragile f = (Fragile)c;
            f.removeMalformedDataListener(this);
        }

        // update the visualization
        revalidate();
    }
    
    /**
     * Removes the component at the given index 
     * from this container.
     *
     * @param index the index of the component to be removed
     * @see #add(Component)
     * @see #add(Component, int)
     * @see #add(Component, Object)
     * @see #add(Component, Object, int)
     * @see #add(String, Component)
     * @see #remove(Component)
     * @see #removeAll()
     */
    public void remove(int index) {
        try {
            Component c = getComponent(index);
            
            // remove the listener for this component if necessary
            if ((c != null) && (c instanceof Fragile)) {
                Fragile f = (Fragile)c;
                f.removeMalformedDataListener(this);
            }
        } catch (Exception ex) {}
        finally {
            super.remove(index);

            // update the visualization
            revalidate();
        }
    }
    
    /**
     * Removes all of the components from this container.
     *
     * @see #add(Component)
     * @see #add(Component, int)
     * @see #add(Component, Object)
     * @see #add(Component, Object, int)
     * @see #add(String, Component)
     * @see #remove(Component)
     * @see #remove(int)
     */
    public void removeAll() {
        while (getComponentCount() > 0)
            remove(0);
    }

    /**
     * <P>Sets the preferred size for all <CODE>JComponent</CODE>s 
     * in this panel to the same preferred size.</P>
     *
     * <P>The preferred size that is used is created from the
     * widest preferred width and tallest preferred height
     * among the contained components.</P>
     *
     * @since 2.0
     */
    public void uniformizeSize() {
        Component[] list = getComponents();
        int length = list.length;
        
        JComponent component = null;
        
        // find the enclosing preferred size
        Dimension d = new Dimension();
        
        for (int i = 0; i < length; i++) {
            if (list[i] instanceof JComponent) {
                component = (JComponent) list[i];
                
                d = DimensionUtilities.max
                    (d, component.getPreferredSize());
            }
        }
        
        // set the preferred size for all components
        for (int i = 0; i < length; i++) {
            if (list[i] instanceof JComponent) {
                component = (JComponent) list[i];
                component.setPreferredSize(d);
            }
        }
    }
    
    /**
     * <P>Sets the preferred width for all <CODE>JComponent</CODE>s 
     * in this panel to the same width.</P>
     *
     * <P>The preferred width that is used is created from the
     * widest preferred width among the contained components.</P>
     *
     * @since 2.3
     */
    public void uniformizeWidth() {
        Component[] list = getComponents();
        int length = list.length;
        
        JComponent component = null;
        Dimension d = null;
        int maxWidth = 0;
        
        // find the maximum preferred width
        for (int i = 0; i < length; i++) {
            if (list[i] instanceof JComponent) {
                component = (JComponent) list[i];
                d = component.getPreferredSize();
                maxWidth = Math.max(maxWidth, (int) d.getWidth());
            }
        }
        
        // set the preferred width for all components
        for (int i = 0; i < length; i++) {
            if (list[i] instanceof JComponent) {
                component = (JComponent) list[i];
                d = component.getPreferredSize();
                d.setSize(maxWidth, (int) d.getHeight());
                component.setPreferredSize(d);
            }
        }
    }
    
    /**
     * <P>Sets the preferred height for all <CODE>JComponent</CODE>s 
     * in this panel to the same height.</P>
     *
     * <P>The preferred height that is used is created from the
     * tallest preferred height among the contained components.</P>
     *
     * @since 2.3
     */
    public void uniformizeHeight() {
        Component[] list = getComponents();
        int length = list.length;
        
        JComponent component = null;
        Dimension d = null;
        int maxHeight = 0;
        
        // find the maximum preferred height
        for (int i = 0; i < length; i++) {
            if (list[i] instanceof JComponent) {
                component = (JComponent) list[i];
                d = component.getPreferredSize();
                maxHeight = Math.max(maxHeight, (int) d.getHeight());
            }
        }
        
        // set the preferred height for all components
        for (int i = 0; i < length; i++) {
            if (list[i] instanceof JComponent) {
                component = (JComponent) list[i];
                d = component.getPreferredSize();
                d.setSize((int) d.getWidth(), maxHeight);
                component.setPreferredSize(d);
            }
        }
    }
    
    /**
     * Sets the identifier for the CODEC to be used 
     * to combine multiple child view states 
     * into an encoded <CODE>String</CODE>.
     *
     * If the given identifier is <CODE>null</CODE>,
     * the CODEC is not changed.
     *
     * @param codecID identifier of the codec to be used
     * @see #getCodec()
     */
    public void setCodec(String codecID) {
        String oldCodec = getCodec();
    
        if (codecID != null)
            codec = codecID;

        // if codec has changed
        if (getCodec() != oldCodec) {
        
            // notify listeners of property change
            firePropertyChange(
                CODEC,
                oldCodec,
                getCodec());
        }                
    }
    
    /**
     * Returns the identifier for the current CODEC to be used
     * to combine multiple child view states 
     * into an encoded <CODE>String</CODE>.
     *
     * @see #setCodec(String)
     */
    public String getCodec() {
        return codec;
    }
    
    
    /**
     * <p>Frame this panel in a JPTFrame
     * and open the frame;
     * return the frame constructed.</p>
     *
     * @return the frame constructed
     * @since 2.3.3
     */
    public JPTFrame frame() {
        return frame(null, CENTER, null);
    }
    
    
    /**
     * <p>Frame this panel in a JPTFrame
     * and open the frame;
     * use the given location which should be either
     * <code>CENTER</code> or one of the standard constants
     * for one of the eight compass directions;
     * return the frame constructed.</p>
     *
     * @param location the constant representing the frame location
     * @return the frame constructed
     * @since 2.3.3
     */
    public JPTFrame frame(int location) {
        return frame(null, location, null);
    }
    
    
    /**
     * <p>Frame this panel in a JPTFrame
     * and open the frame;
     * use the given title for the frame;
     * return the frame constructed.</p>
     *
     * @param title the title for the frame
     * @return the frame constructed
     * @since 2.3.3
     */
    public JPTFrame frame(String title) {
        return frame(title, CENTER, null);
    }
    
    
    /**
     * <p>Frame this panel in a JPTFrame
     * and open the frame;
     * use the given title for the frame;
     * use the given location which should be either
     * <code>CENTER</code> or one of the standard constants
     * for one of the eight compass directions;
     * return the frame constructed.</p>
     *
     * @param title    the title for the frame
     * @param location the constant representing the frame location
     * @return the frame constructed
     * @since 2.3.3
     */
    public JPTFrame frame(String title, int location) {
        return frame(title, location, null);
    }
    
    
    /**
     * <p>Frame this panel in a JPTFrame
     * and open the frame;
     * use the given title for the frame;
     * use the given insets to inset the frame in the screen;
     * return the frame constructed.</p>
     *
     * @param title    the title for the frame
     * @param insets   the screen insets to use to adjust the location
     * @return the frame constructed
     * @since 2.3.4
     */
    public JPTFrame frame(String title, Insets insets) {
        return frame(title, CENTER, insets);
    }
    
    
    /**
     * <p>Frame this panel in a JPTFrame
     * and open the frame;
     * use the given title for the frame;
     * use the given location which should be either
     * <code>CENTER</code> or one of the standard constants
     * for one of the eight compass directions;
     * use the given insets to inset the frame in the screen;
     * return the frame constructed.</p>
     *
     * @param title    the title for the frame
     * @param location the constant representing the frame location
     * @param insets   the screen insets to use to adjust the location
     * @return the frame constructed
     * @since 2.3.3
     */
    public JPTFrame frame(String title, int location, Insets insets) {
        return JPTFrame.frame(this, title, location, insets);
    }
    
    
    /**
     * <p>Place this panel in a modal OK dialog
     * and open the dialog;
     * return the dialog constructed.</p>
     *
     * @return the dialog constructed
     * @since 2.3.3
     */
    public GeneralDialog OKDialog() {
        return OKDialog(null);
    }
    
    
    /**
     * <p>Place this panel in a modal OK dialog
     * and open the dialog;
     * use the given title for the dialog;
     * return the dialog constructed.</p>
     *
     * @param title the title for the dialog
     * @return the dialog constructed
     * @since 2.3.3
     */
    public GeneralDialog OKDialog(String title) {
        GeneralDialog dialog = GeneralDialog.makeOKDialog(this, title);
        dialog.setVisible(true);
        return dialog;
    }
    
    
    /**
     * <p>Place this panel in a modal OK-Cancel dialog
     * and open the dialog;
     * return the dialog constructed.</p>
     *
     * @return the dialog constructed
     * @since 2.3.3
     */
    public GeneralDialog OKCancelDialog() {
        return OKCancelDialog(null);
    }
    
    
    /**
     * <p>Place this panel in a modal OK-Cancel dialog
     * and open the dialog;
     * use the given title for the dialog;
     * return the dialog constructed.</p>
     *
     * @param title the title for the dialog
     * @return the dialog constructed
     * @since 2.3.3
     */
    public GeneralDialog OKCancelDialog(String title) {
        GeneralDialog dialog = GeneralDialog.makeOKCancelDialog(this, title);
        dialog.setVisible(true);
        return dialog;
    }
    
    
    /**
     * <p>Place this panel in a modal Yes-No-Cancel dialog
     * and open the dialog;
     * return the dialog constructed.</p>
     *
     * @return the dialog constructed
     * @since 2.3.3
     */
    public GeneralDialog YesNoCancelDialog() {
        return YesNoCancelDialog(null);
    }
    
    
    /**
     * <p>Place this panel in a modal Yes-No-Cancel dialog
     * and open the dialog;
     * use the given title for the dialog;
     * return the dialog constructed.</p>
     *
     * @param title the title for the dialog
     * @return the dialog constructed
     * @since 2.3.3
     */
    public GeneralDialog YesNoCancelDialog(String title) {
        GeneralDialog dialog = GeneralDialog.makeYesNoCancelDialog(this, title);
        dialog.setVisible(true);
        return dialog;
    }
    
    
    /**
     * <p>Place this panel in a modal general dialog
     * and open the dialog;
     * use the action data to define the dialog buttons;
     * return the dialog constructed.</p>
     *
     * <p>The parameter <code>actionData</code> 
     * is an <code>Object[][]</code> array that specifies 
     * each dialog <code>Action</code> in one of the following ways:</p>
     * 
     * <ul>
     *   <li> A subarray { action }             with an <code>Action</code></li>
     *   <li> A subarray { name }               with an action name</li>
     *   <li> A subarray { name, icon }         with an action name and icon</li>
     *   <li> A subarray { action, option }
     *   <li> A subarray { name, option }
     *   <li> A subarray { name, icon, option }
     * </ul>
     *
     * <p>If the option parameter is specified, it must be one of the following
     * values that will determine what is done to the dialog when the action is
     * finished:</p>
     *
     * <ul><code>
     *   <li> DialogAction.KEEP_OPEN</li>
     *   <li> DialogAction.AUTO_CLOSE</li>
     *   <li> DialogAction.SET_CANCEL</li>
     * </code></ul>
     *
     * <p>If the option parameter is not specified, it is taken to be
     * <code>DialogAction.AUTO_CLOSE</code>.</p>
     *
     * @param actionData the action data
     * @return the dialog constructed
     * @since 2.3.3
     */
    public GeneralDialog generalDialog(Object[][] actionData) {
        return generalDialog(null, actionData, null);
    }
    
    
    /**
     * <p>Place this panel in a modal general dialog
     * and open the dialog;
     * use the action data to define the dialog buttons;
     * use the default action object to define the default button;
     * return the dialog constructed.</p>
     *
     * <p>The parameter <code>actionData</code> 
     * is an <code>Object[][]</code> array that specifies 
     * each dialog <code>Action</code> in one of the following ways:</p>
     * 
     * <ul>
     *   <li> A subarray { action }             with an <code>Action</code></li>
     *   <li> A subarray { name }               with an action name</li>
     *   <li> A subarray { name, icon }         with an action name and icon</li>
     *   <li> A subarray { action, option }
     *   <li> A subarray { name, option }
     *   <li> A subarray { name, icon, option }
     * </ul>
     *
     * <p>If the option parameter is specified, it must be one of the following
     * values that will determine what is done to the dialog when the action is
     * finished:</p>
     *
     * <ul><code>
     *   <li> DialogAction.KEEP_OPEN</li>
     *   <li> DialogAction.AUTO_CLOSE</li>
     *   <li> DialogAction.SET_CANCEL</li>
     * </code></ul>
     *
     * <p>If the option parameter is not specified, it is taken to be
     * <code>DialogAction.AUTO_CLOSE</code>.</p>
     *
     * <p>The <code>Object</code> supplied for the default action must either be
     * an <code>Action</code> or a name that is supplied in the action data.  If
     * the parameter is <code>null</code>, no default action is set.</p>
     * 
     * @param actionData    the action data
     * @param defaultAction the default action
     * @return the dialog constructed
     * @since 2.3.3
     */
    public GeneralDialog generalDialog(Object[][] actionData, Object defaultAction) {
        return generalDialog(null, actionData, defaultAction);
    }
    
    
    /**
     * <p>Place this panel in a modal general dialog
     * and open the dialog;
     * use the given title for the dialog;
     * use the action data to define the dialog buttons;
     * return the dialog constructed.</p>
     *
     * <p>The parameter <code>actionData</code> 
     * is an <code>Object[][]</code> array that specifies 
     * each dialog <code>Action</code> in one of the following ways:</p>
     * 
     * <ul>
     *   <li> A subarray { action }             with an <code>Action</code></li>
     *   <li> A subarray { name }               with an action name</li>
     *   <li> A subarray { name, icon }         with an action name and icon</li>
     *   <li> A subarray { action, option }
     *   <li> A subarray { name, option }
     *   <li> A subarray { name, icon, option }
     * </ul>
     *
     * <p>If the option parameter is specified, it must be one of the following
     * values that will determine what is done to the dialog when the action is
     * finished:</p>
     *
     * <ul><code>
     *   <li> DialogAction.KEEP_OPEN</li>
     *   <li> DialogAction.AUTO_CLOSE</li>
     *   <li> DialogAction.SET_CANCEL</li>
     * </code></ul>
     *
     * <p>If the option parameter is not specified, it is taken to be
     * <code>DialogAction.AUTO_CLOSE</code>.</p>
     *
     * @param title      the title for the dialog
     * @param actionData the action data
     * @return the dialog constructed
     * @since 2.3.3
     */
    public GeneralDialog generalDialog(String title, Object[][] actionData) {
        return generalDialog(title, actionData, null);
    }
    
    
    /**
     * <p>Place this panel in a modal general dialog
     * and open the dialog;
     * use the given title for the dialog;
     * use the action data to define the dialog buttons;
     * use the default action object to define the default button;
     * return the dialog constructed.</p>
     *
     * <p>The parameter <code>actionData</code> 
     * is an <code>Object[][]</code> array that specifies 
     * each dialog <code>Action</code> in one of the following ways:</p>
     * 
     * <ul>
     *   <li> A subarray { action }             with an <code>Action</code></li>
     *   <li> A subarray { name }               with an action name</li>
     *   <li> A subarray { name, icon }         with an action name and icon</li>
     *   <li> A subarray { action, option }
     *   <li> A subarray { name, option }
     *   <li> A subarray { name, icon, option }
     * </ul>
     *
     * <p>If the option parameter is specified, it must be one of the following
     * values that will determine what is done to the dialog when the action is
     * finished:</p>
     *
     * <ul><code>
     *   <li> DialogAction.KEEP_OPEN</li>
     *   <li> DialogAction.AUTO_CLOSE</li>
     *   <li> DialogAction.SET_CANCEL</li>
     * </code></ul>
     *
     * <p>If the option parameter is not specified, it is taken to be
     * <code>DialogAction.AUTO_CLOSE</code>.</p>
     *
     * <p>The <code>Object</code> supplied for the default action must either be
     * an <code>Action</code> or a name that is supplied in the action data.  If
     * the parameter is <code>null</code>, no default action is set.</p>
     * 
     * @param title         the title for the dialog
     * @param actionData    the action data
     * @param defaultAction the default action
     * @return the dialog constructed
     * @since 2.3.3
     */
    public GeneralDialog generalDialog
        (String title, Object[][] actionData, Object defaultAction)
    {
        GeneralDialog dialog = new GeneralDialog(this, title, actionData, defaultAction);
        
        dialog.setVisible(true);
        return dialog;
    }
    
    
    /** Refreshes the component by repacking the parent window. */
    public void refreshComponent() {
        Refresh.packParentWindow(this);
    }
    
}
