swingx-master/swingx-demos/swingx-demos-content/src/main/java/org/jdesktop/swingx/demos/titledpanel/TitledPanelDemo.java
/*
 * $Id$
 *
 * Copyright 2009 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.demos.titledpanel;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.MutableComboBoxModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.FontUIResource;

import org.jdesktop.application.Action;
import org.jdesktop.beansbinding.BeanProperty;
import org.jdesktop.beansbinding.Binding;
import org.jdesktop.beansbinding.BindingGroup;
import org.jdesktop.beansbinding.Bindings;
import org.jdesktop.beansbinding.AutoBinding.UpdateStrategy;
import org.jdesktop.swingx.JXLabel;
import org.jdesktop.swingx.JXPanel;
import org.jdesktop.swingx.JXTitledPanel;
import org.jdesktop.swingx.JXTitledSeparator;
import org.jdesktop.swingx.binding.DisplayInfo;
import org.jdesktop.swingx.binding.DisplayInfoConverter;
import org.jdesktop.swingx.binding.LabelHandler;
import org.jdesktop.swingx.painter.CheckerboardPainter;
import org.jdesktop.swingx.painter.Painter;
import org.jdesktop.swingx.plaf.PainterUIResource;
import org.jdesktop.swingx.renderer.DefaultListRenderer;
import org.jdesktop.swingxset.util.DemoUtils;
import org.jdesktop.swingxset.util.DisplayValues;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.factories.Borders;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.sun.swingset3.DemoProperties;
import com.sun.swingset3.utilities.ArrowIcon;

/**
 * A demo for the {@code JXTitledPanel}.
 * 
 * @author Karl George Schaefer
 */
@DemoProperties(value = "JXTitledPanel Demo", 
        category = "Containers", 
        description = "Demonstrates JXTitledPanel, a container with a title display.", 
        sourceFiles = {
        "org/jdesktop/swingx/demos/titledpanel/TitledPanelDemo.java",
        "org/jdesktop/swingx/demos/titledpanel/resources/TitledPanelDemo.properties"
        })
@SuppressWarnings("serial")
public class TitledPanelDemo extends JXPanel {
    // PENDING JW: removed extending DefaultDemoPanel because fell into the pit
    // of this.fields not yet initialized in overridden methods
    // plus: should consider to not extend a panel at all - this class is-not-a view
    // just a provider of a view :-)
    
    @SuppressWarnings("unused")
    private static final Logger LOG = Logger.getLogger(TitledPanelDemo.class
            .getName());
    
    // private JXTitledPanel panel1;
    private JXTitledPanel titledPanel;

    private JButton prevButton;

    private JButton nextButton;
    
    private JXTitledSeparator controlSeparator;

    private JTextField titleField;

    private JComboBox fontChooserCombo;

    private JComboBox backgroundChooserCombo;
    private List<JComponent> cards;

    private JCheckBox visibleBox;
    

    public TitledPanelDemo() {
        initComponents();
        configureComponents();
        DemoUtils.injectResources(this);
        bind();
    }

//-------------------- Actions
    
    
    @Action (enabledProperty = "trailing")
    public void previousCard() {
        if (!isTrailing()) return;
        boolean oldTrailing = isTrailing();
        boolean oldLeading = isLeading();
        // <snip> JXTitledPanel use decoration components
        // replace content with previous
        int card = cards.indexOf(titledPanel.getContentContainer());
        titledPanel.setContentContainer(cards.get(card - 1));
        // </snip>
        titledPanel.revalidate();
        titledPanel.repaint();
        firePropertyChange("trailing", oldTrailing, isTrailing());
        firePropertyChange("leading", oldLeading, isLeading());
    }
    
    @Action (enabledProperty = "leading")
    public void nextCard() {
        if (!isLeading()) return;
        boolean oldTrailing = isTrailing();
        boolean oldLeading = isLeading();
        // <snip> JXTitledPanel use decoration components
        // replace content with next
        int card = cards.indexOf(titledPanel.getContentContainer());
        titledPanel.setContentContainer(cards.get(card + 1));
        // </snip>

        titledPanel.revalidate();
        titledPanel.repaint();
        firePropertyChange("leading", oldLeading, isLeading());
        firePropertyChange("trailing", oldTrailing, isTrailing());
        
    }

    public boolean isTrailing() {
        return titledPanel.getContentContainer() != cards.get(0);
    }
    
    public boolean isLeading() {
        return titledPanel.getContentContainer() != cards.get(cards.size() - 1);
    }
    
    @Action (selectedProperty = "navigatorVisible") 
    public void toggleNavigatorVisible() {
        // do nothing - action happens in setter of selectedProperty
    }
    
    public boolean isNavigatorVisible() {
        return titledPanel.getLeftDecoration() != null;
    }
    
