fi.jasoft.simplecalendar.SimpleCalendar.java Source code

Java tutorial

Introduction

Here is the source code for fi.jasoft.simplecalendar.SimpleCalendar.java

Source

/*
 * Copyright 2013 John Ahlroos
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package fi.jasoft.simplecalendar;

import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import com.vaadin.data.util.converter.Converter.ConversionException;
import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.AbstractFieldState;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.LegacyComponent;

import fi.jasoft.simplecalendar.shared.DateValueChangeRpc;
import fi.jasoft.simplecalendar.shared.SimpleCalendarState;
import fi.jasoft.simplecalendar.shared.Weekday;

@SuppressWarnings("serial")
public class SimpleCalendar extends AbstractField<Object> {

    private DateValueChangeRpc valueChangeRpc = new DateValueChangeRpc() {

        @Override
        public void selected(Set<Date> dates) {
            setValue(dates, false);
        }
    };

    /**
     * Default constructor
     */
    public SimpleCalendar() {
        registerRpc(valueChangeRpc);
    }

    /**
     * The type is a java.util.Set if in multiselect mode else it is a Date
     */
    @Override
    public Class<?> getType() {
        if (isMultiSelect()) {
            return Set.class;
        }
        return Date.class;
    }

    /*
     * (non-Javadoc)
     * @see com.vaadin.ui.AbstractField#getState()
     */
    @Override
    protected SimpleCalendarState getState() {
        return (SimpleCalendarState) super.getState();
    }

    /*
     * (non-Javadoc)
     * @see com.vaadin.ui.AbstractComponent#getState(boolean)
     */
    @Override
    protected SimpleCalendarState getState(boolean markAsDirty) {
        return (SimpleCalendarState) super.getState(markAsDirty);
    }

    /**
     * Returns a java.util.Set of Dates if in multiselect mode else a single
     * Date or null if no date has been selected.
     */
    @Override
    public Object getValue() {
        if (isMultiSelect() && super.getValue() == null) {
            return Collections.EMPTY_SET;
        }
        return super.getValue();
    }

    /**
     * Set the Date(s) which should be selected. If multiselect mode is set then
     * the value should be a collection of dates, if not in multiselect mode the
     * it should be a Date
     */
    @Override
    public void setValue(Object newValue) throws ReadOnlyException, ConversionException {
        if (newValue == null) {
            super.setValue(null);
        } else if (newValue instanceof Date && !isMultiSelect()) {
            if (isDateDisabled((Date) newValue)) {
                throw new IllegalArgumentException("Date has been disabled");
            } else if (!isDateInRange((Date) newValue)) {
                throw new IllegalArgumentException("Date is outside of start or end date");
            } else {
                super.setValue(newValue);
            }
        } else if (newValue instanceof Date) {
            if (isDateDisabled((Date) newValue)) {
                throw new IllegalArgumentException("Date has been disabled");
            } else if (!isDateInRange((Date) newValue)) {
                throw new IllegalArgumentException("Date is outside of start or end date");
            } else {
                super.setValue(Collections.singleton(newValue));
            }
        } else if (newValue instanceof Collection<?> && isMultiSelect()) {
            for (Date d : (Collection<Date>) newValue) {
                if (isDateDisabled(d)) {
                    throw new IllegalArgumentException("Date has been disabled");
                } else if (!isDateInRange(d)) {
                    throw new IllegalArgumentException("Date is outside of start or end date");
                }
            }
            super.setValue(newValue);
        } else {
            throw new IllegalArgumentException("The value must be a Date or a collection of dates if multiselect.");
        }
    }

    /**
     * Determines if a user can select several dates. Please note that setting
     * this to true will effect {@link #getValue()} and
     * {@link #setValue(Object)}.
     * 
     * @param multiselect
     *            Should the user be able to select several dates
     */
    public void setMultiSelect(boolean multiselect) {
        getState().multiselect = multiselect;
    }

    /**
     * If multiselect is true then several Dates can be selected
     * 
     * @return Is multiselect mode active
     */
    public boolean isMultiSelect() {
        return getState(false).multiselect;
    }

    /**
     * Sets specific weekdays which the user should not be able to select
     * 
     * @param day
     */
    public void setDisabledWeekDays(Weekday... days) {
        getState().disabledWeekdays = Arrays.asList(days);
    }

    /**
     * Returns a set with weekdays which has been disabled
     * 
     * @return
     */
    public Weekday[] getDisabledWeekdays() {
        List<Weekday> weekDays = getState(false).disabledWeekdays;
        if (weekDays == null || weekDays.isEmpty()) {
            return new Weekday[0];
        }
        return weekDays.toArray(new Weekday[weekDays.size()]);
    }

    /**
     * Returns true if a date has been disabled, null dates are always enabled
     * 
     * @param date
     *            The date to check
     * @return True if date is disabled
     */
    protected boolean isDateDisabled(Date date) {
        if (date == null) {
            return false;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        // Check disabled weekdays
        for (Weekday wd : getDisabledWeekdays()) {
            if (Weekday.toInteger(wd) == calendar.get(Calendar.DAY_OF_WEEK)) {
                return true;
            }
        }

        // Check disabled monthly days
        for (Integer d : getDisabledMonthlyDates()) {
            if (calendar.get(Calendar.DAY_OF_MONTH) == d) {
                return true;
            }
        }

        // Check for disabled dates
        Calendar dcal = Calendar.getInstance();
        for (Date d : getDisabledDates()) {
            dcal.setTime(d);
            if (calendar.get(Calendar.YEAR) == dcal.get(Calendar.YEAR)
                    && calendar.get(Calendar.MONTH) == dcal.get(Calendar.MONTH)
                    && calendar.get(Calendar.DAY_OF_MONTH) == dcal.get(Calendar.DAY_OF_MONTH)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Is the date in the given range
     * 
     * @param date
     *            The date to test
     * @return
     */
    protected boolean isDateInRange(Date date) {
        if (getStartDate() != null && date != null && date.before(getStartDate())) {
            return false;
        }
        if (getEndDate() != null && date != null && date.after(getEndDate())) {
            return false;
        }
        return true;
    }

    /**
     * Set which days of the month should be disabled. Values should be between
     * 1 and 31.
     * 
     * @param days
     *            The days of the month which should be disabled each month
     */
    public void setDisabledMonthlyDates(Integer... dates) {
        getState().disabledMonthdays = Arrays.asList(dates);
    }

    /**
     * Returns the monthly days of month which are disabled
     * 
     * @return
     */
    public Integer[] getDisabledMonthlyDates() {
        List<Integer> disabledDates = getState(false).disabledMonthdays;
        if (disabledDates == null || disabledDates.isEmpty()) {
            return new Integer[0];
        }
        return disabledDates.toArray(new Integer[disabledDates.size()]);
    }

    /**
     * Set dates which should be disabled
     * 
     * @param dates
     *            Dates which are disabled
     */
    public void setDisabledDates(Date... dates) {
        getState().disabledDates = Arrays.asList(dates);
    }

    /**
     * Returns dates which have been disabled
     * 
     * @return
     */
    public Date[] getDisabledDates() {
        List<Date> disabledDates = getState(false).disabledDates;
        if (disabledDates == null || disabledDates.isEmpty()) {
            return new Date[0];
        }
        return disabledDates.toArray(new Date[disabledDates.size()]);
    }

    /**
     * Set the oldest date the panel should display or NULL to not have a limit
     * 
     * @param start
     *            The first date in the panel
     */
    public void setStartDate(Date start) {
        getState().startDate = start;
    }

    /**
     * Returns the first date the panel displays or NULL if not set
     * 
     * @return
     */
    public Date getStartDate() {
        return getState(false).startDate;
    }

    /**
     * Set the last date the panel should display or NULL to not have a limit
     * 
     * @param end
     *            The last date the panel should display
     */
    public void setEndDate(Date end) {
        getState().endDate = end;
    }

    /**
     * Returns the last date the panel displays or NULL if no limit has been set
     * 
     * @return
     */
    public Date getEndDate() {
        return getState(false).endDate;
    }

    /*
     * (non-Javadoc)
     * @see com.vaadin.ui.AbstractField#setLocale(java.util.Locale)
     */
    @Override
    public void setLocale(Locale locale) {
        super.setLocale(locale);
        if (getLocale() != null) {
            getState().locale = getLocale().toString();
        } else {
            getState().locale = null;
        }
    }

    /*
     * (non-Javadoc)
     * @see com.vaadin.ui.AbstractField#beforeClientResponse(boolean)
     */
    @Override
    public void beforeClientResponse(boolean initial) {
        super.beforeClientResponse(initial);
        if (initial && getLocale() != null) {
            getState().locale = getLocale().toString();
        }
    }
}