001 package org.apache.myfaces.tobago.util; 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_INLINE; 024 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INNER_HEIGHT; 025 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_INNER_WIDTH; 026 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_LAYOUT_HEIGHT; 027 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_LAYOUT_WIDTH; 028 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_MINIMUM_SIZE; 029 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_WIDTH; 030 import static org.apache.myfaces.tobago.TobagoConstants.FACET_LABEL; 031 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_OUT; 032 import org.apache.myfaces.tobago.component.ComponentUtil; 033 import org.apache.myfaces.tobago.component.UICell; 034 import org.apache.myfaces.tobago.component.UIForm; 035 import org.apache.myfaces.tobago.renderkit.LayoutInformationProvider; 036 037 import javax.faces.component.UIComponent; 038 import javax.faces.component.UINamingContainer; 039 import javax.faces.context.FacesContext; 040 import java.awt.Dimension; 041 import java.util.ArrayList; 042 import java.util.List; 043 044 public final class LayoutUtil { 045 046 private static final Log LOG = LogFactory.getLog(LayoutUtil.class); 047 048 private LayoutUtil() { 049 // to prevent instantiation 050 } 051 052 public static int getInnerSpace(FacesContext facesContext, 053 UIComponent component, boolean width) { 054 String attribute; 055 if (width) { 056 attribute = ATTR_INNER_WIDTH; 057 } else { 058 attribute = ATTR_INNER_HEIGHT; 059 } 060 Integer innerSpace = (Integer) component.getAttributes().get(attribute); 061 062 if (innerSpace == null) { 063 int space = -1; 064 065 Integer spaceInteger; 066 if (width) { 067 spaceInteger = getLayoutWidth(component); 068 } else { 069 spaceInteger = getLayoutHeight(component); 070 } 071 if (spaceInteger != null) { 072 space = spaceInteger; 073 } 074 075 // if (space < 0 && component.getParent() instanceof UIComponentBase) { 076 if (space < 0 && component.getParent() != null) { 077 space = getInnerSpace(facesContext, component.getParent(), width); 078 } 079 080 if (space != -1) { 081 innerSpace = getInnerSpace(facesContext, component, space, width); 082 } else { 083 innerSpace = -1; 084 } 085 086 component.getAttributes().put(attribute, innerSpace); 087 } 088 089 return innerSpace; 090 } 091 092 public static int getInnerSpace(FacesContext facesContext, UIComponent component, 093 int outerSpace, boolean width) { 094 int margin = 0; 095 if (component.getRendererType() != null) { 096 try { 097 098 LayoutInformationProvider renderer = ComponentUtil.getRenderer(facesContext, component); 099 100 if (width) { 101 margin += renderer.getPaddingWidth(facesContext, component); 102 margin += renderer.getComponentExtraWidth(facesContext, component); 103 } else { 104 margin += renderer.getHeaderHeight(facesContext, component); 105 margin += renderer.getPaddingHeight(facesContext, component); 106 margin += renderer.getComponentExtraHeight(facesContext, component); 107 } 108 } catch (Exception e) { 109 if (LOG.isDebugEnabled()) { 110 LOG.debug("cant find margin", e); 111 } 112 } 113 } else { 114 if (LOG.isDebugEnabled()) { 115 LOG.debug("renderertype = null, component: " + component); 116 } 117 } 118 return outerSpace - margin; 119 } 120 121 122 public static int getLabelWidth(UIComponent component) { 123 if (component != null) { 124 UIComponent label = component.getFacet(FACET_LABEL); 125 if (label != null) { 126 String labelWidth = (String) label.getAttributes().get(ATTR_WIDTH); 127 if (labelWidth != null) { 128 try { 129 return Integer.parseInt(labelWidth.replaceAll("\\D", "")); 130 } catch (NumberFormatException e) { 131 LOG.warn("Can't parse label width, using default value", e); 132 } 133 } 134 } 135 } 136 return 0; 137 } 138 139 //TODO Change this to DimensionUtils.getWidth? 140 public static Integer getLayoutWidth(UIComponent component) { 141 return getLayoutSpace(component, ATTR_WIDTH, ATTR_LAYOUT_WIDTH); 142 } 143 //TODO Change this to DimensionUtils.getHeight? 144 public static Integer getLayoutHeight(UIComponent component) { 145 return getLayoutSpace(component, ATTR_HEIGHT, ATTR_LAYOUT_HEIGHT); 146 } 147 148 public static Integer getLayoutSpace(UIComponent component, 149 String sizeAttribute, String layoutAttribute) { 150 Object value = ComponentUtil.getAttribute(component, sizeAttribute); 151 if (value != null) { 152 if (value instanceof String) { 153 return new Integer(((String) value).replaceAll("\\D", "")); 154 } else { 155 return (Integer) value; 156 } 157 } else if (!ComponentUtil.getBooleanAttribute(component, ATTR_INLINE)) { 158 159 value = ComponentUtil.getAttribute(component, layoutAttribute); 160 return (Integer) value; 161 } 162 return null; 163 } 164 165 public static List<UIComponent> addChildren(List<UIComponent> children, UIComponent panel) { 166 for (Object o : panel.getChildren()) { 167 UIComponent child = (UIComponent) o; 168 if (isTransparentForLayout(child)) { 169 addChildren(children, child); 170 } else { 171 children.add(child); 172 } 173 } 174 return children; 175 } 176 177 public static boolean isTransparentForLayout(UIComponent component) { 178 179 // SubViewTag's component is UINamingContainer with 'null' rendererType 180 // is transparent for layouting 181 182 if (component instanceof UINamingContainer 183 && component.getRendererType() == null) { 184 return true; 185 } 186 // TODO find a better way 187 if ("facelets".equals(component.getFamily())) { 188 return !"com.sun.facelets.tag.UIDebug".equals(component.getClass().getName()); 189 } 190 /* TODO disable layouting of facelet stuff 191 if (component.getClass().getPackage().getName().equals("com.sun.facelets.compiler")) { 192 return true; 193 } */ 194 // also Forms are transparent for layouting 195 196 return component instanceof UIForm; 197 } 198 199 public static UIComponent getLayoutParent(UIComponent component) { 200 UIComponent parent = component.getParent(); 201 while (parent != null && isTransparentForLayout(parent)) { 202 parent = parent.getParent(); 203 } 204 return parent; 205 } 206 207 public static void maybeSetLayoutAttribute(UIComponent cell, String attribute, 208 Integer value) { 209 if (RENDERER_TYPE_OUT.equals(cell.getRendererType())) { 210 return; 211 } 212 if (LOG.isDebugEnabled()) { 213 LOG.debug("set " + value + " to " + cell.getRendererType()); 214 } 215 cell.getAttributes().put(attribute, value); 216 if (ATTR_LAYOUT_WIDTH.equals(attribute)) { 217 cell.getAttributes().remove(ATTR_INNER_WIDTH); 218 } else if (ATTR_LAYOUT_HEIGHT.equals(attribute)) { 219 cell.getAttributes().remove(ATTR_INNER_HEIGHT); 220 } 221 if (cell instanceof UICell) { 222 List<UIComponent> children = addChildren(new ArrayList<UIComponent>(), cell); 223 for (UIComponent component : children) { 224 maybeSetLayoutAttribute(component, attribute, value); 225 } 226 } 227 } 228 229 public static int calculateFixedHeightForChildren(FacesContext facesContext, UIComponent component) { 230 int height = 0; 231 for (Object o : component.getChildren()) { 232 UIComponent child = (UIComponent) o; 233 LayoutInformationProvider renderer = ComponentUtil.getRenderer(facesContext, child); 234 if (renderer == null 235 && child instanceof UINamingContainer 236 && child.getChildren().size() > 0) { 237 // this is a subview component ?? 238 renderer = ComponentUtil.getRenderer(facesContext, (UIComponent) child.getChildren().get(0)); 239 } 240 if (renderer != null) { 241 int h = renderer.getFixedHeight(facesContext, child); 242 if (h > 0) { 243 height += h; 244 } 245 } 246 } 247 return height; 248 } 249 250 public static Dimension getMinimumSize( 251 FacesContext facesContext, UIComponent component) { 252 Dimension dimension 253 = (Dimension) component.getAttributes().get(ATTR_MINIMUM_SIZE); 254 if (dimension == null) { 255 LayoutInformationProvider renderer = ComponentUtil.getRenderer(facesContext, component); 256 if (renderer != null) { 257 dimension = renderer.getMinimumSize(facesContext, component); 258 } 259 } 260 if (dimension == null) { 261 dimension = new Dimension(-1, -1); 262 } 263 return dimension; 264 } 265 266 } 267