| /******************************************************************************* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| *******************************************************************************/ |
| package org.apache.ofbiz.widget.renderer.macro; |
| |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.servlet.ServletContext; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.base.util.StringUtil; |
| import org.apache.ofbiz.base.util.UtilGenerics; |
| import org.apache.ofbiz.base.util.UtilMisc; |
| import org.apache.ofbiz.base.util.UtilValidate; |
| import org.apache.ofbiz.base.util.template.FreeMarkerWorker; |
| import org.apache.ofbiz.webapp.control.RequestHandler; |
| import org.apache.ofbiz.webapp.taglib.ContentUrlTag; |
| import org.apache.ofbiz.widget.WidgetWorker; |
| import org.apache.ofbiz.widget.model.ModelTree; |
| import org.apache.ofbiz.widget.model.ModelWidget; |
| import org.apache.ofbiz.widget.renderer.ScreenRenderer; |
| import org.apache.ofbiz.widget.renderer.ScreenStringRenderer; |
| import org.apache.ofbiz.widget.renderer.TreeStringRenderer; |
| |
| import freemarker.core.Environment; |
| import freemarker.template.Template; |
| import freemarker.template.TemplateException; |
| |
| /** |
| * Widget Library - Tree Renderer implementation based on Freemarker macros |
| * |
| */ |
| public class MacroTreeRenderer implements TreeStringRenderer { |
| |
| public static final String module = MacroTreeRenderer.class.getName(); |
| private Template macroLibrary; |
| private Environment environment; |
| |
| |
| public MacroTreeRenderer(String macroLibraryPath, Appendable writer) throws TemplateException, IOException { |
| this.macroLibrary = FreeMarkerWorker.getTemplate(macroLibraryPath); |
| Map<String, Object> input = UtilMisc.toMap("key", null); |
| this.environment = FreeMarkerWorker.renderTemplate(this.macroLibrary, input, writer); |
| } |
| |
| private void executeMacro(String macro) throws IOException { |
| try { |
| Reader templateReader = new StringReader(macro); |
| // FIXME: I am using a Date as an hack to provide a unique name for the template... |
| Template template = new Template((new java.util.Date()).toString(), templateReader, |
| FreeMarkerWorker.getDefaultOfbizConfig()); |
| templateReader.close(); |
| this.environment.include(template); |
| } catch (TemplateException e) { |
| Debug.logError(e, "Error rendering tree thru ftl", module); |
| } catch (IOException e) { |
| Debug.logError(e, "Error rendering tree thru ftl", module); |
| } |
| } |
| |
| /** |
| * Renders the beginning boundary comment string. |
| * @param writer The writer to write to |
| * @param widgetType The widget type: "Screen Widget", "Tree Widget", etc. |
| * @param modelWidget The widget |
| */ |
| public void renderBeginningBoundaryComment(Appendable writer, String widgetType, ModelWidget modelWidget) throws IOException { |
| StringWriter sr = new StringWriter(); |
| sr.append("<@formatBoundaryComment "); |
| sr.append(" boundaryType=\""); |
| sr.append("Begin"); |
| sr.append("\" widgetType=\""); |
| sr.append(widgetType); |
| sr.append("\" widgetName=\""); |
| sr.append(modelWidget.getBoundaryCommentName()); |
| sr.append("\" />"); |
| executeMacro(sr.toString()); |
| } |
| |
| /** |
| * Renders the ending boundary comment string. |
| * @param writer The writer to write to |
| * @param widgetType The widget type: "Screen Widget", "Tree Widget", etc. |
| * @param modelWidget The widget |
| */ |
| public void renderEndingBoundaryComment(Appendable writer, String widgetType, ModelWidget modelWidget) throws IOException { |
| StringWriter sr = new StringWriter(); |
| sr.append("<@formatBoundaryComment "); |
| sr.append(" boundaryType=\""); |
| sr.append("End"); |
| sr.append("\" widgetType=\""); |
| sr.append(widgetType); |
| sr.append("\" widgetName=\""); |
| sr.append(modelWidget.getBoundaryCommentName()); |
| sr.append("\" />"); |
| executeMacro(sr.toString()); |
| } |
| |
| public void renderNodeBegin(Appendable writer, Map<String, Object> context, ModelTree.ModelNode node, int depth) throws IOException { |
| String currentNodeTrailPiped = null; |
| List<String> currentNodeTrail = UtilGenerics.toList(context.get("currentNodeTrail")); |
| |
| String style = ""; |
| if (node.isRootNode()) { |
| if (ModelWidget.widgetBoundaryCommentsEnabled(context)) { |
| renderBeginningBoundaryComment(writer, "Tree Widget", node.getModelTree()); |
| } |
| style = "basic-tree"; |
| } |
| |
| StringWriter sr = new StringWriter(); |
| sr.append("<@renderNodeBegin "); |
| sr.append(" style=\""); |
| sr.append(style); |
| sr.append("\" />"); |
| executeMacro(sr.toString()); |
| |
| String pkName = node.getPkName(context); |
| String entityId = null; |
| String entryName = node.getEntryName(); |
| if (UtilValidate.isNotEmpty(entryName)) { |
| Map<String, String> map = UtilGenerics.checkMap(context.get(entryName)); |
| entityId = map.get(pkName); |
| } else { |
| entityId = (String) context.get(pkName); |
| } |
| boolean hasChildren = node.hasChildren(context); |
| |
| // check to see if this node needs to be expanded. |
| if (hasChildren && node.isExpandCollapse()) { |
| // FIXME: Using a widget model in this way is an ugly hack. |
| ModelTree.ModelNode.Link expandCollapseLink = null; |
| String targetEntityId = null; |
| List<String> targetNodeTrail = UtilGenerics.toList(context.get("targetNodeTrail")); |
| if (depth < targetNodeTrail.size()) { |
| targetEntityId = targetNodeTrail.get(depth); |
| } |
| |
| int openDepth = node.getModelTree().getOpenDepth(); |
| if (depth >= openDepth && (targetEntityId == null || !targetEntityId.equals(entityId))) { |
| // Not on the trail |
| if (node.showPeers(depth, context)) { |
| context.put("processChildren", Boolean.FALSE); |
| //expandCollapseLink.setText(" + "); |
| currentNodeTrailPiped = StringUtil.join(currentNodeTrail, "|"); |
| StringBuilder target = new StringBuilder(node.getModelTree().getExpandCollapseRequest(context)); |
| String trailName = node.getModelTree().getTrailName(context); |
| if (target.indexOf("?") < 0) { |
| target.append("?"); |
| } else { |
| target.append("&"); |
| } |
| target.append(trailName).append("=").append(currentNodeTrailPiped); |
| expandCollapseLink = new ModelTree.ModelNode.Link("collapsed", target.toString(), " "); |
| } |
| } else { |
| context.put("processChildren", Boolean.TRUE); |
| //expandCollapseLink.setText(" - "); |
| String lastContentId = currentNodeTrail.remove(currentNodeTrail.size() - 1); |
| currentNodeTrailPiped = StringUtil.join(currentNodeTrail, "|"); |
| if (currentNodeTrailPiped == null) { |
| currentNodeTrailPiped = ""; |
| } |
| StringBuilder target = new StringBuilder(node.getModelTree().getExpandCollapseRequest(context)); |
| String trailName = node.getModelTree().getTrailName(context); |
| if (target.indexOf("?") < 0) { |
| target.append("?"); |
| } else { |
| target.append("&"); |
| } |
| target.append(trailName).append("=").append(currentNodeTrailPiped); |
| expandCollapseLink = new ModelTree.ModelNode.Link("expanded", target.toString(), " "); |
| // add it so it can be remove in renderNodeEnd |
| currentNodeTrail.add(lastContentId); |
| } |
| if (expandCollapseLink != null) { |
| renderLink(writer, context, expandCollapseLink); |
| } |
| } else if (!hasChildren) { |
| context.put("processChildren", Boolean.FALSE); |
| ModelTree.ModelNode.Link expandCollapseLink = new ModelTree.ModelNode.Link("leafnode", "", " "); |
| renderLink(writer, context, expandCollapseLink); |
| } |
| } |
| |
| public void renderNodeEnd(Appendable writer, Map<String, Object> context, ModelTree.ModelNode node) throws IOException { |
| Boolean processChildren = (Boolean) context.get("processChildren"); |
| StringWriter sr = new StringWriter(); |
| sr.append("<@renderNodeEnd "); |
| sr.append(" processChildren="); |
| sr.append(Boolean.toString(processChildren.booleanValue())); |
| sr.append(" isRootNode="); |
| sr.append(Boolean.toString(node.isRootNode())); |
| sr.append(" />"); |
| executeMacro(sr.toString()); |
| if (node.isRootNode()) { |
| if (ModelWidget.widgetBoundaryCommentsEnabled(context)) { |
| renderEndingBoundaryComment(writer, "Tree Widget", node.getModelTree()); |
| } |
| } |
| } |
| |
| public void renderLastElement(Appendable writer, Map<String, Object> context, ModelTree.ModelNode node) throws IOException { |
| Boolean processChildren = (Boolean) context.get("processChildren"); |
| if (processChildren.booleanValue()) { |
| StringWriter sr = new StringWriter(); |
| sr.append("<@renderLastElement "); |
| sr.append("style=\""); |
| sr.append("basic-tree"); |
| sr.append("\" />"); |
| executeMacro(sr.toString()); |
| } |
| } |
| |
| public void renderLabel(Appendable writer, Map<String, Object> context, ModelTree.ModelNode.Label label) throws IOException { |
| String id = label.getId(context); |
| String style = label.getStyle(context); |
| String labelText = label.getText(context); |
| |
| StringWriter sr = new StringWriter(); |
| sr.append("<@renderLabel "); |
| sr.append("id=\""); |
| sr.append(id); |
| sr.append("\" style=\""); |
| sr.append(style); |
| sr.append("\" labelText=\""); |
| sr.append(labelText); |
| sr.append("\" />"); |
| executeMacro(sr.toString()); |
| } |
| |
| public void renderLink(Appendable writer, Map<String, Object> context, ModelTree.ModelNode.Link link) throws IOException { |
| String target = link.getTarget(context); |
| StringBuilder linkUrl = new StringBuilder(); |
| HttpServletResponse response = (HttpServletResponse) context.get("response"); |
| HttpServletRequest request = (HttpServletRequest) context.get("request"); |
| |
| if (UtilValidate.isNotEmpty(target)) { |
| WidgetWorker.buildHyperlinkUrl(linkUrl, target, link.getUrlMode(), link.getParameterMap(context), link.getPrefix(context), |
| link.getFullPath(), link.getSecure(), link.getEncode(), request, response, context); |
| } |
| |
| String id = link.getId(context); |
| String style = link.getStyle(context); |
| String name = link.getName(context); |
| String title = link.getTitle(context); |
| String targetWindow = link.getTargetWindow(context); |
| String linkText = link.getText(context); |
| |
| String imgStr = ""; |
| ModelTree.ModelNode.Image img = link.getImage(); |
| if (img != null) { |
| StringWriter sw = new StringWriter(); |
| renderImage(sw, context, img); |
| imgStr = sw.toString(); |
| } |
| |
| StringWriter sr = new StringWriter(); |
| sr.append("<@renderLink "); |
| sr.append("id=\""); |
| sr.append(id); |
| sr.append("\" style=\""); |
| sr.append(style); |
| sr.append("\" name=\""); |
| sr.append(name); |
| sr.append("\" title=\""); |
| sr.append(title); |
| sr.append("\" targetWindow=\""); |
| sr.append(targetWindow); |
| sr.append("\" linkUrl=\""); |
| sr.append(linkUrl); |
| sr.append("\" linkText=\""); |
| sr.append(linkText); |
| sr.append("\" imgStr=\""); |
| sr.append(imgStr.replaceAll("\"", "\\\\\"")); |
| sr.append("\" />"); |
| executeMacro(sr.toString().replace("|", "%7C")); // Fix for OFBIZ-9191 |
| } |
| |
| public void renderImage(Appendable writer, Map<String, Object> context, ModelTree.ModelNode.Image image) throws IOException { |
| if (image == null) { |
| return; |
| } |
| HttpServletResponse response = (HttpServletResponse) context.get("response"); |
| HttpServletRequest request = (HttpServletRequest) context.get("request"); |
| |
| String urlMode = image.getUrlMode(); |
| String src = image.getSrc(context); |
| String id = image.getId(context); |
| String style = image.getStyle(context); |
| String wid = image.getWidth(context); |
| String hgt = image.getHeight(context); |
| String border = image.getBorder(context); |
| String alt = ""; //TODO add alt to tree images image.getAlt(context); |
| |
| boolean fullPath = false; |
| boolean secure = false; |
| boolean encode = false; |
| String urlString = ""; |
| |
| if (urlMode != null && urlMode.equalsIgnoreCase("intra-app")) { |
| if (request != null && response != null) { |
| ServletContext ctx = (ServletContext) request.getAttribute("servletContext"); |
| RequestHandler rh = (RequestHandler) ctx.getAttribute("_REQUEST_HANDLER_"); |
| urlString = rh.makeLink(request, response, src, fullPath, secure, encode); |
| } else { |
| urlString = src; |
| } |
| } else if (urlMode != null && urlMode.equalsIgnoreCase("content")) { |
| if (request != null && response != null) { |
| StringBuilder newURL = new StringBuilder(); |
| ContentUrlTag.appendContentPrefix(request, newURL); |
| newURL.append(src); |
| urlString = newURL.toString(); |
| } |
| } else { |
| urlString = src; |
| } |
| StringWriter sr = new StringWriter(); |
| sr.append("<@renderImage "); |
| sr.append("src=\""); |
| sr.append(src); |
| sr.append("\" id=\""); |
| sr.append(id); |
| sr.append("\" style=\""); |
| sr.append(style); |
| sr.append("\" wid=\""); |
| sr.append(wid); |
| sr.append("\" hgt=\""); |
| sr.append(hgt); |
| sr.append("\" border=\""); |
| sr.append(border); |
| sr.append("\" alt=\""); |
| sr.append(alt); |
| sr.append("\" urlString=\""); |
| sr.append(urlString); |
| sr.append("\" />"); |
| executeMacro(sr.toString()); |
| } |
| |
| public ScreenStringRenderer getScreenStringRenderer(Map<String, Object> context) { |
| ScreenRenderer screenRenderer = (ScreenRenderer)context.get("screens"); |
| if (screenRenderer != null) { |
| return screenRenderer.getScreenStringRenderer(); |
| } |
| return null; |
| } |
| } |