/*
 * $Id: JXMonthViewVisualCheck.java,v 1.48 2009/03/31 15:39:28 kleopatra Exp $
 *
 * Copyright 2006 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.Color;
import java.awt.ComponentOrientation;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.logging.Logger;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;

import org.jdesktop.swingx.action.AbstractActionExt;
import org.jdesktop.swingx.calendar.CalendarUtils;
import org.jdesktop.swingx.calendar.DateSelectionModel.SelectionMode;
import org.jdesktop.swingx.event.DateSelectionEvent;
import org.jdesktop.swingx.event.DateSelectionListener;
import org.jdesktop.swingx.test.XTestUtils;

/**
 * Test to expose known issues with JXMonthView.
 * 
 * @author Jeanette Winzenburg
 */
public class JXMonthViewVisualCheck extends InteractiveTestCase {
    private static final Logger LOG = Logger.getLogger(JXMonthViewVisualCheck.class
            .getName());

    @SuppressWarnings("unused")
    private Calendar calendar;

    public static void main(String[] args) {
//        UIManager.put("JXDatePicker.forceZoomable", Boolean.TRUE);
      setSystemLF(true);
      JXMonthViewVisualCheck  test = new JXMonthViewVisualCheck();
      try {
//          test.runInteractiveTests();
//        test.runInteractiveTests(".*Event.*");
          test.runInteractiveTests("interactive.*Zoomable.*");
          test.runInteractiveTests("interactive.*Title.*");
        test.runInteractiveTests("interactive.*Time.*");
      } catch (Exception e) {
          System.err.println("exception when executing interactive tests:");
          e.printStackTrace();
      }
  }
    
    /**
     * Issue #1028-swingx: monthView title looks wrong if box paddings = 0
     */
    public void interactiveTitleBorder() {
        JXMonthView monthView = new JXMonthView();
        monthView.setBoxPaddingX(0);
        monthView.setBoxPaddingY(0);
        monthView.setTraversable(true);
        JComponent comp = Box.createHorizontalBox();
        comp.add(monthView);
        JXMonthView other = new JXMonthView();
        other.setTraversable(true);
        comp.add(other);
        showInFrame(comp, "monthView title border");
        
    }

