001    package org.apache.myfaces.tobago.renderkit.html.scarborough.standard.tag;
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    /*
021     * Created 07.02.2003 16:00:00.
022     * $Id: TreeRenderer.java 652070 2008-04-28 06:38:01Z bommel $
023     */
024    
025    import org.apache.myfaces.tobago.component.AbstractUITree;
026    import org.apache.myfaces.tobago.context.ResourceManagerUtil;
027    import org.apache.myfaces.tobago.context.TobagoFacesContext;
028    import org.apache.myfaces.tobago.renderkit.LayoutableRendererBase;
029    import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
030    import org.apache.myfaces.tobago.renderkit.html.HtmlConstants;
031    import org.apache.myfaces.tobago.renderkit.html.util.HtmlRendererUtil;
032    import org.apache.myfaces.tobago.renderkit.util.RenderUtil;
033    import org.apache.myfaces.tobago.util.ComponentUtil;
034    import org.apache.myfaces.tobago.util.FastStringWriter;
035    import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
036    
037    import javax.faces.component.NamingContainer;
038    import javax.faces.component.UIComponent;
039    import javax.faces.context.FacesContext;
040    import javax.faces.context.ResponseWriter;
041    import java.io.IOException;
042    
043    public class TreeRenderer extends LayoutableRendererBase {
044    
045      /**
046       * Resources to display the tree.
047       */
048      private static final String[] TREE_IMAGES = {
049          "openfoldericon.gif",
050          "foldericon.gif",
051          "unchecked.gif",
052          "uncheckedDisabled.gif",
053          "checked.gif",
054          "checkedDisabled.gif",
055          "new.gif",
056          "T.gif",
057          "L.gif",
058          "I.gif",
059          "Lminus.gif",
060          "Tminus.gif",
061          "Rminus.gif",
062          "Lplus.gif",
063          "Tplus.gif",
064          "Rplus.gif",
065          "treeMenuOpen.gif",
066          "treeMenuClose.gif",
067      };
068    
069      private static final String SCRIPT = "script/tobago-tree.js";
070    
071      public void prepareRender(FacesContext facesContext, UIComponent component) throws IOException {
072        super.prepareRender(facesContext, component);
073        if (facesContext instanceof TobagoFacesContext) {
074          // todo: this may be removed, it is twice on the page 1. in the header 2. in the ScriptLoader
075          ((TobagoFacesContext) facesContext).getScriptFiles().add(SCRIPT);
076        }
077      }
078    
079    
080      @Override
081      public void decode(FacesContext facesContext, UIComponent component) {
082        if (ComponentUtil.isOutputOnly(component)) {
083          return;
084        }
085    
086        AbstractUITree tree = (AbstractUITree) component;
087        tree.setValid(true);
088      }
089    
090      public static boolean isSelectable(AbstractUITree tree) {
091        return tree.isSelectableTree();
092      }
093    
094      public static String createJavascriptVariable(String clientId) {
095        return clientId == null
096            ? null
097            : clientId.replace(NamingContainer.SEPARATOR_CHAR, '_');
098      }
099    
100      @Override
101      public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
102        // will be rendered in encodeEnd()
103      }
104    
105      @Override
106      public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException {
107    
108        AbstractUITree tree = (AbstractUITree) component;
109    
110        String clientId = tree.getClientId(facesContext);
111        UIComponent root = tree.getRoot();
112    
113        TobagoResponseWriter writer = HtmlRendererUtil.getTobagoResponseWriter(facesContext);
114    
115        writer.startElement(HtmlConstants.DIV, tree);
116        writer.writeClassAttribute();
117        writer.writeStyleAttribute();
118    
119        writer.startElement(HtmlConstants.INPUT, tree);
120        writer.writeAttribute(HtmlAttributes.TYPE, "hidden", false);
121        writer.writeNameAttribute(clientId);
122        writer.writeIdAttribute(clientId);
123        writer.writeAttribute(HtmlAttributes.VALUE, ";", false);
124        writer.endElement(HtmlConstants.INPUT);
125    
126        writer.startElement(HtmlConstants.INPUT, tree);
127        writer.writeAttribute(HtmlAttributes.TYPE, "hidden", false);
128        writer.writeNameAttribute(clientId + AbstractUITree.MARKER);
129        writer.writeIdAttribute(clientId + AbstractUITree.MARKER);
130        writer.writeAttribute(HtmlAttributes.VALUE, "", false);
131        writer.endElement(HtmlConstants.INPUT);
132    
133        if (isSelectable(tree)) {
134          writer.startElement(HtmlConstants.INPUT, tree);
135          writer.writeAttribute(HtmlAttributes.TYPE, "hidden", false);
136          writer.writeNameAttribute(clientId + AbstractUITree.SELECT_STATE);
137          writer.writeIdAttribute(clientId + AbstractUITree.SELECT_STATE);
138          writer.writeAttribute(HtmlAttributes.VALUE, ";", false);
139          writer.endElement(HtmlConstants.INPUT);
140        }
141    
142        String scriptTexts = createJavascript(facesContext);
143    
144        HtmlRendererUtil.writeScriptLoader(facesContext, new String[]{SCRIPT}, new String[]{scriptTexts});
145    
146        RenderUtil.encode(facesContext, root);
147    
148        writer.endElement(HtmlConstants.DIV);
149      }
150    
151      private String createJavascript(FacesContext facesContext) throws IOException {
152        StringBuilder sb = new StringBuilder(128);
153    
154        sb.append("{\n");
155    
156        sb.append("  var treeResourcesHelp = new Object();\n");
157        for (String images : TREE_IMAGES) {
158          sb.append("  treeResourcesHelp[\"");
159          sb.append(images);
160          sb.append("\"] = \"");
161          sb.append(ResourceManagerUtil.getImageWithPath(facesContext, "image/" + images));
162          sb.append("\";\n");
163        }
164        sb.append(" \n  treeResourcesHelp.getImage = function (name) {\n");
165        sb.append("    var result = this[name];\n");
166        sb.append("    if (result) {\n");
167        sb.append("      return result;\n");
168        sb.append("    } else {\n");
169        sb.append("      return \"");
170        sb.append(ResourceManagerUtil.getImageWithPath(facesContext, "image/blank.gif"));
171        sb.append("\";\n");
172        sb.append("    }\n");
173        sb.append("  };\n \n");
174        sb.append("}");
175        return sb.toString();
176      }
177    
178      protected String getNodesAsJavascript(FacesContext facesContext, UIComponent root) throws IOException {
179        ResponseWriter writer = facesContext.getResponseWriter();
180        FastStringWriter stringWriter = new FastStringWriter();
181        facesContext.setResponseWriter(writer.cloneWithWriter(stringWriter));
182        RenderUtil.encode(facesContext, root);
183        facesContext.setResponseWriter(writer);
184        return stringWriter.toString();
185      }
186    
187      protected String nodeStateId(FacesContext facesContext, UIComponent node) {
188        // this must do the same as nodeStateId() in tree.js
189        String clientId = node.getClientId(facesContext);
190        int last = clientId.lastIndexOf(':') + 1;
191        return clientId.substring(last);
192      }
193    }