// This example is from _Java Examples in a Nutshell_. (http://www.oreilly.com)
// Copyright (c) 1997 by David Flanagan
// This example is provided WITHOUT ANY WARRANTY either expressed or implied.
// You may study, use, modify, and distribute it for non-commercial purposes.
// For any commercial use, see http://www.davidflanagan.com/javaexamples

import com.sun.java.swing.*;       // Beta package names; will change
import com.sun.java.swing.border.*;
import com.sun.java.swing.table.*; 
import java.awt.*;

/**
 * This class demonstrates the JTable object.
 **/
public class TablePanel extends JBorderedPane {
  public TablePanel() {
    // Set the title for this JTitledPane
    this.setBorder(new JTitledBorder(this, "Table"));

    // Here is some data that we want to display in a table.  Note the
    // use of various types of objects.
    String[] names = {"Abe", "Ben", "Cathy", "Donna", "Earnest", "Frank" };
    Integer[] ages = { new Integer(25), new Integer(39), new Integer(41),
                       new Integer(29), new Integer(21), new Integer(55) };
    Boolean[] status = { Boolean.TRUE, Boolean.FALSE, Boolean.FALSE,
                         Boolean.TRUE, Boolean.FALSE, Boolean.TRUE };
  
    // Now we create JTableColumn objects to represent the columns of the
    // table.  The argument to the constructor is an arbitrary object.  We
    // pass our arrays of data, from which individual values will later be
    // extracted.
    JTableColumn col1 = new JTableColumn(names);
    JTableColumn col2 = new JTableColumn(ages);
    JTableColumn col3 = new JTableColumn(status);

    // Specify the name of each column of the table.
    col1.setHeaderValue("Name");
    col2.setHeaderValue("Age");
    col3.setHeaderValue("Married");

    // Specify some other stuff about the columns
    col1.setWidth(200);
    col2.setWidth(50);
    col1.setResizable(true);
    col2.setResizable(false);
    col3.setResizable(false);

    // Specify that the values in column #3 (Boolean objects) should be
    // displayed with a JCheckbox object rather than as a string.  
    col3.setCellRenderer(new JCellRenderer(new JCheckbox()));

    // Specify that the values in column #3 should also be editable through
    // JCheckbox objects.
    col3.setCellEditor(new JCellEditor(new JCheckbox()));

    // Now, create our JTable object.  The constructor must be passed a
    // TableDataModel object, from which it will
    // extract the data to appear in the table.  The ArrayBasedDataModel
    // is a nested subclass, defined below.
    JTable table = new JTable(new ArrayBasedDataModel(names.length));

    // Add the three columns to the table
    table.addColumn(col1);
    table.addColumn(col2);
    table.addColumn(col3);

    // Set a layout manager for this panel, and specify some generous insets
    this.setLayout(new BorderLayout());
    this.setInsets(new Insets(25, 25, 25, 25));

    // Add the table to the panel, and also add the automatically created
    // table header component to the panel.  (The table header is created
    // separately, so that large tables can be placed in a JScrollPane
    // without scrolling the table header.
    this.add(table, "Center");
    this.add(table.getTableHeader(), "North");
  }

  /**
   * This class is a the TableDataModel.  We pass an instance of it to
   * the JTable() constructor.  Its methods get and set individual values 
   * in the table, and also return the number of rows in the table.
   * Cells in the table are addressed by row number, and by column 
   * "identifier".  These column identifiers are the arbitrary objects that
   * were passed to the JTableColumn() constructor.  Sometimes, it is 
   * convenient to use strings.  In this case we passed arrays to 
   * JTableColumn(), so those column arrays are now passed back to the 
   * methods here.
   **/
  class ArrayBasedDataModel extends JTableDataModelAdapter {
    int numrows;  // How many rows in this table

    // The ArrayBasedDataModel class must be initialized to know how many
    // rows there are in the table.
    public ArrayBasedDataModel(int numrows) { this.numrows = numrows; }

    // Return the number of rows
    public int getRowCount() { return numrows; }

    // This method returns the value of the cell specified by the column
    // identifier object and the row number.  Since our column identifiers
    // are arrays of objects, this is easy.
    public Object getValueAt(Object column, int row) {
      return ((Object[])column)[row];
    }

    // This method sets the value of a cell specified by column identifier
    // (an array of objects, in our case) and row number.
    public void setValueAt(Object value, Object column, int row) {
      ((Object[])column)[row] = value;
    }
  }
}
