/* * 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