swingx-master/swingx-core/src/test/java/org/jdesktop/swingx/JXTableHeaderVisualCheck.java
/*
 * Created on 09.06.2006
 *
 */
package org.jdesktop.swingx;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.util.logging.Logger;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.border.Border;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

import org.jdesktop.swingx.decorator.BorderHighlighter;
import org.jdesktop.swingx.renderer.DefaultTableRenderer;
import org.jdesktop.swingx.table.TableColumnExt;
import org.jdesktop.test.AncientSwingTeam;

/**
 * Interactive "test" methods for <code>JXTableHeader</code>.
 * 
 * @author Jeanette Winzenburg
 */
public class JXTableHeaderVisualCheck extends InteractiveTestCase {
    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(JXTableHeaderVisualCheck.class.getName());
    
    public static void main(String args[]) {
        JXTableHeaderVisualCheck test = new JXTableHeaderVisualCheck();
        try {
//          test.runInteractiveTests();
//            test.runInteractiveTests("interactive.*DoubleSort.*");
//            test.runInteractive("ColumnToolTip");
            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() {
        JXTable table = new JXTable(new AncientSwingTeam());
        table.setColumnSelectionAllowed(true);
        JXTableHeader header = (JXTableHeader) table.getTableHeader();
        JPopupMenu popup = new JPopupMenu();
        Action action = new AbstractAction("cell found in actionPerformed") {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                JXTableHeader table = SwingXUtilities.getAncestor(JXTableHeader.class, (Component) e.getSource());
                Point trigger = table.getPopupTriggerLocation();
                Point cell = null;
                if (trigger != null) {
                    int column = table.columnAtPoint(trigger);
                    table.getColumnModel().getSelectionModel().setSelectionInterval(column, column);
                    cell = new Point(column, -1);
                } else {
                    table.getColumnModel().getSelectionModel().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?
//                JXTable table = SwingXUtilities.getAncestor(JXTable.class, 
//                        (Component) e.getSource());
                JXTableHeader table = (JXTableHeader) ((JPopupMenu) e.getSource()).getInvoker();
                Point trigger = table.getPopupTriggerLocation();
                Point cell = null;
                if (trigger != null) {
                    int column = table.columnAtPoint(trigger);
                    // here we set the cell focus, just to do a bit differently
                    // from the other action
//                    table.setColumnSelectionInterval(column, column);
//                    table.clearSelection();
                    cell = new Point(column, -1);
                }
                onShowing.putValue(Action.NAME, "popupTrigger/cell " + trigger + "/" + cell);
            }
            
            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
            }
            
            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
            }
        };
        popup.addPopupMenuListener(l);
        header.setComponentPopupMenu(popup);
        showWithScrollingInFrame(table, "PopupTriggerLocation");
    }
    

    
    /**
     * Issue 1560-swingx: column tooltip not working in stand-alone header
     * 
     */
    public void interactiveColumnToolTip() {
        JXTable table = new JXTable(new AncientSwingTeam());
        for (TableColumn column : table.getColumns()) {
            ((TableColumnExt) column).setToolTipText("tip: "
                    + column.getHeaderValue());
            
        }
        JXTableHeader header = new JXTableHeader(table.getColumnModel());
        JXFrame frame = wrapWithScrollingInFrame(table, "columnToolTip");
        frame.add(header, BorderLayout.NORTH);
        show(frame);
    }
    
    
    /**
     * Issue 1558-swingx: support custom column tooltip mechanism
     * 
     * The use-case is a dynamic, tableModel-backed tooltip:
     * needs subclassing of header which should not need duplication
     * of column look-up 
     */
    public void interactiveColumnToolTipCustom() {
        JXTable table = new JXTable(new ModelWithToolTip());
        JXTableHeader header = new JXTableHeader(table.getColumnModel()) {

            @Override
            protected String getColumnToolTipText(TableColumnExt column) {
                TableModel model = getTable().getModel();
                if (model instanceof ModelWithToolTip) {
                    return ((ModelWithToolTip) model).getColumnToolTip(column.getModelIndex());
                }
                return model.getColumnName(column.getModelIndex());
            }
            
        };
        DefaultTableCellRenderer r = new DefaultTableCellRenderer() {

            Border padding = BorderFactory.createEmptyBorder(0, 10, 0, 10);
            @Override
            public Component getTableCellRendererComponent(JTable table,
                    Object value, boolean isSelected, boolean hasFocus,
                    int row, int column) {
                super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
                        row, column);
                setBorder(BorderFactory.createCompoundBorder(getBorder(), padding));
                return this;
            }
             
        };
        table.setDefaultRenderer(Object.class, r);
        DefaultTableRenderer renderer = (DefaultTableRenderer) table.getDefaultRenderer(Number.class);
        renderer.getComponentProvider().getRendererComponent(null).setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
        BorderHighlighter hl = new BorderHighlighter(BorderFactory.createEmptyBorder(0, 10, 0, 10));
        hl.setInner(true);
        table.addHighlighter(hl);
        table.setTableHeader(header);
        JXFrame frame = wrapWithScrollingInFrame(table, "custom columnToolTip");
        show(frame);
    }

    /**
     * Issue #1558-swing: model-based column tooltip
     */
    public static class ModelWithToolTip extends AncientSwingTeam {
        
        public String getColumnToolTip(int column) {
            return "model-tip: " + getColumnName(column);
        }
    }
    
    /**
     * Issue #271-swingx: optionally support double sort on double click.
     * 
     */
    public void interactiveDoubleSort() {
        JXTable table = new JXTable(30, 5);
        showWithScrollingInFrame(table, "support double sort on double click");
    }
    
    /**
     * Issue #1225-swingx: JXTableHeader throws on rowSorters which are not
     *   of type SortController when resizing columns with mouse.
     */
    public void interactiveHeaderCoreRowSorter() {
        JXTable table = new JXTable(30, 5);
        table.setAutoCreateRowSorter(false);
        table.setRowSorter(new TableRowSorter<TableModel>(table.getModel()));
        showWithScrollingInFrame(table, "core resize columns with mouse");
    }
    /**
     * Issue #683-swingx: Autoscroll if column dragged outside.
     * 
     */
    public void interactiveHeaderAutoScrollRToL() {
        JXTable table = new JXTable(20, 30);
        table.setColumnControlVisible(true);
        table.setVisibleColumnCount(6);
        assertTrue(table.getAutoscrolls());
        table.getTableHeader().setAutoscrolls(true);
        assertTrue(table.getTableHeader().getAutoscrolls());
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        JXFrame frame = showWithScrollingInFrame(table, "autoScroll column drag - RToL");
        frame.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    }

    /**
     * Issue #683-swingx: Autoscroll if column dragged outside.
     * 
     */
    public void interactiveHeaderAutoScroll() {
        JXTable table = new JXTable(20, 30);
        table.setColumnControlVisible(true);
        table.setVisibleColumnCount(6);
        assertTrue(table.getAutoscrolls());
        table.getTableHeader().setAutoscrolls(true);
        assertTrue(table.getTableHeader().getAutoscrolls());
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        JXFrame frame = showWithScrollingInFrame(table, "autoScroll column drag - LToR");
        frame.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
    }
    
    /**
     * Issue #683-swingx: Autoscroll if column dragged outside.
     * Plain ol' JTable - core bug 6503981
     */
    public void interactiveHeaderAutoScrollCoreIssue() {
        JTable table = new JXTable(20, 30);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        JXFrame frame = showWithScrollingInFrame(table, "core bug 1.6 before u4 - scroll to last column and drag");
        frame.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
        frame.setSize(400, 400);
    }
    
    /**
     * Issue #485-swingx: table header disappears if all header values are
     * empty. Compare core <--> JXTable
     * fixed for SwingX.
     *
     */
    public void interactiveHeaderSizeRequirements() {
        
        final String[] alternate = { 
                null, 
                null, 
                };
        final JTable table = new JTable(10, 2);
        table.getColumnModel().getColumn(0).setHeaderValue(alternate[0]);
        table.getColumnModel().getColumn(1).setHeaderValue(alternate[1]);
        
        JXTable xTable = new JXTable(10, 2);
        xTable.getColumn(0).setHeaderValue(alternate[0]);
        xTable.getColumn(1).setHeaderValue(alternate[1]);
        
        JXFrame frame = wrapWithScrollingInFrame(table, xTable, "header height empty (core - xtable)");
        frame.setVisible(true);
        
    }

    /**
     * Issue #390-swingx: JXTableHeader: throws AIOOB on removing dragged column.
     * 
     */
    public void interactiveDraggedColumnRemoved() {
        final JXTable table = new JXTable(10, 5);
        Action deleteColumn = new AbstractAction("deleteCurrentColumn") {

            @Override
            public void actionPerformed(ActionEvent e) {
                TableColumn column = table.getTableHeader().getDraggedColumn();
                if (column == null) return;
                table.getColumnModel().removeColumn(column);
            }
            
        };
        KeyStroke keyStroke = KeyStroke.getKeyStroke("F1");
        table.getInputMap(JTable.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "f1");
        table.getActionMap().put("f1", deleteColumn);
        JXFrame frame = wrapWithScrollingInFrame(table, "Remove dragged column with F1");
        frame.setVisible(true);
    }
    /**
     * Visual demo that header is always visible.
     */
    public void interactiveHeaderVisible() {
        final JXTable table = new JXTable();
        table.setColumnControlVisible(true);
        JXFrame frame = wrapWithScrollingInFrame(table, "header always visible");
        Action action = new AbstractAction("toggle model") {

            @Override
            public void actionPerformed(ActionEvent e) {
                int columnCount = table.getColumnCount(true);
                table.setModel(columnCount > 0 ?
                        new DefaultTableModel() : new DefaultTableModel(10, 2));
            }
            
        };
        addAction(frame, action);
        frame.setVisible(true);
        
    }

    /**
     * do nothing test - keep the testrunner happy.
     */
    public void testDummy() {
    }

}
