/* * $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.xlist; import static org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Comparator; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SortOrder; import javax.swing.SwingUtilities; import org.jdesktop.application.Action; import org.jdesktop.beansbinding.BeanProperty; import org.jdesktop.beansbinding.Binding; import org.jdesktop.beansbinding.BindingGroup; import org.jdesktop.beansbinding.Bindings; import org.jdesktop.swingx.JXCollapsiblePane; import org.jdesktop.swingx.JXList; import org.jdesktop.swingx.JXPanel; import org.jdesktop.swingx.JXTitledSeparator; import org.jdesktop.swingx.binding.DisplayInfo; import org.jdesktop.swingx.binding.DisplayInfoConverter; import org.jdesktop.swingx.binding.LabelHandler; 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.decorator.PainterHighlighter; import org.jdesktop.swingx.demos.search.Contributor; import org.jdesktop.swingx.demos.search.Contributors; import org.jdesktop.swingx.painter.MattePainter; import org.jdesktop.swingx.renderer.DefaultListRenderer; import org.jdesktop.swingx.renderer.StringValue; import org.jdesktop.swingx.renderer.StringValues; import org.jdesktop.swingx.rollover.RolloverProducer; import org.jdesktop.swingx.sort.DefaultSortController; import org.jdesktop.swingx.util.PaintUtils; import org.jdesktop.swingxset.util.DemoUtils; import org.jdesktop.swingxset.util.DisplayValues; import com.jgoodies.forms.builder.PanelBuilder; import com.jgoodies.forms.factories.Borders; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import com.sun.swingset3.DemoProperties; /** * A demo for the {@code JXList}. * * @author Karl George Schaefer */ //TODO implement @DemoProperties( value = "JXList Demo", category = "Data", description = "Demonstrates JXList, an enhanced list component.", sourceFiles = { "org/jdesktop/swingx/demos/xlist/XListDemo.java", "org/jdesktop/swingx/demos/xlist/resources/XListDemo.properties" } ) @SuppressWarnings("serial") public class XListDemo extends JXPanel { private JXList list; private JComboBox comparatorCombo; private JButton toggleSortOrder; private JButton resetSortOrder; private JCheckBox rolloverEnabledBox; private JComboBox highlighterCombo; public XListDemo() { super(new BorderLayout()); initComponents(); configureComponents(); DemoUtils.injectResources(this); bind(); } //---------------- public api for Binding/Action control @Action // <snip> JXList sorting // api to toggle sorts public void toggleSortOrder() { list.toggleSortOrder(); } // </snip> @Action public void resetSortOrder() { list.resetSortOrder(); } public void setComparator(Comparator<?> comparator) { // <snip> JXList sorting // configure the comparator to use in sorting list.setComparator(comparator); if (list.getSortOrder() != SortOrder.UNSORTED) { // PENDING missing refresh api? ((DefaultSortController<?>) list.getRowSorter()).sort(); } // </snip> } public void setRolloverHighlighter(Highlighter hl) { list.setHighlighters(hl); } public void setRolloverEnabled(boolean enabled) { list.setRolloverEnabled(enabled); list.setToolTipText(list.isRolloverEnabled() ? DemoUtils.getResourceString(getClass(), "stickyRolloverToolTip") : null); } //------------------- ui configuration private void configureComponents() { // <snip> JXList rendering // custom String representation: concat various element fields StringValue sv = new StringValue() { @Override public String getString(Object value) { if (value instanceof Contributor) { Contributor c = (Contributor) value; return c.getFirstName() + " " + c.getLastName() + " (" + c.getMerits() + ")"; } return StringValues.TO_STRING.getString(value); } }; // PENDING JW: add icon (see demos in swingx) // set a renderer configured with the custom string converter list.setCellRenderer(new DefaultListRenderer(sv)); // </snip> // PENDING JW: add visual clue to currentl sortorder toggleSortOrder.setAction(DemoUtils.getAction(this, "toggleSortOrder")); resetSortOrder.setAction(DemoUtils.getAction(this, "resetSortOrder")); comparatorCombo.setRenderer( new DefaultListRenderer(DisplayValues.DISPLAY_INFO_DESCRIPTION)); highlighterCombo.setRenderer( new DefaultListRenderer(DisplayValues.DISPLAY_INFO_DESCRIPTION)); // demo specific config DemoUtils.setSnippet("JXList sorting", toggleSortOrder, resetSortOrder, comparatorCombo); DemoUtils.setSnippet("JXList rollover support", rolloverEnabledBox, highlighterCombo); DemoUtils.setSnippet("JXList rendering", list); } @SuppressWarnings("unchecked") private void bind() { // list properties // <snip> JXlist sorting // enable auto-create RowSorter list.setAutoCreateRowSorter(true); list.setModel(Contributors.getContributorListModel()); //</snip> // control combos comparatorCombo.setModel(createComparators()); highlighterCombo.setModel(createRolloverHighlighters()); BindingGroup group = new BindingGroup(); group.addBinding(Bindings.createAutoBinding(READ, rolloverEnabledBox, BeanProperty.create("selected"), this, BeanProperty.create("rolloverEnabled"))); Binding comparatorBinding = Bindings.createAutoBinding(READ, comparatorCombo, BeanProperty.create("selectedItem"), this, BeanProperty.create("comparator")); comparatorBinding.setConverter(new DisplayInfoConverter<Comparator<?>>()); group.addBinding(comparatorBinding); Binding rolloverBinding = Bindings.createAutoBinding(READ, highlighterCombo, BeanProperty.create("selectedItem"), this, BeanProperty.create("rolloverHighlighter")); rolloverBinding.setConverter(new DisplayInfoConverter<Highlighter>()); group.addBinding(rolloverBinding); group.bind(); } private ComboBoxModel createRolloverHighlighters() { DefaultComboBoxModel model = new DefaultComboBoxModel(); // <snip> JXList rollover support // simple decorations of rollover row model.addElement(new DisplayInfo<Highlighter>("Background Color", new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, Color.MAGENTA, null))); model.addElement(new DisplayInfo<Highlighter>("Foreground Color", new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, null, Color.MAGENTA))); // </snip> model.addElement(new DisplayInfo<Highlighter>("Related Merit", createExtendedRolloverDecoration())); return model; } private Highlighter createExtendedRolloverDecoration() { Color color = PaintUtils.setAlpha(Color.YELLOW, 100); final PainterHighlighter hl = new PainterHighlighter(HighlightPredicate.NEVER, new MattePainter(color)); // <snip> JXList rollover support // listen to changes of cell-rollover property // and set a Highlighters custom predicate accordingly PropertyChangeListener l = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { Point location = (Point) evt.getNewValue(); int row = -1; if (location != null) { row = location.y; } hl.setHighlightPredicate(new MeritRangeHighlightPredicate( row < 0 ? null : list.getElementAt(row))); } }; list.addPropertyChangeListener(RolloverProducer.ROLLOVER_KEY, l); // </snip> return hl; } public static class MeritRangeHighlightPredicate implements HighlightPredicate { private Contributor compare; public MeritRangeHighlightPredicate(Object object) { this.compare = object instanceof Contributor ? (Contributor) object : null; } @Override // <snip> JXList rollover support // custom HighlightPredicate which compare the current value // against a fixed value and returns true if "near" public boolean isHighlighted(Component renderer, ComponentAdapter adapter) { if (compare == null) return false; if (!(adapter.getValue() instanceof Contributor)) return false; Contributor contributor = (Contributor) adapter.getValue(); return contributor.getMerits() >= compare.getMerits() - 5 && contributor.getMerits() <= compare.getMerits() + 5; } // </snip> } private ComboBoxModel createComparators() { DefaultComboBoxModel model = new DefaultComboBoxModel(); // <snip> JXList sorting // null comparator defaults to comparing by the display string model.addElement(new DisplayInfo<Comparator<?>>("None (by display string)", null)); // compare by Comparable as implemented by the elements model.addElement(new DisplayInfo<Comparator<?>>("Comparable (by lastname)", DefaultSortController.COMPARABLE_COMPARATOR)); // custom comparator Comparator<Contributor> meritComparator = new Comparator<Contributor>() { @Override public int compare(Contributor o1, Contributor o2) { return o1.getMerits() - o2.getMerits(); } }; // </snip> model.addElement(new DisplayInfo<Comparator<?>>("Custom (by merits)", meritComparator)); return model; } //-------------------- init ui private void initComponents() { list = new JXList(); list.setName("list"); JPanel monthViewContainer = new JXPanel(); FormLayout formLayout = new FormLayout( "5dlu, f:d:g ", // l:4dlu:n, f:d:g", // columns "c:d:n " + ", t:4dlu:n, f:d:g " + ", t:4dlu:n, c:d:n" + ", t:4dlu:n, c:d:n" + ", t:4dlu:n, c:d:n" ); // rows PanelBuilder builder = new PanelBuilder(formLayout, monthViewContainer); builder.setBorder(Borders.DLU4_BORDER); // CellConstraints cl = new CellConstraints(); CellConstraints cc = new CellConstraints(); JXTitledSeparator areaSeparator = new JXTitledSeparator(); areaSeparator.setName("listSeparator"); builder.add(areaSeparator, cc.xywh(1, 1, 2, 1)); builder.add(new JScrollPane(list), cc.xywh(2, 3, 1, 1)); add(monthViewContainer, BorderLayout.CENTER); JComponent extended = createExtendedConfigPanel(); add(extended, BorderLayout.EAST); } private JComponent createExtendedConfigPanel() { JXCollapsiblePane painterControl = new JXCollapsiblePane(); FormLayout formLayout = new FormLayout( "5dlu, r:d:n, l:4dlu:n, f:d:g", // , l:4dlu:n, f:d:g", // columns "c:d:n " + ", t:4dlu:n, c:d:n " + ", t:4dlu:n, c:d:n" + ", t:4dlu:n, c:d:n" + ", t:4dlu:n, c:d:n" + ", t:4dlu:n, c:d:n" + ", t:4dlu:n, c:d:n" + ", t:4dlu:n, c:d:n" ); // rows PanelBuilder builder = new PanelBuilder(formLayout, painterControl); builder.setBorder(Borders.DLU4_BORDER); CellConstraints cl = new CellConstraints(); CellConstraints cc = new CellConstraints(); JXTitledSeparator areaSeparator = new JXTitledSeparator(); areaSeparator.setName("extendedSeparator"); builder.add(areaSeparator, cc.xywh(1, 1, 4, 1)); int labelColumn = 2; int widgetColumn = labelColumn + 2; int currentRow = 3; toggleSortOrder = new JButton(); toggleSortOrder.setName("toggleSortOrder"); builder.add(toggleSortOrder, cc.xywh(labelColumn, currentRow, 3, 1)); currentRow += 2; resetSortOrder = new JButton(); resetSortOrder.setName("resetSortOrder"); builder.add(resetSortOrder, cc.xywh(labelColumn, currentRow, 3, 1)); currentRow += 2; comparatorCombo = new JComboBox(); comparatorCombo.setName("comparatorCombo"); JLabel comparatorComboLabel = builder.addLabel( "", cl.xywh(labelColumn, currentRow, 1, 1), comparatorCombo, cc.xywh(widgetColumn, currentRow, 1, 1)); comparatorComboLabel.setName("comparatorComboLabel"); LabelHandler.bindLabelFor(comparatorComboLabel, comparatorCombo); currentRow += 2; currentRow += 2; JXTitledSeparator rolloverSeparator = new JXTitledSeparator(); rolloverSeparator.setName("rolloverSeparator"); builder.add(rolloverSeparator, cc.xywh(1, currentRow, 4, 1)); currentRow += 2; rolloverEnabledBox = new JCheckBox(); rolloverEnabledBox.setName("rolloverBox"); builder.add(rolloverEnabledBox, cc.xywh(labelColumn, currentRow, 3, 1)); currentRow += 2; highlighterCombo = new JComboBox(); highlighterCombo.setName("highlighterCombo"); JLabel highlighterComboLabel = builder.addLabel( "", cl.xywh(labelColumn, currentRow, 1, 1), highlighterCombo, cc.xywh(widgetColumn, currentRow, 1, 1)); highlighterComboLabel.setName("highlighterComboLabel"); LabelHandler.bindLabelFor(highlighterComboLabel, highlighterCombo); currentRow += 2; return painterControl; } /** * main method allows us to run as a standalone demo. */ /** * 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(XListDemo.class.getAnnotation(DemoProperties.class).value()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new XListDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } //--------------------- dummy api (to keep bbb happy) public Comparator<?> getComparator() { return null; } public Highlighter getRolloverHighlighter() { return null; } public boolean isRolloverEnabeld() { return list.isRolloverEnabled(); } }