swingx-master/swingx-demos/swingx-demos-content/src/main/java/org/jdesktop/swingx/demos/tree/XTreeDemo.java
/*
 * Created on 18.04.2008
 *
 */
package org.jdesktop.swingx.demos.tree;

/*
 * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Window;
import java.util.logging.Logger;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

import org.jdesktop.application.Action;
import org.jdesktop.swingx.JXPanel;
import org.jdesktop.swingx.JXTree;
import org.jdesktop.swingx.decorator.AbstractHighlighter;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.decorator.HighlightPredicate;
import org.jdesktop.swingx.decorator.Highlighter;
import org.jdesktop.swingx.demos.tree.TreeDemoIconValues.FilteredIconValue;
import org.jdesktop.swingx.demos.tree.TreeDemoIconValues.LazyLoadingIconValue;
import org.jdesktop.swingx.renderer.DefaultTreeRenderer;
import org.jdesktop.swingx.renderer.IconValue;
import org.jdesktop.swingx.renderer.StringValue;
import org.jdesktop.swingx.renderer.StringValues;
import org.jdesktop.swingx.renderer.WrappingIconPanel;
import org.jdesktop.swingx.treetable.TreeTableModel;
import org.jdesktop.swingxset.util.ComponentModels;
import org.jdesktop.swingxset.util.DemoUtils;

import com.sun.swingset3.DemoProperties;

/**
 * JXTree Demo
 * 
 * PENDING JW: make editable to demonstrate terminate enhancement. 
 *
 *@author Jeanette Winzenburg, Berlin
 */
@DemoProperties(
        value = "JXTree Demo",
        category = "Data",
        description = "Demonstrates JXTree, an enhanced tree component",
        sourceFiles = {
                "org/jdesktop/swingx/demos/tree/XTreeDemo.java",
                "org/jdesktop/swingx/demos/tree/TreeDemoIconValues.java"
                }
)
public class XTreeDemo extends JPanel {
    @SuppressWarnings("unused")
    private static final Logger LOG = Logger.getLogger(XTreeDemo.class
            .getName());
    private JXTree tree;
    private JButton refreshButton;
    private JButton expandButton;
    private JButton collapseButton;
    /**
     * TreeDemo Constructor
     */
    public XTreeDemo() {
        super(new BorderLayout());
        initComponents();
        configureComponents();
        DemoUtils.injectResources(this);
        bind();
    }

//---------------- public api for Binding/Action control
    

    @Action
    public void refreshModel() {
        tree.setModel(createTreeModel());
    }
    // <snip> JXTree convenience api
    // expand/collapse all nodes
    @Action
    public void expandAll() {
        tree.expandAll();
    }

    @Action
    public void collapseAll() {
        tree.collapseAll();
    }
    // </snip>

//---------------- binding/configure
    
    private void configureComponents() {
        // <snip> JXTree rendering
        // StringValue provides node text: concat several 
        StringValue sv = new StringValue() {
            
            @Override
            public String getString(Object value) {
                if (value instanceof Component) {
                    Component component = (Component) value;
                    String simpleName = component.getClass().getSimpleName();
                    if (simpleName.length() == 0){
                        // anonymous class
                        simpleName = component.getClass().getSuperclass().getSimpleName();
                    }
                    return simpleName + "(" + component.getName() + ")";
                }
                return StringValues.TO_STRING.getString(value);
            }
        };
        // </snip>
        
        // StringValue for lazy icon loading
        StringValue keyValue = new StringValue() {
            
            @Override
            public String getString(Object value) {
                if (value == null) return "";
                String simpleClassName = value.getClass().getSimpleName();
                if (simpleClassName.length() == 0){
                    // anonymous class
                    simpleClassName = value.getClass().getSuperclass().getSimpleName();
                }
                return simpleClassName + ".png";
            }
        };
        // <snip> JXTree rendering
        // IconValue provides node icon 
        IconValue iv = new LazyLoadingIconValue(getClass(), keyValue, "fallback.png");
        // create and set a tree renderer using the custom Icon-/StringValue
        tree.setCellRenderer(new DefaultTreeRenderer(iv, sv));
        // </snip>
        tree.setRowHeight(-1);
        
        // <snip> JXTree rollover
        // enable and register a highlighter
        tree.setRolloverEnabled(true);
        tree.addHighlighter(createRolloverIconHighlighter(iv));
        // </snip>
        
        refreshButton.setAction(DemoUtils.getAction(this, "refreshModel"));
        expandButton.setAction(DemoUtils.getAction(this, "expandAll"));
        collapseButton.setAction(DemoUtils.getAction(this, "collapseAll"));
        
        // Demo specific config
        DemoUtils.setSnippet("JXTree convenience api", expandButton, collapseButton);
        DemoUtils.setSnippet("JXTree rendering", tree);
    }

    // <snip> JXTree rollover
    // custom implementation of Highlighter which highlights 
    // by changing the node icon on rollover
    private Highlighter createRolloverIconHighlighter(IconValue delegate) {
        // the icon look-up is left to an IconValue
        final IconValue iv = new FilteredIconValue(delegate);
        AbstractHighlighter hl = new AbstractHighlighter(HighlightPredicate.ROLLOVER_ROW) {

            /**
             * {@inheritDoc} <p>
             * 
             * Implemented to highlight by setting the node icon.
             */
            @Override
            protected Component doHighlight(Component component,
                    ComponentAdapter adapter) {
                Icon icon = iv.getIcon(adapter.getValue());
                if (icon != null) {
                    ((WrappingIconPanel) component).setIcon(icon);
                }
                return component;
            }
            // </snip>
            
            /**
             * {@inheritDoc} <p>
             * 
             * Implementated to return true if the component is a WrappingIconPanel,
             * a panel implemenation specialized for rendering tree nodes.
             * 
             */
            @Override
            protected boolean canHighlight(Component component,
                    ComponentAdapter adapter) {
                return component instanceof WrappingIconPanel;
            }
            
        };
        return hl;
    }

    
    private void bind() {
        // example model is component hierarchy of demo application
        // bind in addNotify
        tree.setModel(null);
    }

    /**
     * Overridden to create and install the component tree model.
     */
    @Override
    public void addNotify() {
        super.addNotify();
        if (tree.getModel() == null) {
            tree.setModel(createTreeModel());
        }
    }

    private TreeTableModel createTreeModel() {
       Window window = SwingUtilities.getWindowAncestor(this);
       return ComponentModels.getTreeTableModel(window != null ? window : this);
    }

//-------------- init ui
    /**
     * 
     */
    private void initComponents() {
        tree = new JXTree();
        tree.setName("componentTree");
        tree.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
        add(new JScrollPane(tree), BorderLayout.CENTER);
        
        JComponent control = new JXPanel();
        refreshButton = new JButton();
        refreshButton.setName("refreshButton");

        expandButton = new JButton();
        expandButton.setName("expandButton");
        
        collapseButton = new JButton();
        collapseButton.setName("collapseButton");
        
//        control.add(refreshButton);
        control.add(expandButton);
        control.add(collapseButton);
        add(control, BorderLayout.SOUTH);
    }

    /**
     * main method allows us to run as a standalone demo.
     */
    public static void main(String[] args) {
        JFrame frame = new JFrame(XTreeDemo.class.getAnnotation(DemoProperties.class).value());

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new XTreeDemo());
        frame.setPreferredSize(new Dimension(800, 600));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

}


