/*
* Created on 06.12.2008
*
*/
package org.jdesktop.swingx.demos.highlighterext;
import static org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import org.jdesktop.application.Action;
import org.jdesktop.application.Application;
import org.jdesktop.beans.AbstractBean;
import org.jdesktop.beansbinding.BeanProperty;
import org.jdesktop.beansbinding.BindingGroup;
import org.jdesktop.beansbinding.Bindings;
import org.jdesktop.swingx.JXList;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.JXTree;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.decorator.HighlightPredicate;
import org.jdesktop.swingx.demos.search.Contributor;
import org.jdesktop.swingx.demos.search.Contributors;
import org.jdesktop.swingx.hyperlink.AbstractHyperlinkAction;
import org.jdesktop.swingx.hyperlink.HyperlinkAction;
import org.jdesktop.swingx.painter.MattePainter;
import org.jdesktop.swingx.renderer.DefaultListRenderer;
import org.jdesktop.swingx.renderer.DefaultTableRenderer;
import org.jdesktop.swingx.renderer.DefaultTreeRenderer;
import org.jdesktop.swingx.renderer.HyperlinkProvider;
import org.jdesktop.swingx.renderer.StringValue;
import org.jdesktop.swingx.renderer.StringValues;
import org.jdesktop.swingx.treetable.TreeTableModelAdapter;
import org.jdesktop.swingx.util.PaintUtils;
import org.jdesktop.swingxset.util.DemoUtils;
import org.jdesktop.swingxset.util.RelativePainterHighlighter;
import org.jdesktop.swingxset.util.RelativePainterHighlighter.NumberRelativizer;
import org.pushingpixels.trident.Timeline;
import org.pushingpixels.trident.ease.Spline;
import com.sun.swingset3.DemoProperties;
@DemoProperties(
value = "Highlighter (extended)",
category = "Functionality",
description = "Demonstrates value based highlighting.",
sourceFiles = {
"org/jdesktop/swingx/demos/highlighterext/HighlighterExtDemo.java",
"org/jdesktop/swingxset/util/RelativePainterHighlighter.java"
}
)
public class HighlighterExtDemo extends JPanel {
@SuppressWarnings("unused")
private static final Logger LOG = Logger.getLogger(HighlighterExtDemo.class
.getName());
private Contributors contributors;
private JXTreeTable treeTable;
private JXTree tree;
private JXList list;
private JXTable table;
private JCheckBox extendedMarkerBox;
private JButton raceButton;
private String[] keys = {"name", "date", "merits", "email"};
private Map<String, StringValue> stringValues;
private int meritColumn = 2;
private HighlighterControl highlighterControl;
private JButton fadeInButton;
public HighlighterExtDemo() {
super(new BorderLayout());
initComponents();
Application.getInstance().getContext().getResourceMap(getClass()).injectComponents(this);
bind();
// simple setup of per-column renderers, so can do only after binding
installRenderers();
}
//----------------------- bind
/**
*
*/
private void bind() {
// set the models
contributors = new Contributors();
table.setModel(contributors.getTableModel());
list.setModel(contributors.getListModel());
tree.setModel(new DefaultTreeModel(contributors.getRootNode()));
treeTable.setTreeTableModel(new TreeTableModelAdapter(
tree.getModel(), contributors.getContributorNodeModel()));
// init highlighter control
highlighterControl = new HighlighterControl();
raceButton.setAction(getAction("race"));
fadeInButton.setAction(getAction("fadeIn"));
}
@Action
public void race() {
highlighterControl.race();
}
@Action
public void fadeIn() {
highlighterControl.fadeIn();
}
private javax.swing.Action getAction(String string) {
return Application.getInstance().getContext().getActionMap(this).get(string);
}
// <snip> Relativizer
// implement custom Relativizer class
public static class MeritRelativizer extends NumberRelativizer {
public MeritRelativizer(int column, boolean spreadColumns,
Number max, Number current) {
super(column, spreadColumns, max, current);
}
// custom mapping of content to a Number
@Override
protected Number getNumber(ComponentAdapter adapter) {
if (!(adapter.getValue(getValueColumn()) instanceof Contributor)) {
return null;
}
return ((Contributor) adapter.getValue(getValueColumn())).getMerits();
}
// </snip>
}
public class HighlighterControl extends AbstractBean {
private RelativePainterHighlighter tableValueBasedHighlighter;
private boolean spreadColumns;
private RelativePainterHighlighter valueBasedHighlighter;
private Timeline raceTimeline;
private Timeline fadeInTimeline;
private MattePainter matte;
private Color base = PaintUtils.setSaturation(Color.MAGENTA, .7f);
public HighlighterControl() {
matte = new MattePainter(PaintUtils.setAlpha(base, 125));
tableValueBasedHighlighter = new RelativePainterHighlighter(matte);
table.addHighlighter(tableValueBasedHighlighter);
treeTable.addHighlighter(tableValueBasedHighlighter);
valueBasedHighlighter = new RelativePainterHighlighter(matte);
list.addHighlighter(valueBasedHighlighter);
tree.addHighlighter(valueBasedHighlighter);
setSpreadColumns(false);
BindingGroup group = new BindingGroup();
group.addBinding(Bindings.createAutoBinding(READ,
extendedMarkerBox, BeanProperty.create("selected"),
this, BeanProperty.create("spreadColumns")));
group.bind();
}
// PENDING JW: how-to find the resource of this action for injection?
@Action
public void race() {
if (raceTimeline == null) {
raceTimeline = new Timeline(this);
raceTimeline.addPropertyToInterpolate("currentMerit", 0, 100);
}
raceTimeline.replay();
}
@Action
public void fadeIn() {
if (fadeInTimeline == null) {
fadeInTimeline = new Timeline(this);
fadeInTimeline.addPropertyToInterpolate("background",
PaintUtils.setAlpha(base, 0), PaintUtils.setAlpha(base, 125));
fadeInTimeline.setDuration(2000);
fadeInTimeline.setEase(new Spline(0.7f));
}
fadeInTimeline.replay();
}
public void setBackground(Color color) {
matte.setFillPaint(color);
}
public void setCurrentMerit(int merit) {
MeritRelativizer relativizer = createMeritRelativizer(merit);
tableValueBasedHighlighter.setRelativizer(relativizer);
valueBasedHighlighter.setRelativizer(relativizer);
}
/**
* Creates and returns a relativizer with the given intermediate value.
*
*/
private MeritRelativizer createMeritRelativizer(int intermediate) {
return new MeritRelativizer(meritColumn, isSpreadColumns(), 100, intermediate);
}
/**
*
*/
private void updateTableHighlighter() {
tableValueBasedHighlighter.setRelativizer(createMeritRelativizer(100));
valueBasedHighlighter.setRelativizer(
tableValueBasedHighlighter.getRelativizer());
if (isSpreadColumns()) {
tableValueBasedHighlighter.setHighlightPredicate(HighlightPredicate.ALWAYS);
} else {
tableValueBasedHighlighter.setHighlightPredicate(
new HighlightPredicate.ColumnHighlightPredicate(meritColumn));
}
}
public boolean isSpreadColumns() {
return spreadColumns;
}
public void setSpreadColumns(boolean extendedMarker) {
boolean old = isSpreadColumns();
this.spreadColumns = extendedMarker;
updateTableHighlighter();
firePropertyChange("spreadColumns", old, isSpreadColumns());
}
}
//---------------------- renderers
/**
* Install renderers which use the prepared string representations.
* Note: this method is called after the binding (aka: attach models)
* because it installs per-column renderers which in this setup can be done only
* after the columns are created.
*/
private void installRenderers() {
initStringRepresentation();
StringValue sv = stringValues.get("name");
table.setDefaultRenderer(Contributor.class, new DefaultTableRenderer(sv));
list.setCellRenderer(new DefaultListRenderer(sv));
tree.setCellRenderer(new DefaultTreeRenderer(sv));
treeTable.setTreeCellRenderer(new DefaultTreeRenderer(sv));
for (int i = 1; i < keys.length; i++) {
installColumnRenderers(i, new DefaultTableRenderer(stringValues.get(keys[i])));
}
// <snip> Unrelated, just for fun: Hyperlink
// Use a hyperlinkRenderer for the email column
HyperlinkProvider provider = new HyperlinkProvider(new ContributorMailAction(
stringValues.get("email")));
installColumnRenderers(keys.length - 1, new DefaultTableRenderer(provider));
table.getColumnExt(keys.length - 1).setToolTipText(
"Note: the mail-to action will do nothing in security restricted environments");
// </snip>
table.packAll();
}
private void installColumnRenderers(int column, TableCellRenderer renderer) {
if (column >= table.getColumnCount()) return;
table.getColumn(column).setCellRenderer(renderer);
treeTable.getColumn(column).setCellRenderer(renderer);
}
/**
* Prepare different String representations.
*/
private void initStringRepresentation() {
stringValues = new HashMap<String, StringValue>();
StringValue nameValue = new StringValue() {
@Override
public String getString(Object value) {
if (value instanceof Contributor) {
Contributor c = (Contributor) value;
return c.getLastName() + ", " + c.getFirstName();
}
return StringValues.TO_STRING.getString(value);
}
};
stringValues.put("name", nameValue);
// show the joined date
StringValue dateValue = new StringValue() {
@Override
public String getString(Object value) {
if (value instanceof Contributor) {
return StringValues.DATE_TO_STRING.getString(
((Contributor) value).getJoinedDate());
}
return StringValues.TO_STRING.getString(value);
}
};
stringValues.put("date", dateValue);
// show the merits
StringValue meritValue = new StringValue() {
@Override
public String getString(Object value) {
if (value instanceof Contributor) {
return StringValues.NUMBER_TO_STRING.getString(
((Contributor) value).getMerits());
}
return StringValues.TO_STRING.getString(value);
}
};
stringValues.put("merits", meritValue);
// <snip> Unrelated, just for fun: Hyperlink
// string representation of contributor's email
StringValue emailValue = new StringValue() {
@Override
public String getString(Object value) {
if (value instanceof Contributor) {
URI mail = ((Contributor) value).getEmail();
// strip mailto:
String path = mail.toString();
return path.replace("mailto:", "");
}
return StringValues.EMPTY.getString(value);
}
};
// </snip>
stringValues.put("email", emailValue);
}
// <snip> Unrelated, just for fun: Hyperlink
// custom hyperlink action which delegates to Desktop
public static class ContributorMailAction extends AbstractHyperlinkAction<Contributor> {
HyperlinkAction browse = HyperlinkAction.createHyperlinkAction(null,
java.awt.Desktop.Action.MAIL);
StringValue sv;
public ContributorMailAction(StringValue sv) {
this.sv = sv;
}
@Override
protected void installTarget() {
if (sv == null) return;
// configure the name based on the StringValue
setName(sv.getString(getTarget()));
}
@Override
public void actionPerformed(ActionEvent e) {
if (target == null) return;
browse.setTarget(target.getEmail());
browse.actionPerformed(null);
}
// </snip>
}
//------------------ init ui
private void initComponents() {
setLayout(new BorderLayout());
table = new JXTable();
list = new JXList(true);
tree = new JXTree();
treeTable = new JXTreeTable();
table.setColumnControlVisible(true);
treeTable.setColumnControlVisible(true);
JTabbedPane tab = new JTabbedPane();
addTab(tab, table, "tableTabTitle", true);
addTab(tab, list, "listTabTitle", true);
// addTab(tab, tree, "HighlighterExtDemo.tree", true);
// addTab(tab, treeTable, "HighlighterExtDemo.treeTable", true);
add(tab);
extendedMarkerBox = new JCheckBox();
extendedMarkerBox.setName("extendedMarkerBox");
raceButton = new JButton();
raceButton.setName("playButton");
fadeInButton = new JButton();
fadeInButton.setName("fadeInButton");
JPanel control = new JPanel();
control.add(extendedMarkerBox);
control.add(raceButton);
control.add(fadeInButton);
add(control, BorderLayout.SOUTH);
}
private void addTab(JTabbedPane tab, JComponent comp, String string, boolean createScroll) {
String name = DemoUtils.getResourceString(getClass(), string);
tab.addTab(name, createScroll ? new JScrollPane(comp) : comp);
}
/**
* 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(HighlighterExtDemo.class.getAnnotation(DemoProperties.class).value());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new HighlighterExtDemo());
frame.setPreferredSize(new Dimension(800, 600));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}