/*
 * @(#)TablePanel.java    2.3  30 October 2003
 *
 * 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.util.*;

import java.awt.*;
import javax.swing.*;

/**
 * <P> A DisplayPanel designed to use a <CODE>TableLayout</CODE> as
 * its layout manager.</P>
 *
 * <P>The method <CODE>setLayout</CODE> is overridden so that it is
 * impossible to change the layout manager to any other layout.</P>
 *
 * @author  Richard Rasala
 * @author  Jeff Raab
 * @version 2.3
 * @since   1.1
 * @see TableLayout
 */
public class TablePanel extends DisplayPanel {
    
    ///////////////
    // Constants //
    ///////////////
    
    /** Value of the default cell alignment. */
    public static final int DEFAULT_ALIGNMENT =
        TableLayout.DEFAULT_ALIGNMENT;
        
    /** 
     * Value of the default cell alignment. 
     * @since 2.0
     */
    public static final int DEFAULT_ORIENTATION =
        TableLayout.DEFAULT_ORIENTATION;
    
    /////////////////
    // Member Data //
    /////////////////
    
    /** Generator used to produce the content for this table. */
    protected TableGenerator tg = null;
        
    //////////////////
    // Constructors //
    //////////////////
    
    /**
     * Constructs a default table panel.
     *
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     */
    public TablePanel() {
        this(1, 1, 0, 0, DEFAULT_ALIGNMENT);
    }
    
    /**
     * Constructs a table panel with the given cell alignment.
     *
     * @param align the alignment of a component within a table cell
     * @see #TablePanel()
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see JPTConstants#DEFAULT
     */
    public TablePanel(int align) {
        this(1, 1, 0, 0, align);
    }
    
    /**
     * Constructs a table panel with 
     * the given number of rows and columns.
     *
     * @param rows the number of rows in the table
     * @param cols the number of columns in the table
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     */
    public TablePanel(int rows, int cols) {
        this(rows, cols, 0, 0, DEFAULT_ALIGNMENT);
    }
    
    /**
     * Constructs a table panel with
     * the given number of rows and columns,
     * and the given cell alignment.
     *
     * @param rows the number of rows in the table
     * @param cols the number of columns in the table
     * @param align the alignment of a component within a table cell
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see JPTConstants#DEFAULT
     */
    public TablePanel(int rows, int cols, int align) {
        this(rows, cols, 0, 0, align);
    }
    
    /**
     * Constructs a table panel with
     * the given number of rows and columns,
     * and the given horizontal and vertical gaps between cells.
     *
     * @param rows the number of rows in the table
     * @param cols the number of columns in the table
     * @param hgap the horizontal gap between columns
     * @param vgap the vertical gap between rows
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     */
    public TablePanel(int rows, int cols, int hgap, int vgap) {
        this(rows, cols, hgap, vgap, DEFAULT_ALIGNMENT);
    }
    
    /**
     * Constructs a table panel with
     * the given number of rows and columns,
     * the given horizontal and vertical gaps between cells,
     * and the given cell alignment.
     *
     * @param rows the number of rows in the table
     * @param cols the number of columns in the table
     * @param hgap the horizontal gap between columns
     * @param vgap the vertical gap between rows
     * @param align the alignment of a component within a table cell
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see JPTConstants#DEFAULT
     */
    public TablePanel(int rows, int cols, int hgap, int vgap, int align) {
        this(rows, cols, hgap, vgap, align, DEFAULT_ORIENTATION);
    }
    
    /**
     * Constructs a table panel with
     * the given number of rows and columns,
     * the given horizontal and vertical gaps between cells,
     * the given cell alignment,
     * and the given table layout orientation.
     *
     * @param rows the number of rows in the table
     * @param cols the number of columns in the table
     * @param hgap the horizontal gap between columns
     * @param vgap the vertical gap between rows
     * @param align the alignment of a component within a table cell
     * @param orientation the table layout orientation
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see JPTConstants#DEFAULT
     * @since 2.0
     */
    public TablePanel(
        int rows, 
        int cols, 
        int hgap, 
        int vgap, 
        int align,
        int orientation) 
    {
        super.setLayout(new TableLayout(
            rows, cols, hgap, vgap, align, orientation));

        resetPreferredSize();
    }
    
