001 /*
002 * Apache License
003 * Version 2.0, January 2004
004 * http://www.apache.org/licenses/
005 *
006 * Copyright 2009 by chenillekit.org
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 */
014
015 package org.chenillekit.tapestry.core.components;
016
017 import java.util.Calendar;
018 import java.util.Date;
019 import java.util.List;
020 import java.util.Locale;
021
022 import org.apache.tapestry5.Binding;
023 import org.apache.tapestry5.BindingConstants;
024 import org.apache.tapestry5.ComponentResources;
025 import org.apache.tapestry5.FieldValidationSupport;
026 import org.apache.tapestry5.FieldValidator;
027 import org.apache.tapestry5.MarkupWriter;
028 import org.apache.tapestry5.ValidationException;
029 import org.apache.tapestry5.ValidationTracker;
030 import org.apache.tapestry5.annotations.Environmental;
031 import org.apache.tapestry5.annotations.Parameter;
032 import org.apache.tapestry5.annotations.Persist;
033 import org.apache.tapestry5.annotations.Property;
034 import org.apache.tapestry5.corelib.base.AbstractField;
035 import org.apache.tapestry5.ioc.annotations.Inject;
036 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
037 import org.apache.tapestry5.services.ComponentDefaultProvider;
038 import org.apache.tapestry5.services.Request;
039
040 /**
041 * @author <a href="mailto:shomburg@depot120.dpd.de">S.Homburg</a>
042 * @version $Id: DateSelector.java 471 2009-05-09 09:28:38Z homburgs $
043 */
044 public class DateSelector extends AbstractField
045 {
046 @Parameter(required = true, defaultPrefix = BindingConstants.PROP)
047 private Date value;
048
049 @Parameter(defaultPrefix = BindingConstants.PROP, value = "1970")
050 private int firstYear;
051
052 @Parameter(defaultPrefix = BindingConstants.PROP, value = "2030")
053 private int lastYear;
054
055 @Parameter(defaultPrefix = BindingConstants.PROP, value = "false")
056 private boolean longMonth;
057
058 /**
059 * The object that will perform input validation (which occurs after translation). The validate binding prefix is
060 * generally used to provide this object in a declarative fashion.
061 */
062 @Parameter(defaultPrefix = BindingConstants.VALIDATE)
063 @SuppressWarnings("unchecked")
064 private FieldValidator<Object> validate;
065
066 @Property
067 @Persist
068 private int dayValue;
069
070 @Property
071 @Persist
072 private int monthValue;
073
074 @Property
075 @Persist
076 private int yearValue;
077
078 @Inject
079 private Locale locale;
080
081 @Inject
082 private ComponentDefaultProvider defaultProvider;
083
084 @Inject
085 private Request request;
086
087 @Inject
088 private ComponentResources resources;
089
090 @Environmental
091 private ValidationTracker tracker;
092
093 @Inject
094 private FieldValidationSupport fieldValidationSupport;
095
096 private List<Integer> days = CollectionFactory.newList();
097 private List<Integer> months = CollectionFactory.newList();
098 private List<Integer> years = CollectionFactory.newList();
099
100 private Calendar calendar = Calendar.getInstance(locale);
101
102 /**
103 * Computes a default value for the "validate" parameter using {@link org.apache.tapestry5.services.FieldValidatorDefaultSource}.
104 */
105 final Binding defaultValidate()
106 {
107 return defaultProvider.defaultValidatorBinding("value", resources);
108 }
109
110 /**
111 * Tapestry render phase method.
112 * Initialize temporary instance variables here.
113 */
114 void setupRender()
115 {
116 if (value == null)
117 value = new Date();
118
119 calendar.setTime(value);
120 dayValue = calendar.get(Calendar.DAY_OF_MONTH);
121 monthValue = calendar.get(Calendar.MONTH);
122 yearValue = calendar.get(Calendar.YEAR);
123 }
124
125 /**
126 * Tapestry render phase method.
127 * Start a tag here, end it in afterRender
128 */
129 void beginRender(MarkupWriter writer)
130 {
131 writer.element("span",
132 "class", "ck-dateselector",
133 "id", getClientId());
134
135 writer.element("select",
136 "class", "day",
137 "id", getClientId() + "_day",
138 "name", getControlName() + "_day");
139
140 for (int day = 1; day < 32; day++)
141 {
142 org.apache.tapestry5.dom.Element element = writer.element("option",
143 "value", day);
144
145 if (dayValue == day)
146 element.attribute("selected", "selected");
147
148 writer.write(String.format("%02d", day));
149 writer.end();
150 }
151 writer.end();
152
153 writer.element("select",
154 "class", "month",
155 "id", getClientId() + "_month",
156 "name", getControlName() + "_month");
157
158 for (int month = 0; month < 12; month++)
159 {
160 org.apache.tapestry5.dom.Element element = writer.element("option",
161 "value", month);
162
163 if (monthValue == month)
164 element.attribute("selected", "selected");
165
166 writer.write(String.format("%02d", month + 1));
167
168 writer.end();
169 }
170 writer.end();
171
172 writer.element("select",
173 "class", "year",
174 "id", getClientId() + "_year",
175 "name", getControlName() + "_year");
176
177 for (int year = firstYear; year <= lastYear; year++)
178 {
179 org.apache.tapestry5.dom.Element element = writer.element("option",
180 "value", year);
181
182 if (yearValue == year)
183 element.attribute("selected", "selected");
184
185 writer.write(String.format("%d", year));
186 writer.end();
187 }
188 writer.end();
189 }
190
191 /**
192 * Tapestry render phase method. End a tag here.
193 */
194 void afterRender(MarkupWriter writer)
195 {
196 writer.end();
197 }
198
199
200 public List<Integer> getDaySelectModel()
201 {
202 return days;
203 }
204
205 public List<Integer> getMonthSelectModel()
206 {
207 return months;
208 }
209
210 public List<Integer> getYearSelectModel()
211 {
212 return years;
213 }
214
215 /**
216 * Method implemented by subclasses to actually do the work of processing the submission of the form. The element's
217 * elementName property will already have been set. This method is only invoked if the field is <strong>not {@link
218 * #isDisabled() disabled}</strong>.
219 *
220 * @param elementName the name of the element (used to find the correct parameter in the request)
221 */
222 protected void processSubmission(String elementName)
223 {
224 String rawDayValue = request.getParameter(elementName + "_day");
225 String rawMonthValue = request.getParameter(elementName + "_month");
226 String rawYearValue = request.getParameter(elementName + "_year");
227
228 try
229 {
230 calendar.set(Integer.parseInt(rawYearValue), Integer.parseInt(rawMonthValue), Integer.parseInt(rawDayValue));
231 calendar.setLenient(false);
232 Date translated = calendar.getTime();
233 fieldValidationSupport.validate(translated, resources, validate);
234 value = translated;
235 }
236 catch (ValidationException ex)
237 {
238 tracker.recordError(this, ex.getMessage());
239 }
240 catch (IllegalArgumentException ex)
241 {
242 tracker.recordError(this, ex.getMessage());
243 }
244 }
245 }