/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at .
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox ,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2004 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.venice.ui.dlg;
import java.io.IOException;
import java.text.*;
import java.util.*;
import org.apache.log4j.*;
import org.apache.regexp.*;
import org.w3c.dom.*;
import com.silverwrist.util.*;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.ui.*;
import com.silverwrist.venice.ui.helpers.HTMLRendering;
import com.silverwrist.venice.util.XMLLoader;
public class DateField implements DialogField
{
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
public static final String TAGNAME = "date";
private static Logger logger = Logger.getLogger(DateField.class);
private static final int FLD_MONTH = 1;
private static final int FLD_DAY = 2;
private static final int FLD_YEAR = 3;
private static REProgram YRANGE = null;
private static REProgram YPLUS = null;
private static REProgram YMINUS = null;
private static REProgram YPLUSMINUS = null;
private static REProgram YMINUSPLUS = null;
private static REProgram YSOLO = null;
private static Hashtable s_locale_ordering = new Hashtable();
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private String m_name; // field name (parameter name)
private String m_caption; // primary caption
private String m_caption2; // secondary caption
private boolean m_required; // is this field required?
private boolean m_enabled; // are we enabled?
private int m_year_start; // first year for dropdown
private int m_year_stop; // last year for dropdown
private java.sql.Date m_value = null; // selected date
private int m_ndx_month = -1; // index of selected month
private int m_ndx_day = -1; // index of selected day
private int m_ndx_year = -1; // index of selected year
private boolean m_input_error = false; // input error?
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
public DateField(String name, String caption, String caption2, boolean required, boolean enabled, int year_start,
int year_stop)
{
m_name = name;
m_caption = caption;
m_caption2 = caption2;
m_required = required;
m_enabled = enabled;
m_year_start = year_start;
m_year_stop = year_stop;
} // end constructor
public DateField(Element elt) throws ConfigException
{
XMLLoader loader = XMLLoader.get();
m_name = loader.configGetAttribute(elt,"name");
m_caption = loader.configGetAttribute(elt,"capt");
m_caption2 = elt.getAttribute("capt2");
DOMElementHelper h = new DOMElementHelper(elt);
m_required = h.hasAttribute("required");
m_enabled = !(h.hasAttribute("disabled"));
String countdir = elt.getAttribute("direction");
if (StringUtil.isStringEmpty(countdir))
countdir = "down";
else if (!(countdir.equalsIgnoreCase("up") || countdir.equalsIgnoreCase("down")))
throw new ConfigException(" direction= attribute must be 'up' or 'down'",elt);
int y1, y2;
String yearspec = elt.getAttribute("years");
if (StringUtil.isStringEmpty(yearspec))
{ // use a 70 year span back from the current year
Calendar cal = Calendar.getInstance();
y1 = cal.get(Calendar.YEAR);
y2 = y1 - 70;
} // end if
else
{ // now recognize what the field value is
do
{ // attempt to recognize a range
RE re = new RE(YRANGE);
if (re.match(yearspec))
{ // got a year range
y1 = Integer.parseInt(re.getParen(1));
y2 = Integer.parseInt(re.getParen(2));
break;
} // end if
Calendar cal = Calendar.getInstance();
re = new RE(YPLUS);
if (re.match(yearspec))
{ // +number - range from current year forward some years
y1 = cal.get(Calendar.YEAR);
y2 = y1 + Integer.parseInt(re.getParen(1));
break;
} // end if
re = new RE(YMINUS);
if (re.match(yearspec))
{ // -number - range from current year backward some years
y1 = cal.get(Calendar.YEAR);
y2 = y1 - Integer.parseInt(re.getParen(1));
break;
} // end if
re = new RE(YPLUSMINUS);
if (re.match(yearspec))
{ // +number -number - brackets around the current year
int foo = cal.get(Calendar.YEAR);
y1 = foo + Integer.parseInt(re.getParen(1));
y2 = foo - Integer.parseInt(re.getParen(2));
break;
} // end if
re = new RE(YMINUSPLUS);
if (re.match(yearspec))
{ // -number +number - brackets around the current year
int foo = cal.get(Calendar.YEAR);
y1 = foo - Integer.parseInt(re.getParen(1));
y2 = foo + Integer.parseInt(re.getParen(2));
break;
} // end if
re = new RE(YSOLO);
if (re.match(yearspec))
{ // solo number - one end of year spec, current year being the other
y1 = cal.get(Calendar.YEAR);
y2 = Integer.parseInt(re.getParen(1));
break;
} // end if
throw new ConfigException(" years= attribute: invalid syntax",elt);
} while (false); // end do
} // end else
if (countdir.equalsIgnoreCase("down"))
{ // organize for counting downward
m_year_start = Math.max(y1,y2);
m_year_stop = Math.min(y1,y2);
} // end if
else
{ // organize for counting upward
m_year_start = Math.min(y1,y2);
m_year_stop = Math.max(y1,y2);
} // end else
} // end constructor
protected DateField(DateField other)
{
m_name = other.m_name;
m_caption = other.m_caption;
m_caption2 = other.m_caption2;
m_required = other.m_required;
m_enabled = other.m_enabled;
m_year_start = other.m_year_start;
m_year_stop = other.m_year_stop;
} // end constructor
/*--------------------------------------------------------------------------------
* Internal operations
*--------------------------------------------------------------------------------
*/
private static final int[] getDateFieldOrdering(Locale locale)
{
int[] rc = (int[])(s_locale_ordering.get(locale));
if (rc!=null)
return rc;
// We determine the date format by encoding the date September 18, 2003, into "short"
// date format, then measuring the relative positions of the digits 9, 8, and 3.
// It's severely hackish, but there seems to be no Java API whereby we can directly
// get this information.
DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT,locale);
Calendar cal = fmt.getCalendar();
cal.set(Calendar.YEAR,2003);
cal.set(Calendar.MONTH,Calendar.SEPTEMBER);
cal.set(Calendar.DAY_OF_MONTH,18);
String s = fmt.format(cal.getTime());
int pday = s.indexOf('8');
int pmonth = s.indexOf('9');
int pyear = s.indexOf('3');
rc = new int[3];
if (pday");
DateFormatSymbols syms = new DateFormatSymbols(html.getLocale());
String[] months = syms.getMonths();
for (int i=cal.getMinimum(Calendar.MONTH); i<=cal.getMaximum(Calendar.MONTH); i++)
{ // write the choices
out.write("");
} // end for
out.write("\n");
} // end if
else if (which==FLD_DAY)
{ // render the "day" field
out.write("\n");
} // end if
else if (which==FLD_YEAR)
{ // render the "year" drop down
out.write("\n");
} // end else if
} // end renderDropDown
/*--------------------------------------------------------------------------------
* Implementations from interface RenderDirect
*--------------------------------------------------------------------------------
*/
public void render(RequestOutput out) throws IOException
{
HTMLRendering html = (HTMLRendering)(out.queryService(HTMLRendering.class));
Calendar cal = Calendar.getInstance(TimeZone.getDefault(),html.getLocale());
if ((m_value!=null) && !m_input_error)
{ // split date into month, day, and year
cal.setTime(m_value);
if (m_ndx_month==-1)
m_ndx_month = cal.get(Calendar.MONTH);
if (m_ndx_day==-1)
m_ndx_day = cal.get(Calendar.DAY_OF_MONTH);
if (m_ndx_year==-1)
m_ndx_year = cal.get(Calendar.YEAR);
} // end if
else // everything is not set
m_ndx_month = m_ndx_day = m_ndx_year = -1;
// write the caption and the basic table framework
out.write("
\n
");
out.write(html.getFontTag(m_enabled ? html.CONTENT_FOREGROUND : html.CONTENT_DISABLED,"content"));
out.write(StringUtil.encodeHTML(m_caption));
if (!(StringUtil.isStringEmpty(m_caption2)))
out.write(" " + StringUtil.encodeHTML(m_caption2));
out.write(":");
if (m_required)
out.write(html.getFontTag("red","content") + "*");
out.write("
\n
");
// write the drop-down list boxes
int[] order = getDateFieldOrdering(html.getLocale());
renderDropDown(order[0],out);
out.write(" \n");
renderDropDown(order[1],out);
out.write(" \n");
renderDropDown(order[2],out);
// finish up
out.write("
\n
\n");
} // end render
/*--------------------------------------------------------------------------------
* Implementations from interface DialogField
*--------------------------------------------------------------------------------
*/
public String getName()
{
return m_name;
} // end getName
public Object getValue()
{
return m_value;
} // end getValue
public void setValue(Object o)
{
if (o==null)
m_value = null;
else if (o instanceof java.sql.Date)
m_value = (java.sql.Date)(((java.sql.Date)o).clone());
else if (o instanceof java.util.Date)
m_value = new java.sql.Date(((java.util.Date)o).getTime());
else if (o instanceof Calendar)
m_value = new java.sql.Date(((Calendar)o).getTimeInMillis());
else if (o instanceof Number)
m_value = new java.sql.Date(((Number)o).longValue());
else
throw new IllegalArgumentException("cannot convert argument to java.sql.Date");
if (logger.isDebugEnabled())
logger.debug("Set date: " + m_value);
m_ndx_month = m_ndx_day = m_ndx_year = -1; // kill indexes
m_input_error = false;
} // end setValue
public void setValueFrom(RequestInput ri)
{
m_ndx_month = ri.getParameterInt(m_name + "_month",-1);
m_ndx_day = ri.getParameterInt(m_name + "_day",-1);
m_ndx_year = ri.getParameterInt(m_name + "_year",-1);
if (logger.isDebugEnabled())
logger.debug("Raw input: M=" + m_ndx_month + ", D=" + m_ndx_day + ", Y=" + m_ndx_year);
if ((m_ndx_month==-1) || (m_ndx_day==-1) || (m_ndx_year==-1))
{ // the date is to be treated as "unspecified"
logger.debug("Killing the kittens!");
m_value = null;
m_ndx_month = m_ndx_day = m_ndx_year = -1; // kill indexes
m_input_error = false;
return;
} // end if
HTMLRendering html = (HTMLRendering)(ri.queryService(HTMLRendering.class));
Calendar cal = Calendar.getInstance(TimeZone.getDefault(),html.getLocale());
cal.clear();
cal.setLenient(false);
m_input_error = false;
try
{ // set the calendar and create the actual value
cal.set(Calendar.YEAR,m_ndx_year);
cal.set(Calendar.MONTH,m_ndx_month);
cal.set(Calendar.DAY_OF_MONTH,m_ndx_day);
cal.set(Calendar.HOUR,0);
cal.set(Calendar.MINUTE,0);
cal.set(Calendar.SECOND,0);
cal.set(Calendar.MILLISECOND,0);
m_value = new java.sql.Date(cal.getTimeInMillis());
if (logger.isDebugEnabled())
logger.debug("Verified date: " + m_value);
} // end try
catch (IllegalArgumentException e)
{ // set error flag and recompute value with relaxed rules
m_input_error = true;
cal.clear();
cal.setLenient(true);
cal.set(Calendar.YEAR,m_ndx_year);
cal.set(Calendar.MONTH,m_ndx_month);
cal.set(Calendar.DAY_OF_MONTH,m_ndx_day);
cal.set(Calendar.HOUR,0);
cal.set(Calendar.MINUTE,0);
cal.set(Calendar.SECOND,0);
cal.set(Calendar.MILLISECOND,0);
m_value = new java.sql.Date(cal.getTimeInMillis());
if (logger.isDebugEnabled())
logger.debug("UN-Verified date: " + m_value);
} // end catch
} // end setValueFrom
public boolean isRequired()
{
return m_required;
} // end isRequired
public boolean isFile()
{
return false;
} // end isFile
public boolean isHidden()
{
return false;
} // end isHidden
public void validate() throws ValidationException
{
if (m_required && (m_value==null))
throw new ValidationException("The '" + m_caption + "' field is required.");
if (m_input_error)
throw new ValidationException("Invalid date entered in the '" + m_caption + "' field.");
} // end validate
public boolean isEnabled()
{
return m_enabled;
} // end isEnabled
public void setEnabled(boolean flag)
{
m_enabled = flag;
} // end setEnabled
public Object sendMessage(String msg, Object data)
{
return null;
} // end sendMessage
public DialogField duplicate()
{
return new DateField(this);
} // end duplicate
/*--------------------------------------------------------------------------------
* Static initializer
*--------------------------------------------------------------------------------
*/
static
{
RECompiler compiler = new RECompiler();
try
{ // compile all local regular expressions
YRANGE = compiler.compile("^\\s*(\\d+)\\s*-\\s*(\\d+)\\s*$");
YPLUS = compiler.compile("^\\s*\\+\\s*(\\d+)\\s*$");
YMINUS = compiler.compile("^\\s*-\\s*(\\d+)\\s*$");
YPLUSMINUS = compiler.compile("^\\s*\\+\\s*(\\d+)\\s*-\\s*(\\d+)\\s*$");
YMINUSPLUS = compiler.compile("^\\s*-\\s*(\\d+)\\s*\\+\\s*(\\d+)\\s*$");
YSOLO = compiler.compile("^\\s*(\\d+)\\s*$");
} // end try
catch (RESyntaxException e)
{ // whoops!
logger.fatal("Regexp Syntax Error",e);
} // end catch
} // end static initializer
} // end class DateField