    /**
     * Constructs a table panel containing the given objects
     * in the given orientation.
     *
     * @param contents the array of contents to be used to fill the table
     * @param orientation the table orientation
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see SwingConstants#VERTICAL
     * @see SwingConstants#HORIZONTAL
     */
    public TablePanel(Object[] contents, int orientation) {
        this(contents, orientation, 0, 0, DEFAULT_ALIGNMENT);
    }
    
    /**
     * Constructs a table panel containing the given objects
     * in the given orientation, with the given cell alignment.
     *
     * @param contents the array of contents to be used to fill the table
     * @param orientation the table orientation
     * @param align the alignment of a component within a table cell
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see JPTConstants#DEFAULT
     */
    public TablePanel(Object[] contents, int orientation, int align) {
        this(contents, orientation, 0, 0, align);
    }
    
    /**
     * Constructs a table panel containing the given objects
     * in the given orientation,
     * with the given horizontal and vertical gaps between cells.
     *
     * @param contents the array of contents to be used to fill the table
     * @param orientation the table orientation
     * @param hgap the horizontal gap between columns
     * @param vgap the vertical gap between rows
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see SwingConstants#VERTICAL
     * @see SwingConstants#HORIZONTAL
     */
    public TablePanel
        (Object[] contents, int orientation, int hgap, int vgap)
    {
        this(contents, orientation, hgap, vgap, DEFAULT_ALIGNMENT);
    }
    
    /**
     * Constructs a table panel containing the given objects
     * in the given orientation,
     * with the given horizontal and vertical gaps between cells
     * and the given cell alignment.
     *
     * @param contents the array of contents to be used to fill the table
     * @param orientation the table orientation
     * @param hgap the horizontal gap between columns
     * @param vgap the vertical gap between rows
     * @param align the alignment of a component within a table cell
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see JPTConstants#DEFAULT
     */
    public TablePanel(
        Object[] contents, 
        int orientation, 
        int hgap, 
        int vgap, 
        int align)
    {
        if ((contents == null) || (contents.length == 0)) {
            super.setLayout(new TableLayout(1, 1, hgap, vgap, align, orientation));
            return;
        }
        
        int length = contents.length;
        
        if (orientation == VERTICAL) {
            super.setLayout(new TableLayout(length, 1, hgap, vgap, align, orientation));
            
            for (int row = 0; row < length; row++)
                addObject(contents[row], row, 0);
        }
        
        else /* HORIZONTAL */ {
            super.setLayout(new TableLayout(1, length, hgap, vgap, align, orientation));
        
            for (int col = 0; col < length; col++)
                addObject(contents[col], 0, col);
        }
        
        resetPreferredSize();
    }
    
    /**
     * Constructs a table panel containing the given table of objects,
     * with the default cell alignment
     * and a <CODE>VERTICAL</CODE> orientation.
     *
     * @param contents the array of contents to be used to fill the table
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     */
    public TablePanel(Object[][] contents) {
        this(contents, 0, 0, DEFAULT_ALIGNMENT);
    }
    
    /**
     * Constructs a table panel containing the given table of objects
     * and the given cell alignment,
     * with the default cell alignment
     * and a <CODE>VERTICAL</CODE> orientation.
     *
     * @param contents the array of contents to be used to fill the table
     * @param align the alignment of a component within a table cell
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see JPTConstants#DEFAULT
     */
    public TablePanel(Object[][] contents, int align) {
        this(contents, 0, 0, align);
    }
    
