/* * $Id$ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. */ package org.jdesktop.swingx.table; import static org.hamcrest.CoreMatchers.is; import static org.jdesktop.test.matchers.Matchers.property; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import java.beans.PropertyChangeEvent; import java.util.logging.Logger; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import org.jdesktop.swingx.InteractiveTestCase; import org.jdesktop.swingx.JXTable; import org.jdesktop.swingx.event.TableColumnModelExtListener; import org.jdesktop.swingx.test.ColumnModelReport; import org.jdesktop.test.TestUtils; import org.jdesktop.test.matchers.Matchers; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** * Skeleton to unit test DefaultTableColumnExt. * * Incomplete list of issues to test: * fired added after setVisible(true) * behaviour when adding/removing invisible columns * selection state * * * @author Jeanette Winzenburg */ @RunWith(JUnit4.class) public class TableColumnModelTest extends InteractiveTestCase { @SuppressWarnings("all") private static final Logger LOG = Logger .getLogger(TableColumnModelTest.class.getName()); protected static final int COLUMN_COUNT = 3; /** * Issue 1423 - remove column must not change its visibility state */ @Test public void testRemoveHidden() { TableColumnModelExt model = createColumnModel(4); TableColumnExt column = model.getColumnExt(0); column.setVisible(false); model.removeColumn(column); assertEquals(false, column.isVisible()); } /** * Issue #1340-swingx: DefaultTableColumnModelExt must fire columnRemoved for hidden columns. */ @Test public void testDefaultTableColumnModelExtRemoveHiddenColumns() { DefaultTableColumnModelExt columnModel = (DefaultTableColumnModelExt) new JXTable(10, 2).getColumnModel(); TableColumnExt column = columnModel.getColumnExt(0); column.setVisible(false); ColumnModelReport report = new ColumnModelReport(columnModel); columnModel.removeColumn(column); assertTrue("columnModel must fire removed for hidden columns", report.hasRemovedEvent()); } /** * added api to get array of ext listeners */ @Test public void testGetTableColumnModelExtListener() { // any tableColumnModelExtListener will do JXTable table = new JXTable(); DefaultTableColumnModelExt columnModel = (DefaultTableColumnModelExt) createColumnModel(COLUMN_COUNT); columnModel.addColumnModelListener(table); TableColumnModelExtListener[] listeners = columnModel.getTableColumnModelExtListeners(); assertEquals(1, listeners.length); assertEquals(table, listeners[0]); } /** * Issue #369-swingx: properties of hidden columns are not fired. <p> * test the change from visible to hidden. */ @Test public void testHideTableColumnPropertyNotification() { TableColumnModelExt columnModel = createColumnModel(COLUMN_COUNT); ColumnModelReport report = new ColumnModelReport(); columnModel.addColumnModelListener(report); columnModel.getColumnExt(0).setVisible(false); TestUtils.assertPropertyChangeEvent(report.getPropertyChangeReport(), "visible", true, false); } /** * Issue #846-swingx */ @Test public void testIsAddedFromInvisibleTrue() { final DefaultTableColumnModelExt columnModel = (DefaultTableColumnModelExt) createColumnModel(3); TableColumnExt columnB = columnModel.getColumnExt(1); columnB.setVisible(false); // can't use report: the isRemovedToInvisible is valid during notification only TableColumnModelListener report = new TableColumnModelListener() { public void columnAdded(TableColumnModelEvent e) { int fromIndex = e.getToIndex(); assertEquals("old column really removed", true, columnModel.isAddedFromInvisibleEvent(fromIndex)); // note: the toIndex here is always the last // following are moves to position before hiding } public void columnRemoved(TableColumnModelEvent e) {} public void columnMarginChanged(ChangeEvent e) { } public void columnMoved(TableColumnModelEvent e) {} public void columnSelectionChanged(ListSelectionEvent e) {} }; columnModel.addColumnModelListener(report); columnB.setVisible(true); } /** * Issue #1123-swingx: isRemovedToInvisibleEvent incorrect on second (and subsequent) * hiding of first visible column */ @Test public void testIsRemovedToInvisibleTrue1122() { DefaultTableColumnModelExt columnModel = (DefaultTableColumnModelExt) createColumnModel(3); // hide the first - okay columnModel.getColumnExt(0).setVisible(false); // wire listener assertIsRemovedToInvisible(columnModel, 0, true); // hide the first (== old second) columnModel.getColumnExt(0).setVisible(false); } /** * Issue #846-swingx */ @Test public void testIsRemovedToInvisibleFalse() { DefaultTableColumnModelExt columnModel = (DefaultTableColumnModelExt) createColumnModel(3); // hide a column (paranoid: might create left-over-state) columnModel.getColumnExt(0).setVisible(false); // wire in-process listener assertIsRemovedToInvisible(columnModel, 0, false); // remove first visible column columnModel.removeColumn(columnModel.getColumnExt(0)); } /** * Issue #846-swingx */ @Test public void testIsRemovedToInvisibleTrue() { DefaultTableColumnModelExt columnModel = (DefaultTableColumnModelExt) createColumnModel(3); assertIsRemovedToInvisible(columnModel, 2, true); // hide last column columnModel.getColumnExt(2).setVisible(false); } /** * Wire a TableColumnModelListener to test isRemovedToInvisible. * Note: can't use ColumnModelReport because valid only during notification. * * @param columnModel the model to listen to * @param index the index in the event to test * @param expected the expected result of isRemovedToInvisible */ private void assertIsRemovedToInvisible( final DefaultTableColumnModelExt columnModel, final int index, final boolean expected) { // can't use report: the isRemovedToInvisible is valid during notification only TableColumnModelListener report = new TableColumnModelListener() { public void columnRemoved(TableColumnModelEvent e) { int fromIndex = e.getFromIndex(); assertEquals("old visible index of removed", index, fromIndex); assertEquals("moved to invisible", expected, columnModel.isRemovedToInvisibleEvent(fromIndex)); } public void columnAdded(TableColumnModelEvent e) {} public void columnMarginChanged(ChangeEvent e) { } public void columnMoved(TableColumnModelEvent e) {} public void columnSelectionChanged(ListSelectionEvent e) {} }; columnModel.addColumnModelListener(report); } /** * Issue #369-swingx: properties of hidden columns are not fired. <p> * test the change from hidden to visible. */ @Test public void testShowTableColumnPropertyNotification() { TableColumnModelExt columnModel = createColumnModel(COLUMN_COUNT); Object identifier = "0"; // sanity... assertNotNull(columnModel.getColumnExt(identifier)); columnModel.getColumnExt(identifier).setVisible(false); TableColumnModelExtListener l = mock(TableColumnModelExtListener.class); columnModel.addColumnModelListener(l); columnModel.getColumnExt(identifier).setVisible(true); verify(l).columnPropertyChange(argThat(is(property("visible", false, true)))); } /** * Issue #369-swingx: properties of hidden columns are not fired. <p> * test property changes while hidden * */ @Test public void testHiddenTableColumnPropertyNotification() { TableColumnModelExt columnModel = createColumnModel(COLUMN_COUNT); String identifier = "0"; TableColumnExt columnExt = columnModel.getColumnExt(identifier); columnExt.setVisible(false); // sanity... assertNotNull(columnExt); String title = columnExt.getTitle() + "changed"; ColumnModelReport report = new ColumnModelReport(); columnModel.addColumnModelListener(report); columnExt.setIdentifier(title); TestUtils.assertPropertyChangeEvent(report.getPropertyChangeReport(), "identifier", identifier, title); } /** * Issue #253-swingx: hiding/showing columns changes column sequence. * * The test is modelled after the example code as * http://forums.java.net/jive/thread.jspa?threadID=7344. * */ @Test public void testHideShowColumns() { DefaultTableColumnModelExt model = (DefaultTableColumnModelExt) createColumnModel(10); int[] columnsToHide = new int[] { 4, 7, 6, 8, }; for (int i = 0; i < columnsToHide.length; i++) { model.getColumnExt(String.valueOf(columnsToHide[i])).setVisible(false); } // sanity: actually hidden assertEquals(model.getColumnCount(true) - columnsToHide.length, model.getColumnCount()); for (int i = 0; i < columnsToHide.length; i++) { model.getColumnExt(String.valueOf(columnsToHide[i])).setVisible(true); } // sanity: all visible again assertEquals(10, model.getColumnCount()); for (int i = 0; i < model.getColumnCount(); i++) { // the original sequence assertEquals(i, model.getColumn(i).getModelIndex()); } } /** * test sequence of visible columns after hide/move/show. * * Expected behaviour should be like in Thunderbird. * */ @Test public void testMoveColumns() { DefaultTableColumnModelExt model = (DefaultTableColumnModelExt) createColumnModel(COLUMN_COUNT); TableColumnExt columnExt = model.getColumnExt(1); columnExt.setVisible(false); model.moveColumn(1, 0); columnExt.setVisible(true); assertEquals(columnExt.getModelIndex(), model.getColumnExt(2).getModelIndex()); } /** * test the columnPropertyChangeEvent is fired as expected. * */ @Test public void testColumnPropertyChangeNotification() { DefaultTableColumnModelExt model = (DefaultTableColumnModelExt) createColumnModel(COLUMN_COUNT); ColumnModelReport report = new ColumnModelReport(); model.addColumnModelListener(report); TableColumn column = model.getColumn(0); column.setHeaderValue("somevalue"); assertEquals(1, report.getColumnPropertyEventCount()); PropertyChangeEvent event = report.getLastColumnPropertyEvent(); assertEquals(column, event.getSource()); assertEquals("headerValue", event.getPropertyName()); assertEquals("somevalue", event.getNewValue()); } /** * added TableColumnModelExtListener: test for add/remove extended listeners. * */ @Test public void testAddExtListener() { DefaultTableColumnModelExt model = (DefaultTableColumnModelExt) createColumnModel(COLUMN_COUNT); ColumnModelReport extListener = new ColumnModelReport(); model.addColumnModelListener(extListener); // JW: getListeners returns the count of exactly the given class? // assertEquals(1, model.getListeners(TableColumnModelExtListener.class).length); // assertEquals(2, model.getListeners(EventListener.class).length); // model.removeColumnModelListener(extListener); // assertEquals(0, model.getListeners(TableColumnModelExtListener.class).length); // assertEquals(0, model.getListeners(EventListener.class).length); assertEquals(1, model.getEventListenerList().getListenerCount(TableColumnModelExtListener.class)); assertEquals(2, model.getEventListenerList().getListenerCount()); model.removeColumnModelListener(extListener); assertEquals(0, model.getEventListenerList().getListenerCount(TableColumnModelExtListener.class)); assertEquals(0, model.getEventListenerList().getListenerCount()); } /** * Issue #??-swingx: incorrect isRemovedToInvisible after * removing an invisible column. * */ @Test public void testRemoveInvisibleColumn() { DefaultTableColumnModelExt model = (DefaultTableColumnModelExt) createColumnModel(COLUMN_COUNT); TableColumnExt tableColumnExt = ((TableColumnExt) model.getColumn(0)); tableColumnExt.setVisible(false); model.removeColumn(tableColumnExt); assertEquals("visible column count must be reduced", COLUMN_COUNT - 1, model.getColumns(false).size()); assertEquals("all columns count must be unchanged", COLUMN_COUNT - 1, model.getColumns(true).size()); assertFalse("removing invisible must update event cache", model.isRemovedToInvisibleEvent(0)); } @Test public void testGetColumns() { TableColumnModelExt model = createColumnModel(COLUMN_COUNT); ((TableColumnExt) model.getColumn(0)).setVisible(false); assertEquals("visible column count must be reduced", COLUMN_COUNT - 1, model.getColumns(false).size()); assertEquals("all columns count must be unchanged", COLUMN_COUNT, model.getColumns(true).size()); } /** * column count must be changed on changing * column visibility. * */ @Test public void testColumnCountOnSetInvisible() { TableColumnModel model = createColumnModel(COLUMN_COUNT); int columnCount = model.getColumnCount(); TableColumnExt column = (TableColumnExt) model.getColumn(columnCount - 1); assertTrue(column.isVisible()); column.setVisible(false); assertEquals("columnCount must be decremented", columnCount - 1, model.getColumnCount()); } /** * Issue #156: must update internal state after setting invisible. * Here: the cached totalWidth. Expect similar inconsistency * with selection. * */ @Test public void testTotalColumnWidth() { TableColumnModel model = createColumnModel(COLUMN_COUNT); int totalWidth = model.getTotalColumnWidth(); TableColumnExt column = (TableColumnExt) model.getColumn(0); int columnWidth = column.getWidth(); column.setVisible(false); assertEquals("new total width must be old minus invisible column width " + columnWidth, totalWidth - columnWidth, model.getTotalColumnWidth()); } /** * Issue #157: must fire columnRemoved after setting to invisible. * */ @Test public void testRemovedFired() { TableColumnModel model = createColumnModel(COLUMN_COUNT); ColumnModelReport l = new ColumnModelReport(); model.addColumnModelListener(l); TableColumnExt column = (TableColumnExt) model.getColumn(0); column.setVisible(false); assertTrue("must have fired columnRemoved", l.hasRemovedEvent()); } /** * Issue #157: must fire columnAdded after setting to invisible. * */ @Test public void testAddedFired() { TableColumnModel model = createColumnModel(COLUMN_COUNT); ColumnModelReport l = new ColumnModelReport(); TableColumnExt column = (TableColumnExt) model.getColumn(0); column.setVisible(false); model.addColumnModelListener(l); column.setVisible(true); assertTrue("must have fired columnRemoved", l.hasAddedEvent()); } /** * columnAdded: event.getToIndex must be valid columnIndex. * * */ @Test public void testAddInvisibleColumn() { TableColumnModel model = createColumnModel(COLUMN_COUNT); TableColumnModelListener l = new TableColumnModelListener() { public void columnAdded(TableColumnModelEvent e) { assertTrue("toIndex must be positive", e.getToIndex() >= 0); ((TableColumnModel) e.getSource()).getColumn(e.getToIndex()); } public void columnRemoved(TableColumnModelEvent e) { // TODO Auto-generated method stub } public void columnMoved(TableColumnModelEvent e) { // TODO Auto-generated method stub } public void columnMarginChanged(ChangeEvent e) { // TODO Auto-generated method stub } public void columnSelectionChanged(ListSelectionEvent e) { // TODO Auto-generated method stub } }; model.addColumnModelListener(l); // add invisible column TableColumnExt invisibleColumn = new TableColumnExt(0); invisibleColumn.setVisible(false); model.addColumn(invisibleColumn); // sanity check: add visible column model.addColumn(createTableColumnExt(0)); } /** * columnAt must work on visible columns. * */ @Test public void testColumnAt() { TableColumnModel model = createColumnModel(COLUMN_COUNT); int totalWidth = model.getTotalColumnWidth(); int lastColumn = model.getColumnIndexAtX(totalWidth - 10); assertEquals("lastColumn detected", model.getColumnCount() - 1, lastColumn); TableColumnExt column = (TableColumnExt) model.getColumn(lastColumn); column.setVisible(false); assertEquals("out of range", -1, model.getColumnIndexAtX(totalWidth - 10)); } //------------------ factory methods /** * creates and returns a TableColumnModelExt with the given number * of configured columns of type <code>TableColumnExt</code>. * * @param columns the number of columns to create and add to the model * @return a <code>TableColumnModelExt</code> filled with columns. * * @see createTableColumnExt */ protected TableColumnModelExt createColumnModel(int columns) { TableColumnModelExt model = new DefaultTableColumnModelExt(); for (int i = 0; i < columns; i++) { model.addColumn(createTableColumnExt(i)); } return model; } /** * Creates and returns a TableColumnExt with simple standard configuration. * * <pre><code> * column.getModelIndex() == modelIndex * column.getIdentifier() == String.valueOf(modelIndex); * </code></pre> * * @param modelIndex the model column index to use for config * @return a <code>TableColumnExt</code> with standard configuration */ protected TableColumnExt createTableColumnExt(int modelIndex) { TableColumnExt column = new TableColumnExt(modelIndex); column.setIdentifier(String.valueOf(modelIndex)); return column; } }