/*
* Created on 10.06.2006
*
*/
package org.jdesktop.swingx;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.DefaultRowSorter;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.ListModel;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.RowFilter.Entry;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.UIResource;
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.HighlighterFactory;
import org.jdesktop.swingx.decorator.PatternPredicate;
import org.jdesktop.swingx.hyperlink.EditorPaneLinkVisitor;
import org.jdesktop.swingx.hyperlink.LinkModel;
import org.jdesktop.swingx.hyperlink.LinkModelAction;
import org.jdesktop.swingx.renderer.DefaultListRenderer;
import org.jdesktop.swingx.renderer.HyperlinkProvider;
import org.jdesktop.swingx.renderer.HighlighterClientVisualCheck.FontHighlighter;
import org.jdesktop.swingx.sort.RowFilters;
import org.jdesktop.test.AncientSwingTeam;
import org.junit.After;
import org.junit.Before;
import sun.font.CreatedFontTracker;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class JXListVisualCheck extends InteractiveTestCase { //JXListTest {
@SuppressWarnings("all")
private static final Logger LOG = Logger.getLogger(JXListVisualCheck.class
.getName());
public static void main(String[] args) {
setSystemLF(true);
// LookAndFeel l;
// SynthConstants s;
JXListVisualCheck test = new JXListVisualCheck();
try {
// NimbusLookAndFeel n;
// Region my = XRegion.XLIST;
// setLookAndFeel("Nimbus");
// new XRegion("XList", "XListUI", false);
// test.runInteractiveTests();
// test.runInteractive("RowFilter");
// test.runInteractive("Remove");
test.runInteractive("PopupTrigger");
} catch (Exception e) {
System.err.println("exception when executing interactive tests:");
e.printStackTrace();
}
}
/**
* Issue #1563-swingx: find cell that was clicked for componentPopup
*
* Example of how to use:
* - in actionPerformed
* - in popupMenuWillBecomeVisible
*/
public void interactivePopupTriggerLocation() {
JXList table = new JXList(createListModel());
JPopupMenu popup = new JPopupMenu();
Action action = new AbstractAction("cell found in actionPerformed") {
@Override
public void actionPerformed(ActionEvent e) {
JXList table = SwingXUtilities.getAncestor(JXList.class, (Component) e.getSource());
Point trigger = table.getPopupTriggerLocation();
Point cell = null;
if (trigger != null) {
int row = table.locationToIndex(trigger);
table.setSelectedIndex(row);
cell = new Point(0, row);
} else {
table.clearSelection();
}
LOG.info("popupTrigger/cell " + trigger + "/" + cell);
}
};
popup.add(action);
final Action onShowing = new AbstractAction("dynamic: ") {
@Override
public void actionPerformed(ActionEvent e) {
LOG.info("" + getValue(NAME));
}
};
popup.add(onShowing);
PopupMenuListener l = new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
// doesn't work: popup itself cannot be used as
// starting component, bug?
// JXList list = SwingXUtilities.getAncestor(JXList.class,
// (Component) e.getSource());
JXList list = (JXList) ((JPopupMenu) e.getSource()).getInvoker();
Point trigger = list.getPopupTriggerLocation();
Point cell = null;
if (trigger != null) {
int row = list.locationToIndex(trigger);
list.setSelectedIndex(row);
// here we set the cell focus, just to do a bit differently
// from the other action
list.clearSelection();
cell = new Point(0, row);
}
onShowing.putValue(Action.NAME, "popupTrigger/cell " + trigger + "/" + cell);
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
};
popup.addPopupMenuListener(l);
table.setComponentPopupMenu(popup);
showWithScrollingInFrame(table, "PopupTriggerLocation");
}
/**
* Issue #1536-swingx: AIOOB on restoring selection with filter
* Reopened: overfixed - the removeIndexInterval _does_ take
* the endIndex instead of length.
*/
public void interactiveSortUIRemove() {
final DefaultListModel model = createAscendingListModel(0, 10);
final JXList list = new JXList(model, true);
final RowFilter filter = new RowFilters.GeneralFilter() {
List excludes = Arrays.asList(0);
@Override
protected boolean include(
Entry<? extends Object, ? extends Object> entry,
int index) {
return !excludes.contains(entry.getIdentifier());
}
};
JXFrame frame = wrapWithScrollingInFrame(list, "removeIndexSelectionInterval");
Action toggleSort = new AbstractAction("toggleSort") {
@Override
public void actionPerformed(ActionEvent e) {
list.toggleSortOrder();
}
};
addAction(frame, toggleSort);
Action toggleFilter = new AbstractAction("filter") {
@Override
public void actionPerformed(ActionEvent e) {
list.setRowFilter(list.getRowFilter() != null ?
null : filter
);
}
};
addAction(frame, toggleFilter);
Action remove = new AbstractAction("remove") {
@Override
public void actionPerformed(ActionEvent e) {
model.remove(model.getSize() - 1);
}
};
addAction(frame, remove);
show(frame);
}
public void interactiveRowFilter() {
final JXList list = new JXList(AncientSwingTeam.createNamedColorListModel(), true);
JXFrame frame = wrapWithScrollingInFrame(list, "filter");
Action toggleFilter = new AbstractAction("toggleFilter") {
@Override
public void actionPerformed(ActionEvent e) {
if (list.getRowFilter() == null) {
list.setRowFilter(new RowFilter<ListModel, Integer>() {
@Override
public boolean include(
Entry<? extends ListModel, ? extends Integer> entry) {
boolean include = entry
.getStringValue(entry.getIdentifier())
.toLowerCase().contains("o");
return include;
}
});
} else {
list.setRowFilter(null);
}
}
};
addAction(frame, toggleFilter);
show(frame, 300, 600);
}
/**
* Issue #1261-swingx: list goes blank after setting model and filter.
*
* To reproduce:
* - click on setModel: resets the model and turns on filter (expected)
* - click on filterOff: clears the list (unexpected - the expected behaviour
* is to show all entries
*
* Workaround:
* - click on invalidate to explicitly invalidated the cell size cache
* (should be done automatically) - fixed to now do in ListSortUI.sorterChanged
*
* example adjusted from reporter
*/
public void interactiveRowFilterAfterSetModel() {
final JXList list = new JXList(true);
JXFrame frame = wrapWithScrollingInFrame(list, "filter after model");
final Action filterOnAction = new AbstractAction("filter on") {
@Override
public void actionPerformed(ActionEvent e) {
list.setRowFilter(new RowFilter<ListModel, Integer>() {
@Override
public boolean include(
Entry<? extends ListModel, ? extends Integer> entry) {
boolean include = entry.getStringValue(entry.getIdentifier())
.toLowerCase().contains("o");
return include;
}
});
}
};
// addAction(frame, filterOnAction);
Action modelAction = new AbstractAction("setModel") {
int count;
@Override
public void actionPerformed(ActionEvent e) {
DefaultListModel model = new DefaultListModel();
model.addElement("One" + count++);
model.addElement("Two");
model.addElement("Three");
model.addElement("Four");
model.addElement("Five");
list.setModel(model);
filterOnAction.actionPerformed(e);
}
};
addAction(frame, modelAction);
Action filterOffAction = new AbstractAction("filter off") {
@Override
public void actionPerformed(ActionEvent e) {
list.setRowFilter(new RowFilter<ListModel, Integer>() {
@Override
public boolean include(
Entry<? extends ListModel, ? extends Integer> entry) {
return true;
}
});
}
};
addAction(frame, filterOffAction);
Action invalidateCacheAction = new AbstractAction("invalidateCache") {
@Override
public void actionPerformed(ActionEvent e) {
// this shouldn't be necessary
list.invalidateCellSizeCache();
}
};
addAction(frame, invalidateCacheAction);
addStatusMessage(frame, "setModel == new Model + rowFilter on; filterOff = rowFilter off (should show all)");
show(frame, 500, 300);
}
/**
* Issue #1255-swingx: enhance dynamic row sizing.
*/
public void interactiveDynamicCellHeight() {
final JXList list = new JXList(AncientSwingTeam.createNamedColorListModel(), true);
ListSelectionListener l = new ListSelectionListener() {
@Override
public void valueChanged(final ListSelectionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
list.invalidateCellSizeCache();
}
});
}
};
list.addListSelectionListener(l);
HighlightPredicate selected = new HighlightPredicate() {
@Override
public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
return adapter.isSelected();
}
};
Highlighter hl = new FontHighlighter(selected, list.getFont().deriveFont(50f));
list.addHighlighter(hl);
JXFrame frame = wrapWithScrollingInFrame(list, "big font on focus");
Action toggleSort = new AbstractAction("toggle sort") {
@Override
public void actionPerformed(ActionEvent e) {
list.toggleSortOrder();
}
};
addAction(frame, toggleSort);
show(frame);
}
/**
* Issue 1161-swingx: JXList not completely updated on setRowFilter
* Issue 1162-swingx: JXList getNextMatch access model directly
*/
public void interactiveNextMatch() {
JList core = new JList(AncientSwingTeam.createNamedColorListModel());
final JXList list = new JXList(core.getModel(), true);
// list.toggleSortOrder();
JXFrame frame = showWithScrollingInFrame(list, core, "x <-> core: nextMatch");
Action toggleFilter = new AbstractAction("toggleFilter") {
@Override
public void actionPerformed(ActionEvent e) {
RowFilter<Object, Object> filter = RowFilters.regexFilter(Pattern.CASE_INSENSITIVE, "^b");
list.setRowFilter(list.getRowFilter() == null ? filter : null);
}
};
addAction(frame, toggleFilter);
Action toggleSort = new AbstractAction("toggleSortOrder") {
@Override
public void actionPerformed(ActionEvent e) {
list.toggleSortOrder();
}
};
addAction(frame, toggleSort);
}
public void interactiveTestCompareFocusedCellBackground() {
final JXList xlist = new JXList(listModel);
LOG.info("xlist ui" + xlist.getUI());
final Color bg = new Color(0xF5, 0xFF, 0xF5);
final JList list = new JList(listModel);
// xlist.setBackground(bg);
// list.setBackground(bg);
JXFrame frame = wrapWithScrollingInFrame(xlist, list,
"unselectedd focused background: JXList/JList");
Action toggle = new AbstractAction("toggle background") {
@Override
public void actionPerformed(ActionEvent e) {
Color old = xlist.getBackground();
Color back = ((old == null) || (old instanceof UIResource)) ? bg : null;
xlist.setBackground(back);
list.setBackground(back);
if (back == null) {
// force ui default background
list.updateUI();
xlist.updateUI();
}
}
};
addAction(frame, toggle);
show(frame);
}
public void interactiveTestTablePatternFilter5() {
JXList list = new JXList(listModel);
String pattern = "Row";
list.setHighlighters(new ColorHighlighter(// columns not really important, ListAdapter.getXXValue
// uses row only
new PatternPredicate(pattern, 0), null,
Color.red));
showWithScrollingInFrame(list, "PatternHighlighter: " + pattern);
}
public void interactiveTestTableAlternateHighlighter1() {
JXList list = new JXList(listModel);
list.addHighlighter(
HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER));
showWithScrollingInFrame(list, "AlternateRowHighlighter - lineprinter");
}
/**
* Plain rollover highlight, had been repaint issues.
*
*/
public void interactiveTestRolloverHighlight() {
JXList list = new JXList(listModel);
list.setRolloverEnabled(true);
ColorHighlighter rollover = new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, new Color(0xF0, 0xF0, 0xE0),
null);
list.addHighlighter(rollover);
showWithScrollingInFrame(list, "rollover highlight");
}
/**
* Plain rollover highlight in multi-column layout, had been repaint issues.
*
*/
public void interactiveTestRolloverHighlightMultiColumn() {
LOG.info("rtol-map? " + UIManager.get("List.focusInputMap.RightToLeft"));
LOG.info("ancestor maps? " + UIManager.get("Table.ancestorInputMap"));
LOG.info("ancestor rtol maps? " + UIManager.get("Table.ancestorInputMap.RightToLeft"));
JXList list = new JXList(listModel);
list.setRolloverEnabled(true);
list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
list.addHighlighter(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, new Color(0xF0, 0xF0, 0xE0),
null));
JList core = new JList(listModel);
core.setLayoutOrientation(JList.HORIZONTAL_WRAP);
JComponent box = Box.createVerticalBox();
box.add(new JScrollPane(list));
box.add(new JScrollPane(core));
JXFrame frame = wrapInFrame(box, "rollover highlight - horz. Wrap");
addComponentOrientationToggle(frame);
show(frame);
}
/**
* Issue #503-swingx: rolloverEnabled disables custom cursor
*
*/
public void interactiveTestRolloverHighlightCustomCursor() {
JXList list = new JXList(listModel);
list.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
list.setRolloverEnabled(true);
list.addHighlighter(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, new Color(0xF0, 0xF0, 0xE0),
null));
showWithScrollingInFrame(list, "rollover highlight - custom cursor");
}
/**
* Issue #20: Highlighters and LinkRenderers don't work together
* fixed with overhaul of SwingX renderers?
*/
public void interactiveTestRolloverHighlightAndLink() {
JXList list = new JXList(createListModelWithLinks());
EditorPaneLinkVisitor editorPaneLinkVisitor = new EditorPaneLinkVisitor();
LinkModelAction<?> action = new LinkModelAction<LinkModel>(editorPaneLinkVisitor);
HyperlinkProvider h = new HyperlinkProvider(action, LinkModel.class);
list.setCellRenderer(new DefaultListRenderer(h));
list.setRolloverEnabled(true);
list.addHighlighter(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, new Color(0xF0, 0xF0, 0xE0),
null));
showWithScrollingInFrame(list, editorPaneLinkVisitor.getOutputComponent(), "rollover highlight with links");
}
protected ListModel createListModel() {
JList list = new JList();
return new DefaultComboBoxModel(list.getActionMap().allKeys());
}
protected DefaultListModel createAscendingListModel(int startRow, int count) {
DefaultListModel l = new DefaultListModel();
for (int row = startRow; row < startRow + count; row++) {
l.addElement(new Integer(row));
}
return l;
}
protected DefaultListModel createListModelWithLinks() {
DefaultListModel model = new DefaultListModel();
for (int i = 0; i < 20; 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 resource", null, url);
}
model.addElement(link);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return model;
}
@Override
protected void setUp() throws Exception {
super.setUp();
listModel = createListModel();
ascendingListModel = createAscendingListModel(0, 20);
}
protected ListModel listModel;
protected DefaultListModel ascendingListModel;
@Before
public void setUpJ4() throws Exception {
setUp();
}
@After
public void tearDownJ4() throws Exception {
tearDown();
}
}