001 package org.apache.myfaces.tobago.renderkit;
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 static org.apache.myfaces.tobago.TobagoConstants.ATTR_HEIGHT;
023 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_WIDTH;
024 import static org.apache.myfaces.tobago.TobagoConstants.FACET_MENUBAR;
025 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INNER_WIDTH;
026 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INNER_HEIGHT;
027 import org.apache.myfaces.tobago.util.ComponentUtil;
028 import org.apache.myfaces.tobago.component.Cell;
029 import org.apache.myfaces.tobago.util.LayoutUtil;
030 import org.apache.myfaces.tobago.renderkit.html.StyleClasses;
031 import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
032 import org.apache.myfaces.tobago.renderkit.html.HtmlStyleMap;
033
034 import javax.faces.component.UIComponent;
035 import javax.faces.context.FacesContext;
036 import java.awt.Dimension;
037 import java.io.IOException;
038 import java.util.ArrayList;
039 import java.util.List;
040 import java.util.Map;
041
042 public abstract class LayoutableRendererBase
043 extends RendererBase implements LayoutableRenderer {
044
045 private static final Log LOG = LogFactory.getLog(LayoutableRendererBase.class);
046
047 public int getHeaderHeight(
048 FacesContext facesContext, UIComponent component) {
049 int height = getConfiguredValue(facesContext, component, "headerHeight");
050 final UIComponent menubar = component.getFacet(FACET_MENUBAR);
051 if (menubar != null) {
052 height += getConfiguredValue(facesContext, menubar, "headerHeight");
053 }
054 return height;
055 }
056
057 public int getPaddingWidth(FacesContext facesContext, UIComponent component) {
058 return getConfiguredValue(facesContext, component, "paddingWidth");
059 }
060
061 public int getPaddingHeight(
062 FacesContext facesContext, UIComponent component) {
063 return getConfiguredValue(facesContext, component, "paddingHeight");
064 }
065
066 public int getComponentExtraWidth(
067 FacesContext facesContext,
068 UIComponent component) {
069 return getConfiguredValue(facesContext, component, "componentExtraWidth");
070 }
071
072 public int getComponentExtraHeight(
073 FacesContext facesContext,
074 UIComponent component) {
075 return getConfiguredValue(facesContext, component, "componentExtraHeight");
076 }
077
078 public Dimension getMinimumSize(
079 FacesContext facesContext, UIComponent component) {
080 int width = getMinimumWidth(facesContext, component);
081 int height = getMinimumHeight(facesContext, component);
082 return new Dimension(width, height);
083 }
084
085 public int getMinimumHeight(FacesContext facesContext, UIComponent component) {
086 int height = getConfiguredValue(facesContext, component, "minimumHeight");
087 if (height == -1) {
088 height = getConfiguredValue(facesContext, component, "fixedHeight");
089 }
090 return height;
091 }
092
093 public int getMinimumWidth(FacesContext facesContext, UIComponent component) {
094 int width = getConfiguredValue(facesContext, component, "minimumWidth");
095 if (width == -1) {
096 width = getConfiguredValue(facesContext, component, "fixedWidth");
097 }
098 return width;
099 }
100
101 public int getFixedWidth(FacesContext facesContext, UIComponent component) {
102 return getFixedSpace(facesContext, component, true);
103 }
104
105 public int getFixedHeight(FacesContext facesContext, UIComponent component) {
106 return getFixedSpace(facesContext, component, false);
107 }
108
109 public int getFixedSpace(FacesContext facesContext, UIComponent component, boolean width) {
110
111 int fixedSpace = 0;
112
113 if (component instanceof Cell) {
114 List children = LayoutUtil.addChildren(new ArrayList(), component);
115 for (Object aChildren : children) {
116 UIComponent child = (UIComponent) aChildren;
117
118 LayoutInformationProvider renderer = ComponentUtil.getRenderer(facesContext, child);
119 if (renderer != null) {
120 if (width) {
121 fixedSpace = Math.max(fixedSpace, renderer.getFixedWidth(facesContext, child));
122 } else {
123 fixedSpace = Math.max(fixedSpace, renderer.getFixedHeight(facesContext, child));
124 }
125 }
126 }
127 } else {
128 if (width) {
129 fixedSpace = getFixedSpace(facesContext, component, ATTR_WIDTH, "fixedWidth");
130 } else {
131 fixedSpace = getFixedSpace(facesContext, component, ATTR_HEIGHT, "fixedHeight");
132 }
133 }
134 return fixedSpace;
135 }
136
137 private int getFixedSpace(FacesContext facesContext, UIComponent component,
138 String attr, String attrFixed) {
139 int intSpace = -1;
140 Object space = null;
141 if (component != null) {
142 space = ComponentUtil.getObjectAttribute(component, attr);
143 }
144 if (space != null && space instanceof String) {
145 try {
146 intSpace = Integer.parseInt(((String) space).replaceAll("\\D", ""));
147 } catch (NumberFormatException e) {
148 LOG.error("Caught: " + e.getMessage(), e);
149 }
150 }
151 if (space != null && space instanceof Integer) {
152 intSpace = (Integer) space;
153 }
154 if (intSpace == -1) {
155 return getConfiguredValue(facesContext, component, attrFixed);
156 } else {
157 return intSpace;
158 }
159 }
160
161 public void layoutBegin(FacesContext context, UIComponent component) throws IOException {
162 }
163
164 public void layoutEnd(FacesContext context, UIComponent component) throws IOException {
165 }
166
167 public void prepareRender(FacesContext facesContext, UIComponent component) throws IOException {
168
169 prepareDimension(facesContext, component);
170 final String rendererType = component.getRendererType();
171 if (rendererType != null) {
172 final String rendererName = getRendererName(rendererType);
173 StyleClasses classes = StyleClasses.ensureStyleClasses(component);
174 classes.updateClassAttributeAndMarkup(component, rendererName);
175 } else {
176 LOG.error("No renderType for " + component);
177 }
178 layoutSpace(facesContext, component, true);
179 layoutSpace(facesContext, component, false);
180 }
181
182 void prepareDimension(FacesContext facesContext, UIComponent component) {
183 // LOG.info("prepareDimension for " + component.getClientId(facesContext) + " is " + component.getRendererType());
184 setInnerWidth(facesContext, component);
185 setInnerHeight(facesContext, component);
186 }
187
188 void setInnerWidth(FacesContext facesContext, UIComponent component) {
189 Integer layoutWidth = LayoutUtil.getLayoutWidth(component);
190 if (layoutWidth != null) {
191 int space = layoutWidth.intValue();
192 int innerSpace = LayoutUtil.getInnerSpace(facesContext, component, space, true);
193 component.getAttributes().put(ATTR_INNER_WIDTH, Integer.valueOf(innerSpace));
194 }
195 }
196
197 void setInnerHeight(FacesContext facesContext, UIComponent component) {
198 Integer layoutHeight = LayoutUtil.getLayoutHeight(component);
199 if (layoutHeight != null) {
200 int space = layoutHeight.intValue();
201 int innerSpace = LayoutUtil.getInnerSpace(facesContext, component, space, false);
202 component.getAttributes().put(ATTR_INNER_HEIGHT, Integer.valueOf(innerSpace));
203 }
204 }
205
206 private void layoutSpace(FacesContext facesContext, UIComponent component, boolean width) {
207
208 // prepare html 'style' attribute
209 Integer layoutSpace;
210 String layoutAttribute;
211 String styleAttribute;
212 if (width) {
213 layoutSpace = LayoutUtil.getLayoutWidth(component);
214 layoutAttribute = org.apache.myfaces.tobago.TobagoConstants.ATTR_LAYOUT_WIDTH;
215 styleAttribute = HtmlAttributes.WIDTH;
216 } else {
217 layoutSpace = LayoutUtil.getLayoutHeight(component);
218 layoutAttribute = org.apache.myfaces.tobago.TobagoConstants.ATTR_LAYOUT_HEIGHT;
219 styleAttribute = HtmlAttributes.HEIGHT;
220 }
221 int space = -1;
222 if (layoutSpace != null) {
223 space = layoutSpace.intValue();
224 }
225 if (space == -1
226 && (!org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_OUT.equals(component.getRendererType()))) {
227 UIComponent parent = component.getParent();
228 space = LayoutUtil.getInnerSpace(facesContext, parent, width);
229 if (space > 0 && !ComponentUtil.isFacetOf(component, parent)) {
230 component.getAttributes().put(layoutAttribute, Integer.valueOf(space));
231 if (width) {
232 component.getAttributes().remove(org.apache.myfaces.tobago.TobagoConstants.ATTR_INNER_WIDTH);
233 } else {
234 component.getAttributes().remove(org.apache.myfaces.tobago.TobagoConstants.ATTR_INNER_HEIGHT);
235 }
236 }
237 }
238 if (space > 0) {
239 if (layoutSpace != null
240 || !ComponentUtil.getBooleanAttribute(component, org.apache.myfaces.tobago.TobagoConstants.ATTR_INLINE)) {
241 int styleSpace = space;
242 if (width) {
243 styleSpace -= getComponentExtraWidth(facesContext, component);
244 } else {
245 styleSpace -= getComponentExtraHeight(facesContext, component);
246 }
247
248 replaceStyleAttribute(component, styleAttribute, styleSpace);
249
250 }
251 UIComponent layout = component.getFacet(org.apache.myfaces.tobago.TobagoConstants.FACET_LAYOUT);
252 if (layout != null) {
253 int layoutSpace2 = LayoutUtil.getInnerSpace(facesContext, component,
254 width);
255 if (layoutSpace2 > 0) {
256 layout.getAttributes().put(layoutAttribute, Integer.valueOf(layoutSpace2));
257 }
258 }
259 }
260 }
261
262 private void replaceStyleAttribute(UIComponent component, String styleAttribute, int value) {
263 HtmlStyleMap style = ensureStyleAttributeMap(component);
264 style.put(styleAttribute, value);
265 }
266
267 private HtmlStyleMap ensureStyleAttributeMap(UIComponent component) {
268 return ensureStyleAttributeMap(component, org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE);
269 }
270
271 private HtmlStyleMap ensureStyleAttributeMap(UIComponent component, String attribute) {
272 final Map attributes = component.getAttributes();
273 HtmlStyleMap style = (HtmlStyleMap) attributes.get(attribute);
274 if (style == null) {
275 style = new HtmlStyleMap();
276 attributes.put(attribute, style);
277 }
278 return style;
279 }
280 }