swingx-master/swingx-core/src/test/java/org/jdesktop/swingx/JXTreeTableVisualCheck.java
/*
 * $Id$
 * 
 * Copyright 2004 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;


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.CellEditor;
import javax.swing.DefaultCellEditor;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.jdesktop.swingx.action.AbstractActionExt;
import org.jdesktop.swingx.decorator.AbstractHighlighter;
import org.jdesktop.swingx.decorator.BorderHighlighter;
import org.jdesktop.swingx.decorator.ColorHighlighter;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.decorator.HighlightPredicate;
import org.jdesktop.swingx.decorator.HighlightPredicate.AndHighlightPredicate;
import org.jdesktop.swingx.decorator.HighlightPredicate.ColumnHighlightPredicate;
import org.jdesktop.swingx.decorator.HighlightPredicate.DepthHighlightPredicate;
import org.jdesktop.swingx.decorator.Highlighter;
import org.jdesktop.swingx.decorator.HighlighterFactory;
import org.jdesktop.swingx.decorator.PatternPredicate;
import org.jdesktop.swingx.decorator.ShadingColorHighlighter;
import org.jdesktop.swingx.renderer.DefaultTreeRenderer;
import org.jdesktop.swingx.table.ColumnFactory;
import org.jdesktop.swingx.table.TableColumnExt;
import org.jdesktop.swingx.test.ComponentTreeTableModel;
import org.jdesktop.swingx.test.TreeTableHelper;
import org.jdesktop.swingx.test.TreeTableHelper.PostOrder;
import org.jdesktop.swingx.test.XTestUtils;
import org.jdesktop.swingx.treetable.AbstractTreeTableModel;
import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;
import org.jdesktop.swingx.treetable.FileSystemModel;
import org.jdesktop.swingx.treetable.TreeTableModel;
import org.jdesktop.swingx.treetable.TreeTableModelProvider;
import org.jdesktop.test.AncientSwingTeam;

/**
 * @author Jeanette Winzenburg
 */
public class JXTreeTableVisualCheck extends JXTreeTableUnitTest {
    @SuppressWarnings("all")
    private static final Logger LOG = Logger
            .getLogger(JXTreeTableVisualCheck.class.getName());
    public static void main(String[] args) {
        // NOTE JW: this property has be set "very early" in the application life-cycle
        // it's immutable once read from the UIManager (into a final static field!!)
//        System.setProperty("sun.swing.enableImprovedDragGesture", "true" );
//        setSystemLF(true);
        JXTreeTableVisualCheck test = new JXTreeTableVisualCheck();
        try {
//            test.runInteractiveTests();
//            test.runInteractiveTests("interactive.*Hierarchical.*");
            test.runInteractiveTests("interactive.*HierarchicalToolTip.*");
               test.runInteractive("Rollover");
//               test.runInteractiveTests("interactive.*DnD.*");
//             test.runInteractiveTests("interactive.*ColumnSelection.*");
//             test.runInteractiveTests("interactive.*RowHeightCompare.*");
//             test.runInteractiveTests("interactive.*RToL.*");
//            test.runInteractiveTests("interactive.*ColumnFactory.*");
//             test.runInteractiveTests("interactive.*ScrollPath.*");
//             test.runInteractiveTests("interactive.*Insert.*");
//             test.runInteractiveTests("interactive.*WinP.*");
//            test.runInteractiveTests("interactive.*EditorIcon.*");
//            test.runInteractiveTests("interactive.*ExpandAll.*");
//            test.runInteractiveTests("interactive.*Traversal.*");
//            test.runInteractiveTests("interactive.*Edit.*");
//             test.runInteractiveTests("interactive.*ComboBox.*");
        } catch (Exception ex) {

        }
    }
    /**
     * Issue swingx-1525: borderHighlighter fills tree column completely
     */
    public void interactiveHierarchicalBorderHighlighter() {
        JXTreeTable table = new JXTreeTable(TreeTableHelper.createTreeTableModel(20, 3, 4));
        table.getColumn(0).setPreferredWidth(200);
        table.addHighlighter(new BorderHighlighter(BorderFactory.createLineBorder(Color.RED)));
        showWithScrollingInFrame(table, "borderHighlighter misbehaves in tree column");
    }


    public void interactiveTraversal() {
        JXTree tree = new JXTree();
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
        Enumeration enumer = root.breadthFirstEnumeration();
//        Enumeration<TreeNode> enumer = new PostorderEnumeration(root); //createEnumeration("BreadthFirstEnumeration", root); // root.breadthFirstEnumeration();
//        Enumeration<?> enumer = new PostOrder(tree.getModel(), root); 
       
        int index = 0;
        String text = "";
        int depth = 0;
        TreeNode lastNode = null;
        while (enumer.hasMoreElements()) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) enumer.nextElement();
            text += node.getUserObject();
            node.setUserObject(node.getUserObject() + ": " + index);
            index++;
        }
        LOG.info(text);
