/* * $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.monthview; import static org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ; import java.awt.BorderLayout; import java.awt.Dimension; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.logging.Logger; 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.JSpinner; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.JSpinner.DefaultEditor; import org.jdesktop.application.Application; 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.beansbinding.Converter; import org.jdesktop.swingx.JXCollapsiblePane; import org.jdesktop.swingx.JXDatePicker; import org.jdesktop.swingx.JXMonthView; import org.jdesktop.swingx.JXPanel; import org.jdesktop.swingx.JXTitledSeparator; import org.jdesktop.swingx.binding.LabelHandler; import org.jdesktop.swingx.calendar.CalendarUtils; import org.jdesktop.swingx.calendar.DateSelectionModel.SelectionMode; import org.jdesktop.swingx.combobox.EnumComboBoxModel; import org.jdesktop.swingx.demos.monthview.MonthViewDemoUtils.DayOfWeekConverter; import org.jdesktop.swingx.renderer.DefaultListRenderer; import org.jdesktop.swingx.renderer.FormatStringValue; import org.jdesktop.swingxset.util.DisplayValues; import com.jgoodies.forms.builder.PanelBuilder; import com.jgoodies.forms.factories.Borders; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import com.sun.swingset3.DemoProperties; /** * A demo for the {@code JXMonthView}. * * @author Karl George Schaefer * @author Joshua Outwater (original JXMonthViewDemoPanel) */ @DemoProperties( value = "JXMonthView (basic)", category = "Controls", description = "Demonstrates JXMonthView, a monthly calendar display.", sourceFiles = { "org/jdesktop/swingx/demos/monthview/MonthViewDemo.java", "org/jdesktop/swingx/demos/monthview/MonthViewDemoUtils.java", "org/jdesktop/swingx/demos/monthview/resources/MonthViewDemo.properties", "org/jdesktop/swingx/demos/monthview/resources/MonthViewDemo.html", "org/jdesktop/swingx/demos/monthview/resources/images/MonthViewDemo.png" } ) @SuppressWarnings("serial") public class MonthViewDemo extends JPanel { @SuppressWarnings("unused") private static final Logger LOG = Logger.getLogger(MonthViewDemo.class .getName()); private JXMonthView monthView; private JComboBox selectionModes; private JCheckBox traversable; private JComboBox dayOfWeekComboBox; private JCheckBox leadingDaysBox; private JCheckBox trailingDaysBox; private JSpinner prefColumnSlider; private JCheckBox weekNumberBox; private JSpinner prefRowSlider; private JXDatePicker flaggedDates; private JXDatePicker unselectableDates; private JXDatePicker upperBound; private JXDatePicker lowerBound; //---------------------- bind @SuppressWarnings("unchecked") private void bind() { new MonthViewDemoControl(); // PENDING JW: re-visit distribution of binding control ... // this is quite arbitrary (time of coding ;-) BindingGroup group = new BindingGroup(); group.addBinding(Bindings.createAutoBinding(READ, leadingDaysBox, BeanProperty.create("selected"), monthView, BeanProperty.create("showingLeadingDays"))); group.addBinding(Bindings.createAutoBinding(READ, trailingDaysBox, BeanProperty.create("selected"), monthView, BeanProperty.create("showingTrailingDays"))); group.addBinding(Bindings.createAutoBinding(READ, weekNumberBox, BeanProperty.create("selected"), monthView, BeanProperty.create("showingWeekNumber"))); group.addBinding(Bindings.createAutoBinding(READ, prefColumnSlider, BeanProperty.create("value"), monthView, BeanProperty.create("preferredColumnCount"))); group.addBinding(Bindings.createAutoBinding(READ, prefRowSlider, BeanProperty.create("value"), monthView, BeanProperty.create("preferredRowCount"))); group.bind(); } //--------------------- MonthViewDemoControl public class MonthViewDemoControl extends AbstractBean { private Date lastFlagged; private Date lastUnselectable; private Date upper; private Date lower; @SuppressWarnings("unchecked") public MonthViewDemoControl() { selectionModes.setModel(new EnumComboBoxModel<SelectionMode>(SelectionMode.class)); selectionModes.setRenderer(new DefaultListRenderer(DisplayValues.TITLE_WORDS_UNDERSCORE)); // PENDING JW: this does not survive a change in Locale - // revisit if we add changing Locale to the demo Calendar calendar = monthView.getCalendar(); // start of week == first day of week in the calendar's coordinate space CalendarUtils.startOfWeek(calendar); DefaultComboBoxModel model = new DefaultComboBoxModel(); for (int i = 0; i < 7; i++) { model.addElement(calendar.getTime()); calendar.add(Calendar.DATE, 1); } dayOfWeekComboBox.setModel(model); SimpleDateFormat format = new SimpleDateFormat("EEEE"); dayOfWeekComboBox.setRenderer(new DefaultListRenderer( new FormatStringValue(format))); Converter<?, ?> days = new DayOfWeekConverter(calendar); BindingGroup group = new BindingGroup(); group.addBinding(Bindings.createAutoBinding(READ, selectionModes, BeanProperty.create("selectedItem"), monthView, BeanProperty.create("selectionMode"))); group.addBinding(Bindings.createAutoBinding(READ, traversable, BeanProperty.create("selected"), monthView, BeanProperty.create("traversable"))); Binding dayOfWeek = Bindings.createAutoBinding(READ, dayOfWeekComboBox, BeanProperty.create("selectedItem"), monthView, BeanProperty.create("firstDayOfWeek")); dayOfWeek.setConverter(days); group.addBinding(dayOfWeek); Binding flagged = Bindings.createAutoBinding(READ, flaggedDates, BeanProperty.create("date"), this, BeanProperty.create("lastFlagged")); group.addBinding(flagged); Binding unselectable = Bindings.createAutoBinding(READ, unselectableDates, BeanProperty.create("date"), this, BeanProperty.create("lastUnselectable")); group.addBinding(unselectable); group.addBinding(Bindings.createAutoBinding(READ, upperBound, BeanProperty.create("date"), this, BeanProperty.create("upperBound"))); group.addBinding(Bindings.createAutoBinding(READ, lowerBound, BeanProperty.create("date"), this, BeanProperty.create("lowerBound"))); group.bind(); // PENDING JW: removed the color selection stuff for now // future will be to use highlighters anyway - revisit then } /** * @return the lastFlagged */ public Date getLastFlagged() { return lastFlagged; } /** * @param lastFlagged the lastFlagged to set */ public void setLastFlagged(Date lastFlagged) { Date old = getLastFlagged(); this.lastFlagged = lastFlagged; updateFlaggedDates(); firePropertyChange("lastFlagged", old, getLastFlagged()); } /** * */ private void updateFlaggedDates() { // PENDING JW: should be handled by converter // not working - "flaggedDates" is not a real property because different // types in getter/setter if (getLastFlagged() == null) { monthView.setFlaggedDates(); return; } Set<Date> old = monthView.getFlaggedDates(); Date[] flagged = new Date[old.size() + 1]; int index = 0; for (Date d : old) { flagged[index++] = d; } flagged[index] = getLastFlagged(); monthView.setFlaggedDates(flagged); } /** * @return the lastUnselectable */ public Date getLastUnselectable() { return lastUnselectable; } /** * @param lastUnselectable the lastUnselectable to set */ public void setLastUnselectable(Date lastUnselectable) { Date old = getLastUnselectable(); this.lastUnselectable = lastUnselectable; updateLastUnselectable(); firePropertyChange("lastUnselectable", old, getLastUnselectable()); } /** * */ private void updateLastUnselectable() { // JW: can't bind directly - it's not a property if (getLastUnselectable() == null) { monthView.setUnselectableDates(); return; } Set<Date> old = monthView.getSelectionModel().getUnselectableDates(); SortedSet<Date> result = new TreeSet<Date>(old); result.add(getLastUnselectable()); monthView.getSelectionModel().setUnselectableDates(result); } /** * @param lower the lower to set */ public void setLowerBound(Date lower) { Date old = getLowerBound(); this.lower = lower; monthView.setLowerBound(lower); firePropertyChange("lowerBound", old, getLowerBound()); } /** * @return the lower */ public Date getLowerBound() { return lower; } /** * @param upper the upper to set */ public void setUpperBound(Date upper) { Date old = getUpperBound(); this.upper = upper; monthView.setUpperBound(upper); firePropertyChange("upperBound", old, getUpperBound()); } /** * @return the upper */ public Date getUpperBound() { return upper; } } //--------------------- create ui private void createMonthViewDemo() { monthView = new JXMonthView(); monthView.setName("monthView"); // add to container which doesn't grow the size beyond the pref JComponent monthViewContainer = new JXPanel(); monthViewContainer.add(monthView); JPanel monthViewControlPanel = new JXPanel(); add(monthViewControlPanel, BorderLayout.SOUTH); FormLayout formLayout = new FormLayout( "f:m:g, l:4dlu:n, f:m:g", // columns "c:d:g, t:2dlu:n, t:d:n " ); // rows PanelBuilder builder = new PanelBuilder(formLayout, this); builder.setBorder(Borders.DLU4_BORDER); CellConstraints cc = new CellConstraints(); builder.add(monthViewContainer, cc.xywh(1, 1, 3, 1)); builder.add(createBoxPropertiesPanel(), cc.xywh(1, 3, 1, 1)); builder.add(createConfigPanel(), cc.xywh(3, 3, 1, 1)); } /** * @return */ private JComponent createConfigPanel() { JXCollapsiblePane painterControl = new JXCollapsiblePane(); FormLayout formLayout = new FormLayout( "5dlu, r:d:n, l:4dlu:n, f:m:g, l:4dlu:n, f:m:g", // columns "c:d:n " + ", t:4dlu:n, c:d:n " + ", t:4dlu:n, c:d:n" + ", t:4dlu:n, c:d:n" + ", t:4dlu:n, c:d:n" ); // 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("configurationSeparator"); builder.add(areaSeparator, cc.xywh(1, 1, 6, 1)); int labelColumn = 2; int widgetColumn = labelColumn + 2; int currentRow = 3; dayOfWeekComboBox = new JComboBox(); JLabel dayOfWeekLabel = builder.addLabel("", cl.xywh(labelColumn, currentRow, 1, 1), dayOfWeekComboBox, cc.xywh(widgetColumn, currentRow, 3, 1)); dayOfWeekLabel.setName("dayOfWeekLabel"); LabelHandler.bindLabelFor(dayOfWeekLabel, dayOfWeekComboBox); currentRow += 2; selectionModes = new JComboBox(); JLabel insets = builder.addLabel("", cl.xywh(labelColumn, currentRow, 1, 1), selectionModes, cc.xywh(widgetColumn, currentRow, 3, 1)); currentRow += 2; insets.setName("selectionModesLabel"); LabelHandler.bindLabelFor(insets, selectionModes); unselectableDates = new JXDatePicker(); JLabel unselectables = builder.addLabel("", cl.xywh(labelColumn, currentRow, 1, 1), unselectableDates, cc.xywh(widgetColumn, currentRow, 1, 1)); unselectables.setName("unselectableDatesLabel"); LabelHandler.bindLabelFor(unselectables, unselectableDates); flaggedDates = new JXDatePicker(); builder.add(flaggedDates, cc.xywh(widgetColumn + 2, currentRow, 1, 1)); currentRow += 2; upperBound = new JXDatePicker(); lowerBound = new JXDatePicker(); JLabel lower = builder.addLabel("", cl.xywh(labelColumn, currentRow, 1, 1), lowerBound, cc.xywh(widgetColumn, currentRow, 1, 1)); lower.setName("lowerBoundsLabel"); LabelHandler.bindLabelFor(lower, lowerBound); builder.add(upperBound, cc.xywh(widgetColumn + 2, currentRow, 1, 1)); currentRow += 2; return painterControl; } /** * @return */ private JComponent createBoxPropertiesPanel() { 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" + ", 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("monthBoxSeparator"); builder.add(areaSeparator, cc.xywh(1, 1, 6, 1)); int labelColumn = 2; int widgetColumn = labelColumn + 2; int currentRow = 3; prefColumnSlider = createSpinner(1, 3, 2); prefColumnSlider.setName("preferredColumnSlider"); prefRowSlider = createSpinner(1, 2, 1); prefRowSlider.setName("preferredRowSlider"); JLabel insets = builder.addLabel("", cl.xywh(labelColumn, currentRow, 1, 1), prefRowSlider, cc.xywh(widgetColumn, currentRow, 1, 1)); insets.setName("preferredColumnLabel"); LabelHandler.bindLabelFor(insets, prefRowSlider); builder.add(prefColumnSlider, cc.xywh(widgetColumn + 2, currentRow, 1, 1)); currentRow += 2; leadingDaysBox = new JCheckBox(); leadingDaysBox.setName("leadingDaysBox"); JLabel leadingLabel = builder.addLabel("", cl.xywh(labelColumn, currentRow, 1, 1), leadingDaysBox, cc.xywh(widgetColumn, currentRow, 1, 1)); leadingLabel.setName("leadingDaysLabel"); LabelHandler.bindLabelFor(leadingLabel, leadingDaysBox); trailingDaysBox = new JCheckBox(); trailingDaysBox.setName("trailingDaysBox"); builder.add(trailingDaysBox, cc.xywh(widgetColumn + 2, currentRow, 1, 1)); currentRow += 2; weekNumberBox = new JCheckBox(); weekNumberBox.setName("weekNumberBox"); builder.add(weekNumberBox, cc.xywh(widgetColumn, currentRow, 3, 1)); currentRow += 2; traversable = new JCheckBox(); traversable.setName("traversable"); builder.add(traversable, cc.xywh(widgetColumn, currentRow, 3, 1)); currentRow += 2; return painterControl; } private JSpinner createSpinner(int min, int max, int value) { SpinnerModel model = new SpinnerNumberModel(value, min, max, 1); JSpinner spinner = new JSpinner(model); ((DefaultEditor) spinner.getEditor()).getTextField().setEditable(false); return spinner; } /** * 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(MonthViewDemo.class.getAnnotation(DemoProperties.class).value()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new MonthViewDemo()); frame.setPreferredSize(new Dimension(800, 600)); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public MonthViewDemo() { super(new BorderLayout()); createMonthViewDemo(); Application.getInstance().getContext().getResourceMap(getClass()).injectComponents(this); bind(); } }