    /**
     * Constructs a table panel containing the given table of objects,
     * with the given horizontal and vertical gaps between cells,
     * the default cell alignment, 
     * and a <CODE>VERTICAL</CODE> orientation.
     *
     * @param contents the array of contents to be used to fill the table
     * @param hgap the horizontal gap between columns
     * @param vgap the vertical gap between rows
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     */
    public TablePanel(Object[][] contents, int hgap, int vgap) {
        this(contents, hgap, vgap, DEFAULT_ALIGNMENT);
    }
    
    /**
     * Constructs a table panel containing the given table of objects,
     * with the given horizontal and vertical gaps between cells,
     * the given cell alignment, and 
     * a <CODE>VERTICAL</CODE> orientation.
     *
     * @param contents the array of contents to be used to fill the table
     * @param hgap the horizontal gap between columns
     * @param vgap the vertical gap between rows
     * @param align the alignment of a component within a table cell
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see JPTConstants#DEFAULT
     */
    public TablePanel(
        Object[][] contents, 
        int hgap, 
        int vgap, 
        int align) 
    {
        // build basic layout if contents empty
        if ((contents == null) || (contents.length == 0)) {
            super.setLayout(new TableLayout(
                1, 1, hgap, vgap, align, VERTICAL));

            return;
        }
        
        // find number of rows and columns
        int rows = contents.length;
        int cols = 0;
        
        for (int row = 0; row < rows; row++)
            if (contents[row] != null)
                cols = (int) Math.max(cols, contents[row].length);
        
        if (cols == 0) {
            super.setLayout(
                new TableLayout(1, 1, hgap, vgap, align, VERTICAL));
                
            return;
        }
        
        // set appropriate layout for contents
        super.setLayout(new TableLayout(rows, cols, hgap, vgap, align, VERTICAL));
        
        // add components to table
        for (int row = 0; row < rows; row++) {
            if (contents[row] == null)
                continue;
            
            cols = contents[row].length;
            
            for (int col = 0; col < cols; col++)
                addObject(contents[row][col], row, col);
        }
        
        resetPreferredSize();
    }
    
    /**
     * Constructs a table panel constructed from the given table
     * generator and given rows and cols.
     *
     * @param tg the table generator used to fill the table
     * @param rows the number of rows in the table
     * @param cols the number of columns in the table
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     */
    public TablePanel(TableGenerator tg, int rows, int cols) {
        this(tg, rows, cols, 0, 0, DEFAULT_ALIGNMENT);
    }
    
    /**
     * Constructs a table panel constructed from the given table
     * generator, the given rows and cols,
     * and the given cell alignment.
     *
     * @param tg the table generator used to fill the table
     * @param rows the number of rows in the table
     * @param cols the number of columns in the table
     * @param align the alignment of a component within a table cell
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see JPTConstants#DEFAULT
     */
    public TablePanel(TableGenerator tg, int rows, int cols, int align)
    {
        this(tg, rows, cols, 0, 0, align);
    }
    
    /**
     * Constructs a table panel constructed from the given table
     * generator, the given rows and cols,
     * and the given horizontal and vertical gaps between cells.
     *
     * @param tg the table generator used to fill the table
     * @param rows the number of rows in the table
     * @param cols the number of columns in the table
     * @param hgap the horizontal gap between columns
     * @param vgap the vertical gap between rows
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[], int, int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int, int)
     * @see JPTConstants#DEFAULT
     */
    public TablePanel
        (TableGenerator tg, int rows, int cols, int hgap, int vgap)
    {
        this(tg, rows, cols, hgap, vgap, DEFAULT_ALIGNMENT);
    }
    
