/**
* 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.application.FacesMessage;
import javax.faces.component.UIInput;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
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 {
public static final String COMPONENT_TYPE = "org.richfaces.Calendar";
private static final String COMPONENT_FAMILY = "org.richfaces.Calendar";
private final static Log log = LogFactory.getLog(UICalendar.class);
public abstract Locale getLocale();
public abstract void setLocale(Locale locale);
public abstract TimeZone getTimeZone();
public abstract void setTimeZone(TimeZone timeZone);
public abstract Date getPreloadDateRangeBegin();
public abstract void setPreloadDateRangeBegin(Date date);
public abstract Date getPreloadDateRangeEnd();
public abstract void setPreloadDateRangeEnd(Date date);
public abstract Date getCurrentDate();
public abstract void setCurrentDate(Date 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);
//TODO onclick add users onclick
// currentDate processing -------------------------------------------------
public Calendar getCalendar() {
return Calendar.getInstance(getTimeZone(), 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, Date currentDate) {
if (context == null) {
throw new NullPointerException();
}
try {
ValueBinding vb = getValueBinding("currentDate");
if (vb != null) {
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 = getCurrentDate();
if (date != null) {
return date;
} else {
Calendar calendar = getCalendar();
calendar.set(Calendar.DATE, 1);
return calendar.getTime();
}
}
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(), 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(), 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);
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 = 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 = this.getPreloadDateRangeBegin();
Date dateRangeEnd = this.getPreloadDateRangeEnd();
if (dateRangeBegin.after(dateRangeEnd)) {
// TODO add message
throw new IllegalArgumentException();
}
List dates = new ArrayList();
Calendar calendar = Calendar.getInstance(this.getTimeZone(), 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);
}
}