swingx-master/swingx-core/src/test/java/org/jdesktop/swingx/rollover/RolloverVisualCheck.java
/*
 * Created on 08.12.2010
 *
 */
package org.jdesktop.swingx.rollover;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.util.logging.Logger;

import javax.swing.AbstractAction;
import javax.swing.AbstractListModel;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.ListModel;
import javax.swing.TransferHandler;
import javax.swing.table.TableModel;

import org.jdesktop.swingx.InteractiveTestCase;
import org.jdesktop.swingx.JXFrame;
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.ColorHighlighter;
import org.jdesktop.swingx.decorator.CompoundHighlighter;
import org.jdesktop.swingx.decorator.HighlightPredicate;
import org.jdesktop.swingx.decorator.HighlightPredicate.AndHighlightPredicate;
import org.jdesktop.swingx.decorator.Highlighter;
import org.jdesktop.swingx.renderer.DefaultListRenderer;
import org.jdesktop.swingx.renderer.DefaultTableRenderer;
import org.jdesktop.swingx.renderer.DefaultTreeRenderer;
import org.jdesktop.swingx.treetable.FileSystemModel;
import org.jdesktop.test.AncientSwingTeam;

public class RolloverVisualCheck extends InteractiveTestCase {

    private TableModel sortableTableModel;
    private Highlighter backgroundHighlighter;
    private Highlighter foregroundHighlighter;
    private ListModel listModel;
    private FileSystemModel treeTableModel;

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(RolloverVisualCheck.class.getName());

    public static void main(String[] args) {
        RolloverVisualCheck test = new RolloverVisualCheck();
        try {
            test.runInteractiveTests();
//            test.runInteractive("Drag");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Issue #1249-swingx: RolloverProducer clears rollover point when inserting child
     * 
     * Happens f.i. when starting an edit.
     * 
     */
    public void interactiveExitToChild() {
        JXTable table = new JXTable(new AncientSwingTeam());
        table.addHighlighter(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, 
                Color.MAGENTA, null, Color.MAGENTA, null));
        JXFrame frame = wrapWithScrollingInFrame(table, "rollover child");
        addStatusMessage(frame, "edit under mouse, move");
        show(frame);
    }
    
    /**
     * Issue #1193-swingx: rollover state not updated on scrolling/mouseWheel
     * 
     * visualize behaviour on 
     * - scrolling (with mouse wheel)
     * - resizing (added custom actions)
     */
    public void interactiveTreeRolloverScroll() {
        final JXTree table = new JXTree(new FileSystemModel());
        table.setCellRenderer(new DefaultTreeRenderer());
        table.setRolloverEnabled(true);
        table.addHighlighter(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, Color.YELLOW, null));
        final JXFrame frame = getResizableFrame(table);
        show(frame);
    }

