package com.revolsys.swing.table.editor;
import java.awt.Component;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.EventObject;
import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxEditor;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;
import org.jdesktop.swingx.JXTable;
import com.revolsys.awt.WebColors;
import com.revolsys.datatype.DataType;
import com.revolsys.swing.SwingUtil;
import com.revolsys.swing.field.Field;
import com.revolsys.swing.listener.MouseListeners;
import com.revolsys.swing.listener.MouseListenersBase;
import com.revolsys.swing.table.AbstractTableModel;
import com.revolsys.swing.table.BaseJTable;
public class BaseTableCellEditor extends AbstractCellEditor
implements TableCellEditor, KeyListener, TableModelListener {
private static final long serialVersionUID = 1L;
private int columnIndex;
private DataType dataType;
private JComponent editorComponent;
private final MouseListeners mouseListeners = new MouseListenersBase();
private int rowIndex;
private final BaseJTable table;
public BaseTableCellEditor(final BaseJTable table) {
this.table = table;
final TableModel model = table.getModel();
model.addTableModelListener(this);
}
public synchronized void addMouseListener(final MouseListener listener) {
this.mouseListeners.addMouseListener(listener);
}
@Override
public Object getCellEditorValue() {
final Object value = SwingUtil.getValue(this.editorComponent);
return value;
}
@SuppressWarnings("rawtypes")
@Override
public Component getTableCellEditorComponent(final JTable table, final Object value,
final boolean isSelected, int rowIndex, int columnIndex) {
if (table instanceof JXTable) {
final JXTable jxTable = (JXTable)table;
rowIndex = jxTable.convertRowIndexToModel(rowIndex);
columnIndex = jxTable.convertColumnIndexToModel(columnIndex);
}
final AbstractTableModel model = (AbstractTableModel)table.getModel();
this.editorComponent = model.getEditorField(rowIndex, columnIndex, value);
if (this.editorComponent instanceof JTextField) {
final JTextField textField = (JTextField)this.editorComponent;
textField.setBorder(
BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(WebColors.LightSteelBlue),
BorderFactory.createEmptyBorder(1, 2, 1, 2)));
}
this.editorComponent.setOpaque(false);
SwingUtil.setFieldValue(this.editorComponent, value);
this.rowIndex = rowIndex;
this.columnIndex = columnIndex;
this.editorComponent.addKeyListener(this);
this.editorComponent.addMouseListener(this.mouseListeners);
if (this.editorComponent instanceof JComboBox) {
final JComboBox comboBox = (JComboBox)this.editorComponent;
final ComboBoxEditor editor = comboBox.getEditor();
final Component comboEditorComponent = editor.getEditorComponent();
comboEditorComponent.addKeyListener(this);
comboEditorComponent.addMouseListener(this.mouseListeners);
}
return this.editorComponent;
}
@Override
public boolean isCellEditable(final EventObject event) {
if (event == null) {
return true;
} else {
if (event instanceof MouseEvent) {
final MouseEvent mouseEvent = (MouseEvent)event;
if (SwingUtil.isLeftButtonAndNoModifiers(mouseEvent)) {
return true;
}
}
}
return false;
}
@Override
public void keyPressed(final KeyEvent event) {
final int keyCode = event.getKeyCode();
if (keyCode == KeyEvent.VK_ENTER) {
if (SwingUtil.isShiftDown(event)) {
this.table.editCell(this.rowIndex - 1, this.columnIndex);
} else {
this.table.editCell(this.rowIndex + 1, this.columnIndex);
}
event.consume();
} else if (keyCode == KeyEvent.VK_TAB) {
if (SwingUtil.isShiftDown(event)) {
this.table.editCell(this.rowIndex, this.columnIndex - 1);
} else {
this.table.editCell(this.rowIndex, this.columnIndex + 1);
}
event.consume();
}
}
@Override
public void keyReleased(final KeyEvent e) {
}
@Override
public void keyTyped(final KeyEvent e) {
}
public synchronized void removeMouseListener(final MouseListener listener) {
this.mouseListeners.removeMouseListener(listener);
}
@Override
public boolean stopCellEditing() {
boolean stopped = false;
try {
if (this.editorComponent instanceof Field) {
final Field field = (Field)this.editorComponent;
field.updateFieldValue();
}
stopped = super.stopCellEditing();
} catch (final IndexOutOfBoundsException e) {
return true;
} catch (final Throwable t) {
final int result = JOptionPane.showConfirmDialog(this.editorComponent,
"<html><p><b>'" + getCellEditorValue() + "' is not a valid "
+ this.dataType.getValidationName()
+ ".</b></p><p>Discard changes (Yes) or edit field (No).</p></html>",
"Invalid value", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE);
if (result == JOptionPane.YES_OPTION) {
cancelCellEditing();
return true;
} else {
return false;
}
} finally {
if (stopped) {
if (this.editorComponent != null) {
this.editorComponent.removeMouseListener(this.mouseListeners);
this.editorComponent.removeKeyListener(this);
if (this.editorComponent instanceof JComboBox) {
final JComboBox<?> comboBox = (JComboBox<?>)this.editorComponent;
final ComboBoxEditor editor = comboBox.getEditor();
final Component comboEditorComponent = editor.getEditorComponent();
comboEditorComponent.removeKeyListener(this);
comboEditorComponent.removeMouseListener(this.mouseListeners);
}
}
}
}
return stopped;
}
@Override
public void tableChanged(final TableModelEvent e) {
if (e.getFirstRow() <= this.rowIndex && this.rowIndex <= e.getLastRow()) {
if (e.getColumn() == TableModelEvent.ALL_COLUMNS) {
cancelCellEditing();
}
}
}
}