/**
* License Agreement.
*
* JBoss RichFaces - Ajax4jsf Component Library
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.richfaces.component;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import javax.faces.FacesException;
import javax.faces.application.Application;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIInput;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.DateTimeConverter;
import javax.faces.el.MethodBinding;
import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.ValueChangeEvent;
import org.ajax4jsf.component.AjaxComponent;
import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.event.AjaxEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.event.CurrentDateChangeEvent;
import org.richfaces.event.CurrentDateChangeListener;
import org.richfaces.model.CalendarDataModel;
import org.richfaces.model.CalendarDataModelItem;
import org.richfaces.renderkit.CalendarRendererBase;
// import org.richfaces.renderkit.html.BaseGradient.Data;
/**
* JSF component class
*
*/
public abstract class UICalendar extends UIInput implements AjaxComponent {
/**
* firstWeekDay
* Gets what the first day of the week is; e.g., SUNDAY in the U.S., MONDAY in France.
*/
private int _firstWeekDay = 0;
/**
* Flag indicated what firstWeekDay is set.
*/
private boolean _firstWeekDaySet = false;
/**
* minDaysInFirstWeek
* Gets what the minimal days required in the first week of the year
are; e.g., if the first week is defined as one that contains the first
day of the first month of a year, this method returns 1. If the
minimal days required must be a full week, this method returns 7.
*/
private int _minDaysInFirstWeek = 0;
/**
* Flag indicated what minDaysInFirstWeek is set.
*/
private boolean _minDaysInFirstWeekSet = false;
public static final String COMPONENT_TYPE = "org.richfaces.Calendar";
private static final String COMPONENT_FAMILY = "org.richfaces.Calendar";
public static final String AJAX_MODE = "ajax";
public static final String CLIENT_MODE = "client";
private final static Log log = LogFactory.getLog(UICalendar.class);
public abstract Object getLocale();
public abstract void setLocale(Object locale);
public abstract TimeZone getTimeZone();
public abstract void setTimeZone(TimeZone timeZone);
public abstract Object getPreloadDateRangeBegin();
public abstract void setPreloadDateRangeBegin(Object date);
public abstract Object getPreloadDateRangeEnd();
public abstract void setPreloadDateRangeEnd(Object date);
public abstract Object getCurrentDate();
public abstract void setCurrentDate(Object date);
public abstract CalendarDataModel getDataModel();
public abstract void setDataModel(CalendarDataModel dataModel);
public abstract String getDatePattern();
public abstract void setDatePattern(String pattern);
public abstract Object getMonthLabels();
public abstract void setMonthLabels(Object labels);
public abstract Object getMonthLabelsShort();
public abstract void setMonthLabelsShort(Object labels);
public abstract Object getWeekDayLabels();
public abstract void setWeekDayLabels(Object labels);
public abstract Object getWeekDayLabelsShort();
public abstract void setWeekDayLabelsShort(Object labels);
public abstract String getJointPoint();
public abstract void setJointPoint(String jointPoint);
public abstract String getDirection();
public abstract void setDirection(String direction);
public abstract boolean isPopup();
public abstract void setPopup(boolean popup);
public abstract boolean isDisabled();
public abstract void setDisabled(boolean disabled);
public abstract String getButtonLabel();
public abstract void setButtonLabel(String buttonLabel);
public abstract String getToolTipMode();
public abstract void setToolTipMode(String toolTipMode);
public abstract String getBoundaryDatesMode();
public abstract void setBoundaryDatesMode(String boundaryDatesMode);
public abstract MethodBinding getCurrentDateChangeListener();
public abstract void setCurrentDateChangeListener(
MethodBinding scrollerListener);
public abstract String getMode();
public abstract void setMode(String mode);
public abstract int getVerticalOffset();
public abstract void setVerticalOffset(int verticalOffset);
public abstract int getHorizontalOffset();
public abstract void setHorizontalOffset(int horizontalOffset);
public abstract String getDayStyleClass();
public abstract void setDayStyleClass(String DayStyleClass);
public abstract String getIsDayEnabled();
public abstract void setIsDayEnabled(String isDayEnabled);
public abstract String getCellHeight();
public abstract void setCellHeight(String cellHeight);
public abstract String getCellWidth();
public abstract void setCellWidth(String cellWidth);
public abstract boolean isShowWeekDaysBar();
public abstract void setShowWeekDaysBar(boolean showWeekDaysBar);
public abstract boolean isShowWeeksBar();
public abstract void setShowWeeksBar(boolean showWeeksBar);
public abstract boolean isShowHeader();
public abstract void setShowHeader(boolean showScrollerBar);
public abstract boolean isShowFooter();
public abstract void setShowFooter(boolean showScrollerBar);
public abstract String getTodayControlMode();
public abstract void setTodayControlMode(String todayControlMode);
public abstract boolean isShowApplyButton();
public abstract void setShowApplyButton(boolean showApplyButton);
// TODO onclick add users onclick
// currentDate processing -------------------------------------------------
public Calendar getCalendar() {
return Calendar.getInstance(getTimeZone(), getAsLocale(getLocale()));
}
public Date getConvertedValue(FacesContext context, String currentDateString)
throws ConverterException {
DateTimeConverter datetime = new DateTimeConverter();
datetime.setPattern("m/y");
Date newCurrentDate = (Date) datetime.getAsObject(context, this,
currentDateString);
return newCurrentDate;
}
protected void validateValue(FacesContext context, Object newValue) {
// TODO nick - nick - do we need this?
// store converted value in submitted value to ease client-side code's
// life
// see
// org.richfaces.renderkit.CalendarRendererBase.getSelectedDate(FacesContext,
// UICalendar) for more
setSubmittedValue(newValue);
super.validateValue(context, newValue);
}
public void updateCurrentDate(FacesContext context, Object currentDate) {
if (context == null) {
throw new NullPointerException();
}
//RF-1073
try {
ValueBinding vb = getValueBinding("currentDate");
if (vb != null) {
if(vb.getType(context).equals(String.class)){
DateTimeConverter convert = new DateTimeConverter();
convert.setLocale(getAsLocale(getLocale()));
convert.setPattern(getDatePattern());
vb.setValue(context, convert.getAsString(context, this,
currentDate));
return;
}else if(vb.getType(context).equals(Calendar.class)){
Calendar c = Calendar.getInstance();
c.setTime((Date) currentDate);
vb.setValue(context, c);
return;
}else{
vb.setValue(context, currentDate);
return;
}
} else {
setCurrentDate(currentDate);
}
} catch (Exception e) {
setValid(false);
// XXX nick - kaa - add log.debug(...)
if (log.isDebugEnabled()) {
log.debug(" updateCurrentDate method throws exception: "
+ e.toString(), e);
}
e.printStackTrace();
String messageString = e.toString();
FacesMessage message = new FacesMessage(messageString);
message.setSeverity(FacesMessage.SEVERITY_ERROR);
context.addMessage(getClientId(context), message);
}
}
public Date getCurrentDateOrDefault() {
Date date = getAsDate(getCurrentDate());
if (date != null) {
return date;
} else {
Date value = getAsDate(this.getValue());
if (value != null) {
return value;
} else {
return java.util.Calendar.getInstance(getTimeZone()).getTime();
}
}
}
public Date getAsDate(Object date) {
if (date == null) {
return null;
} else {
if (date instanceof Date) {
return (Date) date;
} else {
if (date instanceof String) {
DateTimeConverter converter = new DateTimeConverter();
converter.setPattern(this.getDatePattern());
converter.setLocale(getAsLocale(this.getLocale()));
converter.setTimeZone(this.getTimeZone());
FacesContext context = FacesContext.getCurrentInstance();
return (Date) converter.getAsObject(context, this,
(String) date);
} else {
if (date instanceof Calendar) {
return ((Calendar) date).getTime();
} else {
throw new FacesException("Wrong attibute type");
}
}
}
}
}
public Object getTooltip(Date date) {
CalendarDataModel calendarDM = (CalendarDataModel) getDataModel();
if (calendarDM != null) {
return calendarDM.getToolTip(date);
} else {
return null;
}
}
protected Date getDefaultPreloadBegin(Date date) {
Calendar calendar = Calendar.getInstance(getTimeZone(), getAsLocale(getLocale()));
calendar.setTime(date);
calendar.set(Calendar.DATE, calendar.getActualMinimum(Calendar.DATE));
/*
* //force recalculation calendar.getTimeInMillis();
* calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
*/
return calendar.getTime();
}
protected Date getDefaultPreloadEnd(Date date) {
Calendar calendar = Calendar.getInstance(getTimeZone(), getAsLocale(getLocale()));
calendar.setTime(date);
calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
/*
* //force recalculation calendar.getTimeInMillis();
* calendar.set(Calendar.DAY_OF_WEEK, getLastDayOfWeek(calendar));
*/
return calendar.getTime();
}
protected Locale getDefaultLocale() {
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext != null) {
UIViewRoot viewRoot = facesContext.getViewRoot();
if (viewRoot != null) {
Locale locale = viewRoot.getLocale();
if (locale != null) {
return locale;
}
}
}
return Locale.US;
}
protected TimeZone getDefaultTimeZone() {
return TimeZone.getDefault();
}
public Date convertCurrentDate(String currentDateString) {
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(Calendar.DATE, 1);
int idx = currentDateString.indexOf('/');
if (idx != -1) {
calendar.set(Calendar.MONTH, Integer.parseInt(currentDateString
.substring(0, idx)) - 1);
calendar.set(Calendar.YEAR, Integer.parseInt(currentDateString
.substring(idx + 1)));
return calendar.getTime();
} else {
return null;
}
}
public void broadcast(FacesEvent event) throws AbortProcessingException {
// TODO Auto-generated method stub
if (event instanceof AjaxEvent) {
FacesContext facesContext = FacesContext.getCurrentInstance();
AjaxContext ajaxContext = AjaxContext
.getCurrentInstance(facesContext);
ajaxContext.addRegionsFromComponent(this);
if (getPreload() != null) {
ajaxContext.setResponseData(getPreload());
}
} else {
if (event instanceof CurrentDateChangeEvent) {
FacesContext facesContext = FacesContext.getCurrentInstance();
CurrentDateChangeEvent dateChangeEvent = (CurrentDateChangeEvent) event;
String currentDateString = dateChangeEvent
.getCurrentDateString();
if (currentDateString != null) {
// if currentDateString is not null then event cames from
// apply request phase
try {
// XXX nick - kaa - we should use datePattern
// attribute-based converter only for selectedDate
// current date string always has predefined format: m/y
// review
// org.richfaces.renderkit.CalendarRendererBase.convertCurrentDate(String)
// method
// for more
// XX nick - kaa - throw exception and review resulting
// message :)
Date currentDate = convertCurrentDate(currentDateString);
CurrentDateChangeEvent newDateChangeEvent = new CurrentDateChangeEvent(
this, currentDate);
newDateChangeEvent.queue();
MethodBinding binding = getCurrentDateChangeListener();
if (binding != null) {
binding
.invoke(facesContext,
new Object[] { event });
}
} catch (Exception e) {
// XXX nick - kaa - add log.debug(...)
// XXX nick - kaa - we should stop processing on exc.
// setValid(false) and then call
// FacesContext.renderResponse(...)
// update model phase shouldn't start
if (log.isDebugEnabled()) {
log.debug(
" currentDate convertion fails with following exception: "
+ e.toString(), e);
}
setValid(false);
String messageString = e.toString();
e.printStackTrace();
FacesMessage message = new FacesMessage(messageString);
message.setSeverity(FacesMessage.SEVERITY_ERROR);
facesContext.addMessage(getClientId(facesContext),
message);
facesContext.renderResponse();
}
} else {
Date currentDate1 = dateChangeEvent.getCurrentDate();
Date currentDate2 = getAsDate(getCurrentDate());
if (!currentDate1.equals(currentDate2)) {
updateCurrentDate(facesContext, currentDate1);
ValueChangeEvent changeEvent = new ValueChangeEvent(
this, currentDate2, currentDate1);
changeEvent.queue();
}
}
} else {
super.broadcast(event);
}
}
}
public Object getPreload() {
Date[] preloadDateRange = getPreloadDateRange();
if (preloadDateRange != null && preloadDateRange.length != 0) {
CalendarDataModel calendarDataModel = (CalendarDataModel) getDataModel();
if (calendarDataModel != null) {
CalendarDataModelItem[] calendarDataModelItems = calendarDataModel
.getData(preloadDateRange);
HashMap args = new HashMap();
args.put("startDate", CalendarRendererBase
.formatDate(preloadDateRange[0]));
args.put("days", calendarDataModelItems);
return args;
}
}
return null;
}
public Date[] getPreloadDateRange() {
Date dateRangeBegin = getAsDate(this.getPreloadDateRangeBegin());
Date dateRangeEnd = getAsDate(this.getPreloadDateRangeEnd());
if (dateRangeBegin == null && dateRangeEnd == null) {
return null;
} else {
if (dateRangeBegin.after(dateRangeEnd)) {
// XXX add message
FacesMessage message = new FacesMessage(
"preloadDateRangeBegin is greater than preloadDateRangeEnd");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(getClientId(context), message);
throw new IllegalArgumentException();
}
List dates = new ArrayList();
Calendar calendar = Calendar.getInstance(this.getTimeZone(), getAsLocale(this.getLocale()));
Calendar calendar2 = (Calendar) calendar.clone();
calendar.setTime(dateRangeBegin);
calendar2.setTime(dateRangeEnd);
do {
dates.add(calendar.getTime());
calendar.add(Calendar.DATE, 1);
} while (!calendar.after(calendar2));
return (Date[]) dates.toArray(new Date[dates.size()]);
}
}
public void addCurrentDateChangeListener(CurrentDateChangeListener listener) {
addFacesListener(listener);
}
public CurrentDateChangeListener[] getCurrentDateChangeListeners() {
return (CurrentDateChangeListener[]) getFacesListeners(CurrentDateChangeListener.class);
}
public void removeCurrentDateChangeListener(
CurrentDateChangeListener listener) {
removeFacesListener(listener);
}
/**
*Parse Locale from String.
*String must be represented as Locale.toString(); xx_XX_XXXX
*/
public Locale parseLocale(String localeStr){
int length = localeStr.length();
if(null==localeStr||length<2){
return Locale.getDefault();
}
//Lookup index of first '_' in string locale representation.
int index1 = localeStr.indexOf("_");
//Get first charters (if exist) from string
String language = null;
if(index1!=-1){
language = localeStr.substring(0, index1);
}else{
return new Locale(localeStr);
}
//Lookup index of second '_' in string locale representation.
int index2 = localeStr.indexOf("_", index1+1);
String country = null;
if(index2!=-1){
country = localeStr.substring(index1+1, index2);
String variant = localeStr.substring(index2+1);
return new Locale(language, country, variant);
}else{
country = localeStr.substring(index1+1);
return new Locale(language, country);
}
}
public Locale getAsLocale(Object locale) {
if (locale instanceof Locale) {
return (Locale) locale;
} else if (locale instanceof String) {
return parseLocale((String) locale);
} else {
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
Converter converter = application
.createConverter(locale.getClass());
if (null != converter) {
return parseLocale(converter.getAsString(context, this, locale));
} else {
throw new FacesException(
"Wrong locale attibute type or there is no converter for custom attibute type");
}
}
}
protected int getDefaultFirstWeekDay() {
Calendar cal = getCalendar();
return cal.getFirstDayOfWeek() - cal.getActualMinimum(Calendar.DAY_OF_WEEK);
}
protected int getDefaultMinDaysInFirstWeek() {
return getCalendar().getMinimalDaysInFirstWeek();
}
/**
* Gets what the minimal days required in the first week of the year
are; e.g., if the first week is defined as one that contains the first
day of the first month of a year, this method returns 1. If the
minimal days required must be a full week, this method returns 7.
* Setter for minDaysInFirstWeek
* @param minDaysInFirstWeek - new value
*/
public void setMinDaysInFirstWeek( int __minDaysInFirstWeek ){
this._minDaysInFirstWeek = __minDaysInFirstWeek;
this._minDaysInFirstWeekSet = true;
}
/**
* Gets what the minimal days required in the first week of the year
are; e.g., if the first week is defined as one that contains the first
day of the first month of a year, this method returns 1. If the
minimal days required must be a full week, this method returns 7.
* Getter for minDaysInFirstWeek
* @return minDaysInFirstWeek value from local variable or value bindings
*/
public int getMinDaysInFirstWeek( ){
if(this._minDaysInFirstWeekSet){
return this._minDaysInFirstWeek;
}
ValueBinding vb = getValueBinding("minDaysInFirstWeek");
if (vb != null) {
Integer value = (Integer) vb.getValue(getFacesContext());
if (null == value) {
return getDefaultMinDaysInFirstWeek();
}
return (value.intValue());
} else {
return getDefaultMinDaysInFirstWeek();
}
}
/**
* Gets what the first day of the week is; e.g., SUNDAY in the U.S., MONDAY in France.
* Setter for firstWeekDay
* @param firstWeekDay - new value
*/
public void setFirstWeekDay( int __firstWeekDay ){
this._firstWeekDay = __firstWeekDay;
this._firstWeekDaySet = true;
}
/**
* Gets what the first day of the week is; e.g., SUNDAY in the U.S., MONDAY in France.
* Getter for firstWeekDay
* @return firstWeekDay value from local variable or value bindings
*/
public int getFirstWeekDay( ){
if(this._firstWeekDaySet){
return this._firstWeekDay;
}
ValueBinding vb = getValueBinding("firstWeekDay");
if (vb != null) {
Integer value = (Integer) vb.getValue(getFacesContext());
if (null == value) {
return getDefaultFirstWeekDay();
}
return (value.intValue());
} else {
return getDefaultFirstWeekDay();
}
}
public Object saveState(FacesContext context) {
return new Object [] {
super.saveState(context),
new Integer(_firstWeekDay),
new Boolean(_firstWeekDaySet),
new Integer(_minDaysInFirstWeek),
new Boolean(_minDaysInFirstWeekSet)
};
}
public void restoreState(FacesContext context, Object state) {
Object[] states = (Object[]) state;
super.restoreState(context, states[0]);
_firstWeekDay = ((Integer)states[1]).intValue();
_firstWeekDaySet = ((Boolean)states[2]).booleanValue();
_minDaysInFirstWeek = ((Integer)states[3]).intValue();
_minDaysInFirstWeekSet = ((Boolean)states[4]).booleanValue();
}
}