    /**
     * Issue 807-swingx: JXMonthView must have visual clue if enabled.
     */
    public void interactiveDisabled() {
        JXMonthView monthView = new JXMonthView();
        monthView.setEnabled(false);
        JComponent comp = Box.createHorizontalBox();
        comp.add(monthView);
        comp.add(new JXMonthView());
        showInFrame(comp, "disabled <--> enabled");
    }
    
    
    public void interactiveRevalidateOnZoomable() {
        final JXMonthView monthView = new JXMonthView();
        final Font font = monthView.getFont();
        JXFrame frame = wrapInFrame(monthView, "Revalidate on zoomable");
        Action toggleBackground = new AbstractAction("toggleZoomable") {
            
            public void actionPerformed(ActionEvent e) {
                monthView.setZoomable(!monthView.isZoomable());
                        
            }
            
        };
        addAction(frame, toggleBackground);
        Action toggleTraversable = new AbstractAction("toggleTraversable") {
            
            private boolean traversable;

            public void actionPerformed(ActionEvent e) {
                traversable = !traversable;
                monthView.setTraversable(traversable);
                        
            }
            
        };
        addAction(frame, toggleTraversable);
        Action toggleFont = new AbstractAction("toggleFont") {
            
            public void actionPerformed(ActionEvent e) {
                
                if (monthView.getFont().isItalic()) {
                    monthView.setFont(font);
                } else {
                    monthView.setFont(font.deriveFont(Font.ITALIC));
                }
            }
            
        };
        addAction(frame, toggleFont);
        show(frame);

    }
    /**
     * Issue #931-swingx: JXMonthView not repainted on property change.
     * 
     * look for
     * - selectionBackground
     * - selectionForeground (not taken?)
     * - flaggedDateForeground
     * - componentOrientation (duplicate #996-swingx)
     * 
     */
    public void interactiveRepaintOnPropertyChange() {
        final JXMonthView monthView = new JXMonthView();
        final Font font = monthView.getFont();
        monthView.setSelectionDate(CalendarUtils.startOfWeek(calendar, new Date()));
        monthView.setFlaggedDates(CalendarUtils.endOfWeek(calendar, new Date()));
        final Color selectionBackground = monthView.getSelectionBackground();
        final Color selectionForeground = monthView.getSelectionForeground();
        final Color flaggedDayForeground = monthView.getFlaggedDayForeground();
        JXFrame frame = wrapInFrame(monthView, "repaint on propertyChange");
        Action toggleBackground = new AbstractAction("toggleSelectionBack") {
            
            public void actionPerformed(ActionEvent e) {
                monthView.setSelectionBackground(
                        Color.PINK.equals(monthView.getSelectionBackground()) ? 
                                selectionBackground : Color.PINK);
            }
            
        };
        addAction(frame, toggleBackground);
        Action toggleForeground = new AbstractAction("toggleSelectionFore") {
            
            public void actionPerformed(ActionEvent e) {
                
                monthView.setSelectionForeground(
                        Color.RED.equals(monthView.getSelectionForeground()) ? 
                                selectionForeground : Color.RED);
            }
            
        };
        addAction(frame, toggleForeground);
        Action toggleFlaggedForeground = new AbstractAction("toggleFlaggedFore") {
            
            public void actionPerformed(ActionEvent e) {
                
                monthView.setFlaggedDayForeground(
                        Color.GREEN.equals(monthView.getFlaggedDayForeground()) ? 
                                flaggedDayForeground : Color.GREEN);
            }
            
        };
        addAction(frame, toggleFlaggedForeground);
        
        Action toggleCO = new AbstractAction("toggleCO") {
            
            public void actionPerformed(ActionEvent e) {
                
                if (monthView.getComponentOrientation().isLeftToRight()) {
                    monthView.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
                } else {
                    monthView.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
                    
                }
            }
            
        };
        addAction(frame, toggleCO);
        Action toggleFont = new AbstractAction("toggleFont") {
            
            public void actionPerformed(ActionEvent e) {
                
                if (monthView.getFont().isItalic()) {
                    monthView.setFont(font);
                } else {
                    monthView.setFont(font.deriveFont(Font.ITALIC));
                }
            }
            
        };
        addAction(frame, toggleFont);
        Action toggleEnabled = new AbstractAction("toggleEnabled") {
            
            public void actionPerformed(ActionEvent e) {
                monthView.setEnabled(!monthView.isEnabled());
            }
            
        };
        addAction(frame, toggleEnabled);
        show(frame);
        
    }

    /**
     * Issue #786-swingx: IllegalStateException when paintDays of April 2008.
     * 
     * Problem was in that particular timezone - traversing to April 
     * 
     * Assumption of staying at startOfWeek in paintDays is wrong if the month
     * is the month of turning on the DST. Remove the check for now.
     * 
     */
    public void interactiveTimeZoneDST() {
        JXMonthView monthView = new JXMonthView();
        monthView.setTraversable(true);
        Calendar calendar = monthView.getCalendar();
        calendar.set(2008, Calendar.MARCH, 31);
        monthView.ensureDateVisible(calendar.getTime());
        TimeZone cairo = TimeZone.getTimeZone("Africa/Cairo");
        monthView.setTimeZone(cairo);
        JXFrame frame = showInFrame(monthView, "MonthView: DST");
        addStatusMessage(frame, "IllegalState in April");
    }


