content: package tim.prune.load;
  
  import javax.swing.table.AbstractTableModel;
  
  import tim.prune.I18nManager;
  import tim.prune.data.Field;
  import tim.prune.data.FieldCustom;
  
  /**
   * Class to hold the table model for the field selection table
   */
  public class FieldSelectionTableModel extends AbstractTableModel
  {
  	private int _numRows = 0;
  	private Field[] _fieldArray = null;
  	private final String _customText;
  
  	/**
  	 * Constructor
  	 */
  	public FieldSelectionTableModel()
  	{
  		// Cache the custom text for the table so it doesn't
  		// have to be looked up so often
  		_customText = I18nManager.getText("fieldname.custom");
  	}
  
  
  	/**
  	 * @return the column count
  	 */
  	public int getColumnCount() {
  		return 3;
  	}
  
  	/** @return the language-specific name defining any custom field */
  	public String getCustomText() {
  		return _customText;
  	}
  
  	/**
  	 * @param inColNum column number
  	 * @return name of the column
  	 */
  	public String getColumnName(int inColNum)
  	{
  		if (inColNum == 0) {
  			return I18nManager.getText("dialog.load.table.field");
  		}
  		else if (inColNum == 1) {
  			return I18nManager.getText("dialog.load.table.datatype");
  		}
  		return I18nManager.getText("dialog.load.table.description");
  	}
  
  
  	/**
  	 * @return the row count
  	 */
  	public int getRowCount() {
  		return _fieldArray == null ? 2 : _numRows;
  	}
  
  
  	/**
  	 * @param inRowIndex row index
  	 * @param inColumnIndex column index
  	 * @return the value of the specified cell
  	 */
  	public Object getValueAt(int inRowIndex, int inColumnIndex)
  	{
  		if (_fieldArray == null) {
  			return "";
  		}
  		if (inColumnIndex == 0) {
  			return ("" + (inRowIndex+1));
  		}
  		Field field = _fieldArray[inRowIndex];
  		if (inColumnIndex == 1)
  		{
  			// Field name - take name from built-in fields
  			return field.isBuiltIn() ? field.getName() : _customText;
  		}
  		// description column - builtin fields don't have one
  		return field.isBuiltIn() ? "" : field.getName();
  	}
  
  
  	/**
  	 * Make sure only second and third columns are editable
  	 * @param inRowIndex row index
  	 * @param inColumnIndex column index
  	 * @return true if cell editable
  	 */
  	public boolean isCellEditable(int inRowIndex, int inColumnIndex)
  	{
  		if (inColumnIndex <= 1) {
  			return (inColumnIndex == 1);
  		}
  		// Column is 2 so only edit non-builtin field names
  		Field field = _fieldArray[inRowIndex];
  		return !field.isBuiltIn();
  	}
  
  
  	/**
  	 * Update the data
  	 * @param inData 2-dimensional Object array containing the data
  	 */
  	public void updateData(Field[] inData)
  	{
  		_fieldArray = inData;
  		_numRows = _fieldArray == null ? 0 : _fieldArray.length;
  		fireTableStructureChanged();
  	}
  
  
  	/**
  	 * React to edits to the table data
  	 * @param inValue value to set
  	 * @param inRowIndex row index
  	 * @param inColumnIndex column index
  	 */
  	public void setValueAt(Object inValue, int inRowIndex, int inColumnIndex)
  	{
  		super.setValueAt(inValue, inRowIndex, inColumnIndex);
  		if (inColumnIndex == 1)
  		{
  			Field field = _fieldArray[inRowIndex];
  			if (!field.getName().equals(inValue.toString())) {
  				manageFieldChange(inRowIndex, inValue.toString());
  			}
  		}
  		else if (inColumnIndex == 2)
  		{
  			// change description if it's custom
  			Field field = _fieldArray[inRowIndex];
  			field.setName(inValue.toString());
  		}
  	}
  
  
  	/**
  	 * Move the selected item up one place
  	 * @param inIndex index of item to move
  	 */
  	public void moveUp(int inIndex)
  	{
  		if (inIndex > 0) {
  			swapItems(inIndex-1, inIndex);
  		}
  	}
  
  
  	/**
  	 * Move the selected item down one place
  	 * @param inIndex index of item to move
  	 */
  	public void moveDown(int inIndex)
  	{
  		if (inIndex > -1 && inIndex < (_numRows - 1)) {
  			swapItems(inIndex, inIndex+1);
  		}
  	}
  
  
  	/**
  	 * Swap the specified items in the array
  	 * @param inIndex1 index of first item
  	 * @param inIndex2 index of second item (higher than inIndex1)
  	 */
  	private void swapItems(int inIndex1, int inIndex2)
  	{
  		Field temp = _fieldArray[inIndex1];
  		_fieldArray[inIndex1] = _fieldArray[inIndex2];
  		_fieldArray[inIndex2] = temp;
  		fireTableRowsUpdated(inIndex1, inIndex2);
  	}
  
  
  	/**
  	 * React to a requested change to one of the fields
  	 * @param inRow row number of change
  	 * @param inValue new string value
  	 */
  	private void manageFieldChange(int inRow, String inValue)
  	{
  		// check if it's lat or long - don't allow changes to these fields
  		Field field = _fieldArray[inRow];
  		if (field == Field.LATITUDE || field == Field.LONGITUDE) {
  			return;
  		}
  		if (inValue.equals(I18nManager.getText("fieldname.latitude"))
  		  || inValue.equals(I18nManager.getText("fieldname.longitude"))) {
  			return;
  		}
  
  		// Changes to custom field need to be handled differently
  		boolean changeToCustom = inValue.equals(_customText);
  		if (changeToCustom)
  		{
  			if (field.isBuiltIn())
  			{
  				String customPrefix = I18nManager.getText("fieldname.prefix") + " ";
  				int index = inRow + 1;
  				while (hasField(customPrefix + index)) {
  					index++;
  				}
  				_fieldArray[inRow] = new FieldCustom(customPrefix + index);
  			}
  			// ignore custom to custom changes
  		}
  		else
  		{
  			// Change to a fixed field - check we've not already got it
  			if (!hasField(inValue))
  			{
  				// Change is ok - find new Field object corresponding to text
  				_fieldArray[inRow] = Field.getField(inValue);
  			}
  		}
  		// fire change
  		fireTableRowsUpdated(inRow, inRow);
  	}
  
  
  	/**
  	 * @return array of Field objects
  	 */
  	public Field[] getFieldArray() {
  		return _fieldArray;
  	}
  
  
  	/**
  	 * @param inName Name of field to find
  	 * @return true if this field is already present
  	 */
  	private boolean hasField(String inName)
  	{
  		if (_fieldArray == null || inName == null) {
  			return false;
  		}
  		for (int i=0; i<_numRows; i++)
  		{
  			if (_fieldArray[i].getName().equals(inName)) {
  				return true;
  			}
  		}
  		return false;
  	}
  }
  