    /**
     * Constructs a table panel constructed from the given table
     * generator, the given rows and cols,
     * the given horizontal and vertical gaps between cells,
     * and the given cell alignment.
     *
     * @param tg the table generator used to fill the table
     * @param rows the number of rows in the table
     * @param cols the number of columns in the table
     * @param hgap the horizontal gap between columns
     * @param vgap the vertical gap between rows
     * @param align the alignment of a component within a table cell
     * @see #TablePanel()
     * @see #TablePanel(int)
     * @see #TablePanel(int, int)
     * @see #TablePanel(int, int, int)
     * @see #TablePanel(int, int, int, int)
     * @see #TablePanel(int, int, int, int, int)
     * @see #TablePanel(int, int, int, int, int, int)
     * @see #TablePanel(Object[], int)
     * @see #TablePanel(Object[], int, int)
     * @see #TablePanel(Object[], int, int, int)
     * @see #TablePanel(Object[][])
     * @see #TablePanel(Object[][], int)
     * @see #TablePanel(Object[][], int, int)
     * @see #TablePanel(Object[][], int, int, int)
     * @see #TablePanel(TableGenerator, int, int)
     * @see #TablePanel(TableGenerator, int, int, int)
     * @see #TablePanel(TableGenerator, int, int, int, int)
     * @see JPTConstants#DEFAULT
     */
    public TablePanel(
        TableGenerator tg,
        int rows, 
        int cols,
        int hgap,
        int vgap,
        int align)
    {
        super.setLayout(
            new TableLayout(rows, cols, hgap, vgap, align));
        
        this.tg = tg;
        
        createCells(0, 0, rows, cols);
        
        resetPreferredSize();
    }
    
    ////////////////
    // Public API //
    ////////////////
    
    /**
     * Add the given object to this <CODE>TablePanel</CODE>
     * at the position specified by the row and column
     * after applying the transformation of the method
     * <CODE>makeComponent</CODE>.
     *
     * @param  object the object to be transformed and added to the table
     * @param  row the row in the table
     * @param  col the column in the table
     * @return the component obtained by transforming the object
     * @see DisplayPanel#addObject(Object, Object)
     * @see DisplayPanel#makeComponent(Object)
     * @since 2.2
     */
    public Component addObject(Object object, int row, int col) {
        return addObject(object, new CellPosition(row, col));
    }
    
    /** Returns a copy of the table of components in this panel. */
    public Component[][] getComponentTable() {
        return getTableLayout().getComponentTable();
    }
    
    /**
     * Returns the table generator used to create the components of
     * this table or null if no generator is being used.
     */
    public TableGenerator getTableGenerator() {
        return tg;
    }
    
    /**
     * Returns the component at the position row,col in the table
     * or null if no such component exists.
     *
     * @param row the row position of the component
     * @param col the column position of the component
     * @see #getTableEntry(CellPosition)
     */
    public Component getTableEntry(int row, int col) {
        if (isValidRow(row) && isValidColumn(col)) {
            Component[][] table = getComponentTable();
            return table[row][col];
        }
        
        return null;
    }
    
    /**
     * Returns the component at the given <CODE>CellPosition</CODE>
     * in the table or null if no such component exists.
     *
     * @param p the CellPosition of the component
     * @see #getTableEntry(int, int)
     */
    public Component getTableEntry(CellPosition p) {
        if (p != null)
            return getTableEntry(p.row, p.col);
        
        return null;
    }
    
    /**
     * Change the number of rows in the table to the given value
     * but ignore invalid parameter values less than 0.
     
     * If the table was created using a <CODE>TableGenerator</CODE>
     * then fill new cells using this table generator.
     *
     * @param rows the desired number of rows
     * @see #setColumns(int)
     */
    public void setRows(int rows) {
        int oldRows = getRowCount();
        
        if ((rows < 0) || (rows == oldRows))
            return;
        
        int cols = getColumnCount();
        
        if (oldRows < rows) {
            getTableLayout().setRows(rows);
            createCells(oldRows, 0, rows, cols);
        }
        else {
            removeCells(rows, 0, oldRows, cols);
            getTableLayout().setRows(rows);
        }
        
        resetPreferredSize();
    }
    
