/*
* $Id$
*
* Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jdesktop.swingx.demos.treetable;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.table.TableModel;
import javax.swing.tree.TreePath;
import org.jdesktop.application.Action;
import org.jdesktop.swingx.JXPanel;
import org.jdesktop.swingx.JXTreeTable;
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.demos.tree.TreeDemoIconValues.LazyLoadingIconValue;
import org.jdesktop.swingx.demos.tree.XTreeDemo;
import org.jdesktop.swingx.event.AbstractInputEventDispatcher;
import org.jdesktop.swingx.renderer.DefaultTableRenderer;
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.table.ColumnFactory;
import org.jdesktop.swingx.table.TableColumnExt;
import org.jdesktop.swingx.treetable.TreeTableModel;
import org.jdesktop.swingx.util.PaintUtils;
import org.jdesktop.swingxset.JXDemoFrame;
import org.jdesktop.swingxset.util.ComponentModels;
import org.jdesktop.swingxset.util.DemoUtils;
import com.sun.swingset3.DemoProperties;
/**
* A demo for the {@code JXTreeTable}.
*
* @author Karl George Schaefer
*/
@DemoProperties(
value = "JXTreeTable Demo",
category = "Data",
description = "Demonstrates JXTreeTable, a tree-based, grid component.",
sourceFiles = {
"org/jdesktop/swingx/demos/treetable/TreeTableDemo.java",
"org/jdesktop/swingx/demos/tree/TreeDemoIconValues.java",
"org/jdesktop/swingxset/JXDemoFrame.java",
"org/jdesktop/swingx/demos/treetable/resources/TreeTableDemo.properties"
}
)
@SuppressWarnings("serial")
public class TreeTableDemo extends JPanel {
@SuppressWarnings("unused")
private static final Logger LOG = Logger.getLogger(TreeTableDemo.class
.getName());
private JXTreeTable treeTable;
private boolean initialized;
private JButton refreshButton;
private JButton expandButton;
private JButton collapseButton;
private AbstractInputEventDispatcher inputEventDispatcher;
private AbstractHighlighter mouseOverHighlighter;
public TreeTableDemo() {
super(new BorderLayout());
initComponents();
configureComponents();
DemoUtils.injectResources(this);
bind();
}
//---------------- public api for Binding/Action control
@Action
public void refreshModel() {
treeTable.setTreeTableModel(createTreeModel());
expandAll();
treeTable.packColumn(treeTable.getHierarchicalColumn(), -1);
}
// <snip> JXTreeTable convenience api
// expand/collapse all nodes
@Action
public void expandAll() {
treeTable.expandAll();
}
@Action
public void collapseAll() {
treeTable.collapseAll();
}
// </snip>
//------------------- config/bind
private void bind() {
// <snip>JXTreeTable column customization
// configure and install a custom columnFactory, arguably data related ;-)
ColumnFactory factory = new ColumnFactory() {
String[] columnNameKeys = { "componentType", "componentName", "componentLocation", "componentSize" };
@Override
public void configureTableColumn(TableModel model,
TableColumnExt columnExt) {
super.configureTableColumn(model, columnExt);
if (columnExt.getModelIndex() < columnNameKeys.length) {
columnExt.setTitle(DemoUtils.getResourceString(TreeTableDemo.class,
columnNameKeys[columnExt.getModelIndex()]));
}
}
};
treeTable.setColumnFactory(factory);
// </snip>
}
private void configureComponents() {
// <snip> JXTreeTable rendering
// StringValue provides node text, used in hierarchical column
StringValue sv = new StringValue() {
@Override
public String getString(Object value) {
if (value instanceof Component) {
Component component = (Component) value;
String simpleName = component.getClass().getSimpleName();
if (simpleName.length() == 0){
// anonymous class
simpleName = component.getClass().getSuperclass().getSimpleName();
}
return simpleName;
}
return StringValues.TO_STRING.getString(value);
}
};
// </snip>
// StringValue for lazy icon loading
StringValue keyValue = new StringValue() {
@Override
public String getString(Object value) {
if (value == null) return "";
String simpleClassName = value.getClass().getSimpleName();
if (simpleClassName.length() == 0){
// anonymous class
simpleClassName = value.getClass().getSuperclass().getSimpleName();
}
return simpleClassName + ".png";
}
};
// <snip> JXTreeTable rendering
// IconValue provides node icon (same as in XTreeDemo)
IconValue iv = new LazyLoadingIconValue(XTreeDemo.class, keyValue, "fallback.png");
// create and set a tree renderer using the custom Icon-/StringValue
treeTable.setTreeCellRenderer(new DefaultTreeRenderer(iv, sv));
// string representation for use of Dimension/Point class
StringValue locSize = new StringValue() {
@Override
public String getString(Object value) {
int x;
int y;
if (value instanceof Dimension) {
x = ((Dimension) value).width;
y = ((Dimension) value).height;
} else if (value instanceof Point) {
x = ((Point) value).x;
y = ((Point) value).y;
} else {
return StringValues.TO_STRING.getString(value);
}
return "(" + x + ", " + y + ")";
}
};
treeTable.setDefaultRenderer(Point.class, new DefaultTableRenderer(locSize, JLabel.CENTER));
treeTable.setDefaultRenderer(Dimension.class, treeTable.getDefaultRenderer(Point.class));
// </snip>
mouseOverHighlighter = new ColorHighlighter(HighlightPredicate.NEVER,
PaintUtils.setSaturation(Color.MAGENTA, 0.3f), null);
treeTable.addHighlighter(mouseOverHighlighter);
treeTable.setColumnControlVisible(true);
refreshButton.setAction(DemoUtils.getAction(this, "refreshModel"));
expandButton.setAction(DemoUtils.getAction(this, "expandAll"));
collapseButton.setAction(DemoUtils.getAction(this, "collapseAll"));
// Demo specific config
DemoUtils.setSnippet("JXTreeTable convenience api", expandButton, collapseButton);
DemoUtils.setSnippet("JXTreeTable rendering", treeTable);
}
// <snip> Input-/FocusEvent notification
// update Highlighter's predicate to highlight the tree row
// which contains the component under the current mouse position
protected void updateHighlighter(Component component) {
mouseOverHighlighter.setHighlightPredicate(HighlightPredicate.NEVER);
if (component != null) {
List<Component> pathList = new ArrayList<Component>();
while (component != null) {
pathList.add(0, component);
component = component.getParent();
}
final TreePath treePath = new TreePath(pathList.toArray());
treeTable.scrollPathToVisible(treePath);
HighlightPredicate predicate = new HighlightPredicate() {
@Override
public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
return adapter.row == treeTable.getRowForPath(treePath);
}
};
mouseOverHighlighter.setHighlightPredicate(predicate);
// </snip>
}
}
/**
* Overridden to create and install the component tree model.
*/
@Override
public void addNotify() {
super.addNotify();
if (!initialized) {
initialized = true;
refreshModel();
}
installInputEventListener();
}
@Override
public void removeNotify() {
uninstallInputEventListener();
super.removeNotify();
}
// <snip> Input-/FocusEvent notification
// install custom dispatcher with demo frame
private void installInputEventListener() {
if (!(SwingUtilities.getWindowAncestor(this) instanceof JXDemoFrame)) return;
JXDemoFrame window = (JXDemoFrame) SwingUtilities.getWindowAncestor(this);
if (inputEventDispatcher == null) {
inputEventDispatcher = new AbstractInputEventDispatcher() {
// updates Highlighter for mouseEntered/mouseExited
// of all components in the frame's container hierarchy
@Override
protected void processMouseEvent(MouseEvent e) {
if (MouseEvent.MOUSE_ENTERED == e.getID()) {
updateHighlighter(e.getComponent());
} else if (MouseEvent.MOUSE_EXITED == e.getID()) {
updateHighlighter(null);
}
}
};
}
window.setInputEventDispatcher(inputEventDispatcher);
// </snip>
}
private void uninstallInputEventListener() {
if (!(SwingUtilities.getWindowAncestor(this) instanceof JXDemoFrame)) return;
JXDemoFrame window = (JXDemoFrame) SwingUtilities.getWindowAncestor(this);
window.setInputEventDispatcher(null);
updateHighlighter(null);
}
private TreeTableModel createTreeModel() {
Window window = SwingUtilities.getWindowAncestor(this);
return ComponentModels.getTreeTableModel(window != null ? window : this);
}
//----------------- init
private void initComponents() {
treeTable = new JXTreeTable();
treeTable.setName("componentTreeTable");
add(new JScrollPane(treeTable));
JComponent control = new JXPanel();
refreshButton = new JButton();
refreshButton.setName("refreshButton");
expandButton = new JButton();
expandButton.setName("expandTreeTableButton");
collapseButton = new JButton();
collapseButton.setName("collapseTreeTableButton");
// control.add(refreshButton);
control.add(expandButton);
control.add(collapseButton);
add(control, BorderLayout.SOUTH);
}
/**
* main method allows us to run as a standalone demo.
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame(TreeTableDemo.class.getAnnotation(DemoProperties.class).value());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new TreeTableDemo());
frame.setPreferredSize(new Dimension(800, 600));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}