swingx-master/swingx-demos/swingx-demos-content/src/main/java/org/jdesktop/swingx/demos/monthviewext/MonthViewExtDemo.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.monthviewext;

import static org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ;
import static org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.util.Calendar;
import java.util.logging.Logger;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.jdesktop.application.Application;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.beans.AbstractBean;
import org.jdesktop.beansbinding.BeanProperty;
import org.jdesktop.beansbinding.Binding;
import org.jdesktop.beansbinding.BindingGroup;
import org.jdesktop.beansbinding.Bindings;
import org.jdesktop.swingx.JXCollapsiblePane;
import org.jdesktop.swingx.JXFrame;
import org.jdesktop.swingx.JXMonthView;
import org.jdesktop.swingx.JXPanel;
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.decorator.AbstractHighlighter;
import org.jdesktop.swingx.decorator.ColorHighlighter;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.decorator.Highlighter;
import org.jdesktop.swingx.demos.monthviewext.MonthViewExtDemoUtils.DayOfWeekHighlightPredicate;
import org.jdesktop.swingx.painter.ImagePainter;
import org.jdesktop.swingx.painter.Painter;
import org.jdesktop.swingx.plaf.basic.CalendarHeaderHandler;
import org.jdesktop.swingx.plaf.basic.CalendarRenderingHandler;
import org.jdesktop.swingx.plaf.basic.DemoCalendarRenderingHandler;
import org.jdesktop.swingx.plaf.basic.DemoMonthViewUI;
import org.jdesktop.swingx.plaf.basic.SpinningCalendarHeaderHandler;
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.jhlabs.image.OpacityFilter;
import com.sun.swingset3.DemoProperties;

/**
 * A demo for the {@code JXMonthView}.
 *
 * @author Karl George Schaefer
 * @author Joshua Outwater (original JXMonthViewDemoPanel)
 */
@DemoProperties(
    value = "JXMonthView (extended)",
    category = "Controls",
    description = "Demonstrates extended JXMonthView features (not yet public)",
    sourceFiles = {
        "org/jdesktop/swingx/demos/monthviewext/MonthViewExtDemo.java",
        "org/jdesktop/swingx/plaf/basic/DemoMonthViewUI.java",
        "org/jdesktop/swingx/plaf/basic/DemoCalendarRenderingHandler.java",
        "org/jdesktop/swingx/demos/monthviewext/MonthViewExtDemoUtils.java",
        "org/jdesktop/swingx/demos/monthviewext/resources/MonthViewExtDemo.properties"
    }
)
@SuppressWarnings("serial")
public class MonthViewExtDemo extends JPanel {
    
    @SuppressWarnings("unused")
    private static final Logger LOG = Logger.getLogger(MonthViewExtDemo.class
            .getName());
    
    private JXMonthView monthView;

    private MonthViewDemoControl monthViewDemoControl;

    private JXFrame calendarFrame;
    private JComponent calendarBox;
    private JComponent zoomableBox;

    private JComboBox customHeaderBox;

    
//---------------------- bind
    
    @SuppressWarnings("unchecked")
    private void bind() {
        monthViewDemoControl = new MonthViewDemoControl();
        
        // PENDING JW: re-visit distribution of binding control ...
        // this is quite arbitrary (time of coding ;-)
        BindingGroup group = new BindingGroup();
        group.bind();
        
    }
    
    /**
     * 
     */
    public void hideCalendarFrame() {
        if (calendarFrame != null) {
            DemoUtils.fadeOutAndDispose(calendarFrame, 1000);
        }
        calendarFrame = null;
        monthViewDemoControl.setCalendarVisible(false);
    }