    /**
     * Issue #1193-swingx: rollover state not updated on scrolling/mouseWheel
     * 
     * visualize behaviour on 
     * - scrolling (with mouse wheel)
     * - resizing (added custom actions)
     */
    public void interactiveListRolloverScroll() {
        final JXList table = new JXList(AncientSwingTeam.createNamedColorListModel());
        table.setRolloverEnabled(true);
        table.addHighlighter(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, Color.YELLOW, null));
        final JXFrame frame = getResizableFrame(table);
        show(frame);
    }
    
    /**
     * Issue #1193-swingx: rollover state not updated on scrolling/mouseWheel
     * 
     * visualize behaviour on 
     * - scrolling (with mouse wheel)
     * - resizing (added custom actions)
     */
    public void interactiveTableRolloverScroll() {
        final JXTable table = new JXTable(new AncientSwingTeam());
        table.setEditable(false);
        table.setHorizontalScrollEnabled(true);
        table.addHighlighter(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, Color.YELLOW, null));
        final JXFrame frame = getResizableFrame(table);
        show(frame);
    }



    /**
     * @param table
     * @return
     */
    private JXFrame getResizableFrame(final JComponent table) {
        final JXFrame frame = wrapWithScrollingInFrame(table, "rollover and wheel");
        Action hd = new AbstractAction("horizontalDecrease") {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                Dimension dim = frame.getSize();
                dim.width -= 50;
                frame.setSize(dim);
            }
            
        };
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke("A"), "horizontalDecrease");
        table.getActionMap().put("horizontalDecrease", hd);
        Action hi = new AbstractAction("horizontalDecrease") {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                Dimension dim = frame.getSize();
                dim.width += 50;
                frame.setSize(dim);
            }
            
        };
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke("D"), "horizontalIncrease");
        table.getActionMap().put("horizontalIncrease", hi);
        Action vd = new AbstractAction("verticalDecrease") {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                Dimension dim = frame.getSize();
                dim.height -= 20;
                frame.setSize(dim);
            }
            
        };
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke("W"), "verticalDecrease");
        table.getActionMap().put("verticalDecrease", vd);
        Action vi = new AbstractAction("verticalIncrease") {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                Dimension dim = frame.getSize();
                dim.height += 20;
                frame.setSize(dim);
            }
            
        };
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke("S"), "verticalIncrease");
        table.getActionMap().put("verticalIncrease", vi);
        addStatusComponent(frame, new JLabel("Horizontal Resize: A <--> D "));
        addStatusComponent(frame, new JLabel("Vertical Resize: W <--> S "));
        return frame;
    }


    
    public void interactiveTableRollover() {
        JXTable table = new JXTable(sortableTableModel);
        final CompoundHighlighter compoundHighlighter = new CompoundHighlighter(foregroundHighlighter);
        table.setHighlighters(compoundHighlighter);
        JXFrame frame = wrapWithScrollingInFrame(table, "Table with rollover");
        Action toggleAction = new AbstractAction("toggle foreground/background") {
            boolean isBackground;
            public void actionPerformed(ActionEvent e) {
                if (isBackground) {
                    compoundHighlighter.addHighlighter(foregroundHighlighter);
                    compoundHighlighter.removeHighlighter(backgroundHighlighter);
                } else {
                    compoundHighlighter.addHighlighter(backgroundHighlighter);
                    compoundHighlighter.removeHighlighter(foregroundHighlighter);
                    
                }
                isBackground = !isBackground;
                
            }
            
        };
        addAction(frame, toggleAction);
        frame.setVisible(true);
    }
    
    
    public void interactiveListRollover() {
        final JXList table = new JXList(listModel);
        table.setRolloverEnabled(true);
        final CompoundHighlighter compoundHighlighter = new CompoundHighlighter(foregroundHighlighter);
        table.setHighlighters(compoundHighlighter);
        JXFrame frame = wrapWithScrollingInFrame(table, "List with rollover");
        Action toggleAction = new AbstractAction("toggle foreground/background") {
            boolean isBackground;
            public void actionPerformed(ActionEvent e) {
                if (isBackground) {
                    compoundHighlighter.addHighlighter(foregroundHighlighter);
                    compoundHighlighter.removeHighlighter(backgroundHighlighter);
                } else {
                    compoundHighlighter.addHighlighter(backgroundHighlighter);
                    compoundHighlighter.removeHighlighter(foregroundHighlighter);
                    
                }
                isBackground = !isBackground;
                
            }
            
        };
        addAction(frame, toggleAction);
        frame.setVisible(true);
    }
    
    /**
     * Issue ??: background highlighter not working in JXTree.
     * Not really an issue, works fine with SwingX renderer.
     */
    public void interactiveTreeRollover() {
        final JXTree table = new JXTree(treeTableModel);
        // Note: we need swingx renderer to make some decorations work reliably.
        table.setCellRenderer(new DefaultTreeRenderer());
        table.setRolloverEnabled(true);
        table.setComponentPopupMenu(createPopup());
        final CompoundHighlighter compoundHighlighter = new CompoundHighlighter(foregroundHighlighter);
        table.setHighlighters(compoundHighlighter);
        JTree tree = new JTree(treeTableModel);
        tree.setComponentPopupMenu(createPopup());
        JXFrame frame = wrapWithScrollingInFrame(table, tree, "JXTree (at left) with rollover");
        Action toggleAction = new AbstractAction("toggle foreground/background") {
            boolean isBackground;
            public void actionPerformed(ActionEvent e) {
                if (isBackground) {
                    compoundHighlighter.addHighlighter(foregroundHighlighter);
                    compoundHighlighter.removeHighlighter(backgroundHighlighter);
                } else {
                    compoundHighlighter.addHighlighter(backgroundHighlighter);
                    compoundHighlighter.removeHighlighter(foregroundHighlighter);
                    
                }
                isBackground = !isBackground;
                
            }
            
        };
        addAction(frame, toggleAction);
        addMessage(frame, "background highlight not working in JXTree (with core renderer)");
        frame.setVisible(true);
    }

    public JPopupMenu createPopup() {
        JPopupMenu popup = new JPopupMenu();
        popup.add("dummy");
        return popup;
    }
    
    public void interactiveTreeTableRollover() {
        final JXTreeTable table = new JXTreeTable(treeTableModel);
        final CompoundHighlighter compoundHighlighter = new CompoundHighlighter(foregroundHighlighter);
        table.setHighlighters(compoundHighlighter);
        JXFrame frame = wrapWithScrollingInFrame(table, "TreeTable with rollover");
        Action toggleAction = new AbstractAction("toggle foreground/background") {
            boolean isBackground;
            public void actionPerformed(ActionEvent e) {
                if (isBackground) {
                    compoundHighlighter.addHighlighter(foregroundHighlighter);
                    compoundHighlighter.removeHighlighter(backgroundHighlighter);
                } else {
                    compoundHighlighter.addHighlighter(backgroundHighlighter);
                    compoundHighlighter.removeHighlighter(foregroundHighlighter);
                    
                }
                isBackground = !isBackground;
                
            }
            
        };
        addAction(frame, toggleAction);
        frame.setVisible(true);
    }

    /**
     * Example for per-cell rollover decoration in JXTreeTable.
     */
    public void interactiveTreeTableRolloverHierarchical() {
        final JXTreeTable table = new JXTreeTable(treeTableModel);
        HighlightPredicate andPredicate = new AndHighlightPredicate(
                new HighlightPredicate.ColumnHighlightPredicate(0),
                HighlightPredicate.ROLLOVER_ROW
                );
        final Highlighter foregroundHighlighter = new ColorHighlighter(andPredicate, null,
                Color.MAGENTA);
        final Highlighter backgroundHighlighter = new ColorHighlighter(andPredicate, Color.YELLOW,
                null);
        table.setHighlighters(foregroundHighlighter);
        JXFrame frame = wrapWithScrollingInFrame(table, "TreeTable with rollover - effect hierarchical column");
        Action toggleAction = new AbstractAction("toggle foreground/background") {
            boolean isBackground;
            public void actionPerformed(ActionEvent e) {
                if (isBackground) {
                    table.setHighlighters(foregroundHighlighter);
                } else {
                    table.setHighlighters(backgroundHighlighter);
                    
                }
                isBackground = !isBackground;
                
            }
            
        };
        addAction(frame, toggleAction);
        frame.setVisible(true);
    }
    

    
    /**
     * Issue #456-swingx: Rollover highlighter not showing while dragging.
     * 
     * Example how to force rollover while dragging (NOT dnd - in that case the visuals
     * are controlled by the dnd mechanism): subclass JXList to install a custom 
     * RolloverProducer
     */
    public void interactiveEnforceRolloverWhileDragging() {
        final JXList list = new JXList(AncientSwingTeam.createNamedColorListModel()) {

            /** 
             * @inherited <p>
             */
            @Override
            protected RolloverProducer createRolloverProducer() {
                ListRolloverProducer producer = new ListRolloverProducer() {

                    /** 
                     * @inherited <p>
                     */
                    @Override
                    public void mouseDragged(MouseEvent e) {
                        super.mouseDragged(e);
                        updateRollover(e, ROLLOVER_KEY, false);
                    }
                    
                };
                return producer;
            }
            
        };
        list.setVisibleRowCount(list.getElementCount());
        list.setRolloverEnabled(true);
        list.addHighlighter(new ColorHighlighter(
                HighlightPredicate.ROLLOVER_ROW, 
                Color.MAGENTA, null, Color.MAGENTA, null));
        
        TransferHandler handler = new TransferHandler() {
            
            /** 
             * @inherited <p>
             */
            @Override
            public boolean canImport(TransferSupport support) {
                return true;
            }
            
        };
        list.setTransferHandler(handler);
        JXFrame frame = wrapWithScrollingInFrame(list, "force Rollover while dragging");
        JTextField textField = new JTextField("just something to drag ...", 40);
        textField.setDragEnabled(true);
        addStatusComponent(frame, textField);
        show(frame);
    }
    
    /**
     * Issue #456-swingx: Rollover highlighter not showing while dragging.
     * 
     * The expected behaviour: 
     * - don't show the xRollover while dragging during a dnd,
     * - update the rollover to the released.
     */
    public void interactiveRolloverWhileDragging() {
        final JXList list = new JXList(AncientSwingTeam.createNamedColorListModel());
        list.setVisibleRowCount(list.getElementCount());
        list.setRolloverEnabled(true);
        list.addHighlighter(new ColorHighlighter(
                HighlightPredicate.ROLLOVER_ROW, 
                Color.MAGENTA, null, Color.MAGENTA, null));

        TransferHandler handler = new TransferHandler() {

            /** 
             * @inherited <p>
             */
            @Override
            public boolean canImport(TransferSupport support) {
                return true;
            }
            
        };
        list.setTransferHandler(handler);
        JXFrame frame = wrapWithScrollingInFrame(list, "rollover and drag-enabled (fake drop)");
        JTextField textField = new JTextField("just something to drag ...", 40);
        textField.setDragEnabled(true);
        addStatusComponent(frame, textField);
        show(frame);
    }
    
    /**
     * Issue #1387-swingx: Rollover click-on-release-after drag.
     * 
     * PENDING JW: what's the expected behaviour?
     */
    public void interactiveRolloverClickAfterDrag() {
        JXList list = new JXList(AncientSwingTeam.createNamedColorListModel());
        list.setVisibleRowCount(list.getElementCount());
        list.setRolloverEnabled(true);
        list.addHighlighter(new ColorHighlighter(
                HighlightPredicate.ROLLOVER_ROW, 
                Color.MAGENTA, null, Color.MAGENTA, null));

        TransferHandler handler = new TransferHandler() {

            /** 
             * @inherited <p>
             */
            @Override
            public boolean canImport(TransferSupport support) {
                return true;
            }
            
        };
        list.setTransferHandler(handler);
        final JXFrame frame = wrapWithScrollingInFrame(list, "release-after-drag must not trigger clicked");
        // rollover-enabled default renderer
        // Note JW: this implicitly changes the cursor to the hand-cursor
        DefaultListRenderer renderer = new DefaultListRenderer() {
            @Override
            public void doClick() {
                JOptionPane.showMessageDialog(frame, "Clicked");
            }
            
            @Override
            public boolean isEnabled() {
                return true;
            }
        };
        list.setCellRenderer(renderer);
        JTextField textField = new JTextField("just something to drag ...", 40);
        textField.setDragEnabled(true);
        addStatusComponent(frame, textField);
        Action action = new AbstractAction("drag into me - am I called on release?") {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                LOG.info("triggered..." + ((Component) e.getSource()).getName());
            }
        };
        JButton button = new JButton(action);
        button.setName("first");
        addStatusComponent(frame, button);
        JButton other = new JButton(action);
        other.setName("second");
        addStatusComponent(frame, other);
        show(frame);
    }
    
    /**
     * Issue #1374-swingx: Rollover click must be disabled if target disabled
     * 
     * Visual test for JXTable, adapted from reporter's test case
     */
    public void interactiveRolloverDisabledClickList() {
        JXList table = new JXList(AncientSwingTeam.createNamedColorListModel());
        table.setEnabled(false);
        table.setRolloverEnabled(true);
        final JXFrame frame = showWithScrollingInFrame(table, "disable list must not trigger rollover renderer");
        // rollover-enabled default renderer
        DefaultListRenderer renderer = new DefaultListRenderer() {
            @Override
            public void doClick() {
                JOptionPane.showMessageDialog(frame, "Click");
            }
            
            @Override
            public boolean isEnabled() {
                return true;
            }
        };
        table.setCellRenderer(renderer);
        addEnabledToggle(frame, table);
    }
    
    /**
     * Issue #1374-swingx: Rollover click must be disabled if target disabled
     * 
     * Visual test for JXTable, adapted from reporter's test case
     */
    public void interactiveRolloverDisabledClickTree() {
        JXTree table = new JXTree();
        table.setEnabled(false);
        table.setRolloverEnabled(true);
        final JXFrame frame = showWithScrollingInFrame(table, "disable tree must not trigger rollover renderer");
        // rollover-enabled default renderer
        DefaultTreeRenderer renderer = new DefaultTreeRenderer() {
            @Override
            public void doClick() {
                JOptionPane.showMessageDialog(frame, "Click");
            }
            
            @Override
            public boolean isEnabled() {
                return true;
            }
        };
        table.setCellRenderer(renderer);
        addEnabledToggle(frame, table);
    }
    
    
    /**
     * Issue #1374-swingx: Rollover click must be disabled if target disabled
     * 
     * Visual test for JXTable, adapted from reporter's test case
     */
    public void interactiveRolloverDisabledClickTable() {
        JXTable table = new JXTable(new AncientSwingTeam());
        table.setEditable(false);
        table.setEnabled(false);
        final JXFrame frame = showWithScrollingInFrame(table, "disable table must not trigger rollover renderer");
        // rollover-enabled default renderer
        DefaultTableRenderer renderer = new DefaultTableRenderer() {
            @Override
            public void doClick() {
                JOptionPane.showMessageDialog(frame, "Click");
            }
            
            @Override
            public boolean isEnabled() {
                return true;
            }
        };
        table.setDefaultRenderer(Object.class, renderer);
        addEnabledToggle(frame, table);
    }
    
    @Override
    protected void setUp() throws Exception {
        super.setUp();
        sortableTableModel = new AncientSwingTeam();
        listModel = new AbstractListModel() {

            public int getSize() {
                return sortableTableModel.getRowCount();
            }

            public Object getElementAt(int index) {
                return sortableTableModel.getValueAt(index, 0);
            }
            
        };
        treeTableModel = new FileSystemModel();
        foregroundHighlighter = new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, null,
                Color.MAGENTA);
        backgroundHighlighter = new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, Color.YELLOW,
                null);
     }
    

}
