001    package org.apache.myfaces.tobago.component;
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.myfaces.tobago.context.ResourceManagerUtil;
021    import org.apache.myfaces.tobago.renderkit.html.StyleClasses;
022    
023    import javax.faces.component.UIComponent;
024    import javax.faces.component.UIGraphic;
025    import javax.faces.context.FacesContext;
026    import javax.faces.event.FacesEvent;
027    import java.util.Map;
028    
029    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ALT;
030    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_CALENDAR_DATE_INPUT_ID;
031    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_COLUMNS;
032    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_LABEL;
033    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_POPUP_RESET;
034    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ROWS;
035    import static org.apache.myfaces.tobago.TobagoConstants.FACET_LAYOUT;
036    import static org.apache.myfaces.tobago.TobagoConstants.FACET_PICKER_POPUP;
037    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_BOX;
038    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_BUTTON;
039    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_CALENDAR;
040    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_GRID_LAYOUT;
041    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_HIDDEN;
042    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_IMAGE;
043    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_PANEL;
044    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_POPUP;
045    import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_TIME;
046    
047    public class UIDatePicker extends UILinkCommand implements OnComponentCreated {
048    
049      public static final String COMPONENT_TYPE = "org.apache.myfaces.tobago.DatePicker";
050    
051      public static final String OPEN_POPUP = "openPopup";
052      public static final String CLOSE_POPUP = "closePopup";
053    
054      private String forComponent;
055    
056      public Object saveState(FacesContext context) {
057        Object[] values = new Object[2];
058        values[0] = super.saveState(context);
059        values[1] = forComponent;
060        return values;
061      }
062    
063      public void restoreState(FacesContext context, Object savedState) {
064        Object[] values = (Object[]) savedState;
065        super.restoreState(context, values[0]);
066        forComponent = (String) values[1];
067      }
068    
069      private UIComponent getUIDateInput(UIComponent parent) {
070        for (Object object : parent.getChildren()) {
071          UIComponent child = (UIComponent) object;
072          if (child instanceof UIDateInput) {
073            return child;
074          }
075        }
076        return null;
077      }
078    
079      public String getFor() {
080        if ("@auto".equals(forComponent)) {
081          UIComponent component = getUIDateInput(getParent());
082          if (component == null && getParent() instanceof UIForm) {
083            component = getUIDateInput(getParent().getParent());
084          }
085          if (component != null) {
086            return component.getId();
087          }
088        }
089        return forComponent;
090      }
091    
092      public UIComponent getForComponent() {
093        if ("@auto".equals(forComponent)) {
094          UIComponent component = getUIDateInput(getParent());
095          if (component == null && getParent() instanceof UIForm) {
096            component = getUIDateInput(getParent().getParent());
097          }
098          return component;
099        } else {
100          return findComponent(forComponent);
101        }
102      }
103    
104      public void setFor(String forComponent) {
105        this.forComponent = forComponent;
106      }
107    
108      public void broadcast(FacesEvent facesEvent) {
109        FacesContext facesContext = FacesContext.getCurrentInstance();
110        UIPopup popup = (UIPopup) getFacets().get(FACET_PICKER_POPUP);
111        String clientId = getForComponent().getClientId(facesContext);
112        UIComponent box = popup.findComponent("box");
113        UIComponent calendar = box.findComponent("calendar");
114        calendar.getAttributes().put(ATTR_CALENDAR_DATE_INPUT_ID, clientId);
115        UIComponent time = box.findComponent("time");
116        if (time != null) {
117          time.getAttributes().put(ATTR_CALENDAR_DATE_INPUT_ID, clientId);
118        }
119        super.broadcast(facesEvent);
120      }
121    
122      public void onComponentCreated() {
123        preparePicker(this);
124      }
125    
126      public void preparePicker(UIDatePicker link) {
127        FacesContext facesContext = FacesContext.getCurrentInstance();
128    
129        if (forComponent == null) {
130          link.setFor("@auto");
131        }
132        link.setImmediate(true);
133        String linkId = link.getId();
134        javax.faces.component.UIViewRoot viewRoot = facesContext.getViewRoot();
135        UIHiddenInput hidden =
136            (UIHiddenInput) ComponentUtil.createComponent(facesContext,
137                UIHiddenInput.COMPONENT_TYPE, RENDERER_TYPE_HIDDEN,
138                (linkId != null ? linkId + "hidden" : viewRoot.createUniqueId()));
139        link.getChildren().add(hidden);
140    
141        // create popup
142        final UIPopup popup =
143            (UIPopup) ComponentUtil.createComponent(facesContext, UIPopup.COMPONENT_TYPE,
144                RENDERER_TYPE_POPUP, (linkId != null ? linkId + "popup" : viewRoot.createUniqueId()));
145        link.getFacets().put(FACET_PICKER_POPUP, popup);
146    
147        popup.setRendered(false);
148    
149        Map<String, Object> attributes = popup.getAttributes();
150        attributes.put(ATTR_POPUP_RESET, Boolean.TRUE);
151        //int popupHeight = ThemeConfig.getValue(facesContext, link, "CalendarPopupHeight");
152        //attributes.put(ATTR_HEIGHT, String.valueOf(popupHeight));
153        final UIComponent box = ComponentUtil.createComponent(
154            facesContext, UIBox.COMPONENT_TYPE, RENDERER_TYPE_BOX);
155        popup.getChildren().add(box);
156        box.setId("box");
157        // TODO: set string resources in renderer
158        box.getAttributes().put(ATTR_LABEL, ResourceManagerUtil.getPropertyNotNull(
159            facesContext, "tobago", "datePickerTitle"));
160        UIComponent layout = ComponentUtil.createComponent(
161            facesContext, UIGridLayout.COMPONENT_TYPE, RENDERER_TYPE_GRID_LAYOUT, "layout");
162        box.getFacets().put(FACET_LAYOUT, layout);
163        layout.getAttributes().put(ATTR_ROWS, "*;fixed;fixed");
164    //    layout.getAttributes().put(TobagoConstants.ATTR_BORDER, "1");
165    
166        final UIComponent calendar = ComponentUtil.createComponent(
167            facesContext, javax.faces.component.UIOutput.COMPONENT_TYPE,
168            RENDERER_TYPE_CALENDAR, "calendar");
169        box.getChildren().add(calendar);
170    
171        // add time input
172        final UIComponent timePanel = ComponentUtil.createComponent(
173            facesContext, UIPanel.COMPONENT_TYPE, RENDERER_TYPE_PANEL, "timePanel");
174        box.getChildren().add(timePanel);
175        layout = ComponentUtil.createComponent(
176            facesContext, UIGridLayout.COMPONENT_TYPE, RENDERER_TYPE_GRID_LAYOUT, "timePanelLayout");
177        timePanel.getFacets().put(FACET_LAYOUT, layout);
178        layout.getAttributes().put(ATTR_COLUMNS, "1*;fixed;1*");
179        UIComponent cell = ComponentUtil.createComponent(
180            facesContext, UIPanel.COMPONENT_TYPE, RENDERER_TYPE_PANEL, "cell1");
181        timePanel.getChildren().add(cell);
182    
183        final UIComponent time = ComponentUtil.createComponent(
184            facesContext,
185            org.apache.myfaces.tobago.component.UITimeInput.COMPONENT_TYPE,
186            RENDERER_TYPE_TIME, "time");
187        timePanel.getChildren().add(time);
188    
189        cell = ComponentUtil.createComponent(
190            facesContext, UIPanel.COMPONENT_TYPE, RENDERER_TYPE_PANEL, "cell2");
191        timePanel.getChildren().add(cell);
192    
193    
194        UIComponent buttonPanel = ComponentUtil.createComponent(
195            facesContext, UIPanel.COMPONENT_TYPE, RENDERER_TYPE_PANEL, "buttonPanel");
196        layout = ComponentUtil.createComponent(
197            facesContext, UIGridLayout.COMPONENT_TYPE, RENDERER_TYPE_GRID_LAYOUT, "buttonPanelLayout");
198        buttonPanel.getFacets().put(FACET_LAYOUT, layout);
199        layout.getAttributes().put(ATTR_COLUMNS, "*;*");
200        layout.getAttributes().put(ATTR_ROWS, "fixed");
201    //    layout.getAttributes().put(TobagoConstants.ATTR_BORDER, "1");
202    
203        box.getChildren().add(buttonPanel);
204    
205        final UICommand okButton =
206            (UICommand) ComponentUtil.createComponent(facesContext,
207                org.apache.myfaces.tobago.component.UIButtonCommand.COMPONENT_TYPE,
208                RENDERER_TYPE_BUTTON, "ok" + CLOSE_POPUP);
209        buttonPanel.getChildren().add(okButton);
210        attributes = okButton.getAttributes();
211        attributes.put(ATTR_LABEL, ResourceManagerUtil.getPropertyNotNull(
212            facesContext, "tobago", "datePickerOk"));
213    
214        final UICommand cancelButton =
215            (UICommand) ComponentUtil.createComponent(facesContext,
216                org.apache.myfaces.tobago.component.UIButtonCommand.COMPONENT_TYPE,
217                RENDERER_TYPE_BUTTON, CLOSE_POPUP);
218        buttonPanel.getChildren().add(cancelButton);
219        attributes = cancelButton.getAttributes();
220        attributes.put(ATTR_LABEL, ResourceManagerUtil.getPropertyNotNull(
221            facesContext, "tobago", "datePickerCancel"));
222    
223        // create image
224        UIGraphic image = (UIGraphic) ComponentUtil.createComponent(
225            facesContext, UIGraphic.COMPONENT_TYPE, RENDERER_TYPE_IMAGE,
226                (linkId != null ? linkId + "image" : viewRoot.createUniqueId()));
227        image.setRendered(true);
228        image.setValue("image/date.gif");
229        image.getAttributes().put(ATTR_ALT, ""); //TODO: i18n
230        StyleClasses.ensureStyleClasses(image).addFullQualifiedClass("tobago-input-picker"); // XXX not a standard name
231        link.getChildren().add(image);
232      }
233    
234    }