    public void setNavigatorVisible(boolean visible) {
        // <snip> JXTitledPanel configure title properties
        // Show/Hide left and right decoration options
        if (isNavigatorVisible() == visible) return;
        boolean old = isNavigatorVisible();
        titledPanel.setLeftDecoration(visible ? prevButton : null);
        titledPanel.setRightDecoration(visible ? nextButton : null);
        // </snip>

        titledPanel.revalidate();
        titledPanel.repaint();
        firePropertyChange("navigatorVisible", old, isNavigatorVisible());
    }
//------------------- bind/configure    
    
    private ComboBoxModel createFontModel() {
        MutableComboBoxModel model = new DefaultComboBoxModel();
        // <snip> JXTitledPanel configure title properties
        // Font options (based on default)
        Font baseFont = UIManager.getFont("JXTitledPanel.titleFont");
        model.addElement(new DisplayInfo<Font>("Default ", baseFont));
        Font italicFont = new FontUIResource(baseFont.deriveFont(Font.ITALIC));
        model.addElement(new DisplayInfo<Font>("Derived (Italic)" , italicFont));
        Font bigFont = new FontUIResource(baseFont.deriveFont(baseFont.getSize2D() * 2));
        model.addElement(new DisplayInfo<Font>("Derived (Doubled Size) ", bigFont));
        // </snip>
        return model;
    }
    
    private ComboBoxModel createBackgroundModel() {
        MutableComboBoxModel model = new DefaultComboBoxModel();
        // <snip> JXTitledPanel configure title properties
        // Background Painter options 
        Painter<?> baseFont =  (Painter<?>) UIManager.get("JXTitledPanel.titlePainter");
        model.addElement(new DisplayInfo<Painter<?>>("Default ", baseFont));
        model.addElement(new DisplayInfo<Painter<?>>("Checkerboard", 
                new PainterUIResource<JComponent>(new CheckerboardPainter())));
        // PENDING JW: add more options - image, gradient, animated... 
        // </snip>
        return model;
    }
    
    @SuppressWarnings("unchecked")
    private void bind() {
        // set actions
        prevButton.setAction(DemoUtils.getAction(this, "previousCard"));
        nextButton.setAction(DemoUtils.getAction(this, "nextCard"));
        // re-set action-independent Icons
        applyNavigationDefaults();
        visibleBox.setAction(DemoUtils.getAction(this, "toggleNavigatorVisible"));
        
        DefaultListRenderer renderer = new DefaultListRenderer(DisplayValues.DISPLAY_INFO_DESCRIPTION);
        fontChooserCombo.setRenderer(renderer);
        backgroundChooserCombo.setRenderer(renderer);
        
        BindingGroup group = new BindingGroup();
        // <snip> JXTitledPanel configure title properties
        // edit title text
        group.addBinding(Bindings.createAutoBinding(UpdateStrategy.READ, 
                titleField, BeanProperty.create("text"),
                titledPanel, BeanProperty.create("title")));
        // </snip>
        Binding fontBinding = Bindings.createAutoBinding(UpdateStrategy.READ, 
                fontChooserCombo, BeanProperty.create("selectedItem"),
                titledPanel, BeanProperty.create("titleFont"));
        fontBinding.setConverter(new DisplayInfoConverter<Font>());
        group.addBinding(fontBinding);
        
        Binding backgroundBinding = Bindings.createAutoBinding(UpdateStrategy.READ, 
                backgroundChooserCombo, BeanProperty.create("selectedItem"),
                titledPanel, BeanProperty.create("titlePainter"));
        backgroundBinding.setConverter(new DisplayInfoConverter<Painter>());
        group.addBinding(backgroundBinding);
        
        group.bind();
        
        updateUIProperties();
        installUIListener();
    }

    // <snip> JXTitledPanel configure title properties
    // reset to ui-defaults on changing LAF
    private void updateUIProperties() {
        fontChooserCombo.setModel(createFontModel());
        backgroundChooserCombo.setModel(createBackgroundModel());
//        applyNavigationDefaults();
    }

    private void installUIListener() {
        PropertyChangeListener listener = new PropertyChangeListener() {
            
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                updateUIProperties();
            }
        };
        UIManager.addPropertyChangeListener(listener);
    }
    // </snip>

    
