/* * Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org * Use is subject to license terms. See license.txt. */ package org.beanfabrics.swing.goodies.calendar; import java.awt.Color; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.Serializable; import java.net.URL; import java.util.Date; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import org.beanfabrics.View; import org.beanfabrics.event.WeakPropertyChangeListener; import org.beanfabrics.model.ConversionException; import org.beanfabrics.model.DatePM; import org.beanfabrics.model.IDatePM; import org.beanfabrics.model.PresentationModel; /** * @author Max Gensthaler */ @SuppressWarnings("serial") public class DatePMCalendarChooserButton extends JButton implements View<IDatePM> { private static final URL ICON_URL = DatePMCalendarChooserButton.class.getResource("bn_calendarchooser_obj16.png"); private static final ImageIcon ICON = new ImageIcon(ICON_URL); private final WeakPropertyChangeListener listener = new MyWeakPropertyChangeListener(); private class MyWeakPropertyChangeListener implements WeakPropertyChangeListener, Serializable { public void propertyChange(java.beans.PropertyChangeEvent evt) { refresh(); } }; private IDatePM pModel; private CalendarChooser calendarChooser; private JPopupMenu popup; private boolean dateSelected; private final ActionListener myActionListener = new MyActionListener(); private class MyActionListener implements ActionListener, Serializable { public void actionPerformed(ActionEvent e) { JPopupMenu popup = createPopup(); int x = DatePMCalendarChooserButton.this.getWidth() - popup.getPreferredSize().width; int y = DatePMCalendarChooserButton.this.getHeight(); dateSelected = false; popup.show(DatePMCalendarChooserButton.this, x, y); } } private final PropertyChangeListener calendarChooserListener = new MyPropertyChangeListener(); private class MyPropertyChangeListener implements PropertyChangeListener, Serializable { /** * Listens for a "date" property change or a "selectedDate" property change event from the CalendarChooser. * Updates the {@link DatePM} and closes the popup. * * @param evt * the event */ public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(CalendarChooser.SELECTEDDATE_PROPERTYNAME)) { if (popup != null && popup.isVisible()) { dateSelected = true; popup.setVisible(false); Date selectedDate = getCalendarChooser().getSelectedDate(); setDate(selectedDate); } } } }; public DatePMCalendarChooserButton() { this(0, 0); } public DatePMCalendarChooserButton(int prevVisMonths, int subsVisMonths) { super(ICON); this.setMargin(new Insets(0, 0, 0, 0)); this.setContentAreaFilled(false); this.addActionListener(myActionListener); CalendarChooser cc = getCalendarChooser(); cc.setNumberOfPreviousVisibleMonths(prevVisMonths); cc.setNumberOfSubsequentVisibleMonths(subsVisMonths); refresh(); } /** {@inheritDoc} */ public IDatePM getPresentationModel() { return pModel; } /** {@inheritDoc} */ public void setPresentationModel(IDatePM newModel) { IDatePM oldModel = this.pModel; if (this.pModel != null) { this.pModel.removePropertyChangeListener(listener); } this.pModel = newModel; if (this.pModel != null) { this.pModel.addPropertyChangeListener(listener); } refresh(); this.firePropertyChange("presentationModel", oldModel, newModel); } /** * Returns whether this component is connected to the target {@link PresentationModel} to synchronize with. This is * a convenience method. * * @return <code>true</code> when this component is connected, else <code>false</code> */ boolean isConnected() { return this.pModel != null; } private void refresh() { if (isConnected()) { try { Date date = getPresentationModel().getDate(); calendarChooser.setSelectedDate(date); } catch (ConversionException ce) { // the date is invalid // -> clear the selected date from the calendar chooser component calendarChooser.setSelectedDate(null); } final String tooltip; if (pModel.isValid()) { tooltip = pModel.getDescription(); this.setBackground(null); } else { tooltip = pModel.getValidationState().getMessage(); this.setBackground(Color.RED); } this.setToolTipText(tooltip); boolean editable = pModel.isEditable(); this.setEnabled(editable); } else { this.setToolTipText(null); this.setEnabled(false); } } /** * Set date to the model. * * @param date * date to set */ private void setDate(Date date) { if (pModel != null) { pModel.setDate(date); } } public JPopupMenu createPopup() { if (this.popup == null) { this.popup = new JPopupMenu() { @Override public void setVisible(boolean b) { Boolean isCanceled = (Boolean) getClientProperty("JPopupMenu.firePopupMenuCanceled"); if (b || (!b && dateSelected) || ((isCanceled != null) && !b && isCanceled.booleanValue())) { super.setVisible(b); } } }; popup.setLightWeightPopupEnabled(true); } popup.removeAll(); popup.add(getCalendarChooser()); return popup; } public CalendarChooser getCalendarChooser() { if (calendarChooser == null) { CalendarChooser chooser = new CalendarChooser(); // chooser.setBackground(new Color(230, 142, 138)); // chooser.setHeaderForegroundColor(Color.WHITE); // chooser.setDateFont(chooser.getDateFont().deriveFont(Font.BOLD)); chooser.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); chooser.setOpaque(false); setCalendarChooser(chooser); } return calendarChooser; } public void setCalendarChooser(CalendarChooser aCalendarChooser) { if (this.calendarChooser != null) { this.calendarChooser.removePropertyChangeListener(CalendarChooser.SELECTEDDATE_PROPERTYNAME, this.calendarChooserListener); } this.calendarChooser = aCalendarChooser; if (this.calendarChooser != null) { this.calendarChooser.addPropertyChangeListener(CalendarChooser.SELECTEDDATE_PROPERTYNAME, this.calendarChooserListener); } } /** * Updates the UI of itself and the popup. */ @Override public void updateUI() { super.updateUI(); setEnabled(isEnabled()); // TODO hmm, why? if (calendarChooser != null) { SwingUtilities.updateComponentTreeUI(calendarChooser); } if (popup != null) { SwingUtilities.updateComponentTreeUI(popup); } } }