    /**
     * Change the number of columns in the table to the given value
     * but ignore invalid parameter values less than 0.
     
     * If the table was created using a <CODE>TableGenerator</CODE>
     * then fill new cells using this table generator.
     *
     * @param cols the desired number of columns
     * @see #setRows(int)
     */
    public void setColumns(int cols) {
        int oldCols = getColumnCount();
        
        if ((cols < 0) || (cols == oldCols))
            return;
        
        int rows = getRowCount();
        
        if (oldCols < cols) {
            getTableLayout().setColumns(cols);
            createCells(0, oldCols, rows, cols);
        }
        else {
            removeCells(0, cols, rows, oldCols);
            getTableLayout().setColumns(cols);
        }
        
        resetPreferredSize();
    }
    
    /** 
     * Returns the number of rows in this table panel. 
     *
     * @see #getColumnCount()
     */
    public int getRowCount() {
        return getTableLayout().getRowCount();
    }
    
    /** 
     * Returns the number of columns in this table panel. 
     *
     * @see #getRowCount()
     */
    public int getColumnCount() {
        return getTableLayout().getColumnCount();
    }
    
    /**
     * Returns whether or not the given row index is valid.
     *
     * @param row the row in question
     * @see #isValidColumn(int)
     */
    public boolean isValidRow(int row) {
        return getTableLayout().isValidRow(row);
    }
    
    /**
     * Returns whether or not the given column index is valid.
     *
     * @param col the column in question
     * @see #isValidRow(int)
     */
    public boolean isValidColumn(int col) {
        return getTableLayout().isValidColumn(col);
    }
    
    /**
     * Returns whether or not the given row is empty.
     *
     * @param row the row in question
     * @see #isEmptyColumn(int)
     */
    public boolean isEmptyRow(int row) {
        return getTableLayout().isEmptyRow(row);
    }
    
    /**
     * Returns whether or not the given column is empty.
     *
     * @param col the column in question
     * @see #isEmptyRow(int)
     */
    public boolean isEmptyColumn(int col) {
        return getTableLayout().isEmptyColumn(col);
    }
    
    /** 
     * Sets the gap between columns in this table panel
     * to the given value, in pixels.
     *
     * @param hgap the desired gap, in pixels
     * @see #getHorizontalGap()
     */
    public void setHorizontalGap(int hgap) {
        getTableLayout().setHorizontalGap(hgap);
        resetPreferredSize();
    }
    
    /** 
     * Returns the gap, in pixels, 
     * between columns in this table panel. 
     *
     * @see #setHorizontalGap(int)
     */
    public int getHorizontalGap() {
        return getTableLayout().getHorizontalGap();
    }

    /** 
     * Sets the gap between rows in this table panel
     * to the given value, in pixels.
     *
     * @param vgap the desired gap, in pixels
     * @see #getVerticalGap()
     */
    public void setVerticalGap(int vgap) {
        getTableLayout().setVerticalGap(vgap);
        resetPreferredSize();
    }
    
    /** 
     * Returns the gap, in pixels, 
     * between rows in this table panel. 
     *
     * @see #setVerticalGap(int)
     */
    public int getVerticalGap() {
        return getTableLayout().getVerticalGap();
    }

    /**
     * Sets the orientation for the layout of this table
     * to the given orientation value.
     *
     * If the given orientation value is invalid,
     * the orientation is not changed.
     *
     * @param orientation the orientation for this layout
     * @see #getOrientation()
     * @see JPTConstants#HORIZONTAL
     * @see JPTConstants#VERTICAL
     * @see JPTConstants#DEFAULT
     * @since 2.0
     */
    public void setOrientation(int orientation) {
        getTableLayout().setOrientation(orientation);
    }
    
    /**
     * Returns the orientation for the layout of this table.
     *
     * @see #setOrientation(int)
     * @see JPTConstants#HORIZONTAL
     * @see JPTConstants#VERTICAL
     * @since 2.0
     */
    public int getOrientation() {
        return getTableLayout().getOrientation();
    }

    /**
     * Sets the alignment for cells in this table panel
     * to the given alignment value.
     *
     * @param align the alignment value for cells
     * @see #getTableAlignment()
     * @see JPTConstants#DEFAULT
     */
    public void setTableAlignment(int align) {
        getTableLayout().setTableAlignment(align);
        refreshComponent();
    }
    
