<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: Date DropDownChoice Component Apache Wicket</title>
	<atom:link href="http://blog.aparnachaudhary.net/2009/07/29/date-dropdownchoice-apache-wicket/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.aparnachaudhary.net/2009/07/29/date-dropdownchoice-apache-wicket/</link>
	<description>My Blog about Java, and Open Source</description>
	<lastBuildDate>Fri, 03 Sep 2010 18:05:40 -0700</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<item>
		<title>By: Hovi</title>
		<link>http://blog.aparnachaudhary.net/2009/07/29/date-dropdownchoice-apache-wicket/comment-page-1/#comment-905</link>
		<dc:creator>Hovi</dc:creator>
		<pubDate>Wed, 25 Aug 2010 09:17:48 +0000</pubDate>
		<guid isPermaLink="false">http://aparnachaudhary.wordpress.com/?p=272#comment-905</guid>
		<description>Hello, 
thanks for sollution, it is nice upgrade from original version of datepicker, however there is little bug. If you change month or year, day resets to current day. It is caused, because day component doesn&#039;t have ajaxupdatingbehavior onchange. However if I add it, set day to 31th and then change month to month that doesn&#039;t have 31th, days is still at 31. This is caused by behavior of GregorianCalendar in DateModel#setModel, where if day limit of the month is reached, month is changed instead of lowering to maximum of the month.

There are 2 workarounds. One is just to update all components so it is visible that month has changed, which isn&#039;t really user friendly. Another workaround is checking max day limit in DateModel#setModel and set it on max if current value is above maximum.

