/*
* $Id$
*
* Copyright 2006 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.renderer;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.DefaultListModel;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.ListModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import org.jdesktop.swingx.InteractiveTestCase;
import org.jdesktop.swingx.JXEditorPaneTest;
import org.jdesktop.swingx.JXFrame;
import org.jdesktop.swingx.JXHyperlink;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.JXTree;
import org.jdesktop.swingx.action.AbstractActionExt;
import org.jdesktop.swingx.decorator.AbstractHighlighter;
import org.jdesktop.swingx.decorator.ColorHighlighter;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.decorator.HighlightPredicate;
import org.jdesktop.swingx.decorator.Highlighter;
import org.jdesktop.swingx.hyperlink.LinkModel;
import org.jdesktop.swingx.test.ActionMapTreeTableModel;
import org.jdesktop.swingx.test.ComponentTreeTableModel;
import org.jdesktop.swingx.treetable.FileSystemModel;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Tests behaviour of SwingX <code>DefaultTreeRenderer</code>.
* Contains characterization to
* guarantee that it behaves similar to the standard.
*
* @author Jeanette Winzenburg
*/
@RunWith(JUnit4.class)
public class TreeRendererTest extends InteractiveTestCase {
@SuppressWarnings("all")
private static final Logger LOG = Logger.getLogger(TreeRendererTest.class
.getName());
private DefaultTreeCellRenderer coreTreeRenderer;
private DefaultTreeRenderer xTreeRenderer;
@Override
protected void setUp() throws Exception {
// setSystemLF(true);
// LOG.info("LF: " + UIManager.getLookAndFeel());
// LOG.info("Theme: " + ((MetalLookAndFeel) UIManager.getLookAndFeel()).getCurrentTheme());
// UIManager.put("Tree.drawsFocusBorderAroundIcon", Boolean.TRUE);
coreTreeRenderer = new DefaultTreeCellRenderer();
xTreeRenderer = new DefaultTreeRenderer();
}
public static void main(String[] args) {
TreeRendererTest test = new TreeRendererTest();
try {
test.runInteractiveTests();
// test.runInteractiveTests(".*Wrapper.*");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Issue #873-swingx: WrappingIconPanel - delegate font unchanged
*/
@Test
public void testDelegateFont() {
JXTree tree = new JXTree();
tree.setCellRenderer(new DefaultTreeRenderer());
final Font bold = tree.getFont().deriveFont(Font.BOLD, 20f);
Highlighter hl = new AbstractHighlighter() {
@Override
protected Component doHighlight(Component component,
ComponentAdapter adapter) {
component.setFont(bold);
return component;
}
};
tree.addHighlighter(hl);
WrappingIconPanel component = (WrappingIconPanel) tree.getCellRenderer()
.getTreeCellRendererComponent(tree, "something", false, false, false, 0, false);
assertEquals(bold, component.getFont());
assertEquals(bold, component.delegate.getFont());
}
/**
* Wrapping provider: hyperlink foreground must be preserved.
*
*/
@Test
public void testTreeHyperlinkForeground() {
JXTree tree = new JXTree(createTreeModelWithLinks(20));
ComponentProvider<JXHyperlink> context = new HyperlinkProvider();
Color foreground = context.rendererComponent.getForeground();
tree.setCellRenderer(new DefaultTreeRenderer(new WrappingProvider(context)));
tree.getCellRenderer().getTreeCellRendererComponent(tree, "something", false, false, false, -1, false);
assertEquals("hyperlink color must be preserved", foreground, context.rendererComponent.getForeground());
}
/**
* related to Issue #22-swingx: tree background highlighting broken.
* test if background color is moved down to delegate component.
*
*/
@Test
public void testDelegateBackground() {
WrappingProvider provider = new WrappingProvider();
DefaultTreeRenderer renderer = new DefaultTreeRenderer(provider);
Component comp = renderer.getTreeCellRendererComponent(null, "dummy", false, false, false, -1, false);
assertTrue(comp instanceof WrappingIconPanel);
comp.setBackground(Color.RED);
// sanity
assertTrue(provider.getRendererComponent(null).isBackgroundSet());
assertEquals(Color.RED, provider.getRendererComponent(null).getBackground());
// sanity
assertTrue(provider.wrappee.getRendererComponent(null).isBackgroundSet());
assertEquals(Color.RED, provider.wrappee.getRendererComponent(null).getBackground());
}
/**
* related to Issue #22-swingx: tree background highlighting broken.
* test if foreground color is moved down to delegate component.
*
*/
@Test
public void testDelegateForeground() {
WrappingProvider provider = new WrappingProvider();
DefaultTreeRenderer renderer = new DefaultTreeRenderer(provider);
Component comp = renderer.getTreeCellRendererComponent(null, "dummy", false, false, false, -1, false);
assertTrue(comp instanceof WrappingIconPanel);
comp.setForeground(Color.RED);
// sanity
assertTrue(provider.getRendererComponent(null).isForegroundSet());
assertEquals(Color.RED, provider.getRendererComponent(null).getForeground());
// sanity
assertTrue(provider.wrappee.getRendererComponent(null).isForegroundSet());
assertEquals(Color.RED, provider.wrappee.getRendererComponent(null).getForeground());
}
/**
* characterize opaqueness of rendering components.
* Hmm... tree-magic is different
*/
@Test
public void testTreeOpaqueRenderer() {
// sanity
assertFalse(new JLabel().isOpaque());
// assertTrue(coreTreeRenderer.isOpaque());
// assertTrue(xListRenderer.getRendererComponent().isOpaque());
}
/**
* base existence/type tests while adding DefaultTableCellRendererExt.
*
*/
@Test
public void testTreeRendererExt() {
DefaultTreeRenderer renderer = new DefaultTreeRenderer();
assertTrue(renderer instanceof TreeCellRenderer);
assertTrue(renderer instanceof Serializable);
}
//---------------------- interactive methods
/**
* Example for using no node icons in the tree.
*
*/
public void interactiveCustomIconPerNodeType() {
JTree tree = new JTree();
tree.setCellRenderer(new DefaultTreeRenderer(IconValues.NONE));
final JXFrame frame = wrapWithScrollingInFrame(tree, "tree - no icons");
frame.setVisible(true);
}
/**
* Sanity check: icons updated on LF change
*
*/
public void interactiveDefaultIconsToggleLF() {
JTree tree = new JTree();
tree.setCellRenderer(new DefaultTreeRenderer());
final JXFrame frame = wrapInFrame(tree, "tree - toggle lf", true);
frame.setSize(400, 400);
frame.setVisible(true);
}
/**
* Example for using arbitrary wrappee controllers. Here: a
* checkbox representing entries in ActionMap.
*
*/
public void interactiveTreeButtonFormatting() {
TreeModel model = createActionTreeModel();
JTree tree = new JTree(model);
CheckBoxProvider wrappee = createButtonProvider();
tree.setCellRenderer(new DefaultTreeRenderer(new WrappingProvider(wrappee)));
JList list = new JList(createActionListModel());
list.setCellRenderer(new DefaultListRenderer(wrappee));
final JXFrame frame = wrapWithScrollingInFrame(tree, list, "custom renderer - same in tree and list");
frame.setVisible(true);
}
/**
* Custom format on JTree/JXTree (latter with highlighter).
*
*/
public void interactiveXTreeLabelFormattingHighlighter() {
TreeModel model = createComponentHierarchyModel();
JTree tree = new JTree(model);
StringValue converter = new StringValue() {
public String getString(Object value) {
if (value instanceof Component) {
return "Name: " + ((Component) value).getName();
}
return StringValues.TO_STRING.getString(value);
}
};
tree.setCellRenderer(new DefaultTreeRenderer(converter));
JXTree xtree = new JXTree(model);
xtree.setHighlighters(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, Color.RED,
Color.YELLOW));
xtree.setRolloverEnabled(true);
// share renderer
xtree.setCellRenderer(tree.getCellRenderer());
final JXFrame frame = wrapWithScrollingInFrame(tree, xtree, "custom format - tree vs. xtree (+Rollover renderer)");
frame.setVisible(true);
}
/**
* Custom tree colors in JTree. Compare core default renderer with Swingx
* default renderer.
*
*/
public void interactiveCompareTreeExtTreeColors() {
JTree xtree = new JTree();
Color background = Color.MAGENTA;
Color foreground = Color.YELLOW;
xtree.setBackground(background);
xtree.setForeground(foreground);
DefaultTreeCellRenderer coreTreeCellRenderer = new DefaultTreeCellRenderer();
// to get a uniform color on both tree and node
// the core default renderer needs to be configured
coreTreeCellRenderer.setBackgroundNonSelectionColor(background);
coreTreeCellRenderer.setTextNonSelectionColor(foreground);
xtree.setCellRenderer(coreTreeCellRenderer);
JTree tree = new JTree();
tree.setBackground(background);
tree.setForeground(foreground);
// swingx renderer uses tree colors
tree.setCellRenderer(xTreeRenderer);
final JXFrame frame = wrapWithScrollingInFrame(xtree, tree,
"custom tree colors - core vs. ext renderer");
frame.setVisible(true);
}
/**
* Component orientation in JTree. Compare core default renderer with Swingx
* default renderer.
*
*/
public void interactiveCompareTreeRToL() {
JTree xtree = new JTree();
xtree.setCellRenderer(coreTreeRenderer);
JTree tree = new JTree();
tree.setCellRenderer(xTreeRenderer);
final JXFrame frame = wrapWithScrollingInFrame(xtree, tree,
"orientation - core vs. ext renderer");
Action toggleComponentOrientation = new AbstractAction(
"toggle orientation") {
public void actionPerformed(ActionEvent e) {
ComponentOrientation current = frame.getComponentOrientation();
if (current == ComponentOrientation.LEFT_TO_RIGHT) {
frame.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
} else {
frame.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
}
}
};
addAction(frame, toggleComponentOrientation);
frame.setVisible(true);
}
/**
* Format custom model.
*
* PENDING: editor uses default toString and looses icons -
* because the renderer is not a label.
*/
public void interactiveDefaultWrapper() {
JTree xtree = new JTree(createComponentHierarchyModel());
StringValue componentFormat = new StringValue() {
public String getString(Object value) {
if (value instanceof Component) {
return ((Component) value).getName();
}
return StringValues.TO_STRING.getString(value);
}};
xtree.setCellRenderer(new DefaultTreeRenderer(componentFormat));
xtree.setEditable(true);
JTree tree = new JTree(new FileSystemModel());
StringValue format = 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(format));
final JXFrame frame = wrapWithScrollingInFrame(xtree, tree, "wrapper and different models");
frame.setVisible(true);
}
//-------------------------- factory methods
private TreeModel createTreeModelWithLinks(int count) {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Links");
for (int i = 0; i < count; i++) {
try {
LinkModel link = new LinkModel("a link text " + i, null, new URL("http://some.dummy.url" + i));
if (i == 1) {
URL url = JXEditorPaneTest.class.getResource("resources/test.html");
link = new LinkModel("a link text " + i, null, url);
}
root.add(new DefaultMutableTreeNode(link));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return new DefaultTreeModel(root);
}
/**
*
* @return a button controller specialized on ActionEntryNode.
*/
private CheckBoxProvider createButtonProvider() {
StringValue sv = new StringValue() {
public String getString(Object value) {
if (value instanceof Action) {
return (String) ((Action) value).getValue(Action.NAME);
}
return "";
}
};
BooleanValue bv = new BooleanValue() {
public boolean getBoolean(Object value) {
if (value instanceof AbstractActionExt) {
return ((AbstractActionExt) value).isSelected();
}
return false;
}
};
CheckBoxProvider wrapper = new CheckBoxProvider(new MappedValue(sv, null, bv), JLabel.LEADING);
return wrapper;
}
/**
* @return
*/
private ListModel createActionListModel() {
JXTable table = new JXTable(10, 10);
table.setHorizontalScrollEnabled(true);
ActionMap map = table.getActionMap();
Object[] keys = map.keys();
DefaultListModel model = new DefaultListModel();
for (Object object : keys) {
model.addElement(map.get(object));
}
return model;
}
/**
* @return
*/
private TreeModel createActionTreeModel() {
JXTable table = new JXTable(10, 10);
table.setHorizontalScrollEnabled(true);
return new ActionMapTreeTableModel(table);
}
/**
* @return
*/
private TreeModel createComponentHierarchyModel() {
JXFrame frame = new JXFrame("dummy");
frame.add(new JScrollPane(new JXTree()));
return new ComponentTreeTableModel(frame);
}
}