org.jdesktop.swingx.calendar.AbstractDateSelectionModel Maven / Gradle / Ivy
Show all versions of swingx-all Show documentation
/*
* $Id: AbstractDateSelectionModel.java 3927 2011-02-22 16:34:11Z kleopatra $
*
* 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.calendar;
import org.jdesktop.swingx.event.DateSelectionEvent;
import org.jdesktop.swingx.event.DateSelectionEvent.EventType;
import org.jdesktop.swingx.event.DateSelectionListener;
import org.jdesktop.swingx.event.EventListenerMap;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.SortedSet;
import java.util.TimeZone;
import java.util.TreeSet;
/**
* Abstract base implementation of DateSelectionModel. Implements
* notification, Calendar related properties and lower/upper bounds.
*
* @author Jeanette Winzenburg
*/
public abstract class AbstractDateSelectionModel implements DateSelectionModel {
public static final SortedSet EMPTY_DATES = Collections.unmodifiableSortedSet(new TreeSet<>());
protected EventListenerMap listenerMap;
protected boolean adjusting;
protected Calendar calendar;
protected Date upperBound;
protected Date lowerBound;
/**
* the locale used by the calendar.
* NOTE: need to keep separately as a Calendar has no getter.
*/
protected Locale locale;
/**
* Instantiates a DateSelectionModel with default locale.
*/
protected AbstractDateSelectionModel() {
this(null);
}
/**
* Instantiates a DateSelectionModel with the given locale. If the locale is
* null, the Locale's default is used.
*
* PENDING JW: fall back to JComponent.getDefaultLocale instead? We use this
* with components anyway?
*
* @param locale the Locale to use with this model, defaults to Locale.default()
* if null.
*/
protected AbstractDateSelectionModel(Locale locale) {
this.listenerMap = new EventListenerMap();
setLocale(locale);
}
/**
* {@inheritDoc}
*/
@Override
public Calendar getCalendar() {
return (Calendar) calendar.clone();
}
/**
* {@inheritDoc}
*/
@Override
public int getFirstDayOfWeek() {
return calendar.getFirstDayOfWeek();
}
/**
* {@inheritDoc}
*/
@Override
public void setFirstDayOfWeek(int firstDayOfWeek) {
if (firstDayOfWeek == getFirstDayOfWeek())
return;
calendar.setFirstDayOfWeek(firstDayOfWeek);
fireValueChanged(EventType.CALENDAR_CHANGED);
}
/**
* {@inheritDoc}
*/
@Override
public int getMinimalDaysInFirstWeek() {
return calendar.getMinimalDaysInFirstWeek();
}
/**
* {@inheritDoc}
*/
@Override
public void setMinimalDaysInFirstWeek(int minimalDays) {
if (minimalDays == getMinimalDaysInFirstWeek())
return;
calendar.setMinimalDaysInFirstWeek(minimalDays);
fireValueChanged(EventType.CALENDAR_CHANGED);
}
/**
* {@inheritDoc}
*/
@Override
public TimeZone getTimeZone() {
return calendar.getTimeZone();
}
/**
* {@inheritDoc}
*/
@Override
public void setTimeZone(TimeZone timeZone) {
if (getTimeZone().equals(timeZone))
return;
TimeZone oldTimeZone = getTimeZone();
calendar.setTimeZone(timeZone);
adjustDatesToTimeZone(oldTimeZone);
fireValueChanged(EventType.CALENDAR_CHANGED);
}
/**
* Adjusts all stored dates to a new time zone.
* This method is called after the change had been made.
*
* This implementation resets all dates to null, clears everything.
* Subclasses may override to really map to the new time zone.
*
* @param oldTimeZone the old time zone
*/
protected void adjustDatesToTimeZone(TimeZone oldTimeZone) {
clearSelection();
setLowerBound(null);
setUpperBound(null);
setUnselectableDates(EMPTY_DATES);
}
/**
* {@inheritDoc}
*/
@Override
public Locale getLocale() {
return locale;
}
/**
* {@inheritDoc}
*/
@Override
public void setLocale(Locale locale) {
if (locale == null) {
locale = Locale.getDefault();
}
if (locale.equals(getLocale()))
return;
this.locale = locale;
if (calendar != null) {
calendar = Calendar.getInstance(calendar.getTimeZone(), locale);
} else {
calendar = Calendar.getInstance(locale);
}
fireValueChanged(EventType.CALENDAR_CHANGED);
}
//------------------- utility methods
/**
* Returns the start of the day of the given date in this model's calendar.
* NOTE: the calendar is changed by this operation.
*
* @param date the Date to get the start for.
* @return the Date representing the start of the day of the input date.
*/
protected Date startOfDay(Date date) {
return CalendarUtils.startOfDay(calendar, date);
}
/**
* Returns the end of the day of the given date in this model's calendar.
* NOTE: the calendar is changed by this operation.
*
* @param date the Date to get the start for.
* @return the Date representing the end of the day of the input date.
*/
protected Date endOfDay(Date date) {
return CalendarUtils.endOfDay(calendar, date);
}
/**
* Returns a boolean indicating whether the given dates are on the same day in
* the coordinates of the model's calendar.
*
* @param selected one of the dates to check, must not be null.
* @param compare the other of the dates to check, must not be null.
* @return true if both dates represent the same day in this model's calendar.
*/
protected boolean isSameDay(Date selected, Date compare) {
return startOfDay(selected).equals(startOfDay(compare));
}
//------------------- bounds
/**
* {@inheritDoc}
*/
@Override
public Date getUpperBound() {
return upperBound;
}
/**
* {@inheritDoc}
*/
@Override
public void setUpperBound(Date upperBound) {
if (upperBound != null) {
upperBound = getNormalizedDate(upperBound);
}
if (CalendarUtils.areEqual(upperBound, getUpperBound()))
return;
this.upperBound = upperBound;
if (this.upperBound != null && !isSelectionEmpty()) {
long justAboveUpperBoundMs = this.upperBound.getTime() + 1;
removeSelectionInterval(new Date(justAboveUpperBoundMs), getLastSelectionDate());
}
fireValueChanged(EventType.UPPER_BOUND_CHANGED);
}
/**
* {@inheritDoc}
*/
@Override
public Date getLowerBound() {
return lowerBound;
}
/**
* {@inheritDoc}
*/
@Override
public void setLowerBound(Date lowerBound) {
if (lowerBound != null) {
lowerBound = getNormalizedDate(lowerBound);
}
if (CalendarUtils.areEqual(lowerBound, getLowerBound()))
return;
this.lowerBound = lowerBound;
if (this.lowerBound != null && !isSelectionEmpty()) {
// Remove anything below the lower bound
long justBelowLowerBoundMs = this.lowerBound.getTime() - 1;
removeSelectionInterval(getFirstSelectionDate(), new Date(justBelowLowerBoundMs));
}
fireValueChanged(EventType.LOWER_BOUND_CHANGED);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isAdjusting() {
return adjusting;
}
/**
* {@inheritDoc}
*/
@Override
public void setAdjusting(boolean adjusting) {
if (adjusting == isAdjusting())
return;
this.adjusting = adjusting;
fireValueChanged(adjusting ? EventType.ADJUSTING_STARTED : EventType.ADJUSTING_STOPPED);
}
//----------------- notification
/**
* {@inheritDoc}
*/
@Override
public void addDateSelectionListener(DateSelectionListener l) {
listenerMap.add(DateSelectionListener.class, l);
}
/**
* {@inheritDoc}
*/
@Override
public void removeDateSelectionListener(DateSelectionListener l) {
listenerMap.remove(DateSelectionListener.class, l);
}
public List getDateSelectionListeners() {
return listenerMap.getListeners(DateSelectionListener.class);
}
protected void fireValueChanged(EventType eventType) {
List listeners = getDateSelectionListeners();
DateSelectionEvent e = null;
for (DateSelectionListener listener : listeners) {
if (e == null) {
e = new DateSelectionEvent(this, eventType, isAdjusting());
}
listener.valueChanged(e);
}
}
}