    /**
     * Returns the default alignment 
     * for cells in this table panel.
     *
     * @see #setTableAlignment(int)
     */
    public int getTableAlignment() {
        return getTableLayout().getTableAlignment();
    }
    
    /**
     * Sets the alignment for cells in the given row
     * to the given alignment value.
     *
     * @param row the row whose alignment is to be set
     * @param align the alignment value for the row
     * @see #getRowAlignment(int)
     * @see JPTConstants#DEFAULT
     */
    public void setRowAlignment(int row, int align) {
        getTableLayout().setRowAlignment(row, align);
        refreshComponent();
    }
    
    /**
     * Returns the default alignment value for the given row.
     *
     * @param row the row whose alignment value is desired
     * @see #setRowAlignment(int, int)
     */
    public int getRowAlignment(int row) {
        return getTableLayout().getRowAlignment(row);
    }
    
    /**
     * Sets the alignment for cells in the given column
     * to the given alignment value.
     *
     * @param col the column whose alignment is to be set
     * @param align the alignment value for the column
     * @see #getColumnAlignment(int)
     * @see JPTConstants#DEFAULT
     */
    public void setColumnAlignment(int col, int align) {
        getTableLayout().setColumnAlignment(col, align);
        refreshComponent();
    }
    
    /**
     * Returns the default alignment value for the given column.
     *
     * @param col the column whose alignment value is desired
     * @see #setColumnAlignment(int, int)
     */
    public int getColumnAlignment(int col) {
        return getTableLayout().getColumnAlignment(col);
    }
    
    /**
     * Sets the alignment for the cell at the given position
     * to the given alignment value.
     *
     * @param p the position of the cell whose alignment is to be changed
     * @param align the alignment value for the cell
     * @see #setCellAlignment(int, int, int)
     * @see #getCellAlignment(CellPosition)
     * @see #getCellAlignment(int, int)
     * @see #getEffectiveCellAlignment(CellPosition)
     * @see #getEffectiveCellAlignment(int, int)
     * @see JPTConstants#DEFAULT
     */
    public void setCellAlignment(CellPosition p, int align) {
        if (p != null)
            setCellAlignment(p.row, p.col, align);
    }
    
    /**
     * Sets the alignment for the cell at the given position
     * to the given alignment value.
     *
     * @param row the row for the cell whose alignment is to be changed
     * @param col the column for the cell whose alignment is to be changed
     * @see #setCellAlignment(CellPosition, int)
     * @see #getCellAlignment(CellPosition)
     * @see #getCellAlignment(int, int)
     * @see #getEffectiveCellAlignment(CellPosition)
     * @see #getEffectiveCellAlignment(int, int)
     * @see JPTConstants#DEFAULT
     */
    public void setCellAlignment(int row, int col, int align) {
        getTableLayout().setCellAlignment(row, col, align);
        refreshComponent();
    }
    
    /**
     * Returns the alignment value for the cell at the given position
     * or the table alignment if an error occurs.
     *
     * @param p the position of the cell whose alignment value is desired
     * @see #setCellAlignment(CellPosition, int)
     * @see #setCellAlignment(int, int, int)
     * @see #getCellAlignment(int, int)
     * @see #getEffectiveCellAlignment(CellPosition)
     * @see #getEffectiveCellAlignment(int, int)
     * @see JPTConstants#DEFAULT
     */
    public int getCellAlignment(CellPosition p) {
        return getTableLayout().getCellAlignment(p);
    }

    /**
     * Returns the alignment value for the cell at the given position
     * or the table alignment if an error occurs.
     *
     * @param row the row for the cell whose alignment value is desired
     * @param col the column for the cell whose alignment value is desired
     * @see #setCellAlignment(CellPosition, int)
     * @see #setCellAlignment(int, int, int)
     * @see #getCellAlignment(CellPosition)
     * @see #getEffectiveCellAlignment(CellPosition)
     * @see #getEffectiveCellAlignment(int, int)
     * @see JPTConstants#DEFAULT
     */
    public int getCellAlignment(int row, int col) {
        return getTableLayout().getCellAlignment(row, col);
    }

