package util.swing;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

import data.Value;
import data.NumberValue;

/**
  * A {@link JTable} that prefers models that are lists of records. A <code>JAbstractTable</code> always must
  * be used together with an {@link util.swing.AbstractTableModel}.
  *
  * <p>Also <code>JAbstractTable</code> supports one selection observer which is basically an int value that
  * will always contain the index of the currently selected record in the table. Setting up such an observer is
  * quite straightforward:</p>
  *
  * <pre>
  * int[] anSelection = new int[1];
  *
  * JAbstractTable jat = new JAbstractTable (...);
  * jat.{@link #setSelectionObserver setSelectionObserver} (anSelection);
  * </pre>
  *
  * <p>To use this observer write code like the following:</p>
  *
  * <pre>
  * ...
  * Object oSelectedRecord = ((util.swing.AbstractTableModel) jat.getModel()).getRecord (anSelection[0]);
  * if (oSelectedRecord != null) {
  *   ...
  * }
  * </pre>
  *
  * <p>Note that although you only use the actual int value, you still have to set up an array of int values.
  * The current selection will always be written to the first element in this array, no matter how long the
  * actual array is.</p>
  *
  * <p><b>Note:</b> This class is not meant to be serialized!</p>
  *
  * @author Steffen Zschaler
  * @version 2.0 28/07/1999
  * @since v2.0
  *
  * @see util.swing.AbstractTableModel
  * @see TableEntryDescriptor
  */
public class JAbstractTable extends JTable {

  /**
    * The current selection observer.
    *
    * @serial This class is not meant to be serialized!
    */
  private int[] m_anSelection;

  /**
    * The monitor that synchronizes access to the selection observer. As this class is not meant to be
    * serialized, no care needs to be taken.
    */
  private final transient Object m_oSelectionLock = new Object();

  /**
    * Construct a new JAbstractTable that is based on an {@link util.swing.AbstractTableModel}.
    *
    * @param atm the TableModel to be used with this table.
    */
  public JAbstractTable(AbstractTableModel atm) {
    super();

    setModel (atm);
    setDefaultRenderer (String.class,
                        new DefaultTableCellRenderer());
    setDefaultRenderer (Value.class,
                        new DefaultTableCellRenderer());

    TableCellRenderer tcr = new DefaultTableCellRenderer();
    ((JLabel) tcr).setHorizontalAlignment (JLabel.RIGHT);

    setDefaultRenderer (NumberValue.class,
                        tcr);

    setSelectionMode (ListSelectionModel.SINGLE_SELECTION);

    m_anSelection = new int[] { -1 };
    getSelectionModel().addListSelectionListener (new ListSelectionListener() {
      public void valueChanged (ListSelectionEvent lse) {
        synchronized (m_oSelectionLock) {
          m_anSelection[0] = getSelectedRow();
        }
      }
    });


    TableEntryDescriptor ted = atm.getEntryDescriptor();
    TableColumnModel tcm = getColumnModel();

    for (int i = 0; i < ted.getColumnCount(); i++) {
      TableColumn tc = tcm.getColumn (i);

      tc.setCellRenderer (ted.getCellRenderer (i));
      tc.setCellEditor (ted.getCellEditor (i));
    }
  }

  /**
    * Set a selection observer for this table. The first element of the given array will henceforward
    * contain the index of the currently selected record.
    *
    * @param anSelection the selection observer
    *
    * @override Never
    */
  public void setSelectionObserver (int[] anSelection) {
    synchronized (m_oSelectionLock) {
      anSelection[0] = getSelectedRow();

      m_anSelection = anSelection;
    }
  }
}