/* * 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.Component; import java.awt.Container; import java.awt.LayoutManager; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.DateFormat; import java.text.SimpleDateFormat; 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.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSpinner; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SpinnerDateModel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.JSpinner.DefaultEditor; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.text.DateFormatter; import javax.swing.text.DefaultFormatterFactory; import javax.swing.text.JTextComponent; import org.jdesktop.swingx.action.AbstractActionExt; import org.jdesktop.swingx.calendar.DateSelectionModel; import org.jdesktop.swingx.calendar.DaySelectionModel; import org.jdesktop.swingx.calendar.SingleDaySelectionModel; import org.jdesktop.swingx.calendar.DateSelectionModel.SelectionMode; import org.jdesktop.swingx.plaf.LookAndFeelAddons; import org.jdesktop.test.VerticalLayoutPref; /** * Simple tests to ensure that the {@code JXDatePicker} can be instantiated and * displayed.<p> * * JW: being lazy - added visuals for <code>JXMonthView</code> as well. * * @author Karl Schaefer */ public class JXDatePickerVisualCheck extends InteractiveTestCase { @SuppressWarnings("all") private static final Logger LOG = Logger .getLogger(JXDatePickerVisualCheck.class.getName()); @SuppressWarnings("unused") private Calendar calendar; /** flag to decide if the menubar should be created */ private boolean showMenu; public JXDatePickerVisualCheck() { super("JXDatePicker Test"); } public static void main(String[] args) throws Exception { UIManager.put("JXDatePicker.forceZoomable", Boolean.TRUE); // setSystemLF(true); JXDatePickerVisualCheck test = new JXDatePickerVisualCheck(); setLAF("Win"); try { // test.runInteractiveTests(); // test.runInteractiveTests("interactive.*PrefSize.*"); // test.runInteractiveTests("interactive.*Keep.*"); // test.runInteractiveTests("interactive.*Multiple.*"); // test.runInteractiveTests("interactive.*Editable.*"); // test.runInteractiveTests("interactive.*Enable.*"); // test.runInteractiveTests("interactive.*Popup.*"); test.runInteractiveTests("interactive.*NullDate.*"); // test.runInteractiveTests("interactive.*Event.*"); } catch (Exception e) { System.err.println("exception when executing interactive tests:"); e.printStackTrace(); } } /** * Quick check if DatePicker behaves correctly in vertical max * (yes, thougnh I don't know why: max size isn't overriden?) */ public void interactivePickerMax() { JXDatePicker picker = new JXDatePicker(); picker.setBorder(BorderFactory.createLineBorder(Color.RED)); JComponent content = new JPanel(); content.setLayout(new BoxLayout(content, BoxLayout.PAGE_AXIS)); content.add(picker); // content.add(new JFormattedTextField(new Date())); JXFrame frame = showInFrame(content, "max size?"); frame.setSize(frame.getWidth() * 2, frame.getHeight() * 4); } /** * Issue #1393-swingx: inherited popup not shown on editor/arrow button. * Issue #1427-swingx: right click on arrow must not open monthView * Issue ??: tooltip on children - okay (JW, Mar 2011). * Issue #1329-swingx: editor border different from textfield border in win7 */ public void interactiveParentPopup() { final JXDatePicker picker = new JXDatePicker(new Date()); picker.setToolTipText("picker toolTip"); picker.setInheritsPopupMenu(true); JComboBox compareBox = new JComboBox(new Object[]{"some", "items", "are ", "better ....."}); compareBox.setToolTipText("combo toolTip"); compareBox.setInheritsPopupMenu(true); JComboBox compareBoxEditable = new JComboBox(new Object[]{"some", "items", "are ", "better ....."}); compareBoxEditable.setToolTipText("editable combo toolTip"); compareBoxEditable.setEditable(true); compareBoxEditable.setInheritsPopupMenu(true); JTextField compareField = new JTextField("just for comparing"); compareField.setInheritsPopupMenu(true); JPanel panel = new JPanel(); JPopupMenu menu = new JPopupMenu(); menu.add("dummy"); panel.setComponentPopupMenu(menu); panel.add(picker); panel.add(compareBoxEditable); panel.add(compareBox); panel.add(compareField); JXFrame frame = wrapInFrame(panel, "inherited popup"); Action printBorder = new AbstractAction("print borders ") { @Override public void actionPerformed(ActionEvent e) { String text = "picker border: " + picker.getBorder() + "\n editor border: " + picker.getEditor().getBorder() + "\n FormattedTextField border: " + new JFormattedTextField().getBorder() ; LOG.info(text); } }; addAction(frame, printBorder); addEnabledToggleWithChildren(frame, panel); addStatusMessage(frame, "right click in components to show parent popup"); show(frame); LOG.info("addon " + LookAndFeelAddons.getAddon()); } public void interactivePopupMenuListener() { JXDatePicker picker = new JXDatePicker(); PopupMenuListener l = new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { LOG.info("visible"); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { LOG.info("invisible"); } @Override public void popupMenuCanceled(PopupMenuEvent e) { LOG.info("canceled"); } }; picker.addPopupMenuListener(l); showInFrame(picker, "picker: notification?"); } public void interactivePopupMenuListenerCompare() { JTextArea textArea = new JTextArea(10, 20); JPopupMenu picker = new JPopupMenu(); picker.add("just something"); PopupMenuListener l = new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { LOG.info("visible"); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { LOG.info("invisible"); } @Override public void popupMenuCanceled(PopupMenuEvent e) { LOG.info("canceled"); } }; textArea.setComponentPopupMenu(picker); picker.addPopupMenuListener(l); showInFrame(textArea, "plain Popup: notification"); } /** * Issue #940-swingx: support multiple selection in picker. * Nothing out-off-the-box, trying to manipulate the mouseEvent. * * No success: no way to unselect */ public void interactiveMultipleSelectionWithoutCtrl() { JXMonthView monthView = new JXMonthView(new Date()) { @Override protected void processMouseEvent(MouseEvent e) { // change the modifiers to believe that control key is down // int modifiers = e.getModifiers() | InputEvent.CTRL_DOWN_MASK; int modifiers = e.getModifiers() | InputEvent.CTRL_MASK; MouseEvent myME = new MouseEvent( (Component) e.getSource(), e.getID(), e.getWhen(), modifiers, // my changed modifier e.getX(), e.getY(), e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), e.isPopupTrigger(), e.getButton()); super.processMouseEvent(myME); // super.processMouseEvent(e); } }; monthView.setSelectionMode(SelectionMode.MULTIPLE_INTERVAL_SELECTION); JXDatePicker picker = new JXDatePicker(); picker.setMonthView(monthView); JXFrame frame = showInFrame(picker, "multiple selection without ctrl"); show(frame); } /** * Issue #940-swingx: support multiple selection in picker. * Nothing out-off-the-box, trying to implement custom * dateSelectionModel with overridden setSelectionInterval. * Looks halfway okay for mouse-interaction, completely * unusable with keyboard interaction. */ public void interactiveMultipleSelectionTogglingModel() { DateSelectionModel model = new ToggleSelectionModel(); model.setSelectionMode(SelectionMode.MULTIPLE_INTERVAL_SELECTION); JXMonthView monthView = new JXMonthView(new Date(), model); JXDatePicker picker = new JXDatePicker(); picker.setMonthView(monthView); JXFrame frame = showInFrame(picker, "multiple selection - toggle"); show(frame); } /** * Trying to interfere in setSelectionInterval. Idea from Sunacle dev forum: * <a href=http://forums.sun.com/thread.jspa?threadID=5431797&tstart=0> * MultiSelect JList without ctrl * </a> */ public static class ToggleSelectionModel extends DaySelectionModel { @Override public void setSelectionInterval(Date startDate, Date endDate) { if (!isSameDay(startDate, endDate)) { super.setSelectionInterval(startDate, endDate); return; } if (isSelected(startDate)) { removeSelectionInterval(startDate, startDate); } else { addSelectionInterval(startDate, startDate); } } } /** * Issue #940-swingx: support multiple selection in picker. * Nothing out-off-the-box, trying to implement custom * dateSelectionModel. No success. */ public void interactiveMultipleSelectionAddingModel() { DateSelectionModel model = new AddingDaySelectionModel(); model.setSelectionMode(SelectionMode.MULTIPLE_INTERVAL_SELECTION); JXMonthView monthView = new JXMonthView(new Date(), model) { @Override public Date getSelectionDate() { if (getSelectionModel() instanceof AddingDaySelectionModel) { return ((AddingDaySelectionModel) getSelectionModel()).getLastAddedDate(); } return super.getSelectionDate(); } }; JXDatePicker picker = new JXDatePicker(); picker.setMonthView(monthView); JXFrame frame = showInFrame(picker, "multiple selection"); show(frame); } /** * Custom model which always adds selection dates. */ public static class AddingDaySelectionModel extends DaySelectionModel { Date lastAdded; @Override public void setSelectionInterval(Date startDate, Date endDate) { addSelectionInterval(startDate, endDate); } @Override public void addSelectionInterval(Date startDate, Date endDate) { if (endDate.before(startDate)) return; super.addSelectionInterval(startDate, endDate); // PENDING: need to do better to cope with unselectables if (isSelected(endDate)) { lastAdded = endDate; } else if (isSelected(startDate)) { lastAdded = startDate; } else { lastAdded = null; } } @Override public void clearSelection() { lastAdded = null; super.clearSelection(); } public Date getLastAddedDate() { return lastAdded; } } /** * Issue #1196-swingx: must not allow edits if disabled. * */ public void interactiveNotEnabled() { final JXDatePicker picker = new JXDatePicker(); Calendar cal = picker.getMonthView().getCalendar(); cal.add(Calendar.MONTH, 5); picker.setDate(cal.getTime()); JXFrame frame = wrapInFrame(picker, "enabled?"); Action enabled = new AbstractAction("toggle enabled") { @Override public void actionPerformed(ActionEvent e) { picker.setEnabled(!picker.isEnabled()); } }; addAction(frame, enabled); show(frame); } /** * Issue #910-swingx: commitToday must not be allowed if field not editable. * */ public void interactiveNotEditableCommitToday() { JXDatePicker picker = new JXDatePicker(); Calendar cal = picker.getMonthView().getCalendar(); cal.add(Calendar.MONTH, 5); picker.setDate(cal.getTime()); picker.setEditable(false); showInFrame(picker, "not editable "); } /** * Issue #910-swingx: commitToday must not be allowed if field not editable. * */ public void interactiveNotEditableCompareTextField() { final JXDatePicker picker = new JXDatePicker(new Date()); final JFormattedTextField field = new JFormattedTextField(picker.getDate()); field.setEditable(false); PropertyChangeListener l = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("date".equals(evt.getPropertyName())) { if (picker.getDate() != null) field.setValue(picker.getDate()); } } }; picker.addPropertyChangeListener(l); JXPanel panel = new JXPanel(); panel.add(picker); panel.add(field); showInFrame(panel, "not editable field "); } /** * From forum: have spinner with the same timezone. */ public void interactiveTimeZoneFormat() { final JSpinner spinner = new JSpinner(new SpinnerDateModel()); final JXDatePicker picker = new JXDatePicker(); picker.setTimeZone(TimeZone.getTimeZone("GMT-10")); picker.setDate(new Date()); spinner.setValue(picker.getDate()); SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss", picker.getLocale()); format.setTimeZone(picker.getTimeZone()); JFormattedTextField textField = ((DefaultEditor) spinner.getEditor()).getTextField(); textField.setFormatterFactory( new DefaultFormatterFactory(new DateFormatter(format))); PropertyChangeListener l = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("date".equals(evt.getPropertyName())) { if (picker.getDate() != null) spinner.setValue(picker.getDate()); } } }; picker.addPropertyChangeListener(l); JXPanel panel = new JXPanel(); panel.add(picker); panel.add(spinner); showInFrame(panel, "formats in picker and spinner"); } /** * Issue #565-swingx: popup not closed if open and * clicking into other focus-tricksing component (like * picker, combo). * * Issue #1011-swingx: popup of first picker opened on click on second * (mac only?) * * And: Compare picker and combo behaviour on toggle lf. * * Not really comparable: the combo has complete control over the popup, re-creates * both popup and content on install. * */ public void interactivePopupPickerCompareCombo() { // Trace14.keyboardFocusManager(true); final JXDatePicker picker = new JXDatePicker(); picker.getEditor().setName("first DateField"); JComboBox box = new JComboBox(new Object[] {"one", "twooooooo", "threeeeeeeeeeee", "GOOO!"}); box.setEditable(true); JComponent comp = new JPanel(); comp.add(picker); comp.add(new JXDatePicker(new Date())); comp.add(box); JXFrame frame = wrapInFrame(comp, "compare combo <-> picker, picker <-> picker", true); addMessage(frame, "open popup, click in other picker/combo - popup must close and other focused"); show(frame); } /** * Issue #1011-swingx: popup of first picker opened on click on second * (mac only?) * */ public void interactivePopupTwoPickers() { // Trace14.keyboardFocusManager(true); final JXDatePicker picker = new JXDatePicker(); picker.getEditor().setName("first DateField"); JComponent comp = new JPanel(); comp.add(picker); JXDatePicker other = new JXDatePicker(new Date()); comp.add(other); // other.setFocusable(false); // picker.setFocusable(false); JXFrame frame = wrapInFrame(comp, "popup: picker <-> picker", true); addMessage(frame, "click on second opens popup of first (mac only?)"); show(frame, 400, 400); } /** * Visually characterize focus behaviour. * * Issue #577-swingx: JXDatePicker focus cleanup. * After commit/cancel in popup: picker's editor should be focused. * * * Issue #757-swingx: JXDatePicker inconsistent focusLost firing. * * JXDatePicker must not fire focusLost, the picker's editor should. * * New (?) problem: after closing focused popup by clicking into * another the focus is in the picker's editor and can't be moved * with tab * - open popup, * - focus popup (by clicking next month, no keyboard, nor commit/cancel) * - click into textfield: popup closed, picker editor has focus * * Independent of forcing focus into picker itself or its editor on open. * Looks dependent on heavyweight popup: okay on resizing the frame so * that the popup fits in. * * */ public void interactiveFocusEventOnTogglePopup() { JXDatePicker picker = new JXDatePicker(); final Action togglePopup = picker.getActionMap().get("TOGGLE_POPUP"); JComboBox box = new JComboBox(new String[] {"one", "twos"}); box.setEditable(true); FocusListener l = new FocusListener() { @Override public void focusGained(FocusEvent e) { if (e.isTemporary()) return; String source = e.getSource().getClass().getSimpleName(); LOG.info("focus gained from: " + source); } @Override public void focusLost(FocusEvent e) { if (e.isTemporary()) return; String source = e.getSource().getClass().getSimpleName(); LOG.info("focus lost from: " + source); }}; picker.getEditor().addFocusListener(l); picker.addFocusListener(l); box.addFocusListener(l); box.getEditor().getEditorComponent().addFocusListener(l); JComponent panel = new JPanel(); panel.add(box); panel.add(picker); panel.add(new JTextField("something to focus")); JXFrame frame = showInFrame(panel, "E: FocusEvents on editor"); addAction(frame, togglePopup); frame.pack(); } /** * Issue #568-swingx: DatePicker must not reset time fields. * * Behaviour defined by selection model of monthView. While the default * (DaySelectionModel) normalizes the dates to the start of the day in the * model's calendar coordinates, a SingleDaySelectionModel keeps the date as-is. * For now, need to explicitly set. <p> * * Note: picking a date in the monthView still resets. And may lead to * inconsistent fields (picker.date different from editor/model selected) the * latter being normalized? Not reproducible here - in the reported example * the time-part was hard-set when getting an actionEvent from the monthView. */ public void interactiveKeepTimeFields() { final JXDatePicker picker = new JXDatePicker(); DateSelectionModel selectionModel = new SingleDaySelectionModel(); picker.getMonthView().setSelectionModel(selectionModel); picker.setDate(new Date()); DateFormat format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.FULL); picker.setFormats(format); final JFormattedTextField field = new JFormattedTextField(format); field.setValue(picker.getDate()); PropertyChangeListener l = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("date".equals(evt.getPropertyName())) { field.setValue(evt.getNewValue()); LOG.info("picker/editor/monthView: " + picker.getDate() + "/" + picker.getEditor().getValue() + "/" + picker.getMonthView().getSelectionDate()); } } }; picker.addPropertyChangeListener(l); Action setDate = new AbstractActionExt("set date") { @Override public void actionPerformed(ActionEvent e) { picker.setDate(new Date()); } }; JComponent box = Box.createHorizontalBox(); box.add(picker); box.add(field); JXFrame frame = wrapInFrame(box, "time fields"); addAction(frame, setDate); frame.pack(); frame.setVisible(true); } /** * Issue #568-swingx: DatePicker must not reset time fields. * * Behaviour defined by selection model of monthView. While the default * (DaySelectionModel) normalizes the dates to the start of the day in the * model's calendar coordinates, a SingleDaySelectionModel keeps the date as-is. * For now, need to explicitly set. <p> * * Note: picking a date in the monthView still resets. And may lead to * inconsistent fields (picker.date different from editor/model selected) the * latter being normalized? Not reproducible here - in the reported example * the time-part was hard-set when getting an actionEvent from the monthView. */ public void interactiveKeepEndOfDay() { final JXDatePicker picker = new JXDatePicker(); SingleDaySelectionModel selectionModel = new SingleDaySelectionModel() { @Override public Date getNormalizedDate(Date date) { return endOfDay(date); } }; picker.getMonthView().setSelectionModel(selectionModel); picker.setDate(new Date()); DateFormat format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.FULL); picker.setFormats(format); final JFormattedTextField field = new JFormattedTextField(format); field.setValue(picker.getDate()); PropertyChangeListener l = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("date".equals(evt.getPropertyName())) { field.setValue(evt.getNewValue()); LOG.info("picker/editor/monthView: " + picker.getDate() + "/" + picker.getEditor().getValue() + "/" + picker.getMonthView().getSelectionDate()); } } }; picker.addPropertyChangeListener(l); Action setDate = new AbstractActionExt("set date") { @Override public void actionPerformed(ActionEvent e) { picker.setDate(new Date()); } }; JComponent box = Box.createHorizontalBox(); box.add(picker); box.add(field); JXFrame frame = wrapInFrame(box, "end of day"); addAction(frame, setDate); frame.pack(); frame.setVisible(true); } /** * Issue #706-swingx: picker doesn't update monthView. * */ public void interactiveUpdateUIPickerMonthView() { final JXDatePicker picker = new JXDatePicker(); JXFrame frame = showInFrame(picker, "picker update ui"); Action action = new AbstractActionExt("toggleUI") { @Override 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); } picker.updateUI(); custom = !custom; } }; addAction(frame, action); frame.pack(); }; /** * Issue #1292-swingx: prefsize growing on inserting text into empty editor. * * PrefSize should be independent of empty/filled picker. * If not, the initial size might appear kind of collapsed. * * adapted code example from bug report: revalidate on text insert/remove * Note: this simulation doesn't survive a LAF change - picker's editor is recreated * and listener not re-wired. */ public void interactivePrefSizeOnInsert() { final JPanel panel = new JPanel(); final JXDatePicker picker = new JXDatePicker(); final JFormattedTextField field = new JFormattedTextField(); DocumentListener l = new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { revalidate(); } /** * @param panel */ private void revalidate() { panel.revalidate(); } @Override public void removeUpdate(DocumentEvent e) { revalidate(); } @Override public void changedUpdate(DocumentEvent e) { } }; picker.getEditor().getDocument().addDocumentListener(l); field.getDocument().addDocumentListener(l); JComboBox box = new JComboBox(new Object[] {}); box.setEditable(true); ((JTextComponent) box.getEditor().getEditorComponent()).getDocument().addDocumentListener(l); panel.add(field); panel.add(picker); panel.add(box); JXFrame frame = wrapInFrame(panel, "compare prefSize on insert"); addMessage(frame, "type text and compare formatted/picker/combo"); show(frame); } /** * Issue #764-swingx: JXDatePicker sizing. * * Compare pref size with/-out date initially. * - null date is slightly narrower than not null * - formats using the day of week are cut a bit (for "long" day names like wed) * - a formatted text field is slightly off, by the width of the caret */ public void interactiveLocalePrefSize() { // wednesday - has width problems calendar.set(2008, Calendar.FEBRUARY, 20); Date date = calendar.getTime(); String formatString = "EEE MM/dd/yyyy"; LayoutManager layout = new VerticalLayoutPref(); JComponent fieldsNull = new JPanel(layout); addFormattedTextField(fieldsNull, Locale.US, null, formatString); addFormattedTextField(fieldsNull, Locale.UK, null, formatString); addFormattedTextField(fieldsNull, Locale.GERMAN, null, formatString); addFormattedTextField(fieldsNull, Locale.ITALIAN, null, formatString); JComponent fields = new JPanel(layout); addFormattedTextField(fields, Locale.US, date, formatString); addFormattedTextField(fields, Locale.UK, date, formatString); addFormattedTextField(fields, Locale.GERMAN, date, formatString); addFormattedTextField(fields, Locale.ITALIAN, date, formatString); JComponent other = new JPanel(layout); addDatePickerWithLocaleSet(other, Locale.US, date, formatString); addDatePickerWithLocaleSet(other, Locale.UK, date, formatString); addDatePickerWithLocaleSet(other, Locale.GERMAN, date, formatString); addDatePickerWithLocaleSet(other, Locale.ITALIAN, date, formatString); JComponent comp = new JPanel(layout); addDatePickerWithLocaleSet(comp, Locale.US, null, formatString); addDatePickerWithLocaleSet(comp, Locale.UK, null, formatString); addDatePickerWithLocaleSet(comp, Locale.GERMAN, null, formatString); addDatePickerWithLocaleSet(comp, Locale.ITALIAN, null, formatString); JComponent outer = Box.createHorizontalBox(); outer.add(other); outer.add(comp); outer.add(fields); outer.add(fieldsNull); JXFrame frame = wrapInFrame(outer, "Sizing DatePicker"); addMessage(frame, "rows: locales, columns: picker/formatted field"); show(frame); } /** * Issue #764-swingx: JXDatePicker sizing. * * Compare pref size with/-out date initially. * - null date is slightly narrower than not null * - formats using the day of week are cut a bit (for "long" day names like wed) * - a formatted text field is slightly off, by the width of the caret */ public void interactiveLocalePrefSize2() { // wednesday - has width problems calendar.set(2008, Calendar.FEBRUARY, 20); Date date = calendar.getTime(); String formatString = "EEE MM/dd/yyyy"; LayoutManager layout = new VerticalLayoutPref(); final JComponent german = new JPanel(layout); addFormattedTextField(german, Locale.GERMAN, date, formatString); addDatePickerWithLocaleSet(german, Locale.GERMAN, date, formatString); addDatePickerWithLocaleSet(german, Locale.GERMAN, null, formatString); addFormattedTextField(german, Locale.GERMAN, null, formatString); JComponent italian = new JPanel(layout); addFormattedTextField(italian, Locale.ITALIAN, date, formatString); addDatePickerWithLocaleSet(italian, Locale.ITALIAN, date, formatString); addDatePickerWithLocaleSet(italian, Locale.ITALIAN, null, formatString); addFormattedTextField(italian, Locale.ITALIAN, null, formatString); JComponent uk = new JPanel(layout); addFormattedTextField(uk, Locale.UK, date, formatString); addDatePickerWithLocaleSet(uk, Locale.UK, date, formatString); addDatePickerWithLocaleSet(uk, Locale.UK, null, formatString); addFormattedTextField(uk, Locale.UK, null, formatString); JComponent us = new JPanel(layout); addFormattedTextField(us, Locale.US, date, formatString); addDatePickerWithLocaleSet(us, Locale.US, date, formatString); addDatePickerWithLocaleSet(us, Locale.US, null, formatString); addFormattedTextField(us, Locale.US, null, formatString); JComponent outer = Box.createHorizontalBox(); outer.add(us); outer.add(uk); outer.add(german); outer.add(italian); final JXFrame frame = wrapInFrame(outer, "Sizing DatePicker"); Action pack = new AbstractAction("pack") { @Override public void actionPerformed(ActionEvent e) { JFormattedTextField field = ((JXDatePicker) german.getComponent(1)).getEditor(); LOG.info("pref " + field.getValue() + field.getText() + field.getPreferredSize()); frame.pack(); } }; addAction(frame, pack); addMessage(frame, "rows: picker/formatted field, columns: locales"); show(frame); } /** * Instantiates a datePicker using the default constructor, set * its locale to the given and adds it to the comp. * @param comp the container to add the picker to * @param uk the locale to use. */ private void addDatePickerWithLocaleSet(JComponent comp, Locale uk, Date date, String formatString) { JXDatePicker datePicker = new JXDatePicker(date); datePicker.setLocale(uk); if (formatString != null) { DateFormat format = new SimpleDateFormat(formatString, uk); datePicker.setFormats(format); } comp.add(datePicker); } /** * Instantiates a datePicker using the default constructor, set * its locale to the given and adds it to the comp. * @param comp the container to add the picker to * @param uk the locale to use. */ private void addFormattedTextField(JComponent comp, Locale uk, Date date, String formatString) { JFormattedTextField datePicker; if (formatString != null) { DateFormat format = new SimpleDateFormat(formatString, uk); datePicker = new JFormattedTextField(format); } else { datePicker = new JFormattedTextField(); } datePicker.setValue(date); comp.add(datePicker); } /** * Issue #665-swingx: make JXDatePicker Locale-aware. * * Here: instantiate the picker with a non-default locale. * Check that the dates in LinkPanel and editor * are formatted as appropriate for the Locale */ public void interactiveLocaleConstructor() { JComponent other = new JPanel(); // wednesday - has width problems calendar.set(2008, Calendar.FEBRUARY, 20); Date date = calendar.getTime(); addDatePickerWithLocaleConstructor(other, Locale.US, date); addDatePickerWithLocaleConstructor(other, Locale.UK, date); addDatePickerWithLocaleConstructor(other, Locale.GERMAN, date); addDatePickerWithLocaleConstructor(other, Locale.ITALIAN, date); JComponent comp = new JPanel(); addDatePickerWithLocaleConstructor(comp, Locale.US, null); addDatePickerWithLocaleConstructor(comp, Locale.UK, null); addDatePickerWithLocaleConstructor(comp, Locale.GERMAN, null); addDatePickerWithLocaleConstructor(comp, Locale.ITALIAN, null); JComponent outer = Box.createVerticalBox(); outer.add(other); outer.add(comp); showInFrame(outer, "Localized DatePicker: constructor"); } /** * Instantiates a datePicker using the constructor with the given locale and * adds it to the comp. * @param comp the container to add the picker to * @param uk the locale to use. */ private void addDatePickerWithLocaleConstructor(JComponent comp, Locale uk, Date date) { JXDatePicker datePicker = new JXDatePicker(uk); datePicker.setDate(date); comp.add(new JLabel(uk.getDisplayName())); comp.add(datePicker); } /** * Issue #665-swingx: make JXDatePicker Locale-aware. * * Tests reaction to default locales set via both JComponent.setDefault and * Locale.setDefault. Going that way, catches the locales fine. * * Also Issue #681-swingx - the first row of days in the monthview * overlaps with the day names for locales which have the monday as the * first day of week. */ public void interactiveLocaleDefault() { JComponent comp = new JPanel(); Locale old = addDatePickerWithLocale(comp, Locale.US); addDatePickerWithLocale(comp, Locale.UK); addDatePickerWithLocale(comp, Locale.GERMAN); addDatePickerWithLocale(comp, Locale.ITALIAN); showInFrame(comp, "DatePicker takes default Locale"); setLocale(old); } /** * Sets the default Locale to the given, instantiates a JXDatePicker with * default Locale and adds it to the given component. Returns the previous * default Locale. * * @param comp the container to add the picker to * @param uk the new default Locale * * @return the previous default Locale */ private Locale addDatePickerWithLocale(JComponent comp, Locale uk) { Locale old = setLocale(uk); JXDatePicker datePicker = new JXDatePicker(); comp.add(new JLabel(uk.getDisplayName())); comp.add(datePicker); return old; } /** * Sets default Locale (on Locale and JComponent) to the given Locale and * returns the previous default. * * @param locale the default Locale to set. * @return the previous default. */ private Locale setLocale(Locale locale) { Locale old = JComponent.getDefaultLocale(); JComponent.setDefaultLocale(locale); Locale.setDefault(locale); return old; } /** * Issue #566-swingx: JXRootPane eats picker's popup esc. * to reproduce: open the picker's popup the press esc - * not closed. Same with combo is working. * */ public void interactiveXRootPaneEatsEscape() { JXDatePicker picker = new JXDatePicker(); JComboBox box = new JComboBox(new String[] {"one", "twos"}); box.setEditable(true); JComponent panel = new JPanel(); panel.add(picker); panel.add(box); showInFrame(panel, "Escape key"); } /** * visual check that toggling the panel adds/removes it * and installs the keybindings. * */ public void interactiveLinkPanelSet() { final JXDatePicker picker = new JXDatePicker(); final JPanel panel = picker.getLinkPanel(); // initial null okay JXFrame frame = showInFrame(picker, "null panel"); Action toggleLinkPanel = new AbstractAction("toggleLinkPanel <-> null") { @Override public void actionPerformed(ActionEvent e) { boolean hasLinkPanel = picker.getLinkPanel() != null; picker.setLinkPanel(hasLinkPanel ? null : panel); } }; addAction(frame, toggleLinkPanel); frame.pack(); } /** * Checking PropertyChangeEvent: report in forum that no event for date fired. * here not reproducible.. problem of WizardPage? */ public void interactivePCEvent() { JXDatePicker picker = new JXDatePicker(new Date()); JFormattedTextField textField = new JFormattedTextField(DateFormat.getDateInstance()); textField.setValue(new Date()); PropertyChangeListener l = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent e) { LOG.info("got pce from: " + e.getSource().getClass().getSimpleName() + "\n" + e.getPropertyName() + e.getNewValue()); } }; textField.addPropertyChangeListener(l); picker.addPropertyChangeListener(l); // picker.getMonthView().addActionListener(l); JPanel panel = new JPanel(); panel.add(textField); panel.add(picker); JTabbedPane tab = new JTabbedPane(); tab.add("fields", panel); tab.add("dummy", new JTextField("dummy")); JXFrame frame = showInFrame(tab, "Compare propertChange events: keyboard/mouse"); frame.pack(); } /** * Issue #235-swingx: action events * * Compare textfield, formatted, picker, combo after keyboard. * * TextField * - simple field fires on enter always * - formatted fire on enter if value had been edited * * ComboBox * - fires on enter always * - fires on click in dropdown * * Calendar widgets after cleanup: * * Picker * - fires "datePickerCommit" on click (actually released) into monthView * - fires "datePickerCommit"/-"Cancel" on enter/escape, both in input field * and if popup is open * * MonthView * - fires "monthViewCommit" on click (actually released) * - fires "monthViewCommit"/-"Cancel" on enter/esc * * */ public void interactiveActionEventSetAction() { JXDatePicker picker = new JXDatePicker(); JTextField simpleField = new JTextField("simple field"); JFormattedTextField textField = new JFormattedTextField(DateFormat.getDateInstance()); textField.setValue(new Date()); JComboBox box = new JComboBox(new Object[] {"one", "two", "three"}); box.setEditable(true); JComboBox nonEditableBox = new JComboBox(new Object[] {"one", "two", "three"}); final Action l = new AbstractActionExt("recived") { @Override public void actionPerformed(ActionEvent e) { LOG.info("got action from: " + e.getSource().getClass().getName() + "\n" + e); } }; simpleField.setAction(l); textField.setAction(l); // picker doesn't have action-related api picker.addActionListener(l); // picker.getMonthView().addActionListener(l); box.setAction(l); nonEditableBox.setAction(l); JPanel panel = new JPanel(); panel.add(simpleField); panel.add(textField); panel.add(picker); panel.add(box); panel.add(new JCheckBox(l)); panel.add(nonEditableBox); JXFrame frame = wrapInFrame(panel, "SetAction - Compare action events: keyboard/mouse"); Action toggleEnabled = new AbstractActionExt("toggleEnabledAction") { @Override public void actionPerformed(ActionEvent e) { l.setEnabled(!l.isEnabled()); } }; addAction(frame, toggleEnabled); show(frame); } /** * Issue #235-swingx: action events * * Compare textfield, formatted, picker and combo: programatic change. * - only combo fires * */ public void interactiveActionEventSetValue() { final JXDatePicker picker = new JXDatePicker(); final JTextField simpleField = new JTextField("simple field"); final JFormattedTextField textField = new JFormattedTextField(DateFormat.getDateInstance()); textField.setValue(new Date()); final JComboBox box = new JComboBox(new Object[] {"one", "two", "three"}); box.setEditable(true); ActionListener l = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { LOG.info("got action from: " + e.getSource().getClass().getName() + "\n" + e); } }; simpleField.addActionListener(l); textField.addActionListener(l); picker.addActionListener(l); picker.getMonthView().addActionListener(l); box.addActionListener(l); Action action = new AbstractAction("set new value") { int dayToAdd = 1; @Override public void actionPerformed(ActionEvent e) { Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, dayToAdd++); Date date = cal.getTime(); String text = DateFormat.getDateInstance().format(date); simpleField.setText(text); textField.setValue(date); picker.setDate(date); box.setSelectedItem(text); } }; JPanel panel = new JPanel(); panel.add(simpleField); panel.add(textField); panel.add(picker); panel.add(box); JXFrame frame = showInFrame(panel, "Compare action events: programmatic change"); addAction(frame, action); frame.pack(); } /** * Issue #99-swingx: null date and opening popup forces selection. * Status? Looks fixed.. * * Sizing issue if init with null date */ public void interactiveNullDate() { JXDatePicker picker = new JXDatePicker(); showInFrame(picker, "null date in picker"); } /** * Issue #??-swingx: not possible to clear the date. * reported on SO: http://stackoverflow.com/q/15133981/203657 * * not reproducible (maybe was a coding error, missed api) * */ public void interactiveSetNullDate() { final JXDatePicker picker = new JXDatePicker(new Date()); JXFrame frame = wrapInFrame(picker, "null date in picker"); Action clearDate = new AbstractAction("clear") { @Override public void actionPerformed(ActionEvent e) { // set the date to null picker.setDate(null); // more model related (if a handle to the model is available // clear the selection on the monthView // DateSelectionModel model = picker.getMonthView().getSelectionModel(); // model.clearSelection(); // don't: the null will not be committed! // picker.getEditor().setText(""); // System.out.println(picker.getDate()); } }; addAction(frame, clearDate); show(frame); } /** * something weird's going on: the picker's date must be null * after setting a monthView with null selection. It is, until * shown? * Looks fixed during synch control cleanup in datePicker. */ public void interactiveShowPickerSetMonthNull() { JXDatePicker picker = new JXDatePicker(); JXMonthView intervalForPicker = new JXMonthView(); intervalForPicker.setSelectionMode(SelectionMode.SINGLE_INTERVAL_SELECTION); picker.setMonthView(intervalForPicker); assertNull(picker.getDate()); showInFrame(picker, "empty selection in monthView"); assertNull(picker.getDate()); } public void interactiveDatePickerDisplay() { JXDatePicker datePicker = new JXDatePicker(); showInFrame(datePicker, "show date picker"); } @Override protected void setUp() throws Exception { calendar = Calendar.getInstance(); } private static class SetPlafAction extends AbstractAction { private String plaf; public SetPlafAction(String name, String plaf) { super(name); this.plaf = plaf; } /** * {@inheritDoc} */ @Override public void actionPerformed(ActionEvent e) { try { Component c = (Component) e.getSource(); Window w = null; for (Container p = c.getParent(); p != null; p = p instanceof JPopupMenu ? (Container) ((JPopupMenu) p) .getInvoker() : p.getParent()) { if (p instanceof Window) { w = (Window) p; } } UIManager.setLookAndFeel(plaf); SwingUtilities.updateComponentTreeUI(w); w.pack(); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } catch (InstantiationException e1) { e1.printStackTrace(); } catch (IllegalAccessException e1) { e1.printStackTrace(); } catch (UnsupportedLookAndFeelException e1) { e1.printStackTrace(); } } } private JMenuBar createMenuBar() { LookAndFeelInfo[] plafs = UIManager.getInstalledLookAndFeels(); JMenuBar bar = new JMenuBar(); JMenu menu = new JMenu("Set L&F"); for (LookAndFeelInfo info : plafs) { menu.add(new SetPlafAction(info.getName(), info.getClassName())); } bar.add(menu); return bar; } @Override public JXFrame wrapInFrame(JComponent component, String title) { JXFrame frame = super.wrapInFrame(component, title); if (showMenu) { frame.setJMenuBar(createMenuBar()); } return frame; } /** * Do nothing, make the test runner happy * (would output a warning without a test fixture). * */ public void testDummy() { } }