    /**
     * Returns the effective alignment value for the cell
     * at the given position, that is,
     * either the cell's own alignment if it has been set
     * or the alignment of the table as a whole.
     *
     * @param p the position of the cell whose alignment value is desired
     * @see #setCellAlignment(CellPosition, int)
     * @see #setCellAlignment(int, int, int)
     * @see #getCellAlignment(CellPosition)
     * @see #getCellAlignment(int, int)
     * @see #getEffectiveCellAlignment(int, int)
     * @see JPTConstants#DEFAULT
     */
    public int getEffectiveCellAlignment(CellPosition p) {
        return getTableLayout().getEffectiveCellAlignment(p);
    }

    /**
     * Returns the effective alignment value for the cell
     * at the given position, that is,
     * either the cell's own alignment if it has been set
     * or the alignment of the table as a whole.
     *
     * @param row the row for the cell whose alignment value is desired
     * @param col the column for the cell whose alignment value is desired
     * @see #setCellAlignment(CellPosition, int)
     * @see #setCellAlignment(int, int, int)
     * @see #getCellAlignment(CellPosition)
     * @see #getCellAlignment(int, int)
     * @see #getEffectiveCellAlignment(CellPosition)
     * @see JPTConstants#DEFAULT
     */
    public int getEffectiveCellAlignment(int row, int col) {
        return getTableLayout().getEffectiveCellAlignment(row, col);
    }

    /**
     * Sets the minimum height for the given row
     * to the given height in pixels.
     *
     * @param row the row whose minimum height is to be set
     * @param height the height for the row in pixels
     * @throws ArrayOutOfBoundsException
     *      if the given row is invalid
     * @see #getMinimumRowHeight(int)
     */
    public void setMinimumRowHeight(int row, int height) {
        getTableLayout().setMinimumRowHeight(row, height);
        resetPreferredSize();
    }
    
    /**
     * Returns the minimum height set for the given row.
     *
     * @param row the row whose minimum height is desired
     * @throws ArrayOutOfBoundsException
     *      if the given row is invalid
     * @see #setMinimumRowHeight(int, int)
     */
    public int getMinimumRowHeight(int row) {
        return getTableLayout().getMinimumRowHeight(row);
    }

    /**
     * Sets the minimum width for the given column
     * to the given width in pixels.
     *
     * @param col the column whose minimum width is to be set
     * @param width the width for the column in pixels
     * @throws ArrayOutOfBoundsException
     *      if the given column is invalid
     * @see #getMinimumColumnWidth(int)
     */
    public void setMinimumColumnWidth(int col, int width) {
        getTableLayout().setMinimumColumnWidth(col, width);
        resetPreferredSize();
    }

    /**
     * Returns the minimum width set for the given column.
     *
     * @param col the column whose minimum width is desired
     * @throws ArrayOutOfBoundsException
     *      if the given column is invalid
     * @see #setMinimumColumnWidth(int, int)
     */
    public int getMinimumColumnWidth(int col) {
        return getTableLayout().getMinimumColumnWidth(col);
    }
    
    /**
     * Sets all minimum row heights to the same value.
     *
     * @see #setMinimumRowHeight(int, int)
     * @see #setAllMinimumColumnWidths(int)
     */
    public void setAllMinimumRowHeights(int height) {
        getTableLayout().setAllMinimumRowHeights(height);
        resetPreferredSize();
    }
    
    /**
     * Sets all minimum column widths to the same value.
     *
     * @see #setMinimumColumnWidth(int, int)
     * @see #setAllMinimumRowHeights(int)
     */
    public void setAllMinimumColumnWidths(int width) {
        getTableLayout().setAllMinimumColumnWidths(width);
        resetPreferredSize();
    }
    
