001 package org.apache.myfaces.tobago.renderkit.html.scarborough.standard.tag;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements. See the NOTICE file distributed with
006 * this work for additional information regarding copyright ownership.
007 * The ASF licenses this file to You under the Apache License, Version 2.0
008 * (the "License"); you may not use this file except in compliance with
009 * the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020 import org.apache.commons.logging.Log;
021 import org.apache.commons.logging.LogFactory;
022 import org.apache.myfaces.tobago.TobagoConstants;
023 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ACTION_ONCLICK;
024 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ALT;
025 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_COLUMNS;
026 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_HEIGHT;
027 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_LABEL;
028 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_LAYOUT_WIDTH;
029 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ROWS;
030 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_WIDTH;
031 import static org.apache.myfaces.tobago.TobagoConstants.FACET_LAYOUT;
032 import static org.apache.myfaces.tobago.TobagoConstants.FACET_PICKER_POPUP;
033 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_BOX;
034 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_BUTTON;
035 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_CALENDAR;
036 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_GRID_LAYOUT;
037 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_HIDDEN;
038 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_IMAGE;
039 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_PANEL;
040 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_POPUP;
041 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_TIME;
042 import org.apache.myfaces.tobago.compat.FacesUtils;
043 import org.apache.myfaces.tobago.component.AbstractUIPopup;
044 import org.apache.myfaces.tobago.component.CreateComponentUtils;
045 import org.apache.myfaces.tobago.component.UIBox;
046 import org.apache.myfaces.tobago.component.UIDateInput;
047 import org.apache.myfaces.tobago.component.UIDatePicker;
048 import org.apache.myfaces.tobago.component.UIGridLayout;
049 import org.apache.myfaces.tobago.component.UIHiddenInput;
050 import org.apache.myfaces.tobago.component.UIPanel;
051 import org.apache.myfaces.tobago.component.UIPopup;
052 import org.apache.myfaces.tobago.component.UITimeInput;
053 import org.apache.myfaces.tobago.config.ThemeConfig;
054 import org.apache.myfaces.tobago.context.ResourceManagerUtil;
055 import org.apache.myfaces.tobago.context.TobagoFacesContext;
056 import org.apache.myfaces.tobago.event.PopupActionListener;
057 import org.apache.myfaces.tobago.renderkit.html.StyleClasses;
058 import org.apache.myfaces.tobago.util.ComponentUtil;
059 import org.apache.myfaces.tobago.util.DateFormatUtils;
060
061 import javax.faces.component.UICommand;
062 import javax.faces.component.UIComponent;
063 import javax.faces.component.UIGraphic;
064 import javax.faces.context.FacesContext;
065 import javax.faces.convert.Converter;
066 import javax.faces.convert.DateTimeConverter;
067 import static javax.faces.convert.DateTimeConverter.CONVERTER_ID;
068 import java.io.IOException;
069 import java.util.Map;
070 import java.util.TimeZone;
071
072 /*
073 * Date: 30.05.2006
074 * Time: 22:21:17
075 */
076 public class DatePickerRenderer extends LinkRenderer {
077 private static final Log LOG = LogFactory.getLog(DatePickerRenderer.class);
078 public static final String CLOSE_POPUP = "closePopup";
079
080 @Override
081 public void onComponentCreated(FacesContext context, UIComponent component) {
082 preparePicker(context, (UIDatePicker) component);
083 }
084
085 public void preparePicker(FacesContext facesContext, UIDatePicker link) {
086 if (link.getFor() == null) {
087 link.setFor("@auto");
088 }
089 link.setImmediate(true);
090 String linkId = link.getId();
091 UIHiddenInput hidden = (UIHiddenInput)
092 CreateComponentUtils.createComponent(facesContext, UIHiddenInput.COMPONENT_TYPE, RENDERER_TYPE_HIDDEN);
093 if (linkId != null) {
094 hidden.setId(linkId + "hidden");
095 } else {
096 hidden.setId(facesContext.getViewRoot().createUniqueId());
097 }
098 link.getChildren().add(hidden);
099
100 // create popup
101 final AbstractUIPopup popup =
102 (AbstractUIPopup) CreateComponentUtils.createComponent(facesContext, UIPopup.COMPONENT_TYPE,
103 RENDERER_TYPE_POPUP);
104 if (linkId != null) {
105 popup.setId(linkId + "popup");
106 } else {
107 popup.setId(facesContext.getViewRoot().createUniqueId());
108 }
109 popup.getAttributes().put(TobagoConstants.ATTR_ZINDEX, 10);
110
111 link.getFacets().put(FACET_PICKER_POPUP, popup);
112
113 popup.setRendered(false);
114
115 final UIComponent box = CreateComponentUtils.createComponent(
116 facesContext, UIBox.COMPONENT_TYPE, RENDERER_TYPE_BOX);
117 popup.getChildren().add(box);
118 box.setId("box");
119 // TODO: set string resources in renderer
120 box.getAttributes().put(ATTR_LABEL, ResourceManagerUtil.getPropertyNotNull(
121 facesContext, "tobago", "datePickerTitle"));
122 UIComponent layout = CreateComponentUtils.createComponent(
123 facesContext, UIGridLayout.COMPONENT_TYPE, RENDERER_TYPE_GRID_LAYOUT);
124 box.getFacets().put(FACET_LAYOUT, layout);
125 layout.setId("layout");
126 layout.getAttributes().put(ATTR_ROWS, "*;fixed;fixed");
127
128 final UIComponent calendar = CreateComponentUtils.createComponent(
129 facesContext, javax.faces.component.UIOutput.COMPONENT_TYPE,
130 RENDERER_TYPE_CALENDAR);
131
132 calendar.setId("calendar");
133 box.getChildren().add(calendar);
134
135 // add time input
136 final UIComponent timePanel = CreateComponentUtils.createComponent(
137 facesContext, UIPanel.COMPONENT_TYPE, RENDERER_TYPE_PANEL);
138 timePanel.setId("timePanel");
139 box.getChildren().add(timePanel);
140 layout = CreateComponentUtils.createComponent(
141 facesContext, UIGridLayout.COMPONENT_TYPE, RENDERER_TYPE_GRID_LAYOUT);
142 timePanel.getFacets().put(FACET_LAYOUT, layout);
143 layout.setId("timePanelLayout");
144 layout.getAttributes().put(ATTR_COLUMNS, "1*;fixed;1*");
145 UIComponent cell = CreateComponentUtils.createComponent(
146 facesContext, UIPanel.COMPONENT_TYPE, RENDERER_TYPE_PANEL);
147 cell.setId("cell1");
148 timePanel.getChildren().add(cell);
149
150 final UIComponent time = CreateComponentUtils.createComponent(
151 facesContext,
152 UITimeInput.COMPONENT_TYPE,
153 RENDERER_TYPE_TIME);
154 timePanel.getChildren().add(time);
155 time.setId("time");
156
157 cell = CreateComponentUtils.createComponent(
158 facesContext, UIPanel.COMPONENT_TYPE, RENDERER_TYPE_PANEL);
159 cell.setId("cell2");
160 timePanel.getChildren().add(cell);
161
162
163 UIComponent buttonPanel = CreateComponentUtils.createComponent(
164 facesContext, UIPanel.COMPONENT_TYPE, RENDERER_TYPE_PANEL);
165 buttonPanel.setId("buttonPanel");
166 layout = CreateComponentUtils.createComponent(
167 facesContext, UIGridLayout.COMPONENT_TYPE, RENDERER_TYPE_GRID_LAYOUT);
168 layout.setId("buttonPanelLayout");
169 buttonPanel.getFacets().put(FACET_LAYOUT, layout);
170 layout.getAttributes().put(ATTR_COLUMNS, "*;*");
171 // layout.getAttributes().put(TobagoConstants.ATTR_BORDER, "1");
172
173 box.getChildren().add(buttonPanel);
174
175 final org.apache.myfaces.tobago.component.UICommand okButton =
176 (org.apache.myfaces.tobago.component.UICommand) CreateComponentUtils.createComponent(facesContext,
177 org.apache.myfaces.tobago.component.UIButtonCommand.COMPONENT_TYPE,
178 RENDERER_TYPE_BUTTON);
179 buttonPanel.getChildren().add(okButton);
180 okButton.setId("ok" + CLOSE_POPUP);
181 okButton.getAttributes().put(ATTR_LABEL, ResourceManagerUtil.getPropertyNotNull(
182 facesContext, "tobago", "datePickerOk"));
183
184 final org.apache.myfaces.tobago.component.UICommand cancelButton =
185 (org.apache.myfaces.tobago.component.UICommand) CreateComponentUtils.createComponent(facesContext,
186 org.apache.myfaces.tobago.component.UIButtonCommand.COMPONENT_TYPE,
187 RENDERER_TYPE_BUTTON);
188 buttonPanel.getChildren().add(cancelButton);
189
190 cancelButton.getAttributes().put(ATTR_LABEL, ResourceManagerUtil.getPropertyNotNull(
191 facesContext, "tobago", "datePickerCancel"));
192 cancelButton.setId(CLOSE_POPUP);
193
194 // create image
195 UIGraphic image = (UIGraphic) CreateComponentUtils.createComponent(
196 facesContext, UIGraphic.COMPONENT_TYPE, RENDERER_TYPE_IMAGE);
197 image.setRendered(true);
198 if (linkId != null) {
199 image.setId(linkId + "image");
200 } else {
201 image.setId(facesContext.getViewRoot().createUniqueId());
202 }
203 image.setValue("image/date.gif");
204 image.getAttributes().put(ATTR_ALT, ""); //TODO: i18n
205 StyleClasses.ensureStyleClasses(image).addFullQualifiedClass("tobago-input-picker"); // XXX not a standard name
206 link.getChildren().add(image);
207 }
208
209
210 public void prepareRender(FacesContext facesContext, UIComponent component) throws IOException {
211 component.getAttributes().put(ATTR_LAYOUT_WIDTH, getConfiguredValue(facesContext, component, "pickerWidth"));
212 if (facesContext instanceof TobagoFacesContext) {
213 UIPopup popup = (UIPopup) component.getFacets().get(FACET_PICKER_POPUP);
214 if (popup != null) {
215 popup.getAttributes().put(ATTR_WIDTH, ThemeConfig.getValue(facesContext, component, "CalendarPopupWidth"));
216 popup.getAttributes().put(ATTR_HEIGHT, ThemeConfig.getValue(facesContext, component, "CalendarPopupHeight"));
217 ((TobagoFacesContext) facesContext).getPopups().add(popup);
218 }
219 }
220 super.prepareRender(facesContext, component);
221 }
222
223 public void encodeBegin(FacesContext facesContext,
224 UIComponent component) throws IOException {
225 UIDatePicker link = (UIDatePicker) component;
226 // DatePickerController datePickerController = new DatePickerController();
227 UIDateInput dateInput = (UIDateInput) link.getForComponent();
228 if (dateInput == null) {
229 LOG.error("No required UIDateInput component found.");
230 return;
231 }
232 if (FacesUtils.hasValueBindingOrValueExpression(dateInput, TobagoConstants.ATTR_READONLY)) {
233 FacesUtils.copyValueBindingOrValueExpression(link, TobagoConstants.ATTR_DISABLED,
234 dateInput, TobagoConstants.ATTR_READONLY);
235 } else {
236 if (FacesUtils.hasValueBindingOrValueExpression(dateInput, TobagoConstants.ATTR_DISABLED)) {
237 FacesUtils.copyValueBindingOrValueExpression(link, TobagoConstants.ATTR_DISABLED,
238 dateInput, TobagoConstants.ATTR_DISABLED);
239 } else {
240 link.setDisabled(dateInput.isReadonly() || dateInput.isDisabled());
241 }
242 }
243 Map<String, Object> attributes = link.getAttributes();
244 // link.setActionListener(datePickerController);
245
246 UIComponent hidden = (UIComponent) link.getChildren().get(0);
247 UIPopup popup = (UIPopup) link.getFacets().get(FACET_PICKER_POPUP);
248
249 attributes.put(ATTR_ACTION_ONCLICK, "Tobago.openPickerPopup(event, '"
250 + link.getClientId(facesContext) + "', '"
251 + hidden.getClientId(facesContext) + "', '"
252 + popup.getClientId(facesContext) + "')");
253
254 Converter converter = getConverter(facesContext, dateInput);
255 String converterPattern = "yyyy-MM-dd"; // from calendar.js initCalendarParse
256 if (converter instanceof DateTimeConverter) {
257 converterPattern = DateFormatUtils.findPattern((DateTimeConverter) converter);
258 } else {
259 // LOG.warn("Converter for DateRenderer is not instance of DateTimeConverter. Using default Pattern "
260 // + converterPattern);
261 }
262
263 UICommand okButton = (UICommand) popup.findComponent("ok" + CLOSE_POPUP);
264 attributes = okButton.getAttributes();
265 attributes.put(ATTR_ACTION_ONCLICK, "var textBox = writeIntoField2(this);Tobago.closePopup(this);textBox.focus();");
266 attributes.put(TobagoConstants.ATTR_POPUP_CLOSE, "afterSubmit");
267
268 UICommand cancelButton = (UICommand) popup.findComponent(CLOSE_POPUP);
269 attributes = cancelButton.getAttributes();
270 attributes.put(ATTR_ACTION_ONCLICK, "var textBox = writeIntoField2(this);Tobago.closePopup(this);textBox.focus();");
271 attributes.put(TobagoConstants.ATTR_POPUP_CLOSE, "immediate");
272
273 applyConverterPattern(facesContext, popup, converterPattern);
274
275 if (!ComponentUtil.containsPopupActionListener(link)) {
276 link.addActionListener(new PopupActionListener(popup.getId()));
277 }
278 super.encodeBegin(facesContext, component);
279 }
280
281 private void applyConverterPattern(FacesContext facesContext, UIPopup popup, String converterPattern) {
282 UIComponent box = (UIComponent) popup.getChildren().get(0);
283 UIComponent timePanel = box.findComponent("timePanel");
284 if (converterPattern != null && (converterPattern.indexOf('h') > -1 || converterPattern.indexOf('H') > -1)) {
285 UIComponent time = timePanel.findComponent("time");
286 int popupHeight = ComponentUtil.getIntAttribute(popup, ATTR_HEIGHT);
287 popupHeight += ThemeConfig.getValue(FacesContext.getCurrentInstance(), time, "fixedHeight");
288 popup.getAttributes().put(ATTR_HEIGHT, popupHeight);
289 DateTimeConverter dateTimeConverter
290 = (DateTimeConverter) facesContext.getApplication().createConverter(CONVERTER_ID);
291 if (converterPattern.indexOf('s') > -1) {
292 dateTimeConverter.setPattern("HH:mm:ss");
293 } else {
294 dateTimeConverter.setPattern("HH:mm");
295 }
296 dateTimeConverter.setTimeZone(TimeZone.getDefault());
297 ((UITimeInput) time).setConverter(dateTimeConverter);
298 } else {
299 timePanel.setRendered(false);
300 }
301 }
302
303 public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException {
304 UIDatePicker link = (UIDatePicker) component;
305 UIDateInput dateInput = (UIDateInput) link.getForComponent();
306 if (dateInput != null) {
307 super.encodeEnd(facesContext, component);
308 } else {
309 LOG.error("No required UIDateInput component found.");
310 }
311 }
312 }