/*
* @(#)CalendarView.java
*
* Copyright 2011 Marcos Vasconcelos
*
* Towel 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 3 of the License, or
* (at your option) any later version.
*
* Towel 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.towel.swing.calendar;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Insets;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import javax.swing.Icon;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import com.towel.awt.ann.Action;
import com.towel.awt.ann.ActionManager;
/**
* <code>CalendarView</code> is a component which has a text field
* associated to a date picker.
*
* @see com.towel.swing.calendar.DatePicker
*
* @author Fabio Rener
* @author Marcos Vasconcelos
* @modified Eric Yuzo
*/
public class CalendarView extends JPanel {
private DatePicker datePicker;
private JTextField editor;
@Action(method = "openPopup")
private JButton button;
private JPopupMenu popup;
private String lastValidString;
/**
* Creates a new <code>CalendarView</code> associated to default locale
*/
public CalendarView() {
this(null, null);
}
/**
* Creates a new <code>CalendarView</code> associated to default locale
* and using specified date format pattern to format selected date.
*
* @param pattern
* the pattern describing the date format
*/
public CalendarView(String pattern) {
this(null, new SimpleDateFormat(pattern));
}
/**
* Creates a new <code>CalendarView</code> associated to given locale
* and using specified date format to format selected date.
*
* @param locale
* the locale associated to the date picker
* @param dateFormat
* the date format used to format selected date
*/
public CalendarView(Locale locale, DateFormat format) {
datePicker = new DatePicker(locale, format);
datePicker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String prop = evt.getPropertyName();
if ("day".equals(prop) || "date".equals(prop)) {
dateSelected(datePicker.getDate());
}
}
});
popup = new JPopupMenu();
popup.add(datePicker);
lastValidString = "";
init();
new ActionManager(this);
}
private void init() {
setLayout(new BorderLayout());
add(getEditor(), BorderLayout.CENTER);
add(getButton(), BorderLayout.EAST);
}
private JTextField getEditor() {
if (editor == null) {
editor = new JTextField(10);
editor.setInputVerifier(new DateInputVerifier());
}
return editor;
}
private JButton getButton() {
if (button == null) {
button = new JButton(". .");
button.setMargin(new Insets(0, 5, 0, 5));
}
return button;
}
/**
* Sets the editor's text.
*
* @param text
* the editor's new text
*/
public void setText(String text) {
getEditor().setText(text);
commitEdit();
}
/**
* Returns the editor's text.
*
* @return the editor's text
*/
public String getText() {
return getEditor().getText();
}
/**
* Sets the button's icon.
*
* @param icon
* the button's new icon.
*/
public void setIcon(Icon icon) {
getButton().setIcon(icon);
if (icon == null) {
getButton().setText(". .");
return;
}
getButton().setText("");
}
/**
* Returns a copy of selected <code>Calendar</code> or <code>null</code> if
* the text is empty.
*
* @return a copy of selected <code>Calendar</code> or <code>null</code> if
* the text is empty
*/
public Calendar getSelectedDate() {
Calendar calendar = null;
if (getText().length() > 0) {
calendar = datePicker.getSelectedDate();
}
return calendar;
}
/**
* Sets the selected <code>Calendar</code>.
*
* @param calendar
* the new selected <code>Calendar</code>
*/
public void setSelectedDate(Calendar calendar) {
datePicker.setSelectedDate(calendar);
}
/**
* Returns the locale associated to the date picker. The locale
* is used to get appropriate week day names and month names.
*
* @return the locale associated to the date picker
*/
public Locale getLocale() {
return datePicker.getLocale();
}
/**
* Changes the locale associated to the date picker. The locale
* is used to get appropriate week day names and month names.
*
* @param locale
* the new locale
*/
public void setLocale(Locale locale) {
datePicker.setLocale(locale);
}
/**
* Returns the date format used to format selected date.
*
* @return the date format used to format selected date
*/
public DateFormat getDateFormat() {
return datePicker.getDateFormat();
}
/**
* Changes the date format used to format selected date.
*
* @param locale
* the new date format
*/
public void setDateFormat(DateFormat dateFormat) {
datePicker.setDateFormat(dateFormat);
if (lastValidString.length() > 0) {
lastValidString = dateFormat.format(getSelectedDate().getTime());
}
commitEdit();
}
/**
* Changes the date format's pattern.
*
* @param pattern
* the pattern describing the date format
*/
public void setPattern(String pattern) {
setDateFormat(new SimpleDateFormat(pattern));
}
/**
* Returns the background color for date picker's header labels
* used to select month and year.
*
* @return the background color for date picker's header labels
*/
public Color getHeaderBackground() {
return datePicker.getHeaderBackground();
}
/**
* Sets the background color for date picker's header labels
* used to select month and year.
*
* @param headerBg
* the background color for date picker's header labels
*/
public void setHeaderBackground(Color headerBackground) {
datePicker.setHeaderBackground(headerBackground);
}
/**
* Returns the background color for date picker's week day labels.
*
* @return the background color for date picker's week day labels
*/
public Color getWeekDaysBackground() {
return datePicker.getWeekDaysBackground();
}
/**
* Sets the background color for date picker's week day labels.
*
* @param weekDaysBg
* the background color for date picker's week day labels
*/
public void setWeekDaysBackground(Color weekDaysBackground) {
datePicker.setWeekDaysBackground(weekDaysBackground);
}
/**
* Returns the background color for date picker's day picker labels.
*
* @return the background color for date picker's day picker labels
*/
public Color getDayPickerBackground() {
return datePicker.getDayPickerBackground();
}
/**
* Sets the background color for date picker's day picker labels.
*
* @param dayPickerBg
* the background color for date picker's day picker labels
*/
public void setDayPickerBackground(Color dayPickerBackground) {
datePicker.setDayPickerBackground(dayPickerBackground);
}
/**
* Returns the background color for date picker's selected day label.
*
* @return the background color for date picker's selected day label
*/
public Color getSelectedDayBackground() {
return datePicker.getSelectedDayBackground();
}
/**
* Sets the background color for date picker's selected day label.
*
* @param selectedDayBg
* the background color for date picker's selected day label
*/
public void setSelectedDayBackground(Color selectedDayBackground) {
datePicker.setSelectedDayBackground(selectedDayBackground);
}
/**
* Returns the foreground color for date picker's header labels
* used to select month and year.
*
* @return the foreground color for date picker's header labels
*/
public Color getHeaderForeground() {
return datePicker.getHeaderForeground();
}
/**
* Sets the foreground color for date picker's header labels
* used to select month and year.
*
* @param headerFg
* the foreground color for date picker's header labels
*/
public void setHeaderForeground(Color headerForeground) {
datePicker.setHeaderForeground(headerForeground);
}
/**
* Returns the foreground color for date picker's week day labels.
*
* @return the foreground color for date picker's week day labels
*/
public Color getWeekDaysForeground() {
return datePicker.getWeekDaysForeground();
}
/**
* Sets the foreground color for date picker's week day labels.
*
* @param weekDaysFg
* the foreground color for date picker's week day labels
*/
public void setWeekDaysForeground(Color weekDaysForeground) {
datePicker.setWeekDaysForeground(weekDaysForeground);
}
/**
* Returns the foreground color for date picker's day picker labels.
*
* @return the foreground color for date picker's day picker labels
*/
public Color getDayPickerForeground() {
return datePicker.getDayPickerForeground();
}
/**
* Sets the foreground color for date picker's day picker labels.
*
* @param dayPickerFg
* the foreground color for date picker's day picker labels
*/
public void setDayPickerForeground(Color dayPickerForeground) {
datePicker.setDayPickerForeground(dayPickerForeground);
}
/**
* Returns the foreground color for date picker's selected day label.
*
* @return the foreground color for date picker's selected day label
*/
public Color getSelectedDayForeground() {
return datePicker.getSelectedDayForeground();
}
/**
* Sets the foreground color for date picker's selected day label.
*
* @param selectedDayFg
* the foreground color for date picker's selected day label
*/
public void setSelectedDayForeground(Color selectedDayForeground) {
datePicker.setSelectedDayForeground(selectedDayForeground);
}
/**
* Sets date picker's today button's text.
*
* @param todayString
* the text to be displayed in today button.
*/
public void setTodayString(String todayString) {
datePicker.setTodayString(todayString);
}
/**
* Makes date picker's today button visible or invisible.
*
* @param visible
* true to make <today button visible; false, otherwise
*/
public void setTodayButtonVisible(boolean visible) {
datePicker.setTodayButtonVisible(visible);
}
/**
* This is the action when button was pressed.
*
* @see com.towel.awt.ann.Action
* @see com.towel.awt.ann.ActionManager
*/
@SuppressWarnings("unused")
private void openPopup() {
popup.show(button, button.getWidth()
- datePicker.getPreferredSize().width, button.getHeight());
} // ActionPerformed
/**
* Sets the editor's text and makes the date picker invisible.
*
* @param strDate
* the editor's new text
*/
public void dateSelected(String strDate) {
getEditor().setText(strDate);
commitEdit();
popup.setVisible(false);
}
@Override
public void setEnabled(boolean enabled) {
getEditor().setEnabled(enabled);
getButton().setEnabled(enabled);
super.setEnabled(enabled);
}
// commits editor's text if it's a valid string or brings back
// the last valid string and sets the datePicker's selected date
private void commitEdit() {
String strDate = getText();
if (strDate.isEmpty() || isValidDate(strDate)) {
lastValidString = strDate;
} else {
getEditor().setText(lastValidString);
strDate = lastValidString;
}
if (strDate.length() > 0) {
try {
Calendar cal = Calendar.getInstance();
cal.setTime(getDateFormat().parse(strDate));
datePicker.setSelectedDate(cal);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
// returns true if given string represents a valid date
private boolean isValidDate(String strDate) {
DateFormat format = getDateFormat();
try {
format.parse(strDate);
return true;
} catch (ParseException e) {
return false;
}
}
// An input verifier to validate editor's text
private class DateInputVerifier extends InputVerifier {
// Commits editor's text and always returns true
@Override
public boolean shouldYieldFocus(JComponent input) {
commitEdit();
return true;
}
// Not used
@Override
public boolean verify(JComponent input) {
String strDate = ((JTextField) input).getText();
return strDate.isEmpty() || isValidDate(strDate);
}
}
}