//        tree.expandAll();
        showWithScrollingInFrame(tree, "traversal");
    }

    /**
     * Issue 1442-swingx: Performance issue with expand all on large/deep tree/table
     * 
     * Crude measurement on local file system
     * Archiv: about 10k files takes 59/60s to expand w/out hack
     * DevTools: about 25k files takes 19/37s to expand w/out hack
     * 
     * - effect seems highly dependent on exact nature
     * - hack is potentially risky: interfers with state synch of ui
     * - if expansion takes long, it must be done on background thread with
     *    logic that reasonably reports back to the EDT (supporting that
     *    would be a worthwhile task, contributions/ideas welcome)
     */
    public void interactiveExpandAll() {
//        final TreeTableModel model = new FileSystemModel(new File("D:/DevTools"));
        final TreeTableModel model = TreeTableHelper.createTreeTableModel(20, 3, 4);
        final JXTree tree = new JXTree(model);
        final JXTreeTable table = new JXTreeTable((TreeTableModel) tree.getModel());
        JXFrame frame = wrapWithScrollingInFrame(tree, table, "expandAll");
        Action traversTree = new AbstractAction("traverse") {

            @Override
            public void actionPerformed(ActionEvent e) {
//                Enumeration enumer = new PostorderEnumeration((TreeNode) model.getRoot());
                Enumeration<?> enumer = new PostOrder(model, model.getRoot());
                int count = 0;
                while (enumer.hasMoreElements()) {
                    enumer.nextElement();
                    count++;
                }
                LOG.info("traversed: " + count);
            }
            
        };
        addAction(frame, traversTree);
        Action action = new AbstractAction("expand tree") {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                tree.setVisible(false);
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        
                        tree.expandAll();
                        tree.setVisible(true);
                        LOG.info("expanded: " + tree.getRowCount());
                    }
                });
            }
        };
        addAction(frame, action);
        Action expandTable = new AbstractAction("expand treetable") {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                LOG.info("before: " + table.getRowCount());
                table.setVisible(false);
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        
                table.expandAll();
                table.setVisible(true);
                LOG.info("expanded: " + table.getRowCount());
                    }
                });
            }
        };
        addAction(frame, expandTable);
        show(frame);
    }

    /**
     * Issue #1379-swingx: support access to underlying treeTableModel of TreeTableModelAdapter.
     * 
     * Needed f.i. in a custom ColumnFactory to configure the hierarchical column specifically.
     */
    public void interactiveCustomColumnFactory() {
        JXTreeTable table = new JXTreeTable();
        ColumnFactory factory = new ColumnFactory() {

            /** 
             * @inherited <p>
             */
            @Override
            public void configureTableColumn(TableModel model,
                    TableColumnExt columnExt) {
                super.configureTableColumn(model, columnExt);
                if (model instanceof TreeTableModelProvider) {
                    TreeTableModel treeTableModel = ((TreeTableModelProvider) model).getTreeTableModel();
                    if (treeTableModel.getHierarchicalColumn() == columnExt.getModelIndex()) {
                        columnExt.setTitle("Hierarchical: " + columnExt.getTitle());
                    }
                }
            }
        };
        table.setColumnFactory(factory);
        table.setTreeTableModel(new FileSystemModel());
        showWithScrollingInFrame(table, "custom columnFactory");
    }
    
    /**
     * Issue #1126: combo editor is closed immediately after starting
     * 
     * Happens if row is not selected at the moment of starting, okay if selected.
     * Inserts on pressed, removes on released. Same for 1.5 and 1.6
     * 
     * Problem was hacker's completeEditing: must only jump in if editing the hierarchical
     * column. Which still leaves the problem if combo editing in hierarchical ... but
     * that's a different issue ... 
     * 
     * Back to start: fix introduced regression on expand/collapse
     */
    public void interactiveEditWithComboBox() {
        // quick for having an editable treeTableModel (non hierarchical column)
        TreeTableModel model = createEditableTreeTableModel();
        JXTreeTable treeTable = new JXTreeTable(model) {

            @Override
            public void removeEditor() {
                // TODO Auto-generated method stub
                super.removeEditor();
            }
            
        };
//        treeTable.setExpandsSelectedPaths(false);
        treeTable.expandAll();
        JComboBox box = new JComboBox(new Object[] {200, 300, 400});
        box.setEditable(true);
        treeTable.getColumn(3).setCellEditor(new DefaultCellEditor(box));
        JTable table = new JXTable(treeTable.getModel());
        JComboBox box2 = new JComboBox(new Object[] {200, 300, 400});
        box2.setEditable(true);
        table.getColumnModel().getColumn(3).setCellEditor(new DefaultCellEditor(box2));
        showWithScrollingInFrame(treeTable, table, "combo editor in column 3");
    }


    /**
     * @return
     */
    private ComponentTreeTableModel createEditableTreeTableModel() {
        JXFrame frame = new JXFrame();
        addStatusMessage(frame, "sometext");
        addStatusMessage(frame, "sometext");
        addStatusMessage(frame, "sometext");
        addStatusMessage(frame, "sometext");
        addStatusMessage(frame, "sometext");
        return new ComponentTreeTableModel(frame);
    }
    

    /**
     * Issue #875-swingx: cell selection incorrect in hierarchical column.
     * 
     */
    public void interactiveColumnSelection() {
        final JXTreeTable treeTable = new JXTreeTable(new FileSystemModel());
        treeTable.setColumnSelectionAllowed(true);
        final JTable table = new JTable(new AncientSwingTeam());
        table.setColumnSelectionAllowed(true);
        JXFrame frame = wrapWithScrollingInFrame(treeTable, table, "columnSelection in treetable");
        Action action = new AbstractActionExt("Toggle dnd: false") {

            @Override
            public void actionPerformed(ActionEvent e) {
                
                boolean dragEnabled = !treeTable.getDragEnabled();
                treeTable.setDragEnabled(dragEnabled);
                table.setDragEnabled(dragEnabled);
                setName("Toggle dnd: " + dragEnabled);
            }
            
        };
        addAction(frame, action);
        show(frame);
    }

    /**
     * Performance problems with Windows LAF.
     */
    public void interactiveTreeTableWinPerformance() {
        JXTreeTable table = new JXTreeTable(new SimpleTestModel());
        showWithScrollingInFrame(table, "JXTreeTable (performance in win");
    }
    public static class SimpleTestModel extends AbstractTreeTableModel {
        private static final String root = "Root";
 
        public SimpleTestModel() {
            super(root);
        }
 
        @Override
        public int getColumnCount() {
            return 4;
        }
 
        @Override
        public Object getValueAt(Object o, int i) {
            return o + ":" + i;
        }
 
        @Override
        public Object getChild(Object parent, int index) {
            return parent == root ? String.valueOf(index) : null;
        }
 
        @Override
        public int getChildCount(Object parent) {
            return parent == root ? 10000 : 0;
        }
 
        @Override
        public int getIndexOfChild(Object parent, Object child) {
            return parent == root ? Integer.valueOf((String) child) : -1;
        }
    }



    
    /**
     * Issue #730-swingx: editor's stop not always called.
     * 
     *  - start edit a cell in the hierarchical column, 
     *  - click into another cell of the hierarchical column
     *  - edit sometimes canceled instead of stopped 
     *  
     *  seems to happen if click into text of cell, okay if outside.
     *  Trying to fix in TreeTableHacker: first try to stop editing
     *  cancel if unsuccessful. 
     *  
     *  PENDING JW: why didn't we do that in the first place? Any
     *  possibility that the edit will end up in the wrong node
     *  in expand/collapse?
     *  
     *  Okay, checked again: the cancel is needed because otherwise
     *  the edited value might end up in the wrong row, that is the
     *  one after the currently edited if the parent of the edited
     *  is collapsed while editing (old issue #120-jdnc).
     *  
     *  To fight the regression, the hacker's completeEditing now is
     *  called before updating renderer's (tree) expansion state. Seems
     *  to fix both issues now. 
     */
    public void interactiveEditingCanceledStopped() {
        final JTextField field = new JTextField();
        DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode("ROOT");
        DefaultMutableTreeTableNode a = new DefaultMutableTreeTableNode("A");
        DefaultMutableTreeTableNode a1 = new DefaultMutableTreeTableNode("A1");
        DefaultMutableTreeTableNode b = new DefaultMutableTreeTableNode("B");
        a.add(a1);
        root.add(a);
        root.add(b);
        // default table: hack around #120-jdnc introduces #730
        final JXTreeTable xTable = new JXTreeTable();
        xTable.setTreeTableModel(new DefaultTreeTableModel(root));
        xTable.expandAll();
        xTable.setVisibleColumnCount(10);
        xTable.packColumn(0, -1);
        CellEditor editor = xTable.getCellEditor(0, 0);
        CellEditorListener l =  new CellEditorListener() {

            @Override
            public void editingCanceled(ChangeEvent e) {
                field.setText("canceled");
                LOG.info("canceled");
            }

            @Override
            public void editingStopped(ChangeEvent e) {
                field.setText("stopped");
                LOG.info("stopped");
                
            }};
        editor.addCellEditorListener(l);
        JXFrame frame = wrapWithScrollingInFrame(xTable, "#730-swingx: click sometimes cancels");
        Action toggleExpansion = new AbstractAction("toggle") {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                boolean isExpanded = xTable.isExpanded(0);
                if (isExpanded) {
                     xTable.collapseRow(0);
                } else {
                    xTable.expandRow(0);
                }
                
            }
            
        };
        KeyStroke stroke = KeyStroke.getKeyStroke("F1");
        xTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(stroke, "toggleExpansion");
        xTable.getActionMap().put("toggleExpansion", toggleExpansion);
        frame.add(field, BorderLayout.SOUTH);
        addStatusMessage(frame, "F1 to toggle expansion of first row");
        show(frame);
    }


    
    /**
     * Issue #862-swingx: JXTree - add api for selection colors.
     * Here: check colors when used in JXTreeTable
     */
    public void interactiveSelectionColors() {
        final JXTreeTable tree = new JXTreeTable(new FileSystemModel());
        // use SwingX renderer which is aware of per-tree selection colors
        tree.setTreeCellRenderer(new DefaultTreeRenderer());
        final Color uiBackground = tree.getSelectionBackground();
        final Color uiForeground = tree.getSelectionForeground();
        Action toggleSelectionColors = new AbstractAction("toggle selection colors") {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                if (tree.getSelectionBackground() == uiBackground) {
                    tree.setSelectionBackground(Color.BLUE);
                    tree.setSelectionForeground(Color.RED);
                } else {
                    tree.setSelectionBackground(uiBackground);
                    tree.setSelectionForeground(uiForeground);
                }
                
            }
            
        };
        JXFrame frame = wrapWithScrollingInFrame(tree, "selection colors");
        addAction(frame, toggleSelectionColors);
        show(frame);
    }
    

    
    /**
     * Issue #853-swingx: tree is not disabled.
     * 
     */
    public void interactiveDisabledTreeColumn() {
        final JXTreeTable treeTable = new JXTreeTable(new FileSystemModel());
        JXFrame frame = showWithScrollingInFrame(treeTable, "disabled - tree follows table");
        Action action = new AbstractActionExt("toggle enabled") {

            @Override
            public void actionPerformed(ActionEvent e) {
                treeTable.setEnabled(!treeTable.isEnabled());
                
            }
            
        };
        addAction(frame, action);
        show(frame);
        
    }

    
    /**
     * Reported: toggling LAF doesn't update treetable?
     * WorksforMe.
     */
    public void interactiveToggleLAF() {
        JXTreeTable table = new JXTreeTable(treeTableModel);
        JXFrame frame = wrapInFrame(new JScrollPane(table), "Toggle LAF", true);
        show(frame);
    }
    
    /**
     * Issue #1554-swingx: cell rollover highlight broken on expand/collapsed
     * <p>
     * 
     * Rollover highlight stuck to the row that was expanded until exiting the
     * comp altogether. Reported and verified against 1.6.4. 
     * 
     * Seems to be fixed as a side-effect of fixing #1527-swingx, works fine 
     * in 1.6.5+
     */
    public void interactiveRolloverHighlighter() {
        final JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setHighlighters( new ColorHighlighter( HighlightPredicate.ROLLOVER_CELL, Color.ORANGE, null ) );
        showWithScrollingInFrame(treeTable, "cellrollover broken on expandj");
    }
    

    
    /**
     * Issue #??-swingx: Tooltip by highlighter in hierarchical column
     * 
     * Issue #1527-swingx: tooltip not shown after changing expansion state.
     *
     * Not reliably updated (independent on whether to use a Highlighter or core renderer
     * with Highlighter set, also @see {@link #interactiveTestToolTipsCoreRenderer()}
     * 
     * To reproduce: 
     * - move to some row over the hierarchical column where the tooltip is showing
     * - move the next row, typically the tooltip is not showing (no, can't reproduce)
     * - reproducible (from bug report): collapse/expand the row, then move (in same or 
     * other row): tooltip not shown until the mouse has been moved completely outside
     * of the table
     * 
     * Seems to happen, if the tooltip was hidden due to the collapse/expose. To reproduce
     * - move to show the tooltip in hierarchical column
     * - wait until it is hidden by the tooltipManager
     * - collapse/expand and move: tooltip shown again
     * 
     */
    public void interactiveHierarchicalToolTip() {
        ToolTipManager manager = ToolTipManager.sharedInstance();
        final JXTreeTable table = new JXTreeTable(treeTableModel);
        Highlighter toolTip = new AbstractHighlighter(
                new AndHighlightPredicate(
                new ColumnHighlightPredicate(0), HighlightPredicate.ROLLOVER_ROW)) {

            @Override
            protected Component doHighlight(Component component,
                    ComponentAdapter adapter) {
                ((JComponent) component).setToolTipText(adapter.getString());
                return component;
            }
            
        };
        table.addHighlighter(toolTip);
        JXFrame frame = wrapWithScrollingInFrame(table, "ToolTip with Highlighter (hierarchical column)");
        addComponentOrientationToggle(frame);
        addStatusComponent(frame, new JTextField("something to focus"));
        frame.setVisible(true);
    }
  
    /**
     * Issue #544-swingx: problem with simple striping in JXTreeTable.
     * start with cross-platform == okay, bluish striping
     * toggle to system (win) == striping color silver, 
     *   but second row bluish, background not reset?
     * toggle back to cross-platform == no striping, all bluish
     * 
     * start with system (win) == okay, silver striping
     * toggle to cross-platform == okay, bluish striping
     * back to system == trouble as above
     * 
     * JXTable looks okay.
     */
    public void interactiveUIHighlight() {
        JXTable table = new JXTable(20, 4);
        JXTreeTable treeTable = new JXTreeTable(new FileSystemModel());
        treeTable.setHighlighters(HighlighterFactory.createSimpleStriping());
        table.setHighlighters(treeTable.getHighlighters());
        final JXFrame frame = wrapWithScrollingInFrame(treeTable, table, "update ui-specific striping");
        Action toggle = new AbstractActionExt("toggle LF") {
            boolean system;
            @Override
            public void actionPerformed(ActionEvent e) {
                String lfName = system ? UIManager.getSystemLookAndFeelClassName() :
                    UIManager.getCrossPlatformLookAndFeelClassName();
                try {
                    UIManager.setLookAndFeel(lfName);
                    SwingUtilities.updateComponentTreeUI(frame);
                 } catch (Exception e1) { 
                     LOG.info("exception when setting LF to " + lfName);
                     LOG.log(Level.FINE, "caused by ", e1);
                } 
                system = !system; 
                
            }
            
        };
        addAction(frame, toggle);
        frame.setVisible(true);
    }
    

    /**
     * Issue #471-swingx: No selection on click into hierarchical column outside
     * node. 
     *
     * Check patch and bidi-compliance.
     */
    public void interactiveHierarchicalSelectionAndRToL() {
        final JXTreeTable table = new JXTreeTable(treeTableModel);
        final JXFrame frame = wrapWithScrollingInFrame(table, "Selection/Expansion Hacks and Bidi Compliance");
        addComponentOrientationToggle(frame);
        frame.setVisible(true);
    }

    
    /**
     * visual check what happens on toggling the largeModel property.
     * It's okay for ComponentTreeModel, blows up for FileSystemModel.
     *
     */
    public void interactiveLargeModel() {
        final JXTreeTable treeTable = new JXTreeTable(createMutableVisualizeModel());
        treeTable.setRootVisible(true);
        ToolTipManager.sharedInstance().unregisterComponent(treeTable);
        Action action = new AbstractAction("toggle largeModel") {

            @Override
            public void actionPerformed(ActionEvent e) {
                treeTable.setLargeModel(!treeTable.isLargeModel());
               
            }
            
        };
        JXFrame frame = wrapWithScrollingInFrame(treeTable, "large model");
        addAction(frame, action);
        frame.setVisible(true);
    }

    private ComponentTreeTableModel createMutableVisualizeModel() {
        JXPanel frame = new JXPanel();
        frame.setName("somename for root");
        JTextField textField = new JTextField();
        textField.setName("firstchild");
        frame.add(textField);
        JComponent box = Box.createVerticalBox();
        box.setName("dumyybox");
        frame.add(box);
        JComponent inner = Box.createHorizontalBox();
        inner.setName("inner");
        box.add(inner);
        inner.add(new JButton());
        inner.add(new JXFindPanel());
        frame.add(new JComboBox());
        frame.add(new JXDatePicker());
        
        return new ComponentTreeTableModel(frame);
    }

    /**  
     * Issue #575-swingx: JXTreeTable - scrollsOnExpand has no effect.
     * 
     * Compare tree/table: 
     * - tree expands if property is true and
     * expand triggered by mouse (not programmatically?). 
     * - treeTable never 
     * 
     * 
     * related issue #296-swingx: expose scrollPathToVisible in JXTreeTable.
     */    
    public void interactiveScrollPathTreeExpand() {
        
        final JXTreeTable treeTable = new JXTreeTable(new FileSystemModel());
        final JXTree tree = new JXTree(treeTable.getTreeTableModel());
        treeTable.setScrollsOnExpand(tree.getScrollsOnExpand());
        tree.setRowHeight(treeTable.getRowHeight());
        Action toggleScrolls = new AbstractAction("Toggle Scroll") {

            @Override
            public void actionPerformed(ActionEvent e) {
                tree.setScrollsOnExpand(!tree.getScrollsOnExpand());
                treeTable.setScrollsOnExpand(tree.getScrollsOnExpand());
            }
            
        };
         Action expand = new AbstractAction("Expand") {

            @Override
            public void actionPerformed(ActionEvent e) {
                int[] selectedRows = tree.getSelectionRows();
                if (selectedRows.length > 0) {
                    tree.expandRow(selectedRows[0]);
                }
               int selected = treeTable.getSelectedRow();
               if (selected >= 0) {
                   treeTable.expandRow(selected);
               }
            }
            
        };
 
        JXFrame frame = wrapWithScrollingInFrame(tree, treeTable,
                "Compare Tree/Table expand properties ");
        addAction(frame, toggleScrolls);
        addAction(frame, expand);
        frame.setVisible(true);
    }


    /**
     * issue #296-swingx: expose scrollPathToVisible in JXTreeTable.
     * 
     * Treetable should behave exactly like Tree - so
     * simply passing through to the hierarchical renderer is not quite
     * enough - need to force a scrollTo after expanding. 
     * Not really: all scrolling is piped through scrollRectToVisible, 
     * so that looks like the central place to fix (f.i. delegate to
     * the enclosing treeTable). Related issue #575-swingx.
     * 
     * note: the action is not guarded against overshooting
     *  at the end of the model!
     */
    public void interactiveScrollPathToVisible() {
        // PENDING: FileSystemModel throws occasional NPE on getChildCount()
        final TreeTableModel model = new FileSystemModel();
        final JXTreeTable table = new JXTreeTable(model);
        table.setColumnControlVisible(true);
        final JXTree tree = new JXTree(model);
        Action action = new AbstractAction("path visible") {

            @Override
            public void actionPerformed(ActionEvent e) {
                Rectangle visible = table.getVisibleRect();
                int lastRow = table.rowAtPoint(new Point(5, visible.y + visible.height + 100));
                TreePath path = table.getPathForRow(lastRow);
                Object last = path.getLastPathComponent();
                 while (model.isLeaf(last) || model.getChildCount(last) == 0) {
                    lastRow++;
                    path = table.getPathForRow(lastRow);
                    last = path.getLastPathComponent();
                }
                // we have a node with children
                int childCount = model.getChildCount(last); 
                Object lastChild = model.getChild(last, childCount - 1); 
                path = path.pathByAddingChild(lastChild);
                table.scrollPathToVisible(path);
                tree.scrollPathToVisible(path);
                
            }
        };
        JXFrame frame = wrapWithScrollingInFrame(table, tree, "compare scrollPathtovisible");
        addAction(frame, action);
        frame.setVisible(true);

    }

    /**
     * http://forums.java.net/jive/thread.jspa?threadID=13966&tstart=0
     * adjust hierarchical column width on expansion. The expansion
     * listener looks like doing the job. Important: auto-resize off, 
     * otherwise the table will run out of width to distribute!
     * 
     */
    public void interactiveUpdateWidthOnExpand() {
        
        final JXTreeTable tree = new JXTreeTable(treeTableModel);
        tree.setColumnControlVisible(true);
        JTree renderer = (JTree) tree.getCellRenderer(0, tree.getHierarchicalColumn());
        
        renderer.addTreeExpansionListener(new TreeExpansionListener(){

           @Override
        public void treeCollapsed(TreeExpansionEvent event) {
           }

           @Override
        public void treeExpanded(TreeExpansionEvent event) {
              
              final JTree renderer = (JTree)event.getSource();
              
              SwingUtilities.invokeLater(new Runnable(){
                 
                 @Override
                public void run() {
                    tree.getColumnModel().getColumn(0).setPreferredWidth(renderer.getPreferredSize().width);

                 }
              });            
           }
           
        });
        JXFrame frame = wrapWithScrollingInFrame(tree, "adjust column on expand");
        frame.setVisible(true);

    }
    /**
     * visualize editing of the hierarchical column, both
     * in a tree and a treeTable
     *
     */
    public void interactiveTreeTableModelEditing() {
        final TreeTableModel model = createMutableVisualizeModel();
        final JXTreeTable table = new JXTreeTable(model);
        JTree tree =  new JTree(model) {

            @Override
            public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
                if (value instanceof Component) {
                    return ((Component) value).getName();
                }
                return super.convertValueToText(value, selected, expanded, leaf, row, hasFocus);
            }
            
        };
        tree.setEditable(true);
        final JXFrame frame = wrapWithScrollingInFrame(table, tree, "Editing: compare treetable and tree");
        addComponentOrientationToggle(frame);
        frame.setVisible(true);
        
    }


    /**
     * Issue #248-swingx: update probs with insert into empty model when root
     * not visible.
     * 
     * Looks like a core JTree problem: a collapsed root is not automatically expanded
     * on hiding. Should it? Yes, IMO (JW).
     * 
     * this exposed a slight glitch in JXTreeTable: toggling the initially invisible
     * root to visible did not result in showing the root in the the table. Needed
     * to modify setRootVisible to force a revalidate.
     *   
     */
    public void interactiveTestInsertNodeEmptyModel() {
        final DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode();
        final InsertTreeTableModel model = new InsertTreeTableModel(root, true);
        final JTree tree = new JTree(model);
        tree.setRootVisible(false);
        final JXTreeTable treeTable = new JXTreeTable(model);
        treeTable.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER));

        treeTable.setColumnControlVisible(true);
        // treetable root invisible by default
        JXFrame frame = wrapWithScrollingInFrame(tree, treeTable, "JTree vs. JXTreeTable: insert into empty model");
        Action insertAction = new AbstractAction("insert node") {

            @Override
            public void actionPerformed(ActionEvent e) {
                model.addChild(root);
                
            }
            
        };
        addAction(frame, insertAction);
        Action toggleRoot = new AbstractAction("toggle root visible") {
            @Override
            public void actionPerformed(ActionEvent e) {
                boolean rootVisible = !tree.isRootVisible();
                treeTable.setRootVisible(rootVisible);
                tree.setRootVisible(rootVisible);
            }
            
        };
        addAction(frame, toggleRoot);
        addMessage(frame, "model reports root as non-leaf");
        frame.pack();
        frame.setVisible(true);
    }
 
    /**
     * Issue #254-swingx: collapseAll/expandAll behaviour depends on 
     * root visibility (same for treeTable/tree)
     * 
     * initial: root not visible, all root children visible
     *  do: collapse all - has no effect, unexpected?
     *  do: toggle root - root and all children visible, expected
     *  do: collapse all - only root visible, expected
     *  do: toggle root - all nodes invisible, expected
     *  do: expand all - still all nodes invisible, unexpected?
     *  
     *   
     */
    public void interactiveTestInsertNodeEmptyModelExpand() {
        final DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode();
        final InsertTreeTableModel model = new InsertTreeTableModel(root, true);
        for (int i = 0; i < 5; i++) {
            model.addChild(root);
        }
        final JXTree tree = new JXTree(model);
        tree.setRootVisible(false);
        final JXTreeTable treeTable = new JXTreeTable(model);
        treeTable.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER));

        treeTable.setColumnControlVisible(true);
        // treetable root invisible by default
        JXFrame frame = wrapWithScrollingInFrame(tree, treeTable, "collaps/expand root");
        Action toggleRoot = new AbstractAction("toggle root") {
            @Override
            public void actionPerformed(ActionEvent e) {
                boolean rootVisible = !tree.isRootVisible();
                treeTable.setRootVisible(rootVisible);
                tree.setRootVisible(rootVisible);
            }
            
        };
        addAction(frame, toggleRoot);
        Action expandAll = new AbstractAction("expandAll") {
            @Override
            public void actionPerformed(ActionEvent e) {
                treeTable.expandAll();
                tree.expandAll();
            }
            
        };
        addAction(frame, expandAll);
        Action collapseAll = new AbstractAction("collapseAll") {
            @Override
            public void actionPerformed(ActionEvent e) {
                treeTable.collapseAll();
                tree.collapseAll();
            }
            
        };
        addAction(frame, collapseAll);
        frame.setVisible(true);
    }
 

    /**
     * Issue #247-swingx: update probs with insert node.
     * The insert under a collapsed node fires a dataChanged on the table 
     * which results in the usual total "memory" loss (f.i. selection)
     * to reproduce: run example, select root's child in both the tree and the 
     * treetable (left and right view), press the insert button, treetable looses 
     * selection, tree doesn't (the latter is the correct behaviour)
     * 
     * couldn't reproduce the reported loss of expansion state. Hmmm..
     *
     */
    public void interactiveTestInsertUnderCollapsedNode() {
        final DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode();
        final InsertTreeTableModel model = new InsertTreeTableModel(root);
        DefaultMutableTreeTableNode childA = model.addChild(root);
        final DefaultMutableTreeTableNode childB = model.addChild(childA);
        model.addChild(childB);
        DefaultMutableTreeTableNode secondRootChild = model.addChild(root);
        model.addChild(secondRootChild);
        JXTree tree = new JXTree(model);
        final JXTreeTable treeTable = new JXTreeTable(model);
        treeTable.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER));

        treeTable.setColumnControlVisible(true);
        treeTable.setRootVisible(true);
        JXFrame frame = wrapWithScrollingInFrame(tree, treeTable, "JXTree vs. JXTreeTable insert node to nested child");
        Action insertAction = new AbstractAction("insert node") {

            @Override
            public void actionPerformed(ActionEvent e) {
                model.addChild(childB);
           
            }
            
        };
        addAction(frame, insertAction);
        addMessage(frame, "insert nested child must not loose selection/expanseion state");
        frame.pack();
        frame.setVisible(true);
    }

    /**
     * Issue #246-swingx: update probs with insert node.
     * 
     * The reported issue is an asymmetry in updating the parent: it's done only
     * if not expanded. With the arguments of #82-swingx, parent's appearance
     * might be effected by child changes if expanded as well.
     * <p>
     * Here's a test for insert: the crazy renderer removes the icon if
     * childCount exceeds a limit (here > 3). Select a node, insert a child,
     * expand the node and keep inserting children. Interestingly the parent is
     * always updated in the treeTable, but not in the tree
     * <p>
     * Quick test if custom icons provided by the renderer are respected. They
     * should appear and seem to do.
     * 
     */
    public void interactiveTestInsertNodeAndChangedParentRendering() {
        final Icon topIcon = XTestUtils.loadDefaultIcon("wellTop.gif");
        final DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode();
        final InsertTreeTableModel model = new InsertTreeTableModel(root);
        JXTree tree = new JXTree(model);
        final JXTreeTable treeTable = new JXTreeTable(model);
        treeTable.setColumnControlVisible(true);
        TreeCellRenderer renderer = new DefaultTreeCellRenderer() {

            @Override
            public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
                Component comp = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
                        row, hasFocus);
                TreePath path = tree.getPathForRow(row);
                if (path != null) {
                    Object node = path.getLastPathComponent();
                    if ((node != null) && (tree.getModel().getChildCount(node) > 2)) {
                        setIcon(topIcon);
                    } 
                }
                return comp;
            }
            
        };
        tree.setCellRenderer(renderer);
        treeTable.setTreeCellRenderer(renderer);
        treeTable.setRootVisible(true);
        JXFrame frame = wrapWithScrollingInFrame(tree, treeTable, "JXTree vs. JXTreeTable - update parent on insert child");
        Action insertAction = new AbstractAction("insert node selected treetable") {

            @Override
            public void actionPerformed(ActionEvent e) {
                int selected = treeTable.getSelectedRow();
                if (selected < 0 ) return;
                TreePath path = treeTable.getPathForRow(selected);
                DefaultMutableTreeTableNode parent = (DefaultMutableTreeTableNode) path.getLastPathComponent();
                model.addChild(parent);
                
            }
            
        };
        addAction(frame, insertAction);
        addMessage(frame, " - rendering changed for > 2 children");
        frame.pack();
        frame.setVisible(true);
    }
 
    /**
     * Issue #82-swingx: update probs with insert node.
     * 
     * Adapted from example code in report.
     * Insert node under selected in treetable (or under root if none selected)
     * Here: old problem with root not expanded because it's reported as a leaf.
     */
    public void interactiveTestInsertNode() {
        final DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode();
        final InsertTreeTableModel model = new InsertTreeTableModel(root);
        JTree tree = new JTree(model);
        tree.setRootVisible(false);
        final JXTreeTable treeTable = new JXTreeTable(model);
        treeTable.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.GENERIC_GRAY));
        Highlighter hl = new ShadingColorHighlighter(
                new ColumnHighlightPredicate(0));

        treeTable.addHighlighter(hl);
        JXFrame frame = wrapWithScrollingInFrame(tree, treeTable, "JTree vs. JXTreeTable - insert to collapsed root");
        Action insertAction = new AbstractAction("insert node") {

            @Override
            public void actionPerformed(ActionEvent e) {
                int selected = treeTable.getSelectedRow();
                DefaultMutableTreeTableNode parent;
                if (selected < 0 ) {
                    parent = root;
                } else {
                TreePath path = treeTable.getPathForRow(selected);
                 parent = (DefaultMutableTreeTableNode) path.getLastPathComponent();
                }
                model.addChild(parent);
                
            }
            
        };
        addAction(frame, insertAction);
        addMessage(frame, "insert into root-only model - does not show");
        frame.pack();
        frame.setVisible(true);
    }
 

    /**
     * Issue #224-swingx: TreeTableEditor not bidi compliant.
     *
     * the textfield for editing is at the wrong position in RToL.
     */
    public void interactiveRToLTreeTableEditor() {
        final TreeTableModel model = createMutableVisualizeModel();
        final JXTreeTable table = new JXTreeTable(model);
//        table.setTreeCellRenderer(new DefaultTreeRenderer());
        table.expandAll();
        
        final JXFrame frame = wrapWithScrollingInFrame(table, new JTable(table.getModel()),
                "Editor: position follows Component orientation");
        addComponentOrientationToggle(frame);
        Action edit = new AbstractAction("edit 1/1") {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                table.editCellAt(1, 1);
            }
        };
        addAction(frame, edit);
        show(frame);
    }

    /**
     * Issue #223-swingx: Icons lost when editing.
     *  Regression after starting to fix #224-swingx? 
     *  
     *  
     */
    public void interactiveTreeTableEditorIcons() {
        final TreeTableModel model = createMutableVisualizeModel();
        final JXTreeTable table = new JXTreeTable(model);
        JXFrame frame = wrapWithScrollingInFrame(table, "Editor: icons showing");
        addComponentOrientationToggle(frame);
        frame.setVisible(true);
    }

    
    
    /**
     * see effect of switching treeTableModel.
     * Problem when toggling back to FileSystemModel: hierarchical 
     * column does not show filenames, need to click into table first.
     * JW: fixed. The issue was updating of the conversionMethod 
     * field - needed to be done before calling super.setModel().
     * 
     */
    public void interactiveTestSetModel() {
        final JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setColumnControlVisible(true);
        JXFrame frame = wrapWithScrollingInFrame(treeTable, "toggle model");
        frame.setVisible(true);
        final TreeTableModel model = new ComponentTreeTableModel(frame);
        Action action = new AbstractAction("Toggle model") {

            @Override
            public void actionPerformed(ActionEvent e) {
                TreeTableModel myModel = treeTable.getTreeTableModel();
                treeTable.setTreeTableModel(myModel == model ? treeTableModel : model);
                
            }
            
        };
        addAction(frame, action);
    }
    /**
     * compare treeTable/table height: default gridlines
     *
     */
    public void interactiveTestAlternateHighlightAndRowGridLines() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setRowHeight(22);