    /**
     * Issue #749-swingx: enhanced flagged dates support (add/remove)
     * 
     * Visually check if the monthView is updated on toggling several properties.
     */
    public void interactiveToggleProperties() {
        final JXMonthView monthView = new JXMonthView(); 
        monthView.setTraversable(true);
        final JXFrame frame = showInFrame(monthView, "MonthView - click property and see the change");
        final Calendar calendar = monthView.getCalendar();
        calendar.add(Calendar.DATE, 5);
        Action unselectable = new AbstractActionExt("lowerbound") {
            public void actionPerformed(ActionEvent e) {
                monthView.setLowerBound(monthView.getLowerBound() == null ? calendar.getTime() : null);
            }
            
        };
        addAction(frame, unselectable);
       Action action = new AbstractActionExt("today flag") {
            public void actionPerformed(ActionEvent e) {
                if (monthView.hasFlaggedDates()) {
                    monthView.clearFlaggedDates();
                } else {
                    monthView.setFlaggedDates(monthView.getToday());
                }
            }
            
        };
        addAction(frame, action);
        Action trailing = new AbstractActionExt("trailing") {
            public void actionPerformed(ActionEvent e) {
                monthView.setShowingTrailingDays(!monthView.isShowingTrailingDays());
            }
            
        };
        addAction(frame, trailing);
        Action leading = new AbstractActionExt("leading") {
            public void actionPerformed(ActionEvent e) {
                monthView.setShowingLeadingDays(!monthView.isShowingLeadingDays());
            }
            
        };
        addAction(frame, leading);
        Action weekNumbers = new AbstractActionExt("weekNumbers") {
            public void actionPerformed(ActionEvent e) {
                monthView.setShowingWeekNumber(!monthView.isShowingWeekNumber());
            }
            
        };
        addAction(frame, weekNumbers);
        Action traversable = new AbstractActionExt("traversable") {
            public void actionPerformed(ActionEvent e) {
                monthView.setTraversable(!monthView.isTraversable());
            }
            
        };
        addAction(frame, traversable);
        Action firstDay = new AbstractActionExt("firstDay") {
            public void actionPerformed(ActionEvent e) {
                int firstDay = monthView.getFirstDayOfWeek();
                monthView.setFirstDayOfWeek(firstDay == Calendar.SUNDAY ? 
                        Calendar.MONDAY : Calendar.SUNDAY);
            }
            
        };
        addAction(frame, firstDay);
        Action today = new AbstractActionExt("today") {
            public void actionPerformed(ActionEvent e) {
                monthView.incrementToday();
            }
            
        };
        addAction(frame, today);
        Action daysOfWeek = new AbstractActionExt("daysOfWeek") {
            String[] days = {"S", "M", "D", "M", "D", "F", "S"};
            public void actionPerformed(ActionEvent e) {
                String[] dof = monthView.getDaysOfTheWeek();
                if (dof[0].equals(days[0])) {
                    monthView.setDaysOfTheWeek(null);
                } else {
                    monthView.setDaysOfTheWeek(days);
                }    
            }
            
        };
        addAction(frame, daysOfWeek);
        frame.pack();
    };
    
