/*
* $Id$
*
* Copyright 2004 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;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.lang.reflect.InvocationTargetException;
import java.util.Vector;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.RowSorter;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.jdesktop.swingx.decorator.BorderHighlighter;
import org.jdesktop.swingx.decorator.ComponentAdapterTest.JXTreeTableT;
import org.jdesktop.swingx.renderer.DefaultTreeRenderer;
import org.jdesktop.swingx.renderer.StringValue;
import org.jdesktop.swingx.renderer.StringValues;
import org.jdesktop.swingx.sort.TableSortController;
import org.jdesktop.swingx.table.TableColumnExt;
import org.jdesktop.swingx.test.ActionMapTreeTableModel;
import org.jdesktop.swingx.test.ComponentTreeTableModel;
import org.jdesktop.swingx.test.TreeTableUtils;
import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;
import org.jdesktop.swingx.treetable.FileSystemModel;
import org.jdesktop.swingx.treetable.MutableTreeTableNode;
import org.jdesktop.swingx.treetable.TreeTableModel;
import org.jdesktop.swingx.treetable.TreeTableModelProvider;
import org.jdesktop.swingx.treetable.TreeTableNode;
import org.jdesktop.test.AncientSwingTeam;
import org.jdesktop.test.PropertyChangeReport;
import org.jdesktop.test.TableModelReport;
import org.jdesktop.test.TreeExpansionReport;
import org.jdesktop.test.TreeSelectionReport;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class JXTreeTableUnitTest extends InteractiveTestCase {
@SuppressWarnings ("unused")
private static final Logger LOG = Logger
.getLogger(JXTreeTableUnitTest.class.getName());
protected TreeTableModel treeTableModel;
protected TreeTableModel simpleTreeTableModel;
public JXTreeTableUnitTest() {
super("JXTreeTable Unit Test");
}
/**
* Issue swingx-1529: IOOB Exception on delete
*
* Stacktrace includes DefaultSortController, so sanity testing here
* to verify that there is none installed by default.
*/
@Test
public void testRowSorterDisabled() {
JXTreeTable table = new JXTreeTable(createActionTreeModel());
assertNull(table.getRowSorter());
}
/**
* Issue #1527-swingx: tooltip not shown on hierarchical column after collapse/expand.
*
* Part of the issue: fixed tooltip on table not returned from treeAsRenderer.
*
*/
@Test
public void testToolTipTextOnTreeColumn() {
JXTreeTable table = new JXTreeTable(createCustomTreeTableModelFromDefault());
String toolTip = "dummy";
table.setToolTipText(toolTip);
JXTree tree = (JXTree) table.getCellRenderer(0, 0);
assertEquals(toolTip, tree.getToolTipText());
}
/**
* Issue swingx-1525: borderHighlighter fills tree column completely
*/
@Test
public void testBorder() {
JXTreeTable table = new JXTreeTable(createCustomTreeTableModelFromDefault());
JXTree renderer = (JXTree) table.getCellRenderer(0, 0);
assertEquals(null, renderer.getBorder());
table.addHighlighter(new BorderHighlighter(BorderFactory.createLineBorder(Color.RED)));
table.prepareRenderer(0, 0);
assertEquals(null, renderer.getBorder());
}
/**
* Issue #1430-swingx: throwing on access of getEditingRow
*/
@Test
public void testEditingRow() {
JXTreeTable table = new JXTreeTable();
table.getEditingRow();
}
@Test
public void testFakeSortable() {
JXTreeTable table = new FakeSortableTreeTable();
table.setSortable(true);
assertTrue("table sortable must be true", table.isSortable());
}
@Test
public void testFakeAutoCreateRowSorter() {
JXTreeTable table = new FakeSortableTreeTable();
table.setAutoCreateRowSorter(true);
assertTrue("table autocreateRowsorter must be true", table.getAutoCreateRowSorter());
}
@Test
public void testFakeSetRowSorter() {
JXTreeTable table = new FakeSortableTreeTable();
TableSortController<TableModel> controller = new TableSortController<TableModel>(table.getModel());
table.setRowSorter(controller);
assertEquals("table sorter must be set", controller, table.getRowSorter());
}
/**
* Test subclass access to super sortable models, Issue #479-swingx.
*/
public static class FakeSortableTreeTable extends JXTreeTable {
/**
* @inherited <p>
*/
@Override
public void setAutoCreateRowSorter(boolean autoCreateRowSorter) {
superSetAutoCreateRowSorter(autoCreateRowSorter);
}
/**
* @inherited <p>
*/
@Override
public void setRowSorter(RowSorter<? extends TableModel> sorter) {
superSetRowSorter(sorter);
}
/**
* @inherited <p>
*/
@Override
public void setSortable(boolean sortable) {
superSetSortable(sortable);
}
}
/**
* Issue #1379-swingx: support access to the underlying TreeTableModel.
*/
@Test (expected= NullPointerException.class)
public void testTreeTableModelAdapter() {
JXTreeTableA table = new JXTreeTableA();
table.createAdapter(null);
}
/**
* Subclass to test model adapter properties.
*/
public static class JXTreeTableA extends JXTreeTable {
public JXTreeTableA() {
super();
}
public JXTreeTableA(TreeTableModel model) {
super(model);
}
public TreeTableModelAdapter createAdapter(JTree tree) {
return new TreeTableModelAdapter(tree);
}
}
/**
* Issue #1379-swingx: support access to the underlying TreeTableModel.
*/
@Test
public void testTreeTableModelProvider() {
JXTreeTable table = new JXTreeTable(treeTableModel);
assertTrue(table.getModel() instanceof TreeTableModelProvider);
assertSame(treeTableModel, ((TreeTableModelProvider) table.getModel()).getTreeTableModel());
}
/**
* Issue #1275-swingx: getToolTipText(MouseEvent) throws IllegalArgumentException.
*
* Happens if the given mouse location doesn't map to a valid column, aka: is
* outside of the tree table (in which case the documented return value for columnAtPoint
* is -1). Code must cope with that.
*
*/
@Test
public void testSafeHierarchicalColumnOnToolTip() {
JXTreeTable table = new JXTreeTable(treeTableModel);
MouseEvent event = new MouseEvent(table, 0, 0, 0, -1, -1, 1, false);
table.getToolTipText(event);
}
/**
* Issue #876-swingx: add support for adding/removing expansion listeners.
*/
@Test
public void testExpansionListenerSourceExpanded() {
JXTreeTable table = new JXTreeTable(new FileSystemModel());
TreeExpansionReport report = new TreeExpansionReport(table);
table.expandRow(0);
assertEquals(1, report.getEventCount());
assertEquals(table, report.getLastExpandedEvent().getSource());
}
/**
* Issue #876-swingx: add support for adding/removing expansion listeners.
*/
@Test
public void testExpansionListenerSourceCollapsed() {
JXTreeTable table = new JXTreeTable(new FileSystemModel());
table.expandRow(0);
TreeExpansionReport report = new TreeExpansionReport(table);
table.collapseRow(0);
assertEquals(1, report.getEventCount());
assertEquals(table, report.getLastCollapsedEvent().getSource());
}
/**
* Part of issue ??-swingx: tree width must be same as hierarchical column width
*/
@Test
public void testTreeWidth() {
JXTreeTable table = new JXTreeTable(new FileSystemModel());
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JXTree tree = (JXTree) table.getCellRenderer(0, 0);
int old = table.getColumn(0).getWidth();
assertEquals(old, tree.getWidth());
int width = old *2;
table.getColumn(0).setWidth(width);
assertEquals(width, table.getColumn(0).getWidth());
assertEquals(width, tree.getWidth());
}
/**
* Issue #1121: most not be sortable
*
* Here: test that the autoCreateRowSorter property is false.
*/
@Test
public void testAutoCreateRowSorterDisabled() {
JXTreeTable table = new JXTreeTable();
assertEquals("treeTable autoCreateRowSorter must be false", false, table.getAutoCreateRowSorter());
}
/**
* Issue #1121: most not be sortable
*
* Here: test that the autoCreateRowSorter property is not settable.
*/
@Test
public void testAutoCreateRowSorterNotSettable() {
JXTreeTable table = new JXTreeTable();
table.setAutoCreateRowSorter(true);
assertEquals("treeTable autoCreateRowSorter must be false", false, table.getAutoCreateRowSorter());
}
/**
* Issue #1121: most not be sortable
*
* Here: test that the no rowSorter installed.
*/
@Test
public void testRowSorterNull() {
JXTreeTable table = new JXTreeTable();
assertNull("null rowsorter initially, was: " + table.getRowSorter(),
table.getRowSorter());
}
/**
* Issue #1121: most not be sortable
*
* Here: test that the no rowSorter installed.
*/
@Test
public void testRowSorterNotSettable() {
JXTreeTable table = new JXTreeTable();
table.setRowSorter(new TableRowSorter<TableModel>());
assertNull("rowsorter not settable, was: " + table.getRowSorter(),
table.getRowSorter());
}
/**
* Issue #766-swingx: drop image is blinking over hierarchical column.
*
* Test the hack - enabled by default, can be disabled by setting the
* client property to Boolean.FALSE.
*
*/
@Test
public void testDropHack() {
JXTree tree = new JXTree();
assertEquals("sanity - default visible", true, tree.isVisible());
JXTreeTable treeTable = new JXTreeTable(new FileSystemModel());
JXTree renderer = (JXTree) treeTable.getCellRenderer(0, 0);
assertEquals("renderer must be invisible by default", false, renderer.isVisible());
treeTable.putClientProperty(JXTreeTable.DROP_HACK_FLAG_KEY, Boolean.FALSE);
assertEquals("renderer must be visible if hack disabled", true, renderer.isVisible());
}
/**
* Issue #862-swingx: JXTree - add api for selection colors.
* Here: test that the tree in JXTreeTable is kept in synch.
*/
@Test
public void testSelectionBackground() {
JXTreeTable treeTable = new JXTreeTable(new FileSystemModel());
treeTable.setSelectionBackground(Color.RED);
assertEquals(treeTable.getSelectionBackground(),
((JXTree) treeTable.getCellRenderer(0, 0)).getSelectionBackground());
}
/**
* Issue #862-swingx: JXTree - add api for selection colors.
* Here: test that the tree in JXTreeTable is kept in synch.
*/
@Test
public void testSelectionForeground() {
JXTreeTable treeTable = new JXTreeTable(new FileSystemModel());
treeTable.setSelectionForeground(Color.RED);
assertEquals(treeTable.getSelectionForeground(),
((JXTree) treeTable.getCellRenderer(0, 0)).getSelectionForeground());
}
/**
* Issue #853-swingx: tree is not disabled.
*
*/
@Test
public void testDisabledTreeColumn() {
JXTreeTable treeTable = new JXTreeTable(new FileSystemModel());
treeTable.setEnabled(false);
assertEquals(false, ((Component) treeTable.getCellRenderer(0, 0)).isEnabled());
}
/**
* Issue #853-swingx: tree is not disabled.
*
*/
@Test
public void testDisabledTreeColumnPrepared() {
JXTreeTable treeTable = new JXTreeTable(new FileSystemModel());
treeTable.setEnabled(false);
assertEquals(false, treeTable.prepareRenderer(treeTable.getCellRenderer(0, 0), 0, 0).isEnabled());
}
/**
* Issue #821-swingx: JXTreeTable broken string rep of hierarchical column
* Here we test the getStringAt for the hierarchical column.
*/
@Test
public void testGetStringAtHierarchicalColumn() {
JXTreeTable table = new JXTreeTableT(AncientSwingTeam.createNamedColorTreeTableModel());
StringValue sv = new StringValue() {
@Override
public String getString(Object value) {
if (value instanceof Color) {
Color color = (Color) value;
return "R/G/B: " + color.getRGB();
}
return StringValues.TO_STRING.getString(value);
}
};
table.setTreeCellRenderer(new DefaultTreeRenderer(sv));
String text = sv.getString(table.getValueAt(2, 0));
assertTrue("sanity: text not empty", text.length() > 0);
assertEquals(text, table.getStringAt(2, 0));
}
/**
* Issue #769-swingx: setXXIcon on renderer vs setXXIcon on Tree/Table.
* Characterize treeTable behaviour.
*
* Here: icon on renderer must be respected if overwrite is false.
*/
@Test
public void testIconSetOnRendererFalseOverwrite() {
JXTreeTable treeTable = new JXTreeTable();
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
renderer.setLeafIcon(null);
treeTable.setTreeCellRenderer(renderer);
assertEquals("renderer must have null leaf icon", null, renderer.getLeafIcon());
}
/**
* Issue #769-swingx: setXXIcon on renderer vs setXXIcon on Tree/Table.
* Characterize treeTable behaviour.
*
* Here: icon on renderer must be overwritten if overwrite is true.
*/
@Test
public void testIconSetOnRendererTrueOverwrite() {
JXTreeTable treeTable = new JXTreeTable();
treeTable.setLeafIcon(null);
treeTable.setOverwriteRendererIcons(true);
// PENDING: incomplete api - no getter
// Icon leaf = treeTable.getLeafIcon();
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
assertNotNull("sanity - the renderer has a leafIcon ", renderer.getLeafIcon());
treeTable.setTreeCellRenderer(renderer);
assertEquals("renderer leaf icon must be overwritten by treeTable's leaf icon",
null, renderer.getLeafIcon());
}
/**
* Issue #769-swingx: setXXIcon on renderer vs setXXIcon on Tree/Table.
* Characterize treeTable behaviour.
*
* Here: set icon on treeTable is passed on to renderer always.
*/
@Test
public void testIconSetOnTreeTableFalseOverwrite() {
JXTreeTable treeTable = new JXTreeTable();
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
assertNotNull(renderer.getLeafIcon());
treeTable.setTreeCellRenderer(renderer);
treeTable.setLeafIcon(null);
assertEquals("renderer must have null leaf icon", null, renderer.getLeafIcon());
}
/**
* Issue #769-swingx: setXXIcon on renderer vs setXXIcon on Tree/Table.
* Characterize treeTable behaviour.
*
* Here: set icon on treeTable is passed on to renderer always.
*/
@Test
public void testIconSetOnTreeTableTrueOverwrite() {
JXTreeTable treeTable = new JXTreeTable();
treeTable.setOverwriteRendererIcons(true);
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
assertNotNull(renderer.getLeafIcon());
treeTable.setTreeCellRenderer(renderer);
treeTable.setLeafIcon(null);
assertEquals("renderer must have null leaf icon", null, renderer.getLeafIcon());
}
/**
* Issue #769-swingx: setXXIcon on renderer vs setXXIcon on Tree/Table.
* Characterize treeTable behaviour.
*
* Here: default overwriteOnRenderer is false.
*/
@Test
public void testIconOverwriteInitial() {
JXTreeTable treeTable = new JXTreeTable();
assertFalse("initial overwriteRendererIcons must be false",
treeTable.isOverwriteRendererIcons());
}
/**
* #561-swingx: KeyEvent on hierarchical column doesn't start editing.
*
* Here: test method without event (delegates to event == null)
*/
@Test
public void testEditCellAt() {
JXTreeTable treeTable = prepareTreeTable(true);
treeTable.expandAll();
// sanity
assertTrue(treeTable.isCellEditable(0, 0));
assertTrue(treeTable.editCellAt(0, 0));
}
/**
* #561-swingx: KeyEvent on hierarchical column doesn't start editing.
*
* Here: test method taking the event
*/
@Test
public void testEditCellAtByKeyEvent() {
JXTreeTable treeTable = prepareTreeTable(true);
treeTable.expandAll();
// sanity
assertTrue(treeTable.isCellEditable(0, 0));
KeyEvent e = new KeyEvent(treeTable, KeyEvent.KEY_PRESSED, 0L,
0, KeyEvent.VK_T, KeyEvent.CHAR_UNDEFINED);
assertTrue("keyEvent must start editing", treeTable.editCellAt(0, 0, e));
}
/**
* #561-swingx: KeyEvent on hierarchical column doesn't start editing.
*
* Here: compare with plain table (in fact plain DefaultCellEditor)
*/
@Test
public void testTableEditCellAtByKeyEvent() {
JXTable table = new JXTable(10, 20);
// sanity
assertTrue(table.isCellEditable(0, 0));
KeyEvent e = new KeyEvent(table, KeyEvent.KEY_PRESSED, 0L,
0, KeyEvent.VK_T, KeyEvent.CHAR_UNDEFINED);
assertTrue(table.editCellAt(0, 0, e));
}
/**
* Issue #493-swingx: incorrect table events fired.
* Issue #592-swingx: (no structureChanged table events) is a special
* case of the former.
*
* Here: must fire structureChanged on setRoot(null).
* fails - because the treeStructureChanged is mapped to a
* tableDataChanged.
*
* @throws InvocationTargetException
* @throws InterruptedException
*/
@Test
public void testTableEventOnSetNullRoot() throws InterruptedException, InvocationTargetException {
TreeTableModel model = createCustomTreeTableModelFromDefault();
final JXTreeTable table = new JXTreeTable(model);
table.setRootVisible(true);
table.expandAll();
final TableModelReport report = new TableModelReport();
table.getModel().addTableModelListener(report);
((DefaultTreeTableModel) model).setRoot(null);
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
assertEquals("tableModel must have fired", 1, report.getEventCount());
assertTrue("event type must be structureChanged " + TableModelReport.printEvent(report.getLastEvent()),
report.isStructureChanged(report.getLastEvent()));
}
});
}
/**
* Issue #493-swingx: incorrect table events fired.
* Issue #592-swingx: (no structureChanged table events) is a special
* case of the former.
*
* Here: must fire structureChanged on setRoot(otherroot).
* failed - because the treeStructureChanged is mapped to a
* tableDataChanged.
*
* @throws InvocationTargetException
* @throws InterruptedException
*/
@Test
public void testTableEventOnSetRoot() throws InterruptedException, InvocationTargetException {
TreeTableModel model = createCustomTreeTableModelFromDefault();
final JXTreeTable table = new JXTreeTable(model);
table.setRootVisible(true);
table.expandAll();
final TableModelReport report = new TableModelReport();
table.getModel().addTableModelListener(report);
((DefaultTreeTableModel) model).setRoot(new DefaultMutableTreeTableNode("other"));
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
assertEquals("tableModel must have fired", 1, report.getEventCount());
assertTrue("event type must be structureChanged " + TableModelReport.printEvent(report.getLastEvent()),
report.isStructureChanged(report.getLastEvent()));
}
});
}
/**
* Issue #493-swingx: incorrect table events fired.
* Issue #592-swingx: (no structureChanged table events) is a special
* case of the former.
*
* Here: must not fire structureChanged on reload(subtree).
* failed - because the treeStructureChanged is mapped to a
* tableDataChanged.
*
* @throws InvocationTargetException
* @throws InterruptedException
*/
@Test
public void testTableEventOnReloadNonRoot() throws InterruptedException, InvocationTargetException {
DefaultTreeTableModel model = new DefaultTreeTableModel(
(TreeTableNode) createCustomTreeTableModelFromDefault().getRoot()) {
/**
* overridden to do nothing but fire a structureChange
* on the node. This is a trick
* for testing only!
*/
@Override
public void removeNodeFromParent(MutableTreeTableNode node) {
TreePath treePath = new TreePath(getPathToRoot(node));
modelSupport.fireTreeStructureChanged(treePath);
}
};
final JXTreeTable table = new JXTreeTable(model);
table.setRootVisible(true);
table.expandAll();
// second child of root
MutableTreeTableNode node = (MutableTreeTableNode) model.getRoot().getChildAt(1);
final TableModelReport report = new TableModelReport();
table.getModel().addTableModelListener(report);
model.removeNodeFromParent(node);
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
assertEquals("tableModel must have fired", 1, report.getEventCount());
assertTrue("event type must be dataChanged " + TableModelReport.printEvent(report.getLastEvent()),
report.isDataChanged(report.getLastEvent()));
}
});
}
/**
* Issue #493-swingx: incorrect table events fired.
* Issue #592-swingx: (no structureChanged table events) is a special
* case of the former.
*
* Here: must fire structureChanged on setModel.
* This was okay, because the setTreeTableModel on the table is handled
* directly (through tableChanged)
* @throws InvocationTargetException
* @throws InterruptedException
*/
@Test
public void testTableEventOnSetModel() throws InterruptedException, InvocationTargetException {
TreeTableModel model = createCustomTreeTableModelFromDefault();
final JXTreeTable table = new JXTreeTable(model);
table.setRootVisible(true);
table.expandAll();
final TableModelReport report = new TableModelReport();
table.getModel().addTableModelListener(report);
table.setTreeTableModel(createCustomTreeTableModelFromDefault());
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
assertEquals("tableModel must have fired", 1, report.getEventCount());
assertTrue("event type must be structureChanged " + TableModelReport.printEvent(report.getLastEvent()),
report.isStructureChanged(report.getLastEvent()));
}
});
}
/**
* Issue #531-swingx: IllegalArgumentException on setModel.
*
*/
@Test
public void testSetModel() {
TreeTableModel model = createCustomTreeTableModelFromDefault();
JXTreeTable treeTable = new JXTreeTable(model);
treeTable.setRootVisible(true);
treeTable.setTreeTableModel(createCustomTreeTableModelFromDefault());
}
/**
* Issue #531-swingx: IllegalArgumentException on setModel.
*
*/
@Test
public void testSetModelOnTree() {
TreeTableModel model = createCustomTreeTableModelFromDefault();
JXTree treeTable = new JXTree(model);
treeTable.setRootVisible(true);
treeTable.setModel(createCustomTreeTableModelFromDefault());
}
/**
* Issue #531-swingx: IllegalArgumentException on setModel.
*
*/
@Test
public void testSetModelEmptyContructor() {
JXTreeTable treeTable = new JXTreeTable();
treeTable.setRootVisible(true);
treeTable.setTreeTableModel(createCustomTreeTableModelFromDefault());
}
/**
* Issue #493-swingx: JXTreeTable.TreeTableModelAdapter: Inconsistency
* firing update.
*
* Test update events after updating treeTableModel.
*
* from tiberiu@dev.java.net
* @throws InvocationTargetException
* @throws InterruptedException
*/
@Test
public void testTableEventUpdateOnTreeTableModelSetValue() throws InterruptedException, InvocationTargetException {
TreeTableModel model = createCustomTreeTableModelFromDefault();
final JXTreeTable table = new JXTreeTable(model);
table.setRootVisible(true);
table.expandAll();
final int row = 6;
// sanity
assertEquals("sports", table.getValueAt(row, 0).toString());
final TableModelReport report = new TableModelReport();
table.getModel().addTableModelListener(report);
model.setValueAt("games",
table.getPathForRow(6).getLastPathComponent(), 0);
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
assertEquals("tableModel must have fired", 1, report.getEventCount());
assertEquals("the event type must be update", 1, report.getUpdateEventCount());
TableModelEvent event = report.getLastUpdateEvent();
assertEquals("the updated row ", row, event.getFirstRow());
}
});
}
/**
* Issue #493-swingx: JXTreeTable.TreeTableModelAdapter: Inconsistency
* firing update.
*
* Test delete events after tree table model.
*
* from tiberiu@dev.java.net
* @throws InvocationTargetException
* @throws InterruptedException
*/
@Test
public void testTableEventDeleteOnTreeTableModel() throws InterruptedException, InvocationTargetException {
TreeTableModel model = createCustomTreeTableModelFromDefault();
MutableTreeTableNode root = (MutableTreeTableNode) model.getRoot();
MutableTreeTableNode sportsNode = (MutableTreeTableNode) root.getChildAt(1);
int childrenToDelete = sportsNode.getChildCount() - 1;
for (int i = 0; i < childrenToDelete; i++) {
MutableTreeTableNode firstChild = (MutableTreeTableNode) sportsNode.getChildAt(0);
((DefaultTreeTableModel) model).removeNodeFromParent(firstChild);
}
// sanity
assertEquals(1, sportsNode.getChildCount());
final JXTreeTable table = new JXTreeTable(model);
table.setRootVisible(true);
table.expandAll();
final int row = 6;
// sanity
assertEquals("sports", table.getValueAt(row, 0).toString());
final TableModelReport report = new TableModelReport();
table.getModel().addTableModelListener(report);
// remove the last child from sports node
MutableTreeTableNode firstChild = (MutableTreeTableNode) sportsNode.getChildAt(0);
((DefaultTreeTableModel) model).removeNodeFromParent(firstChild);
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
assertEquals("tableModel must have fired exactly one event", 1, report.getEventCount());
TableModelEvent event = report.getLastEvent();
assertEquals("event type must be delete", TableModelEvent.DELETE, event.getType());
assertEquals("the deleted row ", row + 1, event.getFirstRow());
}
});
}
/**
* Issue #493-swingx: JXTreeTable.TreeTableModelAdapter: Inconsistency
* firing update.
*
* Test update events after updating table.
*
* from tiberiu@dev.java.net
* @throws InvocationTargetException
* @throws InterruptedException
*/
@Test
public void testTableEventUpdateOnTreeTableSetValue() throws InterruptedException, InvocationTargetException {
TreeTableModel model = createCustomTreeTableModelFromDefault();
final JXTreeTable table = new JXTreeTable(model);
table.setRootVisible(true);
table.expandAll();
final int row = 6;
// sanity
assertEquals("sports", table.getValueAt(row, 0).toString());
assertTrue("cell must be editable at row " + row, table.getModel().isCellEditable(row, 0));
final TableModelReport report = new TableModelReport();
table.getModel().addTableModelListener(report);
// doesn't fire or isn't detectable?
// Problem was: model was not-editable.
table.setValueAt("games", row, 0);
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
assertEquals("tableModel must have fired", 1, report.getEventCount());
assertEquals("the event type must be update", 1, report.getUpdateEventCount());
TableModelEvent event = report.getLastUpdateEvent();
assertEquals("the updated row ", row, event.getFirstRow());
}
});
}
/**
* Issue #465-swingx: NPE if editing node with null icon.
*/
@Test
public void testNPEEditingNullIcon() {
JXTreeTable treeTable = new JXTreeTable(new ComponentTreeTableModel(new JXErrorPane()));
treeTable.setEditable(true);
treeTable.expandAll();
treeTable.setOpenIcon(null);
treeTable.setLeafIcon(null);
treeTable.setClosedIcon(null);
assertTrue(treeTable.isCellEditable(1, 0));
treeTable.editCellAt(1, 0, null);
}
/**
* Issue #??-swingx: ComponentAdapter not fully implemented - leaf always true.
*
*/
@Test
public void testComponentAdapterIsLeaf() {
// build the test treeTableModel
JPanel root = new JPanel();
JLabel label = new JLabel();
JPanel inner = new JPanel();
// last row is leaf
inner.add(label);
// first row is folder
root.add(inner);
TreeTableModel model = new ComponentTreeTableModel(root);
// sanity
assertTrue("label is leaf", model.isLeaf(label));
JXTreeTable table = new JXTreeTable(model);
table.expandAll();
// sanity
assertEquals("number of expanded rows", 2, table.getRowCount());
// test leafness of last
int lastRow = table.getRowCount() - 1;
TreePath leafPath = table.getPathForRow(lastRow);
assertEquals(label, leafPath.getLastPathComponent());
assertEquals("adapter must report same leafness as model",
model.isLeaf(label), table.getComponentAdapter(lastRow, 0).isLeaf());
// test folderness of first
int firstRow = 0;
TreePath folderPath = table.getPathForRow(firstRow);
assertEquals(inner, folderPath.getLastPathComponent());
assertEquals("adapter must report same leafness as model",
model.isLeaf(inner), table.getComponentAdapter(firstRow, 0).isLeaf());
}
/**
* Issue #??-swingx: ComponentAdapter not fully implemented - expanded always true.
*
*/
@Test
public void testComponentAdapterIsExpanded() {
// build the test treeTableModel
JPanel root = new JPanel();
JLabel label = new JLabel();
JPanel inner = new JPanel();
// last row is leaf
inner.add(label);
// first row is folder
root.add(inner);
TreeTableModel model = new ComponentTreeTableModel(root);
// sanity
assertTrue("label is leaf", model.isLeaf(label));
JXTreeTable table = new JXTreeTable(model);
// sanity
assertEquals("number of expanded rows", 1, table.getRowCount());
// test folderness of first
int firstRow = 0;
TreePath folderPath = table.getPathForRow(firstRow);
assertEquals(inner, folderPath.getLastPathComponent());
assertEquals("adapter must report same expansion state as tree", table.isExpanded(firstRow),
table.getComponentAdapter(firstRow, 0).isExpanded());
}
/**
* Issue #342-swingx: default margins in JXTreeTable.
*
* This is not only a treeTable issue: the coupling of
* margins to showing gridlines (and still get a "nice"
* looking selection) is not overly obvious in JTable as
* well. Added convenience method to JXTable to adjust margins to
* 0/1 if hiding/showing grid lines.
*
*/
@Test
public void testShowGrid() {
JXTreeTable table = new JXTreeTable(simpleTreeTableModel);
// sanity: initial margins are (0, 0), grid off
boolean show = false;
assertEquals(0, table.getRowMargin());
assertEquals(show, table.getShowHorizontalLines());
assertEquals(0, table.getColumnMargin());
assertEquals(show, table.getShowVerticalLines());
// show lines
table.setShowGrid(!show, !show);
assertEquals(1, table.getRowMargin());
assertEquals(!show, table.getShowHorizontalLines());
assertEquals(1, table.getColumnMargin());
assertEquals(!show, table.getShowVerticalLines());
}
/**
* Issue #120-jdnc: data corruption if collapsed while editing.
* Note: this tests programatic collapse while editing!
* Don't know how to test mouse-triggered collapse/expand, "looked"
* at it in the visualCheck.
*/
@Test
public void testEditOnCollapse() {
DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode("ROOT");
DefaultMutableTreeTableNode a = new DefaultMutableTreeTableNode("A");
DefaultMutableTreeTableNode a1 = new DefaultMutableTreeTableNode("A1");
DefaultMutableTreeTableNode b = new DefaultMutableTreeTableNode("B");
a.add(a1);
root.add(a);
root.add(b);
Vector<String> columnNames = new Vector<String>();
columnNames.add("A");
TreeTableModel model = new DefaultTreeTableModel(root, columnNames) {
@Override
public boolean isCellEditable(Object obj,int col) {
return true;
}
@Override
public void setValueAt(Object value,Object node,int col) {
MutableTreeTableNode treeNode = (MutableTreeTableNode) node;
treeNode.setUserObject(value);
MutableTreeTableNode parent = (MutableTreeTableNode) treeNode.getParent();
modelSupport.fireChildChanged(new TreePath(
getPathToRoot(parent)), parent.getIndex(treeNode),
treeNode);
}
@Override
public Object getValueAt(Object node,int col) {
return ((DefaultMutableTreeTableNode) node).getUserObject();
}
};
JXTreeTable treeTable = new JXTreeTable(model);
treeTable.setEditable(true);
treeTable.expandAll();
assertEquals(3, treeTable.getRowCount());
Object valueBelow = treeTable.getValueAt(2, 0);
treeTable.editCellAt(1, 0);
((JTextField) treeTable.getEditorComponent()).setText("other");
treeTable.collapseRow(0);
assertEquals(2, treeTable.getRowCount());
if (treeTable.isEditing()) {
treeTable.getCellEditor().stopCellEditing();
}
assertEquals(valueBelow, treeTable.getValueAt(1, 0));
}
/**
* Issue #399-swingx: editing terminated by selecting editing row.<p>
* Assert workaround: setExpandsSelectedPaths(false)
*/
@Test
public void testSelectionKeepsEditingWithExpandsFalse() {
JXTreeTable treeTable = new JXTreeTable(new FileSystemModel()) {
@Override
public boolean isCellEditable(int row, int column) {
return true;
}
};
boolean canEdit = treeTable.editCellAt(1, 2);
// sanity: editing started
assertTrue(canEdit);
// sanity: nothing selected
assertTrue(treeTable.getSelectionModel().isSelectionEmpty());
int editingRow = treeTable.getEditingRow();
treeTable.setExpandsSelectedPaths(false);
treeTable.setRowSelectionInterval(editingRow, editingRow);
assertEquals("after selection treeTable editing state must be unchanged", canEdit, treeTable.isEditing());
}
/**
* Issue #4-, #340-swingx: duplicate notification
*
* starting from unselected, the event count is 1 as expected
*/
@Test
public void testSelectionEvents() {
JXTreeTable treeTable = prepareTreeTable(false);
TreeSelectionReport report = new TreeSelectionReport();
treeTable.getTreeSelectionModel().addTreeSelectionListener(report);
treeTable.setRowSelectionInterval(1, 1);
assertEquals(1, report.getEventCount());
}
/**
* Issue #4-, #340-swingx: duplicate notification
*
* Hmm... unexpected: the eventCount (2) is not effected by
* catching isAdjusting listSelectionEvents. The reason is
* an intermediate clearSelection which fires the additional.
*/
@Test
public void testSelectionChangedEvents() {
JXTreeTable treeTable = prepareTreeTable(true);
TreeSelectionReport report = new TreeSelectionReport();
treeTable.getTreeSelectionModel().addTreeSelectionListener(report);
treeTable.setRowSelectionInterval(1, 1);
assertEquals(1, report.getEventCount());
}
/**
* Issue #4-, #340-swingx: duplicate notification
*
* The old in the event must be the last selected.
*/
@Test
public void testSelectionChangedHasFirstOldPath() {
JXTreeTable treeTable = prepareTreeTable(true);
TreeSelectionReport report = new TreeSelectionReport();
treeTable.getTreeSelectionModel().addTreeSelectionListener(report);
treeTable.setRowSelectionInterval(1, 1);
TreeSelectionEvent event = report.getLastEvent();
assertEquals(treeTable.getPathForRow(1), event.getNewLeadSelectionPath());
assertEquals(treeTable.getPathForRow(0), event.getOldLeadSelectionPath());
}
/**
* creates and configures a treetable for usage in selection tests.
*
* @param selectFirstRow boolean to indicate if the first row should
* be selected.
* @return a tree table configured for selection tests
*/
protected JXTreeTable prepareTreeTable(boolean selectFirstRow) {
JXTreeTable treeTable = new JXTreeTable(simpleTreeTableModel);
treeTable.setRootVisible(true);
// sanity: assert that we have at least two rows to change selection
assertTrue(treeTable.getRowCount() > 1);
if (selectFirstRow) {
treeTable.setRowSelectionInterval(0, 0);
}
return treeTable;
}
/**
* Issue #4-, #340-swingx: duplicate notification
*
* sanity: check if there's only one event fired if selection is
* set directly via the treeSelectionModel. Characterize normal
* treeSelection to mimic.
*/
@Test
public void testSelectionChangedOnTreeSelection() {
JXTreeTable treeTable = prepareTreeTable(true);
TreePath oldSelected = treeTable.getPathForRow(0);
TreeSelectionReport report = new TreeSelectionReport();
treeTable.getTreeSelectionModel().addTreeSelectionListener(report);
TreePath newSelected = treeTable.getPathForRow(1);
treeTable.getTreeSelectionModel().setSelectionPath(newSelected);
assertEquals(1, report.getEventCount());
// check the paths
TreeSelectionEvent event = report.getLastEvent();
assertEquals(oldSelected, event.getOldLeadSelectionPath());
assertEquals(newSelected, event.getNewLeadSelectionPath());
}
/**
* Issue #270-swingx: NPE in some contexts when accessing the
* TreeTableModelAdapter.
*
*/
@Test
public void testConservativeRowForNodeInAdapter() {
// for testing we need a model which relies on
// node != null
TreeTableModel model = new DefaultTreeTableModel((TreeTableNode) simpleTreeTableModel.getRoot()) {
@Override
public int getColumnCount() {
return 1;
}
@Override
public Object getValueAt(Object node, int column) {
// access node
node.toString();
return super.getValueAt(node, column);
}
@Override
public void setValueAt(Object value, Object node, int column) {
// access node
node.toString();
super.setValueAt(value, node, column);
}
@Override
public boolean isCellEditable(Object node, int column) {
// access node
node.toString();
return super.isCellEditable(node, column);
}
};
// can't use ComponentTreeTableModel with JXFrame in headless environment
// JXTreeTable treeTable = new JXTreeTable(new ComponentTreeTableModel(new JXFrame()));
JXTreeTable treeTable = new JXTreeTable(model);
treeTable.setRootVisible(true);
TableModel adapter = treeTable.getModel();
treeTable.collapseAll();
assertEquals(1, treeTable.getRowCount());
// simulate contexts where the accessed row isn't currently visible
adapter.getValueAt(treeTable.getRowCount(), 0);
adapter.isCellEditable(treeTable.getRowCount(), 0);
adapter.setValueAt("somename", treeTable.getRowCount(), 0);
}
/**
* test if table and tree rowHeights are the same.
*
*/
@Test
public void testAdjustedRowHeights() {
JXTreeTable treeTable = new JXTreeTable(simpleTreeTableModel);
JXTree tree = (JXTree) treeTable.getCellRenderer(0, 0);
// sanity: same initially
assertEquals("table and tree rowHeights must be equal",
treeTable.getRowHeight(), tree.getRowHeight());
// change treeTable height
treeTable.setRowHeight(treeTable.getRowHeight() * 2);
assertEquals("table and tree rowHeights must be equal",
treeTable.getRowHeight(), tree.getRowHeight());
// change treeTable height
tree.setRowHeight(tree.getRowHeight() * 2);
assertEquals("table and tree rowHeights must be equal",
treeTable.getRowHeight(), tree.getRowHeight());
}
/**
* #321-swingx: missing tree property toggleClickCount, largeModel.
*
*/
@Test
public void testToggleClickCount() {
JXTreeTable treeTable = new JXTreeTable(simpleTreeTableModel);
int clickCount = treeTable.getToggleClickCount();
// asserting documented default clickCount == 2
assertEquals("default clickCount", 2, clickCount);
int newClickCount = clickCount + 1;
treeTable.setToggleClickCount(newClickCount);
assertEquals("toggleClickCount must be changed",
newClickCount, treeTable.getToggleClickCount());
boolean largeModel = treeTable.isLargeModel();
assertFalse("initial largeModel", largeModel);
treeTable.setLargeModel(!largeModel);
assertTrue("largeModel property must be toggled", treeTable.isLargeModel());
}
/**
* Issue #168-jdnc: dnd enabled breaks node collapse/expand.
* testing auto-detection of dragHackEnabled.
*
* Removed auto-detection (cleanup 1.6)
*/
@Test
public void testDragHackFlagOn() {
JXTreeTable treeTable = new JXTreeTable(simpleTreeTableModel);
assertNull(treeTable.getClientProperty(JXTreeTable.DRAG_HACK_FLAG_KEY));
treeTable.getTreeTableHacker().expandOrCollapseNode(0,
new MouseEvent(treeTable, MouseEvent.MOUSE_PRESSED, 0, InputEvent.BUTTON1_MASK, 0, 0, 1, false));
Boolean dragHackFlag = (Boolean) treeTable.getClientProperty(JXTreeTable.DRAG_HACK_FLAG_KEY);
assertNull(dragHackFlag);
}
/**
* Issue #168-jdnc: dnd enabled breaks node collapse/expand.
* testing auto-detection of dragHackEnabled.
*
* Removed auto-detection (cleanup 1.6)
*
*/
@Test
public void testDragHackFlagOff() {
System.setProperty("sun.swing.enableImprovedDragGesture", "true");
JXTreeTable treeTable = new JXTreeTable(simpleTreeTableModel);
assertNull(treeTable.getClientProperty(JXTreeTable.DRAG_HACK_FLAG_KEY));
treeTable.getTreeTableHacker().expandOrCollapseNode(0,
new MouseEvent(treeTable, MouseEvent.MOUSE_PRESSED, 0, InputEvent.BUTTON1_MASK, 0, 0, 1, false));
Boolean dragHackFlag = (Boolean) treeTable.getClientProperty(JXTreeTable.DRAG_HACK_FLAG_KEY);
assertNull(dragHackFlag);
System.getProperties().remove("sun.swing.enableImprovedDragGesture");
}
/**
* loosely related to Issue #248-swingx: setRootVisible (true) after
* initial rootInvisible didn't show the root.
*
* this here is a sanity test that there is exactly one row, the problem
* is a missing visual update of the table.
*
*/
@Test
public void testEmptyModelInitiallyInvisibleRoot() {
final DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode();
final InsertTreeTableModel model = new InsertTreeTableModel(root);
final JXTreeTable treeTable = new JXTreeTable(model);
// sanity...
assertFalse(treeTable.isRootVisible());
assertEquals("no rows with invisible root", 0, treeTable.getRowCount());
treeTable.setRootVisible(true);
// sanity...
assertTrue(treeTable.isRootVisible());
assertEquals("one row with visible root", 1, treeTable.getRowCount());
}
/**
* Issue #247-swingx: update probs with insert node.
* The insert under a collapsed node fires a dataChanged on the table
* which results in the usual total "memory" loss (f.i. selection)
*
* The tree model is after setup is (see the bug report as well):
* root
* childA
* childB
*
* In the view childA is collapsed:
* root
* childA
* @throws InvocationTargetException
* @throws InterruptedException
*
*/
@Test
public void testInsertUnderCollapsedNode() throws InterruptedException, InvocationTargetException {
final DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode();
final InsertTreeTableModel model = new InsertTreeTableModel(root);
DefaultMutableTreeTableNode childA = model.addChild(root);
final DefaultMutableTreeTableNode childB = model.addChild(childA);
final JXTreeTable treeTable = new JXTreeTable(model);
treeTable.setRootVisible(true);
// sanity...
assertEquals(2, treeTable.getRowCount());
final int selected = 1;
// select childA
treeTable.setRowSelectionInterval(selected, selected);
model.addChild(childB);
// need to invoke - the tableEvent is fired delayed as well
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
int selectedAfterInsert = treeTable.getSelectedRow();
assertEquals(selected, selectedAfterInsert);
}
});
}
/**
* Model used to show insert update issue.
*/
public static class InsertTreeTableModel extends DefaultTreeTableModel {
private boolean rootIsFolder;
public InsertTreeTableModel(TreeTableNode root) {
super(root);
}
public InsertTreeTableModel(TreeTableNode root, boolean rootIsFolder) {
super(root);
this.rootIsFolder = rootIsFolder;
}
@Override
public boolean isLeaf(Object node) {
if (rootIsFolder && (node == getRoot())) {
return false;
}
return super.isLeaf(node);
}
@Override
public int getColumnCount() {
return 2;
}
public DefaultMutableTreeTableNode addChild(DefaultMutableTreeTableNode parent) {
DefaultMutableTreeTableNode newNode = new DefaultMutableTreeTableNode("Child");
parent.add(newNode);
modelSupport.fireChildAdded(new TreePath(getPathToRoot(parent)),
parent.getIndex(newNode), newNode);
return newNode;
}
}
/**
* Issue #230-swingx:
* JXTreeTable should fire property change on setTreeTableModel.
*
*
*
*/
@Test
public void testTreeTableModelIsBoundProperty() {
JXTreeTable treeTable = new JXTreeTable();
PropertyChangeReport report = new PropertyChangeReport();
treeTable.addPropertyChangeListener(report);
treeTable.setTreeTableModel(simpleTreeTableModel);
int allPropertyCount = report.getEventCount();
int treeTMPropertyCount = report.getEventCount("treeTableModel");
assertEquals("treeTable must have fired exactly one event for property treeTableModel",
1, treeTMPropertyCount);
assertEquals("treeTable must have fired event for property treeTableModel only",
allPropertyCount, treeTMPropertyCount);
// sanity: must not fire when setting to same
report.clear();
treeTable.setTreeTableModel(simpleTreeTableModel);
assertEquals("treeTable must not have fired", 0, report.getEventCount());
}
/**
* Issue #54: hidden columns not removed on setModel.
* sanity test (make sure nothing evil introduced in treeTable as
* compared to table)
*/
@Test
public void testRemoveAllColumsAfterModelChanged() {
JXTreeTable table = new JXTreeTable(new FileSystemModel());
TableColumnExt columnX = table.getColumnExt(1);
columnX.setVisible(false);
int columnCount = table.getColumnCount(true);
assertEquals("total column count must be same as model", table.getModel().getColumnCount(), columnCount);
assertEquals("visible column count must one less as total", columnCount - 1, table.getColumnCount());
table.setTreeTableModel(new FileSystemModel());
assertEquals("visible columns must be same as total",
table.getColumnCount(), table.getColumnCount(true));
}
/**
* Issue #241: treeModelListeners not removed.
*
*/
@Test
public void testRemoveListeners() {
JXTreeTable treeTable = new JXTreeTable(treeTableModel);
treeTable.setTreeTableModel(new FileSystemModel());
assertEquals(0, ((FileSystemModel) treeTableModel).getTreeModelListeners().length);
}
/**
* Clarify contract of isHierarchical.
*/
@Test
public void testIsHierarchical() {
TreeTableModel model = new DefaultTreeTableModel();
//sanity
assertEquals(-1, model.getHierarchicalColumn());
JXTreeTable treeTable = new JXTreeTable(model);
assertEquals(model.getHierarchicalColumn(), treeTable.getHierarchicalColumn());
// either this or throw an exception for -1 index
// illegal view index anyway
try {
treeTable.isHierarchical(-1);
fail("expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
//success
}
}
@Test
public void testRowForPath() {
JXTreeTable treeTable = new JXTreeTable(simpleTreeTableModel);
// @todo - make sure we find an expandible row instead of hardcoding
int rowCount = treeTable.getRowCount();
int row = 2;
TreePath path = treeTable.getPathForRow(row);
assertEquals("original row must be retrieved", row, treeTable.getRowForPath(path));
treeTable.expandRow(row - 1);
// sanity assert
assertTrue("really expanded", treeTable.getRowCount() > rowCount);
TreePath expanded = treeTable.getPathForRow(row);
assertNotSame("path at original row must be different when expanded", path, expanded);
assertEquals("original row must be retrieved", row, treeTable.getRowForPath(expanded));
}
@Test
public void testPathForRowContract() {
JXTreeTable treeTable = new JXTreeTable(treeTableModel);
assertNull("row < 0 must return null path", treeTable.getPathForRow(-1));
assertNull("row >= getRowCount must return null path", treeTable.getPathForRow(treeTable.getRowCount()));
}
@Test
public void testTableRowAtNegativePoint() {
JXTable treeTable = new JXTable(1, 4);
int negativeYRowHeight = - treeTable.getRowHeight();
int negativeYRowHeightPlusOne = negativeYRowHeight + 1;
int negativeYMinimal = -1;
assertEquals("negative y location rowheight " + negativeYRowHeight + " must return row -1",
-1, treeTable.rowAtPoint(new Point(-1, negativeYRowHeight)));
assertEquals("negative y location " + negativeYRowHeightPlusOne +" must return row -1",
-1, treeTable.rowAtPoint(new Point(-1, negativeYRowHeightPlusOne)));
assertEquals("minimal negative y location must return row -1",
-1, treeTable.rowAtPoint(new Point(-1, negativeYMinimal)));
}
@Test
public void testPathForLocationContract() {
JXTreeTable treeTable = new JXTreeTable(treeTableModel);
// this is actually a JTable rowAtPoint bug: falsely calculates
// row == 0 if - 1 >= y > - getRowHeight()
//assertEquals("location outside must return null path", null, treeTable.getPathForLocation(-1, -(treeTable.getRowHeight() - 1)));
int negativeYRowHeight = - treeTable.getRowHeight();
int negativeYRowHeightPlusOne = negativeYRowHeight + 1;
int negativeYMinimal = -1;
assertEquals("negative y location rowheight " + negativeYRowHeight + " must return row -1",
-1, treeTable.rowAtPoint(new Point(-1, negativeYRowHeight)));
assertEquals("negative y location " + negativeYRowHeightPlusOne +" must return row -1",
-1, treeTable.rowAtPoint(new Point(-1, negativeYRowHeightPlusOne)));
assertEquals("minimal negative y location must return row -1",
-1, treeTable.rowAtPoint(new Point(-1, negativeYMinimal)));
}
/**
* Issue #151: renderer properties ignored after setting treeTableModel.
*
*/
@Test
public void testRendererProperties() {
JXTreeTable treeTable = new JXTreeTable(treeTableModel);
// storing negates of properties
boolean expandsSelected = !treeTable.getExpandsSelectedPaths();
boolean scrollsOnExpand = !treeTable.getScrollsOnExpand();
boolean showRootHandles = !treeTable.getShowsRootHandles();
boolean rootVisible = !treeTable.isRootVisible();
// setting negates properties
treeTable.setExpandsSelectedPaths(expandsSelected);
treeTable.setScrollsOnExpand(scrollsOnExpand);
treeTable.setShowsRootHandles(showRootHandles);
treeTable.setRootVisible(rootVisible);
// assert negates are set - sanity assert
assertEquals("expand selected", expandsSelected, treeTable
.getExpandsSelectedPaths());
assertEquals("scrolls expand", scrollsOnExpand, treeTable
.getScrollsOnExpand());
assertEquals("shows handles", showRootHandles, treeTable
.getShowsRootHandles());
assertEquals("root visible", rootVisible, treeTable.isRootVisible());
// setting a new model
treeTable.setTreeTableModel(new DefaultTreeTableModel());
// assert negates are set
assertEquals("expand selected", expandsSelected, treeTable
.getExpandsSelectedPaths());
assertEquals("scrolls expand", scrollsOnExpand, treeTable
.getScrollsOnExpand());
assertEquals("shows handles", showRootHandles, treeTable
.getShowsRootHandles());
assertEquals("root visible", rootVisible, treeTable.isRootVisible());
}
/**
* Issue #148: line style client property not respected by renderer.
*
*/
@Test
public void testLineStyle() {
JXTreeTable treeTable = new JXTreeTable(treeTableModel);
String propertyName = "JTree.lineStyle";
treeTable.putClientProperty(propertyName, "Horizontal");
JXTree renderer = (JXTree) treeTable.getCellRenderer(0, 0);
assertEquals(propertyName + " set on renderer", "Horizontal", renderer
.getClientProperty(propertyName));
}
/**
* sanity test: arbitrary client properties not passed to renderer.
*
*/
@Test
public void testArbitraryClientProperty() {
JXTreeTable treeTable = new JXTreeTable(treeTableModel);
String propertyName = "someproperty";
treeTable.putClientProperty(propertyName, "Horizontal");
JXTree renderer = (JXTree) treeTable.getCellRenderer(0, 0);
assertNull(propertyName + " not set on renderer", renderer
.getClientProperty(propertyName));
}
//copied from JTree and modified to use TTNs
protected static TreeTableModel getDefaultTreeTableModel() {
DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode(
"JXTreeTable");
DefaultMutableTreeTableNode parent;
parent = new DefaultMutableTreeTableNode("colors");
root.add(parent);
parent.add(new DefaultMutableTreeTableNode("blue"));
parent.add(new DefaultMutableTreeTableNode("violet"));
parent.add(new DefaultMutableTreeTableNode("red"));
parent.add(new DefaultMutableTreeTableNode("yellow"));
parent = new DefaultMutableTreeTableNode("sports");
root.add(parent);
parent.add(new DefaultMutableTreeTableNode("basketball"));
parent.add(new DefaultMutableTreeTableNode("soccer"));
parent.add(new DefaultMutableTreeTableNode("football"));
parent.add(new DefaultMutableTreeTableNode("hockey"));
parent = new DefaultMutableTreeTableNode("food");
root.add(parent);
parent.add(new DefaultMutableTreeTableNode("hot dogs"));
parent.add(new DefaultMutableTreeTableNode("pizza"));
parent.add(new DefaultMutableTreeTableNode("ravioli"));
parent.add(new DefaultMutableTreeTableNode("bananas"));
return new DefaultTreeTableModel(root);
}
/**
* Creates and returns a custom model from JXTree default model. The model
* is of type DefaultTreeModel, allowing for easy insert/remove.
*
* @return
*/
private TreeTableModel createCustomTreeTableModelFromDefault() {
JXTree tree = new JXTree();
DefaultTreeModel treeModel = (DefaultTreeModel) tree.getModel();
TreeTableModel customTreeTableModel = TreeTableUtils
.convertDefaultTreeModel(treeModel);
return customTreeTableModel;
}
/**
* @return
*/
private TreeTableModel createActionTreeModel() {
JXTable table = new JXTable(10, 10);
table.setHorizontalScrollEnabled(true);
return new ActionMapTreeTableModel(table);
}
// ------------------ init
@Override
@Before
public void setUp() throws Exception {
super.setUp();
simpleTreeTableModel = getDefaultTreeTableModel();
this.treeTableModel = new FileSystemModel();
}
}