001 package org.apache.myfaces.tobago.facelets.extension;
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 com.sun.facelets.FaceletContext;
021 import com.sun.facelets.el.ELAdaptor;
022 import com.sun.facelets.tag.MetaRuleset;
023 import com.sun.facelets.tag.Metadata;
024 import com.sun.facelets.tag.TagAttribute;
025 import com.sun.facelets.tag.jsf.ComponentConfig;
026 import com.sun.facelets.tag.jsf.ComponentHandler;
027 import com.sun.facelets.tag.jsf.ComponentSupport;
028 import org.apache.myfaces.tobago.context.Markup;
029 import org.slf4j.Logger;
030 import org.slf4j.LoggerFactory;
031 import org.apache.myfaces.tobago.component.Attributes;
032 import org.apache.myfaces.tobago.component.Facets;
033 import org.apache.myfaces.tobago.component.InputSuggest;
034 import org.apache.myfaces.tobago.component.OnComponentCreated;
035 import org.apache.myfaces.tobago.component.OnComponentPopulated;
036 import org.apache.myfaces.tobago.component.RendererTypes;
037 import org.apache.myfaces.tobago.component.SupportsMarkup;
038 import org.apache.myfaces.tobago.component.UIGridLayout;
039 import org.apache.myfaces.tobago.component.UILabel;
040 import org.apache.myfaces.tobago.component.UIPanel;
041 import org.apache.myfaces.tobago.facelets.SuggestMethodRule;
042 import org.apache.myfaces.tobago.facelets.SupportsMarkupRule;
043 import org.apache.myfaces.tobago.internal.layout.LayoutUtils;
044
045 import javax.el.ELException;
046 import javax.el.ValueExpression;
047 import javax.faces.FacesException;
048 import javax.faces.application.Application;
049 import javax.faces.component.UIComponent;
050 import javax.faces.component.UIViewRoot;
051 import java.io.IOException;
052 import java.util.List;
053
054 /*
055 * Date: Jul 31, 2007
056 * Time: 6:14:34 PM
057 */
058 public abstract class TobagoLabelExtensionHandler extends ComponentHandler {
059 private static final Logger LOG = LoggerFactory.getLogger(TobagoLabelExtensionHandler.class);
060 private static final String DEFAULT_COLUMNS = "fixed;*";
061 private TagAttribute labelWidthAttribute;
062 private TagAttribute tipAttribute;
063 private TagAttribute labelAttribute;
064 private TagAttribute markupAttribute;
065 private TagAttribute fieldIdAttribute;
066 private Class subComponentLastType = Object.class;
067 private Metadata subComponentMapper;
068
069 public TobagoLabelExtensionHandler(ComponentConfig config) {
070 super(config);
071 labelWidthAttribute = getAttribute("labelWidth");
072 tipAttribute = getAttribute(Attributes.TIP);
073 labelAttribute = getAttribute(Attributes.LABEL);
074 markupAttribute = getAttribute(Attributes.MARKUP);
075 fieldIdAttribute = getAttribute("fieldId");
076 }
077
078 protected abstract String getSubComponentType();
079
080 protected abstract String getSubRendererType();
081
082 protected String getRows() {
083 return "fixed";
084 }
085
086 protected String getColumns(String first) {
087 return first + ";*";
088 }
089
090 protected void applyNextHandler(FaceletContext ctx, UIComponent panel)
091 throws IOException, FacesException, ELException {
092 if (ComponentSupport.isNew(panel)) {
093 // ensure that input has no parent (isNew)
094 UIComponent input = (UIComponent) panel.getChildren().remove(1);
095 nextHandler.apply(ctx, input);
096 UIComponent date = null;
097 if (panel.getChildCount() > 1) {
098 date = (UIComponent) panel.getChildren().get(1);
099 }
100 panel.getChildren().add(input);
101 if (date != null) {
102 panel.getChildren().add(date);
103 }
104 } else {
105 UIComponent input = (UIComponent) panel.getChildren().get(1);
106 nextHandler.apply(ctx, input);
107 }
108 }
109
110 protected void onComponentCreated(FaceletContext faceletContext, UIComponent panel, UIComponent parent) {
111
112 Application application = faceletContext.getFacesContext().getApplication();
113 UIViewRoot root = ComponentSupport.getViewRoot(faceletContext, parent);
114
115 addGridLayout(faceletContext, panel, root);
116
117 addLabel(faceletContext, (UIPanel) panel, root);
118 String uid;
119 if (fieldIdAttribute != null) {
120 uid = fieldIdAttribute.getValue(faceletContext);
121 } else {
122 uid = root.createUniqueId();
123 }
124 if (checkForAlreadyCreated(panel, uid)) {
125 return;
126 }
127
128 UIComponent input = application.createComponent(getSubComponentType());
129 input.setRendererType(getSubRendererType());
130 input.setId(uid);
131 enrichInput(faceletContext, input);
132
133 setSubComponentAttributes(faceletContext, input);
134
135 panel.getChildren().add(input);
136 }
137
138 protected void enrichInput(FaceletContext faceletContext, UIComponent input) {
139 }
140
141 private void addLabel(FaceletContext faceletContext, UIPanel panel, UIViewRoot root) {
142 String uid = root.createUniqueId();
143 if (checkForAlreadyCreated(panel, uid)) {
144 return;
145 }
146 Application application = faceletContext.getFacesContext().getApplication();
147 UILabel label = (UILabel) application.createComponent(UILabel.COMPONENT_TYPE);
148 label.setRendererType(RendererTypes.LABEL);
149 label.setId(uid);
150 label.getAttributes().put(Attributes.FOR, "@auto");
151 if (tipAttribute != null) {
152 if (tipAttribute.isLiteral()) {
153 panel.setTip(tipAttribute.getValue(faceletContext));
154 } else {
155 ValueExpression expression = tipAttribute.getValueExpression(faceletContext, String.class);
156 ELAdaptor.setExpression(panel, Attributes.TIP, expression);
157 }
158 }
159 if (labelAttribute != null) {
160 if (labelAttribute.isLiteral()) {
161 label.setValue(labelAttribute.getValue(faceletContext));
162 } else {
163 ValueExpression expression = labelAttribute.getValueExpression(faceletContext, String.class);
164 ELAdaptor.setExpression(label, Attributes.VALUE, expression);
165 }
166 }
167 if (markupAttribute != null) {
168 if (markupAttribute.isLiteral()) {
169 label.setMarkup(Markup.valueOf(markupAttribute.getValue()));
170 } else {
171 ValueExpression expression = markupAttribute.getValueExpression(faceletContext, Object.class);
172 ELAdaptor.setExpression(label, Attributes.MARKUP, expression);
173 }
174 }
175 panel.getChildren().add(label);
176 }
177
178 private boolean checkForAlreadyCreated(UIComponent panel, String uid) {
179 if (panel.getChildCount() > 0) {
180 List list = panel.getChildren();
181 for (int i = 0; i < list.size(); i++) {
182 UIComponent child = (UIComponent) list.get(i);
183 if (uid.equals(child.getId())) {
184 return true;
185 }
186 }
187 }
188 return false;
189 }
190
191 private void addGridLayout(FaceletContext faceletContext, UIComponent panel, UIViewRoot root) {
192 Application application = faceletContext.getFacesContext().getApplication();
193 UIGridLayout gridLayout = (UIGridLayout) application.createComponent(UIGridLayout.COMPONENT_TYPE);
194 gridLayout.setRendererType(RendererTypes.GRID_LAYOUT);
195 if (labelWidthAttribute != null) {
196 String columns = getColumns(labelWidthAttribute.getValue(faceletContext));
197 if (!LayoutUtils.checkTokens(columns)) {
198 LOG.warn("Illegal value for columns = \"" + columns + "\" replacing with default: \"" + DEFAULT_COLUMNS + "\"");
199 columns = DEFAULT_COLUMNS;
200 }
201 gridLayout.setColumns(columns);
202 } else {
203 gridLayout.setColumns(getColumns("fixed"));
204 }
205 gridLayout.setRows(getRows());
206 gridLayout.setId(root.createUniqueId());
207 if (gridLayout instanceof OnComponentCreated) {
208 ((OnComponentCreated) gridLayout).onComponentCreated(faceletContext.getFacesContext(), panel);
209 }
210 panel.getFacets().put(Facets.LAYOUT, gridLayout);
211 if (gridLayout instanceof OnComponentPopulated) {
212 ((OnComponentPopulated) gridLayout).onComponentPopulated(faceletContext.getFacesContext(), panel);
213 }
214 }
215
216 private void setSubComponentAttributes(FaceletContext ctx, Object instance) {
217 if (instance != null) {
218 Class type = instance.getClass();
219 if (subComponentMapper == null || !subComponentLastType.equals(type)) {
220 subComponentLastType = type;
221 subComponentMapper = createSubComponentMetaRuleset(type).finish();
222 }
223 subComponentMapper.applyMetadata(ctx, instance);
224 }
225 }
226
227 protected MetaRuleset createSubComponentMetaRuleset(Class aClass) {
228 MetaRuleset metaRuleset = super.createMetaRuleset(aClass);
229 //metaRuleset.ignore(Attributes.LABEL);
230 metaRuleset.ignore(Attributes.TIP);
231 metaRuleset.ignore("labelWidth");
232 if (SupportsMarkup.class.isAssignableFrom(aClass)) {
233 metaRuleset.addRule(SupportsMarkupRule.INSTANCE);
234 }
235 if (InputSuggest.class.isAssignableFrom(aClass)) {
236 metaRuleset.addRule(SuggestMethodRule.INSTANCE);
237 }
238 return metaRuleset;
239 }
240
241 protected MetaRuleset createMetaRuleset(Class aClass) {
242 MetaRuleset metaRuleset = super.createMetaRuleset(aClass);
243 TagAttribute [] attrs = tag.getAttributes().getAll();
244 for (int i = 0; i < attrs.length; i++) {
245 TagAttribute attr = attrs[i];
246 if (!attr.getLocalName().equals("rendered")) {
247 metaRuleset.ignore(attr.getLocalName());
248 }
249 }
250 return metaRuleset;
251 }
252 }