/* * $Id$ * * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ package org.jdesktop.swingx.table; import java.awt.Point; import java.text.NumberFormat; import java.text.ParseException; import java.util.Date; import java.util.logging.Logger; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.KeyStroke; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellEditor; import javax.swing.text.InternationalFormatter; import javax.swing.text.NumberFormatter; import org.jdesktop.swingx.InteractiveTestCase; import org.jdesktop.swingx.JXFrame; import org.jdesktop.swingx.JXTable; import org.jdesktop.swingx.table.DatePickerCellEditor; import org.jdesktop.swingx.table.NumberEditorExt; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** * TODO add type doc * * @author Jeanette Winzenburg */ @RunWith(JUnit4.class) public class NumberEditorExtIssues extends InteractiveTestCase { @SuppressWarnings("unused") private static final Logger LOG = Logger .getLogger(NumberEditorExtIssues.class.getName()); private static final String TOO_BIG_INTEGER = "11111111111111111111111111"; private static final int INTEGER_COLUMN = 0; /** a table with a model which has column class Integer in INTEGER_COLUMN. */ private JXTable table; /** a NumberEditorExt configured with IntegerFormat. */ private NumberEditorExt cellEditor; private NumberEditorExt cellEditorStrict; public static void main(String[] args) { NumberEditorExtIssues test = new NumberEditorExtIssues(); try { test.runInteractiveTests(); // test.runInteractiveTests("interactive.*Number.*"); } catch (Exception e) { e.printStackTrace(); } } public void interactiveNumberEditorKeepsEscape() { JFormattedTextField field = new JFormattedTextField(new Date()); KeyStroke keyStroke = KeyStroke.getKeyStroke("ESCAPE"); LOG.info("actionForEscape: " + field.getInputMap().get(keyStroke )); new NumberEditorExt(true); LOG.info("actionForEscape: " + field.getInputMap().get(keyStroke )); JXFrame frame = wrapInFrame(field, "textfield escape"); show(frame, 400, 300); } /** * Issue #1236-swingx: NumberEditorExt only handles columns with type * Number. * * Perceived as overly restrictive, fails f.i. in usage in property sheet. * */ // @Test public void interactiveMixedColumnEditors() { // mixed types in column Object[] values = new Object[] {new Integer(10), new Double(10.5), new Date(), new JLabel("dummy"), new Point(4, 6)}; DefaultTableModel model = new DefaultTableModel(10, 2) { @Override public Class<?> getColumnClass(int columnIndex) { if (columnIndex == getColumnCount() - 1) { return Point.class; } return super.getColumnClass(columnIndex); } }; for (int i = 0; i < values.length; i++) { model.setValueAt(values[i], i, 0); model.setValueAt(new Point(1, i), i, 1); } JXTable table = new JXTable(model) { @Override public TableCellEditor getCellEditor(int row, int column) { Object value = getValueAt(row, column); if (value instanceof Number) { return getDefaultEditor(Number.class); } if (value instanceof Date) { return getDefaultEditor(Date.class); } if (value instanceof JLabel) { // pathological: something with a string param constructor return getDefaultEditor(Number.class); } return super.getCellEditor(row, column); } }; table.setDefaultEditor(Date.class, new DatePickerCellEditor()); // table.setDefaultEditor(Number.class, new NumberEditorExt(false)); JXFrame frame = showWithScrollingInFrame(table, "per-cell number editor? "); JFormattedTextField field = new JFormattedTextField(new Date()); addStatusComponent(frame, field); } /** * Issue #1183-swingx: NumberEditorExt throws in getCellEditorValue if * Integer (short, byte..) below/above min/max. * * Check IllegalStateException as doc'ed - the strict version doesn't. * Need to check the delegate implementation? */ @Test(expected = IllegalStateException.class) public void testEditorStrictValueIllegalState() { JFormattedTextField field = (JFormattedTextField) cellEditorStrict .getTableCellEditorComponent(table, Integer.MAX_VALUE, false, 0, INTEGER_COLUMN); // add valid digit - but exceeds Integer bounds so must not return true field.setText(field.getText() + "9"); cellEditorStrict.getCellEditorValue(); } /** * Issue ??-swingx: editor with strict number formatter throws on * committing null value. * * happens only if active editor in table. Use non-strict for comparison. * InternationalFormatter with bounds throws as well. But not using * strict catches this in isValid, that is stopCellEditing returns false. */ @Test public void testEditorNullValue() { table.getColumn(INTEGER_COLUMN).setCellEditor(cellEditor); ((InternationalFormatter) cellEditor.getComponent().getFormatter()).setMinimum(0); table.editCellAt(0, INTEGER_COLUMN); assertTrue(cellEditor.stopCellEditing()); } //--------------------- core issues /** * This is not really an issue: Double values exceeding the bounds are Infinity. */ @Test (expected = ParseException.class) public void testNumberFormatterDouble() throws ParseException { NumberFormat format = NumberFormat.getInstance(); // no need to do anything special - parsing of doubles fails if out-off range? NumberFormatter formatter = new NumberFormatter(format); String text = "9" + new Double(Double.MAX_VALUE).toString(); Number number = (Number) formatter.stringToValue(text); LOG.info("number: " + number); } /** * Formatted text field commit can't handle empty string. * * @throws ParseException */ @Test public void testTextFieldWithEmptyString() throws ParseException { NumberFormat format = NumberFormat.getIntegerInstance(); JFormattedTextField field = new JFormattedTextField(format); field.setText(""); field.commitEdit(); } /** * NumberFormatter parsing can't handle null. * * @throws ParseException */ @Test public void testNumberFormatterEmptyStringValue() throws ParseException { NumberFormat format = NumberFormat.getIntegerInstance(); NumberFormatter formatter = new NumberFormatter(format); formatter.stringToValue(""); } /** * NumberFormat parsing cant handle empty string. * * @throws ParseException */ @Test public void testNumberFormatEmptyStringValue() throws ParseException { NumberFormat format = NumberFormat.getIntegerInstance(); format.parse(""); } /** * NumberFormatter parsing can't handle null. * @throws ParseException */ @Test public void testNumberFormatterNullValue() throws ParseException { NumberFormat format = NumberFormat.getIntegerInstance(); NumberFormatter formatter = new NumberFormatter(format); formatter.stringToValue(null); } /** * NumberFormat parse can't handle null. * * @throws ParseException */ @Test public void testNumberFormatNullValue() throws ParseException { NumberFormat format = NumberFormat.getIntegerInstance(); format.parse(null); } @Test (expected = ParseException.class) public void testNumberFormatterMinMax() throws ParseException { NumberFormat format = NumberFormat.getIntegerInstance(); NumberFormatter formatter = new NumberFormatter(format); formatter.setMaximum(Integer.MAX_VALUE); formatter.setMinimum(Integer.MIN_VALUE); formatter.stringToValue(TOO_BIG_INTEGER); } @Test public void testNumberFormatInteger() throws ParseException { NumberFormat format = NumberFormat.getIntegerInstance(); // this passes - everything fitting into double range is acceptable format.parse(TOO_BIG_INTEGER); // this blows - must fit into Integer.MIN/MAX new Integer(TOO_BIG_INTEGER); } @Before @Override public void setUp() throws Exception { DefaultTableModel model = new DefaultTableModel(5, 1) { @Override public Class<?> getColumnClass(int columnIndex) { if (columnIndex == INTEGER_COLUMN) return Integer.class; return super.getColumnClass(columnIndex); } }; table = new JXTable(model); cellEditor = new NumberEditorExt(NumberFormat.getIntegerInstance()); cellEditorStrict = new NumberEditorExt(NumberFormat.getIntegerInstance(), true); } }