Here is sourcecode with includng changes (only AjaxFormComponentUpdatingBehavior, updateChoices, DateModel#setModel are changed):


public class DateChooser extends FormComponent {

	/** The day ddc. */
	private DropDownChoice dayDDC;

	/** The month ddc. */
	private DropDownChoice monthDDC;

	/** The year ddc. */
	private DropDownChoice yearDDC;

	/**
	 * Instantiates a new date chooser.
	 * 
	 * @param id
	 *            the id
	 * @param model
	 *            the model
	 */
	public DateChooser(final String id, IModel model) {
		super(id);

		if (model == null) {
			model = new Model(new Date());
		} else if (model.getObject() == null) {
			model.setObject(new Date());
		}

		setModel(model);

		monthDDC = new DropDownChoice(&quot;month&quot;, new DateModel(model, Calendar.MONTH), getMonths(), new IChoiceRenderer() {

			public Object getDisplayValue(Integer object) {
				SimpleDateFormat format = new SimpleDateFormat(&quot;MMM&quot;);

				Calendar cal = Calendar.getInstance();
				cal.set(Calendar.MONTH, object.intValue());

				return format.format(cal.getTime());
			}

			public String getIdValue(Integer integer, int index) {
				return String.valueOf(index);
			}
		});
		monthDDC.add(new AjaxFormComponentUpdatingBehavior(&quot;onchange&quot;) {
			@Override
			protected void onUpdate(AjaxRequestTarget target) {
				// change the days dropdown when month changes
				updateChoices(target);
			}
		});
		add(monthDDC);

		yearDDC = new DropDownChoice(&quot;year&quot;, new DateModel(model, Calendar.YEAR), getYears());
		add(yearDDC);
		yearDDC.add(new AjaxFormComponentUpdatingBehavior(&quot;onchange&quot;) {
			@Override
			protected void onUpdate(AjaxRequestTarget target) {
				// change the days dropdown when year changes
				updateChoices(target);
			}
		});

		dayDDC = new DropDownChoice(&quot;day&quot;, new DateModel(model, Calendar.DAY_OF_MONTH), getDays());
		dayDDC.add(new AjaxFormComponentUpdatingBehavior(&quot;onchange&quot;) {

			@Override
			protected void onUpdate(AjaxRequestTarget target) {
			}
		});

		dayDDC.setOutputMarkupId(true);
		add(dayDDC);
	}

	protected void updateChoices(AjaxRequestTarget target) {
		dayDDC.setChoices(getDays());
		target.addComponent(dayDDC);
		target.addComponent(yearDDC);
		target.addComponent(monthDDC);
	}

	/**
	 * The Class DateModel.
	 */
	private class DateModel extends Model {

		/** The date model. */
		private final IModel dateModel;

		/** The calendar field. */
		private final int calendarField;

		/**
		 * Instantiates a new date model.
		 * 
		 * @param dateModel
		 *            the date model
		 * @param calendarField
		 *            the calendar field
		 */
		public DateModel(IModel dateModel, int calendarField) {
			this.dateModel = dateModel;
			this.calendarField = calendarField;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.apache.wicket.model.Model#detach()
		 */
		@Override
		public void detach() {
			dateModel.detach();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.apache.wicket.model.Model#getObject()
		 */
		@Override
		public Integer getObject() {
			if (dateModel.getObject() == null) {
				return null;
			}

			Calendar cal = Calendar.getInstance();
			cal.setTime(dateModel.getObject());

			return cal.get(calendarField);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.apache.wicket.model.Model#setObject(java.io.Serializable)
		 */
		@Override
		public void setObject(Integer object) {
			Date date = dateModel.getObject();
			if (date == null) {
				date = new Date();
			}
			Calendar cal = Calendar.getInstance();
			cal.setTime(date);

			// if current day of the month is higher than allowed in new
			// month/yer, set it to max allowed day in month
			if (calendarField == Calendar.YEAR &#124;&#124; calendarField == Calendar.MONTH) {
				int totalDays = 31;
				int year = yearDDC.getModelObject().intValue();
				int month = monthDDC.getModelObject().intValue();
				if (calendarField == Calendar.YEAR) {
					year = object.intValue();
				} else {
					month = object.intValue();
				}
				Calendar cal2 = new GregorianCalendar(year, month, 1);
				totalDays = cal2.getActualMaximum(Calendar.DAY_OF_MONTH);
				if (dayDDC.getModelObject().intValue() &gt; totalDays) {
					dayDDC.setModelObject(Integer.valueOf(totalDays));
					cal.set(Calendar.DAY_OF_MONTH, totalDays);
				}
			}

			cal.set(calendarField, object);

			dateModel.setObject(cal.getTime());
		}
	}

	/**
	 * Gets the months.
	 * 
	 * @return the months
	 */
	private List getMonths() {
		List months = new ArrayList(12);

		for (int i = 0; i &lt; 12; i++) {
			months.add(i);
		}

		return months;
	}

	/**
	 * Gets the days.
	 * 
	 * @return the days
	 */
	protected List getDays() {
		List days = new ArrayList(31);
		int totalDays = 31;
		if (yearDDC.getModelObject() != null &amp;&amp; monthDDC.getModelObject() != null) {
			Calendar cal = new GregorianCalendar(yearDDC.getModelObject(), monthDDC.getModelObject(), 1);
			totalDays = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
		}
		for (int i = 1; i &lt;= totalDays; i++) {
			days.add(i);
		}
		return days;
	}

	/**
	 * Gets the years.
	 * 
	 * @return the years
	 */
	protected List getYears() {
		List years = new ArrayList(10);

		Calendar cal = Calendar.getInstance();

		for (int i = cal.get(Calendar.YEAR) - 2; i &lt; cal.get(Calendar.YEAR) + 8; i++) {
			years.add(i);
		}

		return years;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.wicket.markup.html.form.FormComponent#convertInput()
	 */
	@Override
	protected void convertInput() {
		Calendar cal = Calendar.getInstance();
		cal.set(yearDDC.getConvertedInput(), monthDDC.getConvertedInput(), dayDDC.getConvertedInput(), 0, 0, 0);
		Date selectedDate = cal.getTime();
		setModel(new Model(selectedDate));
	}

}</description>
		<content:encoded><![CDATA[<p>Hello,<br />
thanks for sollution, it is nice upgrade from original version of datepicker, however there is little bug. If you change month or year, day resets to current day. It is caused, because day component doesn&#8217;t have ajaxupdatingbehavior onchange. However if I add it, set day to 31th and then change month to month that doesn&#8217;t have 31th, days is still at 31. This is caused by behavior of GregorianCalendar in DateModel#setModel, where if day limit of the month is reached, month is changed instead of lowering to maximum of the month.</p>
<p>There are 2 workarounds. One is just to update all components so it is visible that month has changed, which isn&#8217;t really user friendly. Another workaround is checking max day limit in DateModel#setModel and set it on max if current value is above maximum.</p>
<p>Here is sourcecode with includng changes (only AjaxFormComponentUpdatingBehavior, updateChoices, DateModel#setModel are changed):</p>
<p>public class DateChooser extends FormComponent {</p>
<p>	/** The day ddc. */<br />
	private DropDownChoice dayDDC;</p>
<p>	/** The month ddc. */<br />
	private DropDownChoice monthDDC;</p>
<p>	/** The year ddc. */<br />
	private DropDownChoice yearDDC;</p>
<p>	/**<br />
	 * Instantiates a new date chooser.<br />
	 *<br />
	 * @param id<br />
	 *            the id<br />
	 * @param model<br />
	 *            the model<br />
	 */<br />
	public DateChooser(final String id, IModel model) {<br />
		super(id);</p>
<p>		if (model == null) {<br />
			model = new Model(new Date());<br />
		} else if (model.getObject() == null) {<br />
			model.setObject(new Date());<br />
		}</p>
<p>		setModel(model);</p>
<p>		monthDDC = new DropDownChoice(&#8221;month&#8221;, new DateModel(model, Calendar.MONTH), getMonths(), new IChoiceRenderer() {</p>
<p>			public Object getDisplayValue(Integer object) {<br />
				SimpleDateFormat format = new SimpleDateFormat(&#8221;MMM&#8221;);</p>
<p>				Calendar cal = Calendar.getInstance();<br />
				cal.set(Calendar.MONTH, object.intValue());</p>
<p>				return format.format(cal.getTime());<br />
			}</p>
<p>			public String getIdValue(Integer integer, int index) {<br />
				return String.valueOf(index);<br />
			}<br />
		});<br />
		monthDDC.add(new AjaxFormComponentUpdatingBehavior(&#8221;onchange&#8221;) {<br />
			@Override<br />
			protected void onUpdate(AjaxRequestTarget target) {<br />
				// change the days dropdown when month changes<br />
				updateChoices(target);<br />
			}<br />
		});<br />
		add(monthDDC);</p>
<p>		yearDDC = new DropDownChoice(&#8221;year&#8221;, new DateModel(model, Calendar.YEAR), getYears());<br />
		add(yearDDC);<br />
		yearDDC.add(new AjaxFormComponentUpdatingBehavior(&#8221;onchange&#8221;) {<br />
			@Override<br />
			protected void onUpdate(AjaxRequestTarget target) {<br />
				// change the days dropdown when year changes<br />
				updateChoices(target);<br />
			}<br />
		});</p>
<p>		dayDDC = new DropDownChoice(&#8221;day&#8221;, new DateModel(model, Calendar.DAY_OF_MONTH), getDays());<br />
		dayDDC.add(new AjaxFormComponentUpdatingBehavior(&#8221;onchange&#8221;) {</p>
<p>			@Override<br />
			protected void onUpdate(AjaxRequestTarget target) {<br />
			}<br />
		});</p>
<p>		dayDDC.setOutputMarkupId(true);<br />
		add(dayDDC);<br />
	}</p>
<p>	protected void updateChoices(AjaxRequestTarget target) {<br />
		dayDDC.setChoices(getDays());<br />
		target.addComponent(dayDDC);<br />
		target.addComponent(yearDDC);<br />
		target.addComponent(monthDDC);<br />
	}</p>
<p>	/**<br />
	 * The Class DateModel.<br />
	 */<br />
	private class DateModel extends Model {</p>
<p>		/** The date model. */<br />
		private final IModel dateModel;</p>
<p>		/** The calendar field. */<br />
		private final int calendarField;</p>
<p>		/**<br />
		 * Instantiates a new date model.<br />
		 *<br />
		 * @param dateModel<br />
		 *            the date model<br />
		 * @param calendarField<br />
		 *            the calendar field<br />
		 */<br />
		public DateModel(IModel dateModel, int calendarField) {<br />
			this.dateModel = dateModel;<br />
			this.calendarField = calendarField;<br />
		}</p>
<p>		/*<br />
		 * (non-Javadoc)<br />
		 *<br />
		 * @see org.apache.wicket.model.Model#detach()<br />
		 */<br />
		@Override<br />
		public void detach() {<br />
			dateModel.detach();<br />
		}</p>
<p>		/*<br />
		 * (non-Javadoc)<br />
		 *<br />
		 * @see org.apache.wicket.model.Model#getObject()<br />
		 */<br />
		@Override<br />
		public Integer getObject() {<br />
			if (dateModel.getObject() == null) {<br />
				return null;<br />
			}</p>
<p>			Calendar cal = Calendar.getInstance();<br />
			cal.setTime(dateModel.getObject());</p>
<p>			return cal.get(calendarField);<br />
		}</p>
<p>		/*<br />
		 * (non-Javadoc)<br />
		 *<br />
		 * @see org.apache.wicket.model.Model#setObject(java.io.Serializable)<br />
		 */<br />
		@Override<br />
		public void setObject(Integer object) {<br />
			Date date = dateModel.getObject();<br />
			if (date == null) {<br />
				date = new Date();<br />
			}<br />
			Calendar cal = Calendar.getInstance();<br />
			cal.setTime(date);</p>
<p>			// if current day of the month is higher than allowed in new<br />
			// month/yer, set it to max allowed day in month<br />
			if (calendarField == Calendar.YEAR || calendarField == Calendar.MONTH) {<br />
				int totalDays = 31;<br />
				int year = yearDDC.getModelObject().intValue();<br />
				int month = monthDDC.getModelObject().intValue();<br />
				if (calendarField == Calendar.YEAR) {<br />
					year = object.intValue();<br />
				} else {<br />
					month = object.intValue();<br />
				}<br />
				Calendar cal2 = new GregorianCalendar(year, month, 1);<br />
				totalDays = cal2.getActualMaximum(Calendar.DAY_OF_MONTH);<br />
				if (dayDDC.getModelObject().intValue() &gt; totalDays) {<br />
					dayDDC.setModelObject(Integer.valueOf(totalDays));<br />
					cal.set(Calendar.DAY_OF_MONTH, totalDays);<br />
				}<br />
			}</p>
<p>			cal.set(calendarField, object);</p>
<p>			dateModel.setObject(cal.getTime());<br />
		}<br />
	}</p>
<p>	/**<br />
	 * Gets the months.<br />
	 *<br />
	 * @return the months<br />
	 */<br />
	private List getMonths() {<br />
		List months = new ArrayList(12);</p>
<p>		for (int i = 0; i &lt; 12; i++) {<br />
			months.add(i);<br />
		}</p>
<p>		return months;<br />
	}</p>
<p>	/**<br />
	 * Gets the days.<br />
	 *<br />
	 * @return the days<br />
	 */<br />
	protected List getDays() {<br />
		List days = new ArrayList(31);<br />
		int totalDays = 31;<br />
		if (yearDDC.getModelObject() != null &amp;&amp; monthDDC.getModelObject() != null) {<br />
			Calendar cal = new GregorianCalendar(yearDDC.getModelObject(), monthDDC.getModelObject(), 1);<br />
			totalDays = cal.getActualMaximum(Calendar.DAY_OF_MONTH);<br />
		}<br />
		for (int i = 1; i &lt;= totalDays; i++) {<br />
			days.add(i);<br />
		}<br />
		return days;<br />
	}</p>
<p>	/**<br />
	 * Gets the years.<br />
	 *<br />
	 * @return the years<br />
	 */<br />
	protected List getYears() {<br />
		List years = new ArrayList(10);</p>
<p>		Calendar cal = Calendar.getInstance();</p>
<p>		for (int i = cal.get(Calendar.YEAR) &#8211; 2; i &lt; cal.get(Calendar.YEAR) + 8; i++) {<br />
			years.add(i);<br />
		}</p>
<p>		return years;<br />
	}</p>
<p>	/*<br />
	 * (non-Javadoc)<br />
	 *<br />
	 * @see org.apache.wicket.markup.html.form.FormComponent#convertInput()<br />
	 */<br />
	@Override<br />
	protected void convertInput() {<br />
		Calendar cal = Calendar.getInstance();<br />
		cal.set(yearDDC.getConvertedInput(), monthDDC.getConvertedInput(), dayDDC.getConvertedInput(), 0, 0, 0);<br />
		Date selectedDate = cal.getTime();<br />
		setModel(new Model(selectedDate));<br />
	}</p>
<p>}</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: victor</title>
		<link>http://blog.aparnachaudhary.net/2009/07/29/date-dropdownchoice-apache-wicket/comment-page-1/#comment-218</link>
		<dc:creator>victor</dc:creator>
		<pubDate>Tue, 02 Mar 2010 10:02:49 +0000</pubDate>
		<guid isPermaLink="false">http://aparnachaudhary.wordpress.com/?p=272#comment-218</guid>
		<description>This updates is very helpful for me. Original DateChooser component was written in 2006 year and doesn&#039;t work as expected.</description>
		<content:encoded><![CDATA[<p>This updates is very helpful for me. Original DateChooser component was written in 2006 year and doesn&#8217;t work as expected.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