//        treeTable.setRootVisible(true);
        // this leads to lines not properly drawn, as always,
        // the margins need to be set as well.
//        treeTable.setShowGrid(true);
        treeTable.setShowGrid(true, true);
        treeTable.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER));

        JXTable table = new JXTable(new AncientSwingTeam());
        table.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER));
        table.setRowHeight(22);
        JFrame frame = wrapWithScrollingInFrame(treeTable, table, 
                "AlternateRow LinePrinter-with Gridlines");
        frame.setVisible(true);
    }

    /**
     * compare table/table height: 
     * with and without default gridlines and margins
     *
     */
    public void interactiveTestAlternateHighlightAndNoGridLines() {
        JXTable treeTable = new JXTable(new AncientSwingTeam());
        treeTable.setRowHeight(22);
        treeTable.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER));

        JXTable table = new JXTable(new AncientSwingTeam());
        table.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER));

        table.setRowHeight(22);
        table.setShowGrid(false, false);
        JFrame frame = wrapWithScrollingInFrame(treeTable, table, 
                "AlternateRow LinePrinter- left== with, right == out Gridlines");
        frame.setVisible(true);
    }


    /**
     * compare treeTable/tree height
     *
     */
    public void interactiveTestHighlightAndRowHeightCompareTree() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setRowHeight(22);
        treeTable.setShowGrid(true, false);
        Highlighter hl = new ShadingColorHighlighter(
                new ColumnHighlightPredicate(0));

        treeTable.setHighlighters(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.GENERIC_GRAY),

                hl);
        final JXTree tree = new JXTree(treeTableModel);
        JXTree renderer = (JXTree) treeTable.getCellRenderer(0, treeTable
                .getHierarchicalColumn());
        tree.setRowHeight(renderer.getRowHeight());

        JFrame frame = wrapWithScrollingInFrame(treeTable, tree, 
                "LinePrinter-, ColumnHighlighter and RowHeight");
        frame.setVisible(true);
    }

    /**
     * compare treeTable/tree height
     *
     */
    public void interactiveTestHighlighterRowHeightCompareTree() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.addHighlighter(new ColorHighlighter(Color.orange, null));
        treeTable.setIntercellSpacing(new Dimension(15, 15));
        treeTable.setRowHeight(48);
        treeTable.setShowHorizontalLines(true);
        final JXTree tree = new JXTree(treeTableModel);
        JXTree renderer = (JXTree) treeTable.getCellRenderer(0, treeTable
                .getHierarchicalColumn());
        tree.setRowHeight(renderer.getRowHeight());
        JFrame frame = wrapWithScrollingInFrame(treeTable, tree,
                "compare rowheight of treetable vs tree - rowheight 48, margin 15");
        frame.setVisible(true);
    }

    /**
     * Issue #168-jdnc: dnd enabled breaks node collapse/expand.
     * Regression? Dnd doesn't work at all?
     * 
     */
    public void interactiveToggleDnDEnabled() {
        final JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setColumnControlVisible(true);
        final JXTree tree = new JXTree(treeTableModel);
        JXTree renderer = (JXTree) treeTable.getCellRenderer(0, 0);
        tree.setRowHeight(renderer.getRowHeight());
        JXFrame frame = wrapWithScrollingInFrame(treeTable, tree, "toggle dragEnabled (starting with false)");
        Action action = new AbstractActionExt("Toggle dnd: false") {

            @Override
            public void actionPerformed(ActionEvent e) {
                
                boolean dragEnabled = !treeTable.getDragEnabled();
                treeTable.setDragEnabled(dragEnabled);
                tree.setDragEnabled(dragEnabled);
                setName("Toggle dnd: " + dragEnabled);
            }
            
        };
        addAction(frame, action);
        addComponentOrientationToggle(frame);
        show(frame);
    }

    /**
     * Issue #226: no per-cell tooltips in TreeColumn. 
     * Note: this explicitly uses core default renderers!
     * 
     * Issue #1527-swingx: tooltip not shown after changing expansion state.
     * @see #interactiveHierarchicalToolTip for an example using Highlighter

     */
    public void interactiveTestToolTipsCoreRenderer() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setTreeCellRenderer(createTreeRenderer());
        treeTable.setDefaultRenderer(Object.class, createTableRenderer());
        
        JXTree tree = new JXTree(treeTableModel);
        tree.setCellRenderer(createTreeRenderer());
        // I'm registered to do tool tips so we can draw tips for the renderers
        ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
        toolTipManager.registerComponent(tree);
        JXFrame frame = wrapWithScrollingInFrame(treeTable, tree, "tooltips with core renderers");
        frame.setVisible(true);  
    }

    /**
     * Creates and returns a core default table cell renderer with tooltip.
     * @return
     */
    private TableCellRenderer createTableRenderer() {
        final TableCellRenderer delegate = new DefaultTableCellRenderer();
        TableCellRenderer l = new TableCellRenderer() {

            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                Component result = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                ((JComponent) result).setToolTipText(String.valueOf(value));
                return result;
            }
            
        };
        return l;
    }

    /**
     * Creates and returns a core default tree cell renderer with tooltip.
     * @return
     */
    private TreeCellRenderer createTreeRenderer() {
        final TreeCellRenderer delegate = new DefaultTreeCellRenderer();
        TreeCellRenderer renderer = new TreeCellRenderer() {

            @Override
            public Component getTreeCellRendererComponent(JTree tree, Object value, 
                    boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
                Component result = delegate.getTreeCellRendererComponent(tree, value, 
                        selected, expanded, leaf, row, hasFocus);
                ((JComponent) result).setToolTipText(String.valueOf(tree.getPathForRow(row)));
                 return result;
            }
            
        };
        return renderer;
    }

    
    /**    
     * setting tree properties: tree not updated correctly.
     */    
    public void interactiveTestTreeProperties() {
        final JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        Action toggleHandles = new AbstractAction("Toggle Handles") {

            @Override
            public void actionPerformed(ActionEvent e) {
                treeTable.setShowsRootHandles(!treeTable.getShowsRootHandles());
                
            }
            
        };
        Action toggleRoot = new AbstractAction("Toggle Root") {

            @Override
            public void actionPerformed(ActionEvent e) {
                treeTable.setRootVisible(!treeTable.isRootVisible());
                
            }
            
        };
        treeTable.setRowHeight(22);
        JXFrame frame = wrapWithScrollingInFrame(treeTable,
                "Toggle Tree properties ");
        addAction(frame, toggleRoot);
        addAction(frame, toggleHandles);
        frame.setVisible(true);
    }

    /**    
     * Issue #242: CCE when setting icons. Not reproducible? 
     * Another issue: icon setting does not repaint (with core default renderer)
     * Does not work at all with SwingX renderer (not surprisingly, the
     * delegating renderer in JXTree looks for a core default to wrap).
     * Think: tree/table should trigger repaint?
     */    
    public void interactiveTestTreeIcons() {
        final JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        final Icon downIcon = XTestUtils.loadDefaultIcon("wellbottom.gif");
        final Icon upIcon = XTestUtils.loadDefaultIcon("welltop.gif");
        Action toggleClosedIcon = new AbstractAction("Toggle closed icon") {
            boolean down;
            @Override
            public void actionPerformed(ActionEvent e) {
                if (down) {
                    treeTable.setClosedIcon(downIcon);
                } else {
                    treeTable.setClosedIcon(upIcon);
                }
                down = !down;
                // need to force - but shouldn't that be done in the
                // tree/table itself? and shouldn't the tree fire a 
                // property change?
                //treeTable.repaint();
            }
            
        };
        treeTable.setRowHeight(22);
        JXFrame frame = wrapWithScrollingInFrame(treeTable,
                "Toggle Tree icons ");
//        addAction(frame, toggleRoot);
        addAction(frame, toggleClosedIcon);
        frame.setVisible(true);
    }

    /**    issue #148
     *   did not work on LFs which normally respect lineStyle
     *   winLF does not respect it anyway...
     */    
    public void interactiveTestFilterHighlightAndLineStyle() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        // issue #148
        // did not work on LFs which normally respect lineStyle
        // winLF does not respect it anyway...
        treeTable.putClientProperty("JTree.lineStyle", "Angled");
        treeTable.setRowHeight(22);
       // add a bunch of highlighters directly
        treeTable.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.QUICKSILVER));
        Highlighter hl = new ShadingColorHighlighter(
                new ColumnHighlightPredicate(0));

        treeTable.addHighlighter(hl);
        treeTable.addHighlighter(new ColorHighlighter(new PatternPredicate(Pattern.compile("^s", Pattern.CASE_INSENSITIVE), 0), null, 
                Color.red));
        JFrame frame = wrapWithScrollingInFrame(treeTable,
                "QuickSilver-, Column-, PatternHighligher and LineStyle");
        frame.setVisible(true);
    }

    
    
    
    public void interactiveTestHighlightAndRowHeight() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setRowHeight(22);
        Highlighter hl = new ShadingColorHighlighter(
                new ColumnHighlightPredicate(0));
        treeTable.setHighlighters(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER),
                hl);
        JFrame frame = wrapWithScrollingInFrame(treeTable,
                "LinePrinter-, ColumnHighlighter and RowHeight");
        frame.setVisible(true);
    }

    public void interactiveTestAlternateRowHighlighter() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER));

        treeTable.setRowHeight(22);
        JFrame frame = wrapWithScrollingInFrame(treeTable,
                "ClassicLinePrinter and RowHeight");
        frame.setVisible(true);
    }
    
    public void interactiveTestBackgroundHighlighter() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        Highlighter hl = new ShadingColorHighlighter(
                new ColumnHighlightPredicate(0));
        treeTable.setHighlighters(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.LINE_PRINTER),
                hl);
        treeTable.setBackground(new Color(0xFF, 0xFF, 0xCC)); // notepad
        treeTable.setGridColor(Color.cyan.darker());
        treeTable.setRowHeight(22);
        treeTable.setShowGrid(true, false);
        JFrame frame = wrapWithScrollingInFrame(treeTable,
                "NotePadBackground- HierarchicalColumnHighlighter and horiz lines");
        frame.setVisible(true);
    }

    public void interactiveTestLedgerBackground() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setBackground(new Color(0xF5, 0xFF, 0xF5)); // ledger
        treeTable.setGridColor(Color.cyan.darker());
        treeTable.setRowHeight(22);
        treeTable.setShowGrid(true, false);
        JFrame frame = wrapWithScrollingInFrame(treeTable, "LedgerBackground");
        frame.setVisible(true);
    }

    /**
     * Requirement: color the leafs of the hierarchical columns differently.
     * 
     * http://forums.java.net/jive/thread.jspa?messageID=165876
     * 
     *
     */
    public void interactiveTestHierarchicalColumnHighlightConditional() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        HighlightPredicate hierarchical = new ColumnHighlightPredicate(0);
        treeTable.addHighlighter(new ShadingColorHighlighter(hierarchical));
        HighlightPredicate predicate = new HighlightPredicate() {

            @Override
            public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
                return adapter.isLeaf();
            }
            
        };
        ColorHighlighter highlighter = new ColorHighlighter(new AndHighlightPredicate(hierarchical, predicate),
                new Color(247,246,239), null);
        treeTable.addHighlighter(highlighter);
        showWithScrollingInFrame(treeTable,
        "HierarchicalColumn And Conditional ");
    }
    
    public void interactiveTestHierarchicalColumnHighlight() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        Highlighter hl = new ShadingColorHighlighter(
                new ColumnHighlightPredicate(0));
        treeTable.addHighlighter(hl);
        JFrame frame = wrapWithScrollingInFrame(treeTable,
                "HierarchicalColumnHigh");
        frame.setVisible(true);
    }

    public void interactiveTestIntercellSpacing1() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setIntercellSpacing(new Dimension(1, 1));
        treeTable.setShowGrid(true);
        JFrame frame = wrapWithScrollingInFrame(treeTable, "Intercellspacing 1");
        frame.setVisible(true);
    }

    public void interactiveTestIntercellSpacing2() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setIntercellSpacing(new Dimension(2, 2));
        treeTable.setShowGrid(true);
        JFrame frame = wrapWithScrollingInFrame(treeTable, "Intercellspacing 2");
        frame.setVisible(true);
    }

    public void interactiveTestIntercellSpacing3() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setIntercellSpacing(new Dimension(3, 3));
        treeTable.setShowGrid(true);
        JFrame frame = wrapWithScrollingInFrame(treeTable, "Intercellspacing 3");
        frame.setVisible(true);
    }

    public void interactiveTestHighlighterRowHeight() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.addHighlighter(new ColorHighlighter(Color.orange, null));
        treeTable.setIntercellSpacing(new Dimension(15, 15));
        treeTable.setRowHeight(48);
        JFrame frame = wrapWithScrollingInFrame(treeTable,
                "Orange, big rowheight");
        frame.setVisible(true);
    }
    
    public void interactiveTestDepthHighlighter() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.addHighlighter(new ColorHighlighter(new DepthHighlightPredicate(1), Color.MAGENTA, null));
        treeTable.setIntercellSpacing(new Dimension(15, 15));
        treeTable.setRowHeight(48);
        JFrame frame = wrapWithScrollingInFrame(treeTable,
                "Magenta depth 1, big rowheight");
        frame.setVisible(true);
    }

    public void interactiveTestHighlighters() {
        JXTreeTable treeTable = new JXTreeTable(treeTableModel);
        treeTable.setIntercellSpacing(new Dimension(15, 15));
        treeTable.setRowHeight(48);
        // not supported in JXTreeTable
 //       treeTable.setRowHeight(0, 96);
        treeTable.setShowGrid(true);
        // set a bunch of highlighters as a pipeline
        Highlighter hl = new ShadingColorHighlighter(
                new ColumnHighlightPredicate(0));

        treeTable.setHighlighters(
                        new ColorHighlighter(Color.orange, null),
                        hl,
                        new ColorHighlighter(new PatternPredicate("D", 0), null,
                                Color.red));

        HighlightPredicate predicate = new HighlightPredicate() {

            @Override
            public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
                return adapter.hasFocus();
            }
            
        };
        // add the conditional highlighter laterb
        treeTable.addHighlighter(new ColorHighlighter(new AndHighlightPredicate(predicate, new ColumnHighlightPredicate(0)), Color.BLUE, 
                Color.WHITE));
        JFrame frame = wrapWithScrollingInFrame(treeTable, "Highlighters: conditional, orange, hierarchy, pattern D");
        frame.setVisible(true);
    }


}
