/* * $Id$ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. */ package org.jdesktop.swingx; import java.awt.Component; import java.awt.Font; import java.awt.event.ActionEvent; import java.io.File; import java.util.Locale; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.AbstractListModel; import javax.swing.Action; import javax.swing.DefaultComboBoxModel; import javax.swing.Icon; import javax.swing.JTree; import javax.swing.ListModel; import javax.swing.plaf.UIResource; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeCellRenderer; import org.jdesktop.swingx.decorator.AbstractHighlighter; import org.jdesktop.swingx.decorator.ComponentAdapter; import org.jdesktop.swingx.decorator.HighlightPredicate; import org.jdesktop.swingx.decorator.Highlighter; import org.jdesktop.swingx.renderer.CellContext; import org.jdesktop.swingx.renderer.CheckBoxProvider; import org.jdesktop.swingx.renderer.ComponentProvider; import org.jdesktop.swingx.renderer.DefaultListRenderer; import org.jdesktop.swingx.renderer.DefaultTreeRenderer; import org.jdesktop.swingx.renderer.IconValue; import org.jdesktop.swingx.renderer.StringValue; import org.jdesktop.swingx.renderer.StringValues; import org.jdesktop.swingx.renderer.WrappingIconPanel; import org.jdesktop.swingx.renderer.WrappingProvider; import org.jdesktop.swingx.test.XTestUtils; import org.jdesktop.swingx.tree.DefaultXTreeCellEditor; import org.jdesktop.swingx.tree.DefaultXTreeCellRenderer; import org.junit.Test; /** * Test to expose known issues of <code>JXTree</code>. * <p> * * Ideally, there would be at least one failing test method per open issue in * the issue tracker. Plus additional failing test methods for not fully * specified or not yet decided upon features/behaviour. * <p> * * If an issue is fixed and the corresponding methods are passing, they * should be moved over to the XXTest. * * @author Jeanette Winzenburg */ public class JXTreeIssues extends JXTreeUnitTest { @SuppressWarnings("unused") private static final Logger LOG = Logger.getLogger(JXTreeIssues.class .getName()); public static void main(String[] args) { setSystemLF(true); JXTreeIssues test = new JXTreeIssues(); try { // test.runInteractiveTests(); test.runInteractiveTests("interactive.*UpdateUI.*"); // test.runInteractiveTests("interactive.*Icons.*"); } catch (Exception e) { System.err.println("exception when executing interactive tests:"); e.printStackTrace(); } } /** * Issue #1061-swingx: renderer/editor inconsistent on startup. * Note: this test will fail once we use an enhanced cellEditor (which can cope with * SwingX default renderers). */ @Test public void testRendererUsedInEditorAfterSet() { TestTree tree = new TestTree(); assertTrue("sanity: editor is of type DefaultXTreeCellEditor", tree.getCellEditor() instanceof DefaultXTreeCellEditor); TreeCellRenderer renderer = new DefaultTreeCellRenderer(); tree.setCellRenderer(renderer); assertSame("sanity: new renderer is wrapped", renderer, tree.getWrappedCellRenderer()); assertSame("editor must be updated with new renderer", renderer, ((DefaultXTreeCellEditor) tree.getCellEditor()).getRenderer()); } /** * Issue #601-swingx: allow LAF to hook in LAF provided renderers. * * Unexpected: plain ol' tree doesn't install UIResource? */ @Test public void testLAFRendererTree() { JTree tree = new JTree(); assertNotNull("default renderer installed", tree.getCellRenderer()); assertTrue("expected UIResource, but was: " + tree.getCellRenderer().getClass(), tree.getCellRenderer() instanceof UIResource); } /** * Issue #601-swingx: allow LAF to hook in LAF provided renderers. * * Unexpected: plain ol' tree doesn't install UIResource? */ @Test public void testLAFRendererXTree() { JXTree tree = new JXTree(); assertNotNull("default renderer installed", tree.getCellRenderer()); assertTrue("expected UIResource, but was: " + tree.getCellRenderer().getClass(), tree.getCellRenderer() instanceof UIResource); } private DefaultTreeRenderer sharedRenderer; ComponentProvider<?> provider; @Override protected void setUp() throws Exception { super.setUp(); provider = new CheckBoxProvider(StringValues.TO_STRING); sharedRenderer = new DefaultTreeRenderer(new WrappingProvider(provider)); } /** * Issue ??-swingx: JXTree must update renderer. * It does ... the renderer comp is never removed from the tree's * rendererPane? Not true - removed at end of paint. * Why is this renderer replaced on LAF-toggle? */ public void interactiveUpdateUIRendererProvider() { JXTree tree = new JXTree(); tree.setCellRenderer(sharedRenderer); showWithScrollingInFrame(tree, "updateUI must update renderer??"); } /** * share in list - okay. */ public void interactiveUpdateUISharedProvider() { JXList list = new JXList(new DefaultComboBoxModel(new String[] {"one", "two", "three"})); list.setCellRenderer(new DefaultListRenderer(provider)); showWithScrollingInFrame(list, "list with shared provider"); } /** * Issue ??-swingx: JXTree must update renderer * share in other tree - okay */ public void interactiveUpdateUIRendererOther() { JXTree tree = new JXTree(); tree.setCellRenderer(sharedRenderer); showWithScrollingInFrame(tree, "updateUI must update renderer"); } /** * Issue #1060-swingx: JXTree must update renderer * * tree renderer not updated if set on the tree (as opposed to using the * default set by the ui-delegate) */ public void interactiveUpdateUICoreTreeDefaultRenderer() { JTree tree = new JTree(); tree.getModel().valueForPathChanged(tree.getPathForRow(0), "core with ui provided renderer"); tree.setEditable(true); JTree treeSetRenderer = new JTree(); treeSetRenderer.getModel().valueForPathChanged(treeSetRenderer.getPathForRow(0), "core with renderer set"); treeSetRenderer.setCellRenderer(new DefaultTreeCellRenderer()); treeSetRenderer.setEditable(true); JXFrame frame = wrapWithScrollingInFrame(tree, treeSetRenderer, "JTree/core renderer: updateUI must update renderer"); addComponentOrientationToggle(frame); show(frame); } /** * Issue #1060-swingx: JXTree must update renderer * * tree renderer not updated if set on the tree (as opposed to using the * default set by the ui-delegate) */ public void interactiveUpdateUIXTreeDefaultRenderer() { JXTree tree = new JXTree(); tree.getModel().valueForPathChanged(tree.getPathForRow(0), "x with ui provided renderer"); tree.setEditable(true); JXTree treeSetRenderer = new JXTree(); treeSetRenderer.getModel().valueForPathChanged(treeSetRenderer.getPathForRow(0), "x with renderer set"); treeSetRenderer.setCellRenderer(new DefaultXTreeCellRenderer()); treeSetRenderer.setEditable(true); JXFrame frame = wrapWithScrollingInFrame(tree, treeSetRenderer, "JXTree/core renderer: updateUI must update renderer"); addComponentOrientationToggle(frame); show(frame); } /** * Issue #1060-swingx: JXTree must update renderer * * tree renderer not updated if set on the tree (as opposed to using the * default set by the ui-delegate) */ public void interactiveUpdateUIXTreeXRenderer() { JXTree treeSetRenderer = new JXTree(); treeSetRenderer.getModel().valueForPathChanged(treeSetRenderer.getPathForRow(0), "x with renderer set"); treeSetRenderer.setCellRenderer(new DefaultTreeRenderer()); treeSetRenderer.setEditable(true); JXFrame frame = wrapWithScrollingInFrame(treeSetRenderer, "JXTree/x renderer: updateUI must update renderer/editor"); addComponentOrientationToggle(frame); show(frame); } /** * Size effecting decoration vs. initial config (in provider). * * Decoration: use highlighter * - works correctly only with largeModel (due to caching issues) * * Config in Provider (usually not recommended): * - override getRendererComponent, width always correct, height only * if enabled via setRowHeight(0) * */ public void interactiveBold() { JXTree tree = new JXTree(); tree.setCellRenderer(new DefaultTreeRenderer()); // tree.setRowHeight(0); tree.setLargeModel(true); final Font bold = tree.getFont().deriveFont(Font.BOLD, 20f); Highlighter hl = new AbstractHighlighter(HighlightPredicate.IS_LEAF) { @Override protected Component doHighlight(Component component, ComponentAdapter adapter) { component.setFont(bold); return component; } }; tree.addHighlighter(hl); JXTree treeP = new JXTree(); treeP.setRowHeight(0); WrappingProvider provider = new WrappingProvider() { @Override public WrappingIconPanel getRendererComponent(CellContext context) { super.getRendererComponent(context); if (context.isLeaf()) { rendererComponent.setFont(bold); } return rendererComponent; } }; treeP.setCellRenderer(new DefaultTreeRenderer(provider)); showWithScrollingInFrame(tree, treeP, "bold font: decorate vs. config"); } /** * Size effecting decoration vs. initial config (in provider). * * For comparison: JXList * * Decoration: use highlighter * - works correctly * * Config in Provider (usually not recommended): * - override getRendererComponent, works correctly * */ public void interactiveBoldList() { final Locale[] locales = Locale.getAvailableLocales(); ListModel model = new AbstractListModel() { public Object getElementAt(int index) { return locales[index]; } public int getSize() { return locales.length; } }; JXList tree = new JXList(model); tree.setCellRenderer(new DefaultListRenderer()); final Font bold = tree.getFont().deriveFont(Font.BOLD, 20f); Highlighter hl = new AbstractHighlighter(HighlightPredicate.EVEN) { @Override protected Component doHighlight(Component component, ComponentAdapter adapter) { component.setFont(bold); return component; } }; tree.addHighlighter(hl); JXList treeP = new JXList(model); WrappingProvider provider = new WrappingProvider() { @Override public WrappingIconPanel getRendererComponent(CellContext context) { super.getRendererComponent(context); if (context.getRow() % 2 == 0) { rendererComponent.setFont(bold); } return rendererComponent; } }; treeP.setCellRenderer(new DefaultListRenderer(provider)); showWithScrollingInFrame(tree, treeP, "bold font: decorate vs. config"); } /** * Issue #242: CCE when setting icons. Not reproducible? * Another issue: icon setting does not repaint (with core default renderer) * Does not work at all with SwingX renderer (not surprisingly, the * delegating renderer in JXTree looks for a core default to wrap). * Think: tree/table should trigger repaint? */ public void interactiveTreeIcons() { final JXTree tree = new JXTree(treeTableModel); final Icon downIcon = XTestUtils.loadDefaultIcon("wellbottom.gif"); final Icon upIcon = XTestUtils.loadDefaultIcon("welltop.gif"); Action toggleClosedIcon = new AbstractAction("Toggle closed icon") { boolean down; public void actionPerformed(ActionEvent e) { if (down) { tree.setClosedIcon(downIcon); } else { tree.setClosedIcon(upIcon); } down = !down; // need to force - but shouldn't that be done in the // tree/table itself? and shouldn't the tree fire a // property change? tree.repaint(); } }; tree.setRowHeight(22); JXFrame frame = wrapWithScrollingInFrame(tree, "Toggle Tree icons "); addAction(frame, toggleClosedIcon); frame.setVisible(true); } /** * use WrappingProvider: custom icons */ public void interactiveProviderIcons() { final JXTree tree = new JXTree(treeTableModel); final Icon downIcon = XTestUtils.loadDefaultIcon("wellbottom.gif"); final Icon upIcon = XTestUtils.loadDefaultIcon("welltop.gif"); final StringValue sv = StringValues.FILE_NAME; IconValue iv = new IconValue() { public Icon getIcon(Object value) { if (sv.getString(value).startsWith("A")) { return downIcon; } else if (sv.getString(value).startsWith("D")) { return upIcon; } return null; } }; tree.setCellRenderer(new DefaultTreeRenderer(iv, sv)); tree.setRowHeight(22); JXFrame frame = wrapWithScrollingInFrame(tree, "IconValue on WrappingProvider"); // addAction(frame, toggleClosedIcon); frame.setVisible(true); } /** * use WrappingProvider: default icons */ public void interactiveProviderStringValue() { final JXTree tree = new JXTree(treeTableModel); final StringValue sv = new StringValue() { public String getString(Object value) { if (value instanceof File) { return ((File) value).getName(); } return StringValues.TO_STRING.getString(value); } }; tree.setCellRenderer(new DefaultTreeRenderer(sv)); tree.setRowHeight(22); JXFrame frame = wrapWithScrollingInFrame(tree, "Custom StringValue on WrappingProvider, default icons"); // addAction(frame, toggleClosedIcon); frame.setVisible(true); } public void testDummy() { // do nothing - it's here let the test pass } }