    /**
     * Returns the <CODE>TableLayout</CODE> managing this panel.
     *
     * @throws ClassCastException if the layout for this panel
     *      is not an instance of <CODE>TableLayout</CODE>
     */
    public TableLayout getTableLayout() {
        return (TableLayout)getLayout();
    }
    
    /**
     * Overrides the setLayout method to do nothing so that the
     * user of TablePanel cannot change its layout.
     *
     * @param manager parameter ignored
     */
    public void setLayout(LayoutManager manager) {
        // Intentionally does not change the layout
    }

    /**
     * Return the minimum size of the table
     * as computed by the table layout.
     */
    public Dimension getMinimumSize() {
        return getTableLayout().minimumLayoutSize(this);
    }
    
    /**
     * Return the preferred size of the table
     * as computed by the table layout.
     */
    public Dimension getPreferredSize() {
        return getTableLayout().preferredLayoutSize(this);
    }
    
    /**
     * Return the maximum size of the table
     * as computed by the table layout.
     */
    public Dimension getMaximumSize() {
        return getTableLayout().maximumLayoutSize(this);
    }
    
    /**
     * <P>Sets the table cell size for all cells 
     * in this panel to the same size.</P>
     *
     * <P>The size that is used is created from the
     * widest preferred width and tallest preferred
     * height among the contained components.</P>
     *
     * @since 2.3
     */
    public void uniformizeCellSize() {
        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 preferred column width and row height
        setAllMinimumColumnWidths( (int) d.getWidth()  );
        setAllMinimumRowHeights  ( (int) d.getHeight() );
    }
    
    /**
     * <P>Sets the table cell width for all cells 
     * in this panel to the same width.</P>
     *
     * <P>The width that is used is created from the
     * widest preferred width among the contained
     * components.</P>
     *
     * @since 2.3
     */
    public void uniformizeCellWidth() {
        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 preferred column width
        setAllMinimumColumnWidths(maxWidth);
    }
    
    /**
     * <P>Sets the table cell height for all cells 
     * in this panel to the same width.</P>
     *
     * <P>The height that is used is created from the
     * tallest preferred height among the contained
     * components.</P>
     *
     * @since 2.3
     */
    public void uniformizeCellHeight() {
        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 preferred row height
        setAllMinimumRowHeights(maxHeight);
    }
    
    ///////////////////////
    // Protected Methods //
    ///////////////////////
    
    /**
     * Create the table cells at position (row, col) for
     * loRows <= row < hiRows and loCols <= col < hiCols.
     *
     * This method does nothing if the table was not created with
     * a <CODE>TableGenerator</CODE>.
     *
     * @param loRows the starting row index for generating cells
     * @param loCols the starting column index for generating cells
     * @param hiRows the limiting row index for generating cells
     * @param hiCols the limiting column index for generating cells
     */
    protected void createCells
        (int loRows, int loCols, int hiRows, int hiCols)
    {
        if (tg == null)
            return;
        
        for (int row = loRows; row < hiRows; row++)
            for (int col = loCols; col < hiCols; col++)
                addObject(tg.makeContents(row, col), row, col);
    }
    
    /**
     * Remove the table cells at position (row, col) for
     * loRows <= row < hiRows and loCols <= col < hiCols.
     *
     * @param loRows the starting row index for generating cells
     * @param loCols the starting column index for generating cells
     * @param hiRows the limiting row index for generating cells
     * @param hiCols the limiting column index for generating cells
     */
    protected void removeCells
        (int loRows, int loCols, int hiRows, int hiCols)
    {
        Component[][] cell = getComponentTable();
        
        Component c = null;
        CellPosition p = new CellPosition();
        
        for (int row = loRows; row < hiRows; row++) {
            for (int col = loCols; col < hiCols; col++) {
                c = cell[row][col];
                
                if (c != null)
                    remove(c);
            }
        }
    }
    
    /**
     * Sets the preferred size for this panel 
     * to its preferred size, and updates the screen UI.
     */
    protected void resetPreferredSize() {
        setPreferredSize(getPreferredSize());
        refreshComponent();
    }
    
}
