CIVLTable.java

package edu.udel.cis.vsl.civl.gui.common;

import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.event.EventListenerList;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

import edu.udel.cis.vsl.gmc.Option;

/**
 * This class is used to ensure that the first column of the
 * <code>CIVLTable</code>(JTable) is not editable, as we do not want users to be
 * able to change the option names in the table where selected options are
 * displayed. In addition to this, it contains a custom cell renderer and a
 * custom cell editor to override undesirable JTable behavior.
 * 
 * @author noyes
 * 
 */
public class CIVLTable extends JTable implements MouseListener{
	/**
	 * 
	 */
	private static final long serialVersionUID = -5345179673948036576L;

	/**
	 * The custom renderer to be used for cells that have a boolean value.
	 */
	private BooleanCellRenderer boolean_render;

	/**
	 * The custom editor to be used for cells that have a boolean value.
	 */
	private BooleanCellEditor boolean_edit;

	/**
	 * A renderer used to render Strings and Numbers.
	 */
	private FormattedTextFieldRenderer text_render;

	/**
	 * An editor used to edit Strings and Numbers.
	 */
	private FormattedTextFieldEditor text_edit;

	/**
	 * The columns that can be edited in an instance of a
	 * <code>CIVL_Table</code>.
	 */
	private int[] editableCols;

	/**
	 * The type of table stored as a String. The supported types currently are:
	 * <li>"option" for the option tables in the GUI</li> <li>"input" for the
	 * input tables in the GUI</li>
	 */
	private String tableType;

	/**
	 * The renderer for option values.
	 */
	private OptionCellRenderer option_render;
	
	/**
	 * The list of EventListeners
	 */
	protected EventListenerList listenerList = new EventListenerList();

	/**
	 * This custom class renders option values as option.name() in uneditable
	 * JTextAreas.
	 * 
	 * @author noyes
	 * 
	 */
	private class OptionCellRenderer implements TableCellRenderer {
		private Option option;

		@Override
		public Component getTableCellRendererComponent(JTable table,
				Object value, boolean isSelected, boolean hasFocus, int row,
				int column) {
			return new JTextArea(option.name());
		}

	}

	CIVLTable(int[] editableCols, String tableType) {
		super();
		boolean_render = new BooleanCellRenderer();
		boolean_edit = new BooleanCellEditor();
		option_render = new OptionCellRenderer();
		text_render = new FormattedTextFieldRenderer();
		text_edit = new FormattedTextFieldEditor();
		this.editableCols = editableCols;
		this.tableType = tableType;
		this.addMouseListener(this);
	}

	/**
	 * Gets the <code>CIVL_Table</code>'s cell editor for a specific cell.
	 * 
	 * @param row
	 *            The row of the cell.
	 * @param col
	 *            The column of the cell.
	 * 
	 * @return The specified <code>TableCellEditor</code>
	 */
	public TableCellEditor getCellEditor(int row, int column) {
		Object value = super.getValueAt(row, column);
		if (value == null)
			value = "";

		if (value instanceof Number) {
			return text_edit;
		}

		// only for option table
		else if (value instanceof String && column == 1
				&& tableType == "option") {
			return text_edit;
		}

		else if (value instanceof Boolean)
			return boolean_edit;

		return super.getCellEditor(row, column);
	}

	/**
	 * Gets the <code>CIVL_Table</code>'s cell renderer for a specific cell.
	 * 
	 * @param row
	 *            The row of the cell.
	 * @param col
	 *            The column of the cell.
	 * 
	 * @return The specified <code>TableCellRenderer</code>
	 */
	public TableCellRenderer getCellRenderer(int row, int column) {
		Object value = super.getValueAt(row, column);
		if (value == null)
			value = "";

		if (value instanceof Number) {
			return text_render;
		}

		// only for option table
		else if (value instanceof String && column == 1
				&& tableType == "option") {
			return text_render;
		}
		
		else if (value instanceof Option){
			option_render.option = (Option) value;
			return option_render;
		}

		else if (value instanceof Boolean)
			return boolean_render;

		return super.getCellRenderer(row, column);
	}

	/**
	 * Uses the editableCols field to specify which columns can be edited and
	 * which cannot. This method is called by swing on specific cells to check
	 * if they are editable.
	 * 
	 * @param row
	 *            The row of the cell.
	 * @param col
	 *            The column of the cell.
	 * 
	 * @return A boolean representing if the cell is editable or not.
	 */
	public boolean isCellEditable(int row, int col) {
		boolean found = false;
		for (int i = 0; i < editableCols.length; i++) {
			if (col == editableCols[i]) {
				found = true;
				break;
			}
		}

		return found;
	}
	
	/**
	 * Sets the toolTip text that describes each option.
	 * 
	 * @param e
	 * 		The mouse event.
	 * 
	 * @return The Tool Tip Text for the desired cell.
	 */
	public String getToolTipText(MouseEvent e) {
		String tip = null;
		java.awt.Point p = e.getPoint();
		int rowIndex = rowAtPoint(p);
		int colIndex = columnAtPoint(p);

		try {
			if (colIndex == 0 && tableType == "option") {
				tip = ((Option) getValueAt(rowIndex, colIndex)).description();

			}
		} catch (RuntimeException e1) {
			// catch null pointer exception if mouse is over an empty line
		}

		return tip;
	}
	
	public void addSaveTableListener(SaveTableListener listener) {
		listenerList.add(SaveTableListener.class, listener);
	}

	public void removeSaveTableListener(SaveTableListener listener) {
		listenerList.remove(SaveTableListener.class, listener);
	}
	
	void fireSaveTableEvent(SaveTableEvent evt) {
		Object[] listeners = listenerList.getListenerList();
		for (int i = 0; i < listeners.length; i = i + 2) {
			if (listeners[i] == SaveTableListener.class) {
				((SaveTableListener) listeners[i + 1]).SaveTableTriggered(evt);
			}
		}
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		java.awt.Point p = e.getPoint();
		int colIndex = columnAtPoint(p);
		try {
			if (colIndex == 1 && tableType == "option") {
				fireSaveTableEvent(new SaveTableEvent(this));
				System.out.println("fire table save");
			}
			else if (colIndex == 2 && tableType == "input") {
				//save input code of some kind
			}
		} catch (RuntimeException e1) {
			// catch null pointer exception if mouse is over an empty line
		}
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
	}

	@Override
	public void mouseReleased(MouseEvent e) {
	}

	@Override
	public void mouseEntered(MouseEvent e) {
	}

	@Override
	public void mouseExited(MouseEvent e) {
	}
	
}