/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* Copyright (C) 2003 Vivid Solutions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jump.workbench.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import com.vividsolutions.jts.util.Assert;
import com.vividsolutions.jump.I18N;
import com.vividsolutions.jump.feature.AttributeType;
import com.vividsolutions.jump.util.StringUtil;
import com.vividsolutions.jump.workbench.WorkbenchContext;
import com.vividsolutions.jump.workbench.model.CategoryEvent;
import com.vividsolutions.jump.workbench.model.FeatureEvent;
import com.vividsolutions.jump.workbench.model.Layer;
import com.vividsolutions.jump.workbench.model.LayerEvent;
import com.vividsolutions.jump.workbench.model.LayerEventType;
import com.vividsolutions.jump.workbench.model.LayerListener;
import com.vividsolutions.jump.workbench.plugin.AbstractPlugIn;
import com.vividsolutions.jump.workbench.plugin.EnableCheck;
import com.vividsolutions.jump.workbench.plugin.MultiEnableCheck;
import com.vividsolutions.jump.workbench.plugin.PlugIn;
import com.vividsolutions.jump.workbench.plugin.PlugInContext;
import com.vividsolutions.jump.workbench.ui.addremove.AddRemovePanel;
import com.vividsolutions.jump.workbench.ui.cursortool.editing.EditingPlugIn;
import com.vividsolutions.jump.workbench.ui.images.IconLoader;
import com.vividsolutions.jump.workbench.ui.plugin.EditablePlugIn;
import com.vividsolutions.jump.workbench.ui.plugin.FeatureInstaller;
public class SchemaPanel extends JPanel {
private JPanel jPanel3 = new JPanel();
private JPanel jPanel1 = new JPanel();
private GridBagLayout gridBagLayout1 = new GridBagLayout();
private JLabel statusLabel = new JLabel();
private Layer layer;
private Point currentClickPoint;
private JPopupMenu popupMenu = new JPopupMenu();
private GridBagLayout gridBagLayout2 = new GridBagLayout();
private JPanel buttonPanel = new JPanel();
private JButton applyButton = new JButton();
private JCheckBox forceInvalidConversionsToNullCheckBox = new JCheckBox();
private GridBagLayout gridBagLayout3 = new GridBagLayout();
private JPanel jPanel2 = new JPanel();
private Border border1;
private boolean modified = false;
private ArrayList listeners = new ArrayList();
private JButton revertButton = new JButton();
private BorderLayout borderLayout1 = new BorderLayout();
private WorkbenchToolBar toolBar = new WorkbenchToolBar(null) {
public JButton addPlugIn(
Icon icon,
PlugIn plugIn,
EnableCheck enableCheck,
WorkbenchContext workbenchContext) {
return super.addPlugIn(icon, addCleanUp(plugIn), enableCheck, workbenchContext);
}
};
private void setModel(SchemaTableModel model) {
table.setModel(model);
table.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
updateComponents();
}
});
//Must init cell editors every time we init model. [Jon Aquino]
initCellEditors();
updateComponents();
}
public SchemaPanel(final Layer layer, EditingPlugIn editingPlugIn, WorkbenchContext context) {
editablePlugIn = new EditablePlugIn(editingPlugIn);
try {
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
updateComponents();
}
});
this.layer = layer;
jbInit();
//Call #initPopupMenu and #initToolBar before #setModel, because #setModel
//calls #updateComponents. [Jon Aquino]
initPopupMenu(context);
initToolBar(context);
setModel(new SchemaTableModel(layer));
layer.getLayerManager().addLayerListener(new LayerListener() {
public void categoryChanged(CategoryEvent e) {}
public void featuresChanged(FeatureEvent e) {}
public void layerChanged(LayerEvent e) {
if (e.getLayerable() != layer) {
return;
}
if (e.getType() == LayerEventType.METADATA_CHANGED) {
//If layer becomes editable, apply row striping and remove gridlines,
//as recommended in Java Look and Feel Design Guidelines: Advanced Topics [Jon Aquino]
updateComponents();
repaint();
}
}
});
} catch (Exception ex) {
Assert.shouldNeverReachHere(ex.toString());
}
}
private int[] rowsToActOn() {
if (table.getSelectedRowCount() > 0) {
return table.getSelectedRows();
}
if (getCurrentClickPoint() != null && table.rowAtPoint(getCurrentClickPoint()) != -1) {
return new int[] { table.rowAtPoint(getCurrentClickPoint())};
}
return new int[] {};
}
private EnableCheck basicEnableCheck = new EnableCheck() {
public String check(JComponent component) {
if (!layer.isEditable()) {
return I18N.get("ui.SchemaPanel.layer-must-be-editable");
}
if (rowsToActOn().length == 0) {
return I18N.get("ui.SchemaPanel.at-least-1-row-must-be-selected");
}
return null;
}
};
private abstract class MyPlugIn extends AbstractPlugIn {
public MultiEnableCheck createEnableCheck() {
return new MultiEnableCheck().add(basicEnableCheck);
}
public abstract Icon getIcon();
}
private MyPlugIn insertPlugIn = new MyPlugIn() {
public String getName() {
return I18N.get("ui.SchemaPanel.insert");
}
public Icon getIcon() { return GUIUtil.toSmallIcon(IconLoader.icon("Plus.gif")); }
public boolean execute(PlugInContext context) throws Exception {
markAsModified();
getModel().insertBlankRow(rowsToActOn()[0]);
return true;
}
};
private MyPlugIn deletePlugIn = new MyPlugIn() {
public String getName() {
return I18N.get("ui.SchemaPanel.delete");
}
public Icon getIcon() { return GUIUtil.toSmallIcon(IconLoader.icon("Delete.gif")); }
public boolean execute(PlugInContext context) throws Exception {
markAsModified();
getModel().removeFields(rowsToActOn());
return true;
}
};
private MyPlugIn moveUpPlugIn = new MyPlugIn() {
public Icon getIcon() { return GUIUtil.toSmallIcon(IconLoader.icon("VCRUp.gif")); }
public String getName() {
return I18N.get("ui.SchemaPanel.move-field-up");
}
public boolean execute(PlugInContext context) throws Exception {
markAsModified();
move(AddRemovePanel.itemsToMoveUp(getModel().getFields(), toFields(rowsToActOn())), -1);
return true;
}
public MultiEnableCheck createEnableCheck() {
return super.createEnableCheck().add(new EnableCheck() {
public String check(JComponent component) {
return min(rowsToActOn()) == 0 ? I18N.get("ui.SchemaPanel.field-is-already-at-the-top") : null;
//No corresponding check in moveDownPlugIn because there is no
//bottom! (We keep adding rows as necessary) [Jon Aquino]
}
});
}
};
private EditablePlugIn editablePlugIn;
private MyPlugIn moveDownPlugIn = new MyPlugIn() {
public Icon getIcon() { return GUIUtil.toSmallIcon(IconLoader.icon("VCRDown.gif")); }
public String getName() {
return I18N.get("ui.SchemaPanel.move-field-down");
}
public boolean execute(PlugInContext context) throws Exception {
markAsModified();
move(
AddRemovePanel.itemsToMoveDown(getModel().getFields(), toFields(rowsToActOn())),
1);
return true;
}
};
private JScrollPane jScrollPane1 = new JScrollPane();
private JTable table = new JTable();
private void initToolBar(WorkbenchContext context) {
toolBar.addPlugIn(
insertPlugIn.getIcon(),
insertPlugIn,
insertPlugIn.createEnableCheck(),
context);
toolBar.addPlugIn(
deletePlugIn.getIcon(),
deletePlugIn,
deletePlugIn.createEnableCheck(),
context);
toolBar.addPlugIn(
moveUpPlugIn.getIcon(),
moveUpPlugIn,
moveUpPlugIn.createEnableCheck(),
context);
toolBar.addPlugIn(
moveDownPlugIn.getIcon(),
moveDownPlugIn,
moveDownPlugIn.createEnableCheck(),
context);
}
private void initPopupMenu(WorkbenchContext context) {
table.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
setCurrentClickPoint(e.getPoint());
if (SwingUtilities.isRightMouseButton(e)) {
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
addPopupMenuItem(
editablePlugIn,
true,
null,
editablePlugIn.createEnableCheck(context), context);
popupMenu.addSeparator();
addPopupMenuItem(
insertPlugIn,
false,
insertPlugIn.getIcon(),
insertPlugIn.createEnableCheck(), context);
addPopupMenuItem(
deletePlugIn,
false,
deletePlugIn.getIcon(),
deletePlugIn.createEnableCheck(), context);
popupMenu.addSeparator();
addPopupMenuItem(
moveUpPlugIn,
false,
moveUpPlugIn.getIcon(),
moveUpPlugIn.createEnableCheck(), context);
addPopupMenuItem(
moveDownPlugIn,
false,
moveDownPlugIn.getIcon(),
moveDownPlugIn.createEnableCheck(), context);
}
private void addPopupMenuItem(PlugIn plugIn, boolean checkBox, Icon icon, EnableCheck enableCheck, WorkbenchContext context) {
FeatureInstaller installer = new FeatureInstaller(context);
installer.addPopupMenuItem(popupMenu,
addCleanUp(plugIn),
plugIn.getName(), checkBox, icon, enableCheck);
}
private PlugIn addCleanUp(final PlugIn plugIn) {
return new PlugIn() {
public String toString() {
return plugIn.toString();
}
public boolean execute(PlugInContext context) throws Exception {
try {
return plugIn.execute(context);
}
finally {
setCurrentClickPoint(null);
updateComponents();
}
}
public void initialize(PlugInContext context) throws Exception {
plugIn.initialize(context);
}
public String getName() {
return plugIn.getName();
}
};
}
public boolean isModified() {
return modified;
}
private Collection toFields(int[] rows) {
ArrayList fields = new ArrayList();
for (int i = 0; i < rows.length; i++) {
fields.add(getModel().get(rows[i]));
}
return fields;
}
private void updateComponents() {
table.setShowGrid(layer.isEditable());
table.setRowHeight(20); // fix proposed by uwe to have readable comboboxes with MetalL&F
applyButton.setEnabled(layer.isEditable());
revertButton.setEnabled(layer.isEditable());
forceInvalidConversionsToNullCheckBox.setEnabled(layer.isEditable());
reportError(validateInput());
toolBar.updateEnabledState();
}
public SchemaTableModel getModel() {
return (SchemaTableModel) table.getModel();
}
private TableColumn fieldNameColumn() {
return table.getColumnModel().getColumn(
getModel().indexOfColumn(SchemaTableModel.FIELD_NAME_COLUMN_NAME));
}
private TableColumn dataTypeColumn() {
return table.getColumnModel().getColumn(
getModel().indexOfColumn(SchemaTableModel.DATA_TYPE_COLUMN_NAME));
}
private void initCellEditors() {
fieldNameColumn().setCellEditor(new MyFieldNameEditor());
dataTypeColumn().setCellEditor(new MyDataTypeEditor(AttributeType.allTypes().toArray()));
fieldNameColumn().setCellRenderer(
new StripingRenderer(table.getDefaultRenderer(String.class)));
dataTypeColumn().setCellRenderer(new StripingRenderer(new TableCellRenderer() {
public Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
return table.getDefaultRenderer(String.class).getTableCellRendererComponent(
table,
(value != null) ? capitalizeFirstLetter(value.toString()) : null,
isSelected,
hasFocus,
row,
column);
}
}));
table.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
for (int i = 0; i < table.getColumnCount(); i++) {
((MyEditor) table.getColumnModel().getColumn(i).getCellEditor())
.cancelCellEditing();
}
}
});
}
private String capitalizeFirstLetter(String string) {
return string.toUpperCase().charAt(0) + string.toLowerCase().substring(1);
}
void jbInit() throws Exception {
toolBar.setOrientation(JToolBar.VERTICAL);
border1 = BorderFactory.createEtchedBorder(Color.white, new Color(148, 145, 140));
this.setLayout(gridBagLayout2);
jPanel1.setLayout(gridBagLayout1);
statusLabel.setBorder(BorderFactory.createLoweredBevelBorder());
statusLabel.setText(" ");
applyButton.setText(I18N.get("ui.SchemaPanel.apply-changes"));
applyButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
applyButton_actionPerformed(e);
}
});
forceInvalidConversionsToNullCheckBox.setToolTipText(I18N.get("ui.SchemaPanel.leave-unchecked-if-you-want-to-be-notified-of-conversion-errors"));
forceInvalidConversionsToNullCheckBox.setText(I18N.get("ui.SchemaPanel.force-invalid-conversions-to-null"));
buttonPanel.setLayout(gridBagLayout3);
buttonPanel.setBorder(BorderFactory.createLoweredBevelBorder());
revertButton.setText(I18N.get("ui.SchemaPanel.revert-changes"));
revertButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
revertButton_actionPerformed(e);
}
});
jPanel3.setLayout(borderLayout1);
this.add(
jPanel3,
new GridBagConstraints(
0,
0,
1,
1,
1.0,
1.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0),
0,
0));
jPanel3.add(toolBar, BorderLayout.WEST);
jPanel3.add(jScrollPane1, BorderLayout.CENTER);
jScrollPane1.getViewport().add(table, null);
this.add(
jPanel1,
new GridBagConstraints(
0,
3,
1,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0),
0,
0));
jPanel1.add(
statusLabel,
new GridBagConstraints(
0,
0,
1,
1,
1.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0),
0,
0));
this.add(
buttonPanel,
new GridBagConstraints(
0,
2,
1,
1,
1.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0),
0,
0));
buttonPanel.add(
applyButton,
new GridBagConstraints(
1,
1,
1,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(4, 4, 4, 4),
0,
0));
buttonPanel.add(
forceInvalidConversionsToNullCheckBox,
new GridBagConstraints(
4,
1,
1,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(0, 0, 0, 0),
0,
0));
buttonPanel.add(
jPanel2,
new GridBagConstraints(
3,
1,
1,
1,
1.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0),
0,
0));
buttonPanel.add(
revertButton,
new GridBagConstraints(
2,
1,
1,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(0, 0, 0, 4),
0,
0));
}
private void reportError(String message) {
if (message != null) {
statusLabel.setText(message);
statusLabel.setIcon(GUIUtil.toSmallIcon(IconLoader.icon("Delete.gif")));
} else {
statusLabel.setText(" ");
statusLabel.setIcon(null);
}
}
private int geometryCount() {
int geometryCount = 0;
for (int i = 0; i < getModel().getRowCount(); i++) {
if (getModel().get(i).getType() == AttributeType.GEOMETRY) {
geometryCount++;
}
}
return geometryCount;
}
public String validateInput() {
for (int i = 0; i < table.getColumnCount(); i++) {
String error =
((MyEditor) table.getColumnModel().getColumn(i).getCellEditor())
.getCurrentErrorMessage();
if (error != null) {
return error;
}
}
if (geometryCount() > 1) {
return I18N.get("ui.SchemaPanel.only-one-geometry-field-is-allowed");
}
if (geometryCount() == 0) {
return I18N.get("ui.SchemaPanel.a-geometry-field-must-be-defined");
}
return null;
}
private String validate(int row, AttributeType type) {
if (type == AttributeType.GEOMETRY) {
for (int i = 0; i < getModel().getRowCount(); i++) {
if (i == row) {
continue;
}
if (getModel().get(i).getType() == null) {
//One of the blank rows. [Jon Aquino]
continue;
}
}
}
return null;
}
private String validate(int row, String name) {
if (name.trim().length() == 0) {
return I18N.get("ui.SchemaPanel.field-name-cannot-be-blank");
}
//Existing fields are already trimmed. [Jon Aquino]
for (int i = 0; i < getModel().getRowCount(); i++) {
if (i == row) {
continue;
}
if (getModel().get(i).getName() == null) {
//One of the blank rows. [Jon Aquino]
continue;
}
if (getModel().get(i).getName().equalsIgnoreCase(name.trim())) {
return I18N.get("ui.SchemaPanel.field-name-already-exists")+": " + name;
}
}
return null;
}
private void markAsModified() {
modified = true;
}
public void markAsUnmodified() {
modified = false;
}
public JTable getTable() {
return table;
}
void applyButton_actionPerformed(ActionEvent e) {
fireActionPerformed();
}
public void add(ActionListener l) {
listeners.add(l);
}
private void fireActionPerformed() {
for (Iterator i = listeners.iterator(); i.hasNext();) {
ActionListener l = (ActionListener) i.next();
l.actionPerformed(null);
}
}
public boolean isForcingInvalidConversionsToNull() {
return forceInvalidConversionsToNullCheckBox.isSelected();
}
public void move(Collection fieldsToMove, int displacement) {
//Use rows-to-act-on, not selected row, because no rows may be selected
//i.e. we might just be operating on the row the user right-clicked on. [Jon Aquino]
int guaranteedVisibleRow = displacement > 0 ? max(rowsToActOn()) : min(rowsToActOn());
guaranteedVisibleRow += displacement;
//Compute guaranteedVisibleRow before doing the move, because after the
//move the selection would have moved, or if a row were merely clicked and not
//selected, its click point would *not* have moved -- would tricky to compute it
//after the move! [Jon Aquino]
ArrayList selectedFields = new ArrayList();
int[] selectedRows = table.getSelectedRows();
for (int i = 0; i < selectedRows.length; i++) {
selectedFields.add(getModel().get(selectedRows[i]));
}
getModel().move(fieldsToMove, displacement);
table.clearSelection();
for (Iterator i = selectedFields.iterator(); i.hasNext();) {
SchemaTableModel.Field field = (SchemaTableModel.Field) i.next();
table.addRowSelectionInterval(getModel().indexOf(field), getModel().indexOf(field));
}
Rectangle r = table.getCellRect(guaranteedVisibleRow, 0, true);
table.scrollRectToVisible(r);
}
private int min(int[] ints) {
int min = ints[0];
for (int i = 0; i < ints.length; i++) {
min = Math.min(min, ints[i]);
}
return min;
}
private int max(int[] ints) {
int max = ints[0];
for (int i = 0; i < ints.length; i++) {
max = Math.max(max, ints[i]);
}
return max;
}
private class StripingRenderer implements TableCellRenderer {
private TableCellRenderer originalRenderer;
//Row-stripe colour recommended in
//Java Look and Feel Design Guidelines: Advanced Topics [Jon Aquino]
private final Color LIGHT_GRAY = new Color(230, 230, 230);
public StripingRenderer(TableCellRenderer originalRenderer) {
this.originalRenderer = originalRenderer;
}
public Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
JComponent component =
(JComponent) originalRenderer.getTableCellRendererComponent(
table,
value,
isSelected,
hasFocus,
row,
column);
//If not editable, use row striping, as recommended in
//Java Look and Feel Design Guidelines: Advanced Topics [Jon Aquino]
component.setOpaque(true);
if (!isSelected) {
component.setForeground(Color.black);
component.setBackground(
(layer.isEditable() || ((row % 2) == 0)) ? Color.white : LIGHT_GRAY);
}
return component;
}
}
public class MyDataTypeEditor extends MyEditor {
private AttributeType originalType;
public MyDataTypeEditor(Object[] items) {
super(new JComboBox(items));
final ListCellRenderer originalRenderer = comboBox().getRenderer();
comboBox().setRenderer(new ListCellRenderer() {
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
return originalRenderer.getListCellRendererComponent(
list,
(value != null) ? capitalizeFirstLetter(value.toString()) : null,
index,
isSelected,
cellHasFocus);
}
});
}
public Component getTableCellEditorComponent(
JTable table,
Object value,
boolean isSelected,
int row,
int column) {
originalType = (AttributeType) value;
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
private JComboBox comboBox() {
return (JComboBox) getComponent();
}
public boolean stopCellEditing() {
if (originalType != comboBox().getSelectedItem()) {
markAsModified();
}
return super.stopCellEditing();
}
protected String validate() {
return SchemaPanel.this.validate(row, (AttributeType) comboBox().getSelectedItem());
}
}
public abstract class MyEditor extends DefaultCellEditor {
protected int row;
private String currentErrorMessage = null;
public MyEditor(JComboBox comboBox) {
super(comboBox);
}
public MyEditor(JTextField textField) {
super(textField);
}
public Component getTableCellEditorComponent(
JTable table,
Object value,
boolean isSelected,
int row,
int column) {
this.row = row;
((JComponent) getComponent()).setBorder(new LineBorder(Color.black));
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
public void cancelCellEditing() {
currentErrorMessage = null;
updateComponents();
super.cancelCellEditing();
}
public boolean stopCellEditing() {
try {
if (validate() != null) {
((JComponent) getComponent()).setBorder(new LineBorder(Color.red));
return false;
}
return super.stopCellEditing();
} finally {
//Can't just call #validate at the top of this method, because other validations
//apply to when the edit is finished (e.g. checking the number of geometries). [Jon Aquino]
currentErrorMessage = validate();
updateComponents();
}
}
protected abstract String validate();
public String getCurrentErrorMessage() {
return currentErrorMessage;
}
}
public class MyFieldNameEditor extends MyEditor {
public MyFieldNameEditor() {
super(new JTextField());
}
public boolean stopCellEditing() {
if (!textField().getText().equals(originalText)) {
markAsModified();
}
return super.stopCellEditing();
}
private String originalText;
public Component getTableCellEditorComponent(
JTable table,
Object value,
boolean isSelected,
int row,
int column) {
originalText = (String) value;
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
private JTextField textField() {
return (JTextField) getComponent();
}
protected String validate() {
return SchemaPanel.this.validate(row, textField().getText());
}
}
void revertButton_actionPerformed(ActionEvent e) {
setModel(new SchemaTableModel(layer));
}
private void setCurrentClickPoint(Point currentClickPoint) {
this.currentClickPoint = currentClickPoint;
}
private Point getCurrentClickPoint() {
return currentClickPoint;
}
}