//------------------- init view
    
    private void configureComponents() {
        // JW: default bevel border is ugly - should change?
        titledPanel.setBorder(BorderFactory.createEmptyBorder());
        
        // demo specifics
        DemoUtils.setSnippet("JXTitledPanel use decoration components", titledPanel);
        DemoUtils.setSnippet("JXTitledPanel configure title properties", 
                titleField, fontChooserCombo, backgroundChooserCombo, visibleBox);
    }

    private void initComponents() {

        setLayout(new BorderLayout());
        titledPanel = new JXTitledPanel() {

            /** 
             * @inherited <p>
             * 
             * Overridden to adjust to size requirements of invisible cards.
             */
            @Override
            public Dimension getPreferredSize() {
                Dimension dim = super.getPreferredSize();
                Dimension child = getContentContainer().getPreferredSize();
                int width = child.width;
                for (JComponent card : cards) {
                    if (card != getContentContainer()) {
                        Dimension cardDim = card.getPreferredSize();
                        width = Math.max(width, cardDim.width);
                    }
                }
                if (width > child.width) {
                    dim.width += width - child.width;
                }
                return dim;
            }
            
        };
        titledPanel.setName("titledPanel");

        prevButton = new JButton();
        prevButton.setName("previousButton");
        nextButton = new JButton(); 
        nextButton.setName("nextButton");

        
        JComponent firstCard = createFirstCard();
        firstCard.setName("firstCard");
        
        titledPanel.setContentContainer(firstCard);
        
        JComponent secondCard = createSecondCard();
        secondCard.setName("secondCard");
        
        JComponent thirdCard = createThirdCard();
        thirdCard.setName("thirdCard");
        
        cards = new ArrayList<JComponent>();
        cards.add(firstCard);
        cards.add(secondCard);
        cards.add(thirdCard);
        
        add(titledPanel);
        // panel4 = new JXTitledPanel("Image");
        // //TODO add image
        // add(panel4);
    }

    private JXPanel createFirstCard() {
        JXPanel control = new JXPanel();
        FormLayout formLayout = new FormLayout(
                "5dlu, r:d:n, l:4dlu:n, f:d:g", // columns
                "c:d:n " +
                ", t:4dlu:n, c:d:n " +
                ", t:4dlu:n, c:d:n" +
                ", t:4dlu:n, c:d:n" +
                ", t:4dlu:n, c:d:n" +
                ", t:4dlu:n, c:d:n"
                ); // rows
        PanelBuilder builder = new PanelBuilder(formLayout, control);
        builder.setBorder(Borders.DIALOG_BORDER);
        CellConstraints cl = new CellConstraints();
        CellConstraints cc = new CellConstraints();
        
        controlSeparator = new JXTitledSeparator();
        controlSeparator.setName("controlSeparator");
        builder.add(controlSeparator, cc.xywh(1, 1, 4, 1));
        
        int labelColumn = 2;
        int widgetColumn = labelColumn + 2;
        int currentRow = 3;
        titleField = new JTextField(20);
        titleField.setName("titleField");
        
        JLabel titleLabel = builder.addLabel("", cl.xywh(labelColumn, currentRow, 1, 1),
                titleField, cc.xywh(widgetColumn, currentRow, 1, 1));
        currentRow += 2;
        
        titleLabel.setName("titleLabel");
        LabelHandler.bindLabelFor(titleLabel, titleField);
        
        fontChooserCombo = new JComboBox();
        fontChooserCombo.setName("fontChooserCombo");
        
        JLabel fontLabel = builder.addLabel("", cl.xywh(labelColumn, currentRow, 1, 1),
                fontChooserCombo, cc.xywh(widgetColumn, currentRow, 1, 1));
        currentRow += 2;
        fontLabel.setName("fontChooserLabel");
        LabelHandler.bindLabelFor(fontLabel, fontChooserCombo);
        
        backgroundChooserCombo = new JComboBox();
        backgroundChooserCombo.setName("backgroundChooserCombo");
        
        JLabel backgroundLabel = builder.addLabel("", cl.xywh(labelColumn, currentRow, 1, 1),
                backgroundChooserCombo, cc.xywh(widgetColumn, currentRow, 1, 1));
        currentRow += 2;
        backgroundLabel.setName("backgroundChooserLabel");
        LabelHandler.bindLabelFor(backgroundLabel, backgroundChooserCombo);
        
        
        visibleBox = new JCheckBox();
        visibleBox.setName("visibleBox");
        
        builder.add(visibleBox, cc.xywh(widgetColumn, currentRow, 1, 1));
        currentRow += 2;
        return control;
    }
    
    
    private JComponent createThirdCard() {
        JComponent thirdCard = new JXPanel();
        thirdCard.add(new
                JXLabel("The quick brown fox\n jumped over the lazy dog."));
        return thirdCard;
    }
    
    
    private JXPanel createSecondCard() {
        JXPanel content = new JXPanel();
        content.add(new JButton("Button 1"));
        content.add(new JButton("Button 2"));
        content.add(new JButton("Button 3"));
        return content;
    }

    /**
     * @param prevButton
     * @param orientation
     * @param arrowSize
     */
    private void applyNavigationDefaults(JButton prevButton, int orientation) {
        int arrowSize = 10;
        Color arrowColor = UIManager.getColor("Label.foreground");
        Color inactiveColor = UIManager.getColor("Label.disabledText");
        Dimension buttonSize = new Dimension(arrowSize + 12 ,
                arrowSize + 12);

        prevButton.setIcon(new ArrowIcon(orientation, arrowSize, arrowColor));
        prevButton.setDisabledIcon(new ArrowIcon(orientation, arrowSize, inactiveColor));
        prevButton.setPreferredSize(buttonSize);
        prevButton.setFocusable(false);
    }

    /**
     * 
     */
    private void applyNavigationDefaults() {
        applyNavigationDefaults(prevButton, ArrowIcon.WEST);
        applyNavigationDefaults(nextButton, ArrowIcon.EAST);
    }

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

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


}