    /**
     * 
     */
    public void showCalendarFrame() {
        calendarFrame = new JXFrame("Calendar 2010");
        calendarFrame.setName("calendar2010");
        calendarFrame.setDefaultCloseOperation(JXFrame.DO_NOTHING_ON_CLOSE);
        WindowListener l = new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                calendarFrame.removeWindowListener(this);
                hideCalendarFrame();
            }
            
        };
        calendarFrame.addWindowListener(l);
        JXPanel calendar = new JXPanel();
        calendar.setBackground(Color.WHITE);
        Painter<?> painter = createBackgroundPainter();
        calendar.setBackgroundPainter(painter);

        JXMonthView monthView = new JXMonthView();
        Calendar cal = monthView.getCalendar();
        cal.set(Calendar.YEAR, 2010);
        cal.set(Calendar.MONTH, Calendar.JANUARY);
        monthView.setFirstDisplayedDay(cal.getTime());
        monthView.setOpaque(false);
        monthView.setPreferredColumnCount(3);
        monthView.setPreferredRowCount(4);
        // old style: set visual property with JXMonthView api
        monthView.setDayForeground(Calendar.SUNDAY, Color.MAGENTA);
        // <snip> Custom CalendarRenderingHandler
        // new style: install a custom renderingHandler 
        // (as client property, because no public api support yet)
        // which allows to add Highlighters
        monthView.putClientProperty(DemoMonthViewUI.RENDERING_HANDLER_KEY, 
                createRenderingHandler());
        // </snip>
        DemoUtils.setSnippet("Custom CalendarRenderingHandler", monthView);
        calendar.add(monthView);
        calendarFrame.add(calendar);
        Application application = Application.getInstance(Application.class);
        if (application instanceof SingleFrameApplication) {
            ((SingleFrameApplication) application).show(calendarFrame);
        } else {
            calendarFrame.pack();
            calendarFrame.setLocationRelativeTo(this);
            calendarFrame.setVisible(true);
        }
    }


    /**
     * @return
     */
    private Painter<?> createBackgroundPainter() {
        ImagePainter painter = null;
        try {
            BufferedImage img = ImageIO.read(getClass().
                    getResourceAsStream("resources/images/demo_duke.png"));
            painter = new ImagePainter(img);
            painter.setFilters(new OpacityFilter(10));
            painter.setHorizontalRepeat(true);
            painter.setVerticalRepeat(true);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return painter;
    }


    
    /**
     * Creates and returns a RenderingHandler which supports adding
     * Highlighters.
     *  
     * @return
     */
    private CalendarRenderingHandler createRenderingHandler() {
        // <snip> Custom CalendarRenderingHandler
        // use a RenderingHandler which supports adding Highlighters.
        DemoCalendarRenderingHandler handler = new DemoCalendarRenderingHandler();
        // new style: use highlighter for color config
        handler.addHighlighters(new ColorHighlighter(
                new DayOfWeekHighlightPredicate(Calendar.SATURDAY), 
                null, Color.BLUE));
        // highlight property is setting opacity to true
        Highlighter transparent = new AbstractHighlighter(MonthViewExtDemoUtils.SELECTED) {
            
            @Override
            public Component highlight(Component component,
                    ComponentAdapter adapter) {
                // opacity is not one of the properties which are
                // guaranteed to be reset, so we have to do it here
                ((JComponent) component).setOpaque(adapter.getComponent()
                        .isOpaque());
                // call super to apply the highight - which is to
                // set the component's opacity to true
                return super.highlight(component, adapter);
            }
            
            @Override
            protected Component doHighlight(Component component,
                    ComponentAdapter adapter) {
                ((JComponent) component).setOpaque(true);
                return component;
            }
            
        };
        handler.addHighlighters(transparent);
        // </snip>
        return handler;
    }

    private ComboBoxModel createHeaderInfos() {
        // <snip> Custom CalendarHeaderHandler
        // create combo model containing handlers to choose
        DefaultComboBoxModel model = new DefaultComboBoxModel();
        model.addElement(new DisplayInfo<CalendarHeaderHandler>("base (does nothing)", null));
        model.addElement(new DisplayInfo<CalendarHeaderHandler>(
                "default",
                new SpinningCalendarHeaderHandler()));
        model.addElement(new DisplayInfo<CalendarHeaderHandler>(
                "default (customized)",
                new DemoCalendarHeaderHandler(true, true)));
        // </snip>
        return model;
        
    }
//--------------------- MonthViewDemoControl
    public class MonthViewDemoControl extends AbstractBean {
        
        private boolean calendarVisible;
        
        @SuppressWarnings("unchecked")
        public MonthViewDemoControl() {
            DemoUtils.setSnippet("Custom CalendarRenderingHandler", calendarBox);
            
            // <snip> Custom CalendarHeaderHandler
            // configure the comboBox
            customHeaderBox.setModel(createHeaderInfos());
            customHeaderBox.setRenderer(new DefaultListRenderer(
                    DisplayValues.DISPLAY_INFO_DESCRIPTION));
            // </snip>
            
            DemoUtils.setSnippet("Custom CalendarHeaderHandler", customHeaderBox, zoomableBox);
            
            BindingGroup group = new BindingGroup();
            
            group.addBinding(Bindings.createAutoBinding(READ_WRITE, 
                    calendarBox, BeanProperty.create("selected"),
                    this, BeanProperty.create("calendarVisible")));
            
            group.addBinding(Bindings.createAutoBinding(READ, 
                    zoomableBox, BeanProperty.create("selected"),
                    monthView, BeanProperty.create("zoomable")));
            
            // <snip> Custom CalendarHeaderHandler
            // bind the combo box
            group.addBinding(Bindings.createAutoBinding(READ, 
                    monthView, BeanProperty.create("zoomable"),
                    customHeaderBox, BeanProperty.create("enabled")
                    ));
            Binding handlerBinding = Bindings.createAutoBinding(READ,
                    customHeaderBox, BeanProperty.create("selectedItem"),
                    this, BeanProperty.create("calendarHeaderHandler"));
            handlerBinding.setConverter(new DisplayInfoConverter<CalendarHeaderHandler>());
            // </snip>
            group.addBinding(handlerBinding);
            group.bind();
        }
        
        /**
         * @param handler the handler to set
         */
        // <snip> Custom CalendarHeaderHandler
        // wrapper around not yet public api: property on control for binding
        public void setCalendarHeaderHandler(CalendarHeaderHandler handler) {
            Object old = getCalendarHeaderHandler();
            monthView.putClientProperty(CalendarHeaderHandler.uiControllerID, handler);
            firePropertyChange("calendarHeaderHandler", old, getCalendarHeaderHandler());
        }
        // </snip>

        /**
         * @return the handler
         */
        public CalendarHeaderHandler getCalendarHeaderHandler() {
            return (CalendarHeaderHandler) 
                monthView.getClientProperty(CalendarHeaderHandler.uiControllerID);
        }



        /**
         * @param calendarVisible the calendarVisible to set
         */
        public void setCalendarVisible(boolean calendarVisible) {
            boolean old = isCalendarVisible();
            if (old == calendarVisible) return;
            this.calendarVisible = calendarVisible;
            updateCalendar();
            firePropertyChange("calendarVisible", old, isCalendarVisible());
        }
        
        /**
         * @return the calendarVisible
         */
        public boolean isCalendarVisible() {
            return calendarVisible;
        }
        
        /**
         * 
         */
        private void updateCalendar() {
            if (isCalendarVisible()) {
                showCalendarFrame();
            } else {
                hideCalendarFrame();
            }
        }
        
    }

//--------------------- create ui
    

    private void createMonthViewDemo() {
        monthView = new JXMonthView(){

            @Override
            public void setZoomable(boolean zoomable) {
                super.setZoomable(zoomable);
                ((JComponent) getParent()).revalidate();
            }
            
        };
        monthView.setName("monthView");
        monthView.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        JPanel monthViewContainer = new JXPanel();
        FormLayout formLayout = new FormLayout(
                "5dlu, c:d:n, l:4dlu:n, f:d:n", // columns
                "c:d:n " +
                ", t:4dlu:n, t: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, monthViewContainer);
        builder.setBorder(Borders.DLU4_BORDER);
//        CellConstraints cl = new CellConstraints();
        CellConstraints cc = new CellConstraints();
        
        JXTitledSeparator areaSeparator = new JXTitledSeparator();
        areaSeparator.setName("monthViewSeparator");
        builder.add(areaSeparator, cc.xywh(1, 1, 4, 1));
        builder.add(monthView, cc.xywh(2, 3, 1, 1));
        
        
        add(monthViewContainer, BorderLayout.CENTER);
        
        JComponent monthViewControlPanel = new JXPanel();
        add(monthViewControlPanel, BorderLayout.EAST);
        JComponent extended = createExtendedConfigPanel();
        monthViewControlPanel.add(extended);

    }


    /**
     * @return
     */
    private JComponent createExtendedConfigPanel() {
        JXCollapsiblePane painterControl = new JXCollapsiblePane();
        FormLayout formLayout = new FormLayout(
                "5dlu, r:d:n, l:4dlu:n, f:d:n, l:4dlu:n, f:d:n", // 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"
        ); // rows
        PanelBuilder builder = new PanelBuilder(formLayout, painterControl);
        builder.setBorder(Borders.DLU4_BORDER);
        CellConstraints cl = new CellConstraints();
        CellConstraints cc = new CellConstraints();
        
        JXTitledSeparator areaSeparator = new JXTitledSeparator();
        areaSeparator.setName("extendedSeparator");
        builder.add(areaSeparator, cc.xywh(1, 1, 4, 1));
        
        int labelColumn = 2;
        int widgetColumn = labelColumn + 2;
        int currentRow = 3;

        
        calendarBox = new JCheckBox();
        calendarBox.setName("calendarBox");
        builder.add(calendarBox, cc.xywh(labelColumn, currentRow, 3, 1));
        currentRow += 2;
        
        zoomableBox = new JCheckBox();
        zoomableBox.setName("zoomableBox");
        builder.add(zoomableBox, cc.xywh(labelColumn, currentRow, 3, 1));
        currentRow += 2;

        customHeaderBox = new JComboBox();
        customHeaderBox.setName("customHeaderBox");
        JLabel headerBoxLabel = builder.addLabel(
                "", cl.xywh(labelColumn, currentRow, 1, 1),
                customHeaderBox, cc.xywh(widgetColumn, currentRow, 1, 1));
        headerBoxLabel.setName("customHeaderBoxLabel");
        LabelHandler.bindLabelFor(headerBoxLabel, customHeaderBox);
        currentRow += 2;
        
        return painterControl;
    }

    /**
     * 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(MonthViewExtDemo.class.getAnnotation(DemoProperties.class).value());
                
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().add(new MonthViewExtDemo());
                frame.setPreferredSize(new Dimension(800, 600));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
    
    public MonthViewExtDemo() {
        super(new BorderLayout());
        // <snip> Custom MonthViewUI
        // register a custom monthView ui which provides support for custom
        // CalendarRenderingHandler and CalendarHeaderHandler
        UIManager.put(JXMonthView.uiClassID, "org.jdesktop.swingx.plaf.basic.DemoMonthViewUI");
        // </snip>
        createMonthViewDemo();
        DemoUtils.injectResources(this);
        bind();
    }

    
    
}
