package de.wannawork.jcalendar;
/*
* Copyright (c) 2003, Bodo Tasche (http://www.wannawork.de)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Locale;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* This JCalendarPanel shows a Calendar.
*
* It is coded with 2 rules:
* <ul>
* <li>No hard coded Fonts or Colors, use the current Look and Feel</li>
* <li>No hard coded locale behaviour, use the given Locale (Start of Week, Name
* of Days/Months)</li>
* </ul>
*
* You can add a ChangeListener to this JCalendarPanel to receive change events.
*
* @author Bodo Tasche, Scott Sirovy
*/
public class JCalendarPanel extends JPanel implements ItemListener, ChangeListener {
/**
* Creates a Calendar using the current Date and current Local settings.
*/
public JCalendarPanel() {
createGUI((Calendar) Calendar.getInstance().clone(), Locale.getDefault(), DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault()), true, false);
}
/**
* Creates a Calendar using the cal-Date and current Locale Settings. It
* doesn't use the Locale in the Calendar-Object !
*
* @param cal Calendar to use
*/
public JCalendarPanel(Calendar cal) {
createGUI(cal, Locale.getDefault(), DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault()), true, false);
}
/**
* Creates a Calendar using the current Date and the given Locale Settings.
*
* @param locale Locale to use
*/
public JCalendarPanel(Locale locale) {
createGUI(Calendar.getInstance(locale), locale, DateFormat.getDateInstance(DateFormat.MEDIUM, locale), true, false);
}
/**
* Creates a Calender using the given Date and Locale
*
* @param cal Calendar to use
* @param locale Locale to use
*/
public JCalendarPanel(Calendar cal, Locale locale) {
createGUI(cal, locale, DateFormat.getDateInstance(DateFormat.MEDIUM, locale), true, false);
}
/**
* Creates a Calender using the given Calendar, Locale and DateFormat.
*
* @param cal Calendar to use
* @param locale Locale to use
* @param dateFormat DateFormat for the ComboBox
*/
public JCalendarPanel(Calendar cal, Locale locale, DateFormat dateFormat) {
createGUI(cal, locale, dateFormat, true, false);
}
/**
* Creates a Calender using the given Calendar, Locale and DateFormat.
*
* @param cal Calendar to use
* @param locale Locale to use
* @param dateFormat DateFormat for the ComboBox
* @param flat Flat Buttons for Navigation at the Bottom ?
*/
public JCalendarPanel(Calendar cal, Locale locale, DateFormat dateFormat, boolean flat) {
createGUI(cal, locale, dateFormat, flat, false);
}
/**
* Creates a Calender using the given Calendar, Locale and DateFormat.
*
* @param cal Calendar to use
* @param locale Locale to use
* @param dateFormat DateFormat for the ComboBox
* @param flat Flat Buttons for Navigation at the Bottom ?
*/
public JCalendarPanel(Calendar cal, Locale locale, DateFormat dateFormat, boolean flat, boolean calendarPanelDialogStyle) {
dialogStyle = calendarPanelDialogStyle;
createGUI(cal, locale, dateFormat, flat, calendarPanelDialogStyle);
}
private void checkYears(JComboBox aCombo, int aYear) {
if (aCombo != null) {
for (int i = 0; i < aCombo.getItemCount(); i++) {
if (aCombo.getItemAt(i).equals(aYear)) {
return;
}
}
aCombo.addItem(aYear);
}
}
/**
* Creates the GUI
*
* @param cal Calendar to use
* @param locale Locale to use
* @param dateFormat DateFormat to use
* @param flat Flat Buttons for Navigation at the Bottom ?
*/
private void createGUI(Calendar cal, Locale locale, DateFormat dateFormat, boolean flat, boolean calendarPanelDialogStyle) {
_locale = locale;
_cal = Calendar.getInstance(locale);
_cal.set(Calendar.DAY_OF_MONTH, cal.get(Calendar.DAY_OF_MONTH));
_cal.set(Calendar.MONTH, cal.get(Calendar.MONTH));
_cal.set(Calendar.YEAR, cal.get(Calendar.YEAR));
_format = dateFormat;
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
add(createButtonPanel(flat), c);
c.gridwidth = GridBagConstraints.BOTH;
_month = createMonth();
_month.addItemListener(this);
add(_month, c);
_year = createYear();
_year.addItemListener(this);
c.gridwidth = GridBagConstraints.REMAINDER;
add(_year, c);
c.anchor = GridBagConstraints.CENTER;
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(1, 1, 1, 1);
_monthPanel = new JMonthPanel(_cal, _locale);
_monthPanel.addChangeListener(this);
if (!((_format instanceof SimpleDateFormat)
&& ((SimpleDateFormat) _format).toPattern().startsWith("MM."))) {
add(_monthPanel, c);
}
c.insets = new Insets(0, 0, 1, 0);
if (calendarPanelDialogStyle) {
add(createDialogButtonPanel(flat), c);
}
}
/**
* Creates the ButtonPanel on the bottom
*
* @param flat Flat Buttons for Navigation at the Bottom ?
* @return JPanel with Buttons
*/
private JPanel createButtonPanel(boolean flat) {
JPanel buttonpanel = new JPanel();
JButton yearLeft;
JButton dayLeft;
JButton today;
JButton dayRight;
JButton yearRight;
if (flat) {
yearLeft = new FlatButton("<<"); //$NON-NLS-1$
dayLeft = new FlatButton("<"); //$NON-NLS-1$
today = new FlatButton(LocaleStrings.getString("JCalendarPanel.Today")); //$NON-NLS-1$
dayRight = new FlatButton(">"); //$NON-NLS-1$
yearRight = new FlatButton(">>"); //$NON-NLS-1$
} else {
yearLeft = new JButton("<<"); //$NON-NLS-1$
yearLeft.setMargin(new Insets(1, 1, 1, 1));
dayLeft = new JButton("<"); //$NON-NLS-1$
dayLeft.setMargin(new Insets(1, 1, 1, 1));
today = new JButton(LocaleStrings.getString("JCalendarPanel.Today")); //$NON-NLS-1$
today.setMargin(new Insets(2, 2, 2, 2));
dayRight = new JButton(">"); //$NON-NLS-1$
dayRight.setMargin(new Insets(1, 1, 1, 1));
yearRight = new JButton(">>"); //$NON-NLS-1$
yearRight.setMargin(new Insets(1, 1, 1, 1));
}
buttonpanel.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.NONE;
c.insets = new Insets(0, 0, 0, 5);
yearLeft.setMargin(new Insets(1, 1, 1, 1));
yearLeft.setToolTipText(LocaleStrings.getString("JCalendarPanel.Last_Year")); //$NON-NLS-1$
yearLeft.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (_year.getSelectedIndex() > 0) {
if (_cal == null) {
_cal = (Calendar) Calendar.getInstance().clone();
}
int month = _cal.get(Calendar.MONTH);
_cal.set(Calendar.YEAR, _cal.get(Calendar.YEAR) - 1);
if (_cal.get(Calendar.MONTH) != month) {
_cal.set(Calendar.MONTH, month);
}
setCalendar(_cal);
if (!dialogStyle) {
fireChangeEvent();
}
}
}
});
buttonpanel.add(yearLeft, c);
dayLeft.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (_cal == null) {
_cal = (Calendar) Calendar.getInstance().clone();
}
int monthIndex = _cal.get(Calendar.MONTH);
_cal.set(Calendar.MONTH, monthIndex - 1);
if (_cal.get(Calendar.MONTH) == monthIndex) {
_cal.set(Calendar.DAY_OF_MONTH, 0);
}
setCalendar(_cal);
if (!dialogStyle) {
fireChangeEvent();
}
}
});
dayLeft.setMargin(new Insets(1, 1, 1, 1));
dayLeft.setToolTipText(LocaleStrings.getString("JCalendarPanel.Last_Month")); //$NON-NLS-1$
buttonpanel.add(dayLeft, c);
GridBagConstraints c2 = new GridBagConstraints();
c2.fill = GridBagConstraints.HORIZONTAL;
c2.weightx = 1.0;
today.setMargin(new Insets(2, 2, 2, 2));
today.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setCalendar((Calendar) Calendar.getInstance().clone());
if (!dialogStyle) {
fireChangeEvent();
}
}
});
buttonpanel.add(today, c2);
c.insets = new Insets(0, 5, 0, 0);
dayRight.setMargin(new Insets(1, 1, 1, 1));
dayRight.setToolTipText(LocaleStrings.getString("JCalendarPanel.Next_Month")); //$NON-NLS-1$
dayRight.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (_cal == null) {
_cal = (Calendar) Calendar.getInstance().clone();
}
int monthIndex = _cal.get(Calendar.MONTH);
_cal.set(Calendar.MONTH, monthIndex + 1);
if (_cal.get(Calendar.MONTH) != (monthIndex + 1) % 12) {
_cal.set(Calendar.DAY_OF_MONTH, 0);
}
setCalendar(_cal);
if (!dialogStyle) {
fireChangeEvent();
}
}
});
buttonpanel.add(dayRight, c);
yearRight.setMargin(new Insets(1, 1, 1, 1));
yearRight.setToolTipText(LocaleStrings.getString("JCalendarPanel.Next_Year")); //$NON-NLS-1$
yearRight.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (_year.getSelectedIndex() < _year.getItemCount() - 1) {
if (_cal == null) {
_cal = (Calendar) Calendar.getInstance().clone();
}
int month = _cal.get(Calendar.MONTH);
_cal.set(Calendar.YEAR, _cal.get(Calendar.YEAR) + 1);
if (_cal.get(Calendar.MONTH) != month) {
_cal.set(Calendar.MONTH, month);
}
setCalendar(_cal);
if (!dialogStyle) {
fireChangeEvent();
}
}
}
});
buttonpanel.add(yearRight, c);
return buttonpanel;
}
/**
* Creates the ButtonPanel on the post bottom
*
* @param flat Flat Buttons for Navigation at the Bottom ?
* @return JPanel with Buttons
*/
private JPanel createDialogButtonPanel(boolean flat) {
JPanel buttonpanel = new JPanel();
JButton btnOk;
JButton btnCancel;
if (flat) {
btnOk = new FlatButton(LocaleStrings.getString("JCalendarPanel.OK"));
btnCancel = new FlatButton(LocaleStrings.getString("JCalendarPanel.Cancel"));
} else {
btnOk = new JButton(LocaleStrings.getString("JCalendarPanel.OK"));
btnOk.setMargin(new Insets(2, 2, 2, 2));
btnCancel = new JButton(LocaleStrings.getString("JCalendarPanel.Cancel"));
btnCancel.setMargin(new Insets(1, 1, 1, 1));
}
buttonpanel.setLayout(new GridBagLayout());
GridBagConstraints okConstraints = new GridBagConstraints();
okConstraints.fill = GridBagConstraints.HORIZONTAL;
okConstraints.weightx = 1.6;
GridBagConstraints cancelContsraints = new GridBagConstraints();
cancelContsraints.fill = GridBagConstraints.HORIZONTAL;
cancelContsraints.weightx = 1.0;
btnOk.setMargin(new Insets(2, 2, 2, 2));
btnOk.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireChangeEvent(e.getSource());
}
});
buttonpanel.add(btnOk, okConstraints);
btnCancel.setMargin(new Insets(1, 1, 1, 1));
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireHiddenEvent();
}
});
buttonpanel.add(btnCancel, cancelContsraints);
return buttonpanel;
}
/**
* Creates a JComboBox filled with year values (1900-2100)
*
* @return JComboBox with Years
*/
private JComboBox createYear() {
JComboBox year = new JComboBox();
boolean needArbitraryYear = true;
int lYear = _cal.get(Calendar.YEAR);
int beginingYear = 1900;
for (int i = beginingYear; i <= 2100; i++) {
year.addItem(i); //$NON-NLS-1$
if (i == lYear) {
needArbitraryYear = false;
}
}
if (needArbitraryYear) {
year.addItem(lYear);
}
year.setSelectedItem(lYear);
return year;
}
/**
* Creates a JComboBox filled with Months. The name for the Month is created
* using the locale given in the constructor.
*
* @return JComboBox filled with Months
*/
private JComboBox createMonth() {
JComboBox month = new JComboBox();
SimpleDateFormat format = new SimpleDateFormat("MMMMM", _locale);
// Probably should be using the same locale as the rest of the widget.
Calendar currentCal = Calendar.getInstance(_locale);
// Setting the day to 1 will avoids problems with leap years.
// If the calendar is created on March 30, 2004 (like I just did)
// then the day defaults to 30. When the month is set to 1 (February)
// the currentCal will *adjust* it to become March 1. This results
// in TWO entries with the value of \"March\" in the month combo.
currentCal.set(Calendar.DAY_OF_MONTH, 1);
for (int i = 0; i < 12; i++) {
currentCal.set(Calendar.MONTH, i);
currentCal.set(Calendar.YEAR, _cal.get(Calendar.YEAR));
String myString = format.format(currentCal.getTime());
month.addItem(myString);
}
month.setSelectedIndex(_cal.get(Calendar.MONTH));
return month;
}
/**
* Updates the Calendar
*/
private void updateCalendar() {
if (!_updating) {
_updating = true;
if (_cal == null) {
_cal = (Calendar) Calendar.getInstance().clone();
}
_cal.set(Calendar.MONTH, _month.getSelectedIndex());
_cal.set(Calendar.YEAR, (Integer) _year.getSelectedItem());
if (_monthPanel.getCalendar() != null) {
_cal.set(Calendar.DAY_OF_MONTH, _monthPanel.getSelectedDayOfMonth());
}
_monthPanel.setCalendar(_cal);
_updating = false;
}
}
/**
* Returns the current selected Date as Calender-Object
*
* @return current selected Date
*/
public Calendar getCalendar() {
updateCalendar();
return _cal;
}
/**
* Sets the current selected Date
*
* @param cal the Date to select
*/
public void setCalendar(Calendar cal) {
_updating = true;
if (cal != null) {
if (_cal == null) {
_cal = (Calendar) Calendar.getInstance().clone();
}
_cal.set(Calendar.DAY_OF_MONTH, cal.get(Calendar.DAY_OF_MONTH));
_cal.set(Calendar.MONTH, cal.get(Calendar.MONTH));
_cal.set(Calendar.YEAR, cal.get(Calendar.YEAR));
_cal.set(Calendar.HOUR_OF_DAY, cal.get(Calendar.HOUR_OF_DAY));
_cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE));
_cal.set(Calendar.SECOND, cal.get(Calendar.SECOND));
_cal.set(Calendar.MILLISECOND, cal.get(Calendar.MILLISECOND));
_monthPanel.setCalendar(_cal);
checkYears(_year, _cal.get(Calendar.YEAR));
_year.setSelectedItem(_cal.get(Calendar.YEAR));
_month.setSelectedIndex(_cal.get(Calendar.MONTH));
} else {
_cal = null;
_monthPanel.setCalendar(_cal);
}
_updating = false;
}
public void go2Today() {
setCalendar((Calendar) Calendar.getInstance().clone());
if (!dialogStyle) {
fireChangeEvent();
}
}
/**
* Returns a String-Representation of this Calendar using the DateFormat
* given in the Constructor
*
* @return String-Representation of this Calendar
*/
@Override
public String toString() {
updateCalendar();
return _format.format(_cal.getTime());
}
/**
* Returns a String-Representation of this Calendar using the given
* DateFormat
*
* @param format DateFormat to use
* @return String-Representation of this Calendar
*/
public String toString(DateFormat format) {
updateCalendar();
return format.format(_cal.getTime());
}
/**
* Recieves StateChanges from the ComboBoxes for Month/Year and updates the
* Calendar
*
* @param e ItemEvent
* @see
* java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
*/
@Override
public void itemStateChanged(ItemEvent e) {
updateCalendar();
if (_listenermode == FIRE_EVERYTIME) {
fireChangeEvent();
}
}
/**
* Recieves StateChanges from the MonthPanel and updates the Calendar
*
* @param e ChangeEvent
*
* @see
* javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
*/
@Override
public void stateChanged(ChangeEvent e) {
updateCalendar();
if (!dialogStyle) {
fireChangeEvent();
}
}
protected void fireHiddenEvent() {
ComponentListener[] listeners = getComponentListeners();
if (listeners != null) {
ComponentEvent e = new ComponentEvent(this, ComponentEvent.COMPONENT_HIDDEN);
for (ComponentListener l : listeners) {
if (l != null) {
l.componentHidden(e);
}
}
}
}
/**
* Adds a Changelistener to this JCalendarPanel.
*
* It will be called every time the selected Date changes.
*
* @param listener ChangeListener
*/
public void addChangeListener(ChangeListener listener) {
_changeListener.add(listener);
}
/**
* Removes a ChangeListener from this JCalendarPanel
*
* @param listener listener to remove
*/
public void removeChangeListener(ChangeListener listener) {
_changeListener.remove(listener);
}
/**
* Gets all ChangeListeners
*
* @return all ChangeListeners
*/
public ChangeListener[] getChangeListener() {
return (ChangeListener[]) _changeListener.toArray();
}
/**
* Fires the ChangeEvent
*/
protected void fireChangeEvent() {
fireChangeEvent(this);
}
protected void fireChangeEvent(Object aSource) {
if (!_fireingChangeEvent) {
_fireingChangeEvent = true;
ChangeEvent event = new ChangeEvent(aSource);
for (int i = 0; i < _changeListener.size(); i++) {
((ChangeListener) _changeListener.get(i)).stateChanged(event);
}
_fireingChangeEvent = false;
}
}
/**
* Sets the Mode when the FireChangeEvent is called. Use FIRE_EVERYTIME or
* FIRE_DAYCHANGES as parameter.
*
* @param mode The Mode of the Listener
*/
public void setListenerModus(int mode) {
_listenermode = mode;
}
/**
* Enables/Disables the Panel
*
* @param enabled Enabled ?
*/
@Override
public void setEnabled(boolean enabled) {
_month.setEnabled(enabled);
_year.setEnabled(enabled);
_monthPanel.setEnabled(enabled);
}
/**
* Is the Panel enabled ?
*
* @return enabled ?
*/
@Override
public boolean isEnabled() {
return _month.isEnabled();
}
public boolean isDialogStyle() {
return dialogStyle;
}
/**
* Returns the Dateformat the Panel is using
*
* @return DateFormat
*/
public DateFormat getDateFormat() {
return _format;
}
/**
* Fires everytime the Date changes
*/
public static final int FIRE_EVERYTIME = 1;
/**
* Fires only if the Day changes
*/
public static final int FIRE_DAYCHANGES = 2;
/**
* When does FireEvent() fire events? Every time there is an update or only
* if the Day was changed?
*/
private int _listenermode = FIRE_EVERYTIME;
/**
* Current change in progress?
*/
private boolean _updating = false;
protected boolean dialogStyle = false;
/**
* The current Date
*/
private Calendar _cal;
/**
* The DateFormat for Output
*/
private DateFormat _format;
/**
* The Locale to use
*/
private Locale _locale;
/**
* The JComboBox for Month-Selection
*/
private JComboBox _month;
/**
* The JComboBox for Year-Selection
*/
private JComboBox _year;
/**
* The JMonthPanel for Day-Selection
*/
private JMonthPanel _monthPanel;
/**
* The list of ChangeListeners
*/
private ArrayList _changeListener = new ArrayList();
/**
* Currently firing an ChangeEvent?
*/
private boolean _fireingChangeEvent = false;
}