    /**
     * Issue #736-swingx: monthView cannot cope with minimalDaysInFirstWeek.
     * 
     * Here: look at impact of forcing the minimalDays to a value different
     * from the calendar. Days must be displayed in starting from the 
     * first row under the days-of-week.
     */
    public void interactiveMinimalDaysInFirstWeek() {
        final JXMonthView monthView = new JXMonthView();
        monthView.setTraversable(true);
        monthView.setShowingWeekNumber(true);
        monthView.setShowingLeadingDays(true);
        monthView.setShowingTrailingDays(true);
        Action action = new AbstractActionExt("toggle minimal") {

            public void actionPerformed(ActionEvent e) {
                int minimal = monthView.getSelectionModel().getMinimalDaysInFirstWeek();
                monthView.getSelectionModel().setMinimalDaysInFirstWeek(minimal > 1 ? 1 : 4);
            }
            
        };
        final JXFrame frame = wrapInFrame(monthView, "click unselectable fires ActionEvent");
        addAction(frame, action);
        addComponentOrientationToggle(frame);
        JXStatusBar bar = getStatusBar(frame);
        final JComboBox dayOfWeekComboBox = new JComboBox(new String[]{"Sunday", "Monday", "Tuesday",
                "Wednesday", "Thursday", "Friday", "Saturday"});
        dayOfWeekComboBox.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                int selected = dayOfWeekComboBox.getSelectedIndex();
                monthView.setFirstDayOfWeek(selected + Calendar.SUNDAY);
                
            }
            
        });
        dayOfWeekComboBox.setSelectedIndex(monthView.getFirstDayOfWeek() - Calendar.SUNDAY);
        bar.add(dayOfWeekComboBox);
        frame.pack();
        frame.setVisible(true);
    }

    /**
     * Issue #736-swingx: monthView cannot cope with minimalDaysInFirstWeek.
     * 
     * Here: look at impact of forcing the minimalDays to a value different
     * from the calendar. Days must be displayed in starting from the 
     * first row under the days-of-week. Selection must be reflected in the 
     * datepicker.
     */
    public void interactiveMinimalDaysInFirstWeekPicker() {
        JXDatePicker picker = new JXDatePicker();
        final JXMonthView monthView = picker.getMonthView();
        monthView.setShowingWeekNumber(true);
        monthView.setShowingLeadingDays(true);
        monthView.setShowingTrailingDays(true);
        Action action = new AbstractActionExt("toggle minimal") {

            public void actionPerformed(ActionEvent e) {
                int minimal = monthView.getSelectionModel().getMinimalDaysInFirstWeek();
                monthView.getSelectionModel().setMinimalDaysInFirstWeek(minimal > 1 ? 1 : 4);
            }
            
        };
        final JXFrame frame = wrapInFrame(picker, "click unselectable fires ActionEvent");
        addAction(frame, action);
        frame.pack();
        frame.setVisible(true);
    }


    
    /**
     * Issue #711-swingx: fake properties.
     * 
     * visually testing today increment (it's not public api but can't
     * think of a way to simulate the timer).
     */
    public void interactiveSetToday() {
        final JXMonthView monthView = new JXMonthView(); 
        monthView.setTraversable(true);
        final JXFrame frame = showInFrame(monthView, "MonthView today");
        Action action = new AbstractActionExt("increment today") {
            public void actionPerformed(ActionEvent e) {
                monthView.incrementToday();
            }
            
        };
        addAction(frame, action);
        frame.pack();
    };


    /**
     * Issue #706-swingx: picker doesn't update monthView.
     * 
     * Here: visualize weird side-effects of monthView.updateUI - year 
     * incremented.
     */
    public void interactiveUpdateUIMonthView() {
//        calendar.set(1955, 10, 9);
        final JXMonthView monthView = new JXMonthView(); 
        monthView.setTraversable(true);
        final JXFrame frame = showInFrame(monthView, "MonthView update ui - visible month kept");
        Action action = new AbstractActionExt("toggleUI") {
            public void actionPerformed(ActionEvent e) {
                monthView.updateUI();
            }
            
        };
        addAction(frame, action);
        frame.pack();
    };

    /**
     * Issue #706-swingx: picker doesn't update monthView.
     * 
     * Show toggle of UI (selectin color)
     */
    public void interactiveUpdateUIMonthViewCustomUI() {
        final JXMonthView monthView = new JXMonthView();
        monthView.setSelectionDate(new Date());
        final JXFrame frame = showInFrame(monthView, "MonthView custom ui (selection color)");
        Action action = new AbstractActionExt("toggleUI") {
            public void actionPerformed(ActionEvent e) {
                String uiClass = (String) UIManager.get(JXMonthView.uiClassID);
                boolean custom = uiClass.indexOf("Custom") > 0;
                if (!custom) {
                    UIManager.put(JXMonthView.uiClassID, "org.jdesktop.swingx.test.CustomMonthViewUI");
                } else {
                    UIManager.put(JXMonthView.uiClassID, null);
                }
                monthView.updateUI();
                custom = !custom;
            }
            
        };
        addAction(frame, action);
        frame.pack();
    };
    
    /**
     * #705-swingx: JXMonthview must not scroll on revalidate.
     * 
     * Misbehaviour here : multi-month spanning selection, travers two month into the future and
     * resize the frame - jumps back to first. Auto-scroll in the delegates
     * selection listener would have a similar effect.
     * 
     */
    public void interactiveAutoScrollOnResize() {
        final JXMonthView us = new JXMonthView();
        us.setTraversable(true);
        us.setSelectionMode(SelectionMode.SINGLE_INTERVAL_SELECTION);
        final Calendar today = Calendar.getInstance();
        CalendarUtils.endOfMonth(today);
        Date start = today.getTime();
        today.add(Calendar.DAY_OF_MONTH, 60);
        us.setSelectionInterval(start, today.getTime());
        JXFrame frame = wrapInFrame(us, "resize");
        // quick check if lastDisplayed is updated on resize
        Action printLast = new AbstractActionExt("log last") {

            public void actionPerformed(ActionEvent e) {
                
                LOG.info("last updated?" + us.getLastDisplayedDay());
            }
            
        };
        addAction(frame, printLast);
        frame.pack();
        frame.setVisible(true);
    }

    /**
     * #703-swingx: set date to first of next doesn't update the view.
     * 
     * Behaviour is consistent with core components. Except that it is doing 
     * too much: revalidate most probably shouldn't change the scrolling state?
     * 
     * Simulated misbehaviour here: multi-month spanning selection, travers into the future and
     * add selection at the end - jumps back to first. Auto-scroll in the delegates
     * selection listener would have the effect.
     * 
     */
    public void interactiveAutoScrollOnSelectionSim() {
        final JXMonthView us = new JXMonthView();
        us.setTraversable(true);
        us.setSelectionMode(SelectionMode.SINGLE_INTERVAL_SELECTION);
        final Calendar today = Calendar.getInstance();
        CalendarUtils.endOfMonth(today);
        Date start = today.getTime();
        today.add(Calendar.DAY_OF_MONTH, 60);
        us.setSelectionInterval(start, today.getTime());
        JXFrame frame = wrapInFrame(us, "Simulate autoscroll on selection");
        Action nextMonthInterval = new AbstractActionExt("add selected") {

            public void actionPerformed(ActionEvent e) {
                if (us.isSelectionEmpty()) return;
                Date start = us.getSelectionDate();
                
                today.setTime(us.getLastSelectionDate());
                today.add(Calendar.DAY_OF_MONTH, 5);
                us.addSelectionInterval(start, today.getTime());
                // here we simulate an auto-scroll
                us.ensureDateVisible(start);
            }
            
        };
        addAction(frame, nextMonthInterval);
        frame.pack();
        frame.setVisible(true);
    }

    /**
     * #681-swingx: first row overlaps days.
     * 
     * Looks like a problem with the constructor taking a locale? 
     * Default is okay (even if German), US is okay, explicit german is wrong.
     */
    public void interactiveFirstRowOfMonthSetLocale() {
        JPanel p = new JPanel();
        // default constructor
        p.add(new JXMonthView());
        // explicit us locale
        JXMonthView us = new JXMonthView();
        us.setLocale(Locale.US);
        p.add(us);
        // explicit german locale
        JXMonthView german = new JXMonthView();
        german.setLocale(Locale.GERMAN);
        p.add(german);
        showInFrame(p, "first row overlapping - setLocale");
    }

   
    /**
     * #681-swingx: first row overlaps days.
     * 
     * Looks like a problem with the constructor taking a locale? 
     * Default is okay (even if German), US is okay, explicit german is wrong.
     */
    public void interactiveFirstRowOfMonthLocaleConstructor() {
        JPanel p = new JPanel();
        // default constructor
        p.add(new JXMonthView());
        // explicit us locale
        p.add(new JXMonthView(Locale.US));
//         explicit german locale
        p.add(new JXMonthView(Locale.GERMAN));
        showInFrame(p, "first row overlapping - constructor");
    }
    /**
     * #681-swingx: first row overlaps days.
     * Here everything looks okay.
     * 
     * @see #interactiveFirstRowOfMonthLocaleDependent()
     */
    public void interactiveFirstRowOfMonth() {
        JXMonthView monthView = new JXMonthView();
        calendar.set(2008, 0, 1);
        monthView.setSelectionDate(calendar.getTime());
        showInFrame(monthView, "first row");
    }

    /**
     * Issue #618-swingx: JXMonthView displays problems with non-default
     * timezones.
     * 
     */
    public void interactiveUpdateLocale() {
        JComponent panel = Box.createVerticalBox();

        final JXMonthView monthView = new JXMonthView();
        monthView.setTraversable(true);
        monthView.setShowingWeekNumber(true);
        final JComboBox zoneSelector = new JComboBox(Locale.getAvailableLocales());
        // Synchronize the monthView's and selector's zones.
        zoneSelector.setSelectedItem(monthView.getLocale());

        // Set the monthView's time zone based on the selected time zone.
        zoneSelector.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                Locale zone = (Locale) zoneSelector.getSelectedItem();
                monthView.setLocale(zone);
            }
        });

        panel.add(monthView);
        panel.add(zoneSelector);
        showInFrame(panel, "Locale");
    }

    
    /**
     * Issue #618-swingx: JXMonthView displays problems with non-default
     * timezones.
     * 
     */
    public void interactiveUpdateOnTimeZone() {
        JComponent panel = Box.createVerticalBox();

        final JComboBox zoneSelector = new JComboBox(TimeZone.getAvailableIDs());
        final JXMonthView monthView = new JXMonthView();
        monthView.setTraversable(true);
        // Synchronize the picker and selector's zones.
        zoneSelector.setSelectedItem(monthView.getTimeZone().getID());

        // Set the picker's time zone based on the selected time zone.
        zoneSelector.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                String zone = (String) zoneSelector.getSelectedItem();
                TimeZone tz = TimeZone.getTimeZone(zone);
                monthView.setTimeZone(tz);
              
                assertEquals(tz, monthView.getCalendar().getTimeZone());
            }
        });

        panel.add(monthView);
        panel.add(zoneSelector);
        showInFrame(panel, "TimeZone");
    }
    
    /**
     * Issue #618-swingx: JXMonthView displays problems with non-default
     * timezones.
     * Issue #658-swingx: JXDatePicker today is not updated on timezone.
     * 
     * 
     */
    public void interactiveTimeZoneClearDateState() {
        JPanel panel = new JPanel();

        final JComboBox zoneSelector = new JComboBox(TimeZone.getAvailableIDs());
        final JXDatePicker picker = new JXDatePicker(new Date());
        final JXMonthView monthView = new JXMonthView();
        monthView.setSelectionDate(picker.getDate());
        monthView.setLowerBound(XTestUtils.getStartOfToday(-10));
        monthView.setUpperBound(XTestUtils.getStartOfToday(10));
        monthView.setUnselectableDates(XTestUtils.getStartOfToday(2));
        monthView.setFlaggedDates(new Date[] {XTestUtils.getStartOfToday(4)});
        monthView.setTraversable(true);
        // Synchronize the picker and selector's zones.
        zoneSelector.setSelectedItem(picker.getTimeZone().getID());

        // Set the picker's time zone based on the selected time zone.
        zoneSelector.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                String zone = (String) zoneSelector.getSelectedItem();
                TimeZone tz = TimeZone.getTimeZone(zone);
                picker.setTimeZone(tz);
                monthView.setTimeZone(tz);
              
                assertEquals(tz, monthView.getCalendar().getTimeZone());
            }
        });

        panel.add(zoneSelector);
        panel.add(picker);
        panel.add(monthView);
        JXFrame frame = showInFrame(panel, "clear internal date-related state");
        Action assertAction = new AbstractActionExt("assert dates") {

            public void actionPerformed(ActionEvent e) {
                Calendar cal = monthView.getCalendar();
                DateFormat format = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
                format.setTimeZone(monthView.getTimeZone());
                LOG.info("cal/firstDisplayed " + 
                        format.format(cal.getTime()) + " / " 
                        +format.format(monthView.getFirstDisplayedDay()));
            }
            
        };
        addAction(frame, assertAction);
        frame.pack();
    }
    
    /**
     * Issue #659-swingx: lastDisplayedDate must be synched.
     * 
     */
    public void interactiveLastDisplayed() {
        final JXMonthView month = new JXMonthView();
        month.setSelectionMode(SelectionMode.SINGLE_INTERVAL_SELECTION);
        month.setTraversable(true);
        Action action = new AbstractActionExt("check lastDisplayed") {

            public void actionPerformed(ActionEvent e) {
                Calendar cal = Calendar.getInstance();
                cal.setTime(month.getLastDisplayedDay());
                Date viewLast = cal.getTime();
                cal.setTime(month.getUI().getLastDisplayedDay());
                Date uiLast = cal.getTime();
                LOG.info("last(view/ui): " + viewLast + "/" + uiLast);
                
            }
            
        };
        JXFrame frame = wrapInFrame(month, "default - for debugging only");
        addAction(frame, action);
        frame.setVisible(true);
    }


    /**
     * Issue #637-swingx: make JXMonthView Locale-aware.
     * 
     * Applied the patch as provided by pes17.
     * 
     */
    public void interactiveLocale() {
        JXMonthView monthView = new JXMonthView(Locale.GERMAN);
        JXMonthView other = new JXMonthView(Locale.FRANCE);
        JComponent comp = new JPanel();
        comp.add(monthView);
        comp.add(other);
        showInFrame(comp, "Localized monthView");
    }

    /**
     * Issue #563-swingx: arrow keys active even if not focused.
     * focus the button and use the arrow keys: selection moves.
     * Reason was that the WHEN_IN_FOCUSED_WINDOW key bindings
     * were always installed. 
     * 
     * Fixed by dynamically bind/unbind component input map bindings
     * based on the JXMonthView's componentInputMapEnabled property.
     *
     */
    public void interactiveMistargetedKeyStrokes() {
        JXMonthView month = new JXMonthView();
        JComponent panel = new JPanel();
        panel.add(new JButton("something to focus"));
        panel.add(month);
        showInFrame(panel, "default - for debugging only");
    }
    
    /**
     * Issue #563-swingx: arrow keys active even if not focused.
     * focus the button and use the arrow keys: selection moves.
     *
     * Fixed by dynamically bind/unbind component input map bindings
     * based on the JXMonthView's componentInputMapEnabled property.
     */
    public void interactiveMistargetedKeyStrokesPicker() {
        JXMonthView month = new JXMonthView();
        JComponent panel = new JPanel();
        JXDatePicker button = new JXDatePicker();
        panel.add(button);
        panel.add(month);
        showInFrame(panel, "default - for debugging only");
    }
    
    /**
     * Informally testing adjusting property on mouse events.
     * 
     * Hmm .. not formally testable without mocks/ui unit tests?
     *
     */
    public void interactiveAdjustingOnMouse() {
        final JXMonthView month = new JXMonthView();
        // we rely on being notified after the ui delegate ... brittle.
        MouseAdapter m = new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {
                LOG.info("pressed - expect true " + month.getSelectionModel().isAdjusting());
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                LOG.info("released - expect false" + month.getSelectionModel().isAdjusting());
            }
            
        };
        month.addMouseListener(m);
        showInFrame(month, "Mouse and adjusting - state on pressed/released");
    }

    /**
     * Issue #555-swingx: multiple selection with keyboard not working
     * Happens for standalone, okay for monthview in popup.
     * 
     * Fixed as a side-effect of cleanup of input map bindings. 
     * 
     * Regression #555 
     * 
     * Issue #996-swingx: NPE while dragging 
     * 
     * to reproduce: first click into a empty (leading/trailing) day then
     * drag into month. Fixed (brutish? - not entirely sure as the user
     * interaction is suboptimal anyway ..)
     */
    public void interactiveMultipleSelectionWithKeyboard() {
        JXMonthView single = new JXMonthView();
        single.setSelectionMode(SelectionMode.SINGLE_SELECTION);
        JXMonthView interval = new JXMonthView();
        interval.setSelectionMode(SelectionMode.SINGLE_INTERVAL_SELECTION);
        JXMonthView multiple = new JXMonthView();
        multiple.setSelectionMode(SelectionMode.MULTIPLE_INTERVAL_SELECTION);
        // for comparison: single interval in popup is working
        JXDatePicker picker = new JXDatePicker();
        JXMonthView intervalForPicker = new JXMonthView();
        intervalForPicker.setSelectionMode(SelectionMode.MULTIPLE_INTERVAL_SELECTION);
        picker.setMonthView(intervalForPicker);
        
        JComponent comp = new JPanel();
        comp.add(single);
        comp.add(interval);
        comp.add(multiple);
        comp.add(picker);
        showInFrame(comp, "select interval with keyboard: single vs. singleInt vs. multipleInt");
        
    }
    /**
     * Issue #??-swingx: esc/enter does not always fire actionEvent.
     * 
     * Fixed: committing/canceling user gestures always fire.
     * 
     * Open: mouse-gestures?
     *
     */
    public void interactiveMonthViewEvents() {
        JXMonthView monthView = new JXMonthView();
        JXMonthView interval = new JXMonthView();
        interval.setSelectionMode(SelectionMode.SINGLE_INTERVAL_SELECTION);
        JXMonthView multiple = new JXMonthView();
        multiple.setSelectionMode(SelectionMode.MULTIPLE_INTERVAL_SELECTION);
        ActionListener l = new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                LOG.info("got action from: " + e.getSource().getClass().getName() + 
                        "\n" + e);
            }
            
        };
        monthView.addActionListener(l);
        interval.addActionListener(l);
        multiple.addActionListener(l);
        DateSelectionListener d = new DateSelectionListener() {

            public void valueChanged(DateSelectionEvent ev) {
                LOG.info("got selection from: " + ev.getSource().getClass().getName() + 
                        "\n" + ev);
            }
            
        };
        monthView.getSelectionModel().addDateSelectionListener(d);
        interval.getSelectionModel().addDateSelectionListener(d);
        multiple.getSelectionModel().addDateSelectionListener(d);
        
        JXDatePicker picker = new JXDatePicker();
        JXMonthView intervalForPicker = new JXMonthView();
        intervalForPicker.setSelectionMode(SelectionMode.SINGLE_INTERVAL_SELECTION);
        // JW: this picker comes up with today - should have taken the
        // empty selection (which it does the unit test)
        picker.setMonthView(intervalForPicker);
        
        JComponent comp = new JPanel();
        comp.add(monthView);
        comp.add(interval);
        comp.add(multiple);
        comp.add(picker);
        JXFrame frame = showInFrame(comp, "events from monthView");
        // JXRootPane eats esc 
        frame.getRootPaneExt().getActionMap().remove("esc-action");

    }

    /**
     * Issue #426-swingx: NPE on traversing 
     * 
     * example from bug report
     *
     */
    public void interactiveMonthViewTravers() {
        JXMonthView monthView = new JXMonthView();
        monthView.setTraversable(true);
        showInFrame(monthView, "travers throws NPE");
    }

//----------------------
    @Override
    protected void setUp() throws Exception {
        calendar = Calendar.getInstance();
    }

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

}
