001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *   http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    
020    package org.apache.myfaces.tobago.renderkit;
021    
022    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_HEIGHT;
023    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ONCLICK;
024    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_WIDTH;
025    import static org.apache.myfaces.tobago.TobagoConstants.FACET_MENUBAR;
026    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_READONLY;
027    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_DISABLED;
028    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_TRANSITION;
029    
030    import org.apache.commons.lang.StringUtils;
031    import org.apache.myfaces.tobago.component.ComponentUtil;
032    import org.apache.myfaces.tobago.component.UICell;
033    import org.apache.myfaces.tobago.component.UICommand;
034    import org.apache.myfaces.tobago.renderkit.html.HtmlRendererUtil;
035    import org.apache.myfaces.tobago.util.LayoutUtil;
036    import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
037    
038    import javax.faces.component.UIComponent;
039    import javax.faces.context.FacesContext;
040    import java.awt.Dimension;
041    import java.io.IOException;
042    import java.util.ArrayList;
043    import java.util.Arrays;
044    import java.util.List;
045    import java.util.Map;
046    
047    public abstract class LayoutableRendererBase
048        extends RendererBase implements LayoutInformationProvider {
049    
050      public int getHeaderHeight(
051          FacesContext facesContext, UIComponent component) {
052        int height = getConfiguredValue(facesContext, component, "headerHeight");
053        final UIComponent menubar = component.getFacet(FACET_MENUBAR);
054        if (menubar != null) {
055          height += getConfiguredValue(facesContext, menubar, "headerHeight");
056        }
057        return height;
058      }
059    
060      public int getPaddingWidth(FacesContext facesContext, UIComponent component) {
061        return getConfiguredValue(facesContext, component, "paddingWidth");
062      }
063    
064      public int getPaddingHeight(
065          FacesContext facesContext, UIComponent component) {
066        return getConfiguredValue(facesContext, component, "paddingHeight");
067      }
068    
069      public int getComponentExtraWidth(
070          FacesContext facesContext,
071          UIComponent component) {
072        return getConfiguredValue(facesContext, component, "componentExtraWidth");
073      }
074    
075      public int getComponentExtraHeight(
076          FacesContext facesContext,
077          UIComponent component) {
078        return getConfiguredValue(facesContext, component, "componentExtraHeight");
079      }
080    
081      public Dimension getMinimumSize(
082          FacesContext facesContext, UIComponent component) {
083        int width = getConfiguredValue(facesContext, component, "minimumWidth");
084        if (width == -1) {
085          width = getConfiguredValue(facesContext, component, "fixedWidth");
086        }
087        int height = getConfiguredValue(facesContext, component, "minimumHeight");
088        if (height == -1) {
089          height = getConfiguredValue(facesContext, component, "fixedHeight");
090        }
091        return new Dimension(width, height);
092      }
093    
094      public int getFixedWidth(FacesContext facesContext, UIComponent component) {
095        return getFixedSpace(facesContext, component, true);
096      }
097    
098      public int getFixedHeight(FacesContext facesContext, UIComponent component) {
099        return getFixedSpace(facesContext, component, false);
100      }
101    
102      public int getFixedSpace(FacesContext facesContext, UIComponent component, boolean width) {
103    
104        int fixedSpace = 0;
105    
106        if (component instanceof UICell) {
107          List children = LayoutUtil.addChildren(new ArrayList(), component);
108          for (Object aChildren : children) {
109            UIComponent child = (UIComponent) aChildren;
110    
111            LayoutInformationProvider renderer = ComponentUtil.getRenderer(facesContext, child);
112            if (renderer != null) {
113              if (width) {
114                fixedSpace = Math.max(fixedSpace, renderer.getFixedWidth(facesContext, child));
115              } else {
116                fixedSpace = Math.max(fixedSpace, renderer.getFixedHeight(facesContext, child));
117              }
118            }
119          }
120        } else {
121          if (width) {
122            fixedSpace = getFixedSpace(facesContext, component, ATTR_WIDTH, "fixedWidth");
123          } else {
124            fixedSpace = getFixedSpace(facesContext, component, ATTR_HEIGHT, "fixedHeight");
125          }
126        }
127        return fixedSpace;
128      }
129    
130      private int getFixedSpace(FacesContext facesContext, UIComponent component,
131          String attr, String attrFixed) {
132        int intSpace = -1;
133        String space = null;
134        if (component != null) {
135          space = ComponentUtil.getStringAttribute(component, attr);
136        }
137        if (space != null) {
138          try {
139            intSpace = Integer.parseInt(LayoutUtil.stripNonNumericChars(space));
140          } catch (NumberFormatException e) {
141            LOG.error("Caught: " + e.getMessage(), e);
142          }
143        }
144        if (intSpace == -1) {
145          return getConfiguredValue(facesContext, component, attrFixed);
146        } else {
147          return intSpace;
148        }
149      }
150    
151      protected void checkForCommandFacet(UIComponent component, FacesContext facesContext, TobagoResponseWriter writer)
152          throws IOException {
153        checkForCommandFacet(component, Arrays.asList(component.getClientId(facesContext)), facesContext, writer);
154      }
155    
156      protected void checkForCommandFacet(UIComponent component, List<String> clientIds, FacesContext facesContext,
157          TobagoResponseWriter writer) throws IOException {
158        if (ComponentUtil.getBooleanAttribute(component, ATTR_READONLY)
159            || ComponentUtil.getBooleanAttribute(component, ATTR_DISABLED)) {
160          // skip if readonly
161          return;
162        }
163        Map<String, UIComponent> facets = component.getFacets();
164        for (Map.Entry<String, UIComponent> entry : facets.entrySet()) {
165          if (entry.getValue() instanceof UICommand) {
166            addCommandFacet(clientIds, entry, facesContext, writer);
167          }
168        }
169      }
170    
171      // TODO create HtmlRendererBase
172      private void addCommandFacet(List<String> clientIds, Map.Entry<String, UIComponent> facetEntry,
173          FacesContext facesContext, TobagoResponseWriter writer) throws
174          IOException {
175        for (String clientId : clientIds) {
176          writeScriptForClientId(clientId, facetEntry, facesContext, writer);
177        }
178      }
179    
180      private void writeScriptForClientId(String clientId, Map.Entry<String, UIComponent> facetEntry,
181          FacesContext facesContext, TobagoResponseWriter writer) throws IOException {
182        if (facetEntry.getValue() instanceof UICommand
183            && ((UICommand) facetEntry.getValue()).getRenderedPartially().length > 0) {
184          String script =
185              "var element = Tobago.element(\"" + clientId + "\");\n"
186                  + "if (element) {\n"
187                  + "   Tobago.addEventListener(element, \"" + facetEntry.getKey()
188                  + "\", function(){Tobago.reloadComponent2(this, '"
189                  + HtmlRendererUtil.getComponentId(facesContext, facetEntry.getValue(),
190                  ((UICommand) facetEntry.getValue()).getRenderedPartially()[0]) + "','"
191                  + facetEntry.getValue().getClientId(facesContext) + "', {})});\n"
192                  + "}";
193          writer.writeJavascript(script);
194        } else {
195          UIComponent facetComponent = facetEntry.getValue();
196          String facetAction = (String) facetComponent.getAttributes().get(ATTR_ONCLICK);
197          if (facetAction == null) {
198            facetAction = "Tobago.submitAction2(this, '" + facetComponent.getClientId(facesContext) + "', "
199                + ComponentUtil.getBooleanAttribute(facetComponent, ATTR_TRANSITION) + ", null, '" + clientId +"')";
200          } else {
201             // Replace @autoId
202            facetAction = StringUtils.replace(facetAction, "@autoId", facetComponent.getClientId(facesContext));
203          }
204          String script =
205              "var element = Tobago.element(\"" + clientId + "\");\n"
206                  + "if (element) {\n"
207                  + "   Tobago.addEventListener(element, \"" + facetEntry.getKey() + "\", function(){"
208                  + facetAction + "});\n}";
209          writer.writeJavascript(script);
210        }
211      }
212    }