/******************************************************************************* | |
* 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.ofbiz.widget.tree; | |
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.ofbiz.base.util.Debug; | |
import org.ofbiz.base.util.StringUtil; | |
import org.ofbiz.base.util.UtilGenerics; | |
import org.ofbiz.base.util.UtilMisc; | |
import org.ofbiz.base.util.UtilValidate; | |
import org.ofbiz.base.util.template.FreeMarkerWorker; | |
import org.ofbiz.webapp.control.RequestHandler; | |
import org.ofbiz.webapp.taglib.ContentUrlTag; | |
import org.ofbiz.widget.ModelWidget; | |
import org.ofbiz.widget.WidgetWorker; | |
import org.ofbiz.widget.screen.ScreenRenderer; | |
import org.ofbiz.widget.screen.ScreenStringRenderer; | |
import org.ofbiz.widget.tree.ModelTree; | |
import org.ofbiz.widget.tree.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(); | |
ScreenStringRenderer screenStringRenderer = null; | |
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(Appendable writer, 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(); | |
if (writer != null) { | |
Map<String, Object> input = UtilMisc.toMap("key", null); | |
Environment tmpEnvironment = FreeMarkerWorker.renderTemplate(this.macroLibrary, input, writer); | |
tmpEnvironment.include(template); | |
} else { | |
this.environment.include(template); | |
} | |
} catch (TemplateException e) { | |
Debug.logError(e, "Error rendering screen thru ftl", module); | |
} catch (IOException e) { | |
Debug.logError(e, "Error rendering screen thru ftl", module); | |
} | |
} | |
private void executeMacro(String macro) throws IOException { | |
executeMacro(null, macro); | |
} | |
/** | |
* 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 { | |
if (modelWidget.boundaryCommentsEnabled()) { | |
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 { | |
if (modelWidget.boundaryCommentsEnabled()) { | |
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()) { | |
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(); | |
String entityId = null; | |
String entryName = node.getEntryName(); | |
if (UtilValidate.isNotEmpty(entryName)) { | |
Map map = (Map)context.get(entryName); | |
entityId = (String)map.get(pkName); | |
} else { | |
entityId = (String) context.get(pkName); | |
} | |
boolean hasChildren = node.hasChildren(context); | |
ModelTree.ModelNode.Link expandCollapseLink = new ModelTree.ModelNode.Link(); | |
// check to see if this node needs to be expanded. | |
if (hasChildren && node.isExpandCollapse()) { | |
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, "|"); | |
expandCollapseLink.setStyle("collapsed"); | |
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.setTarget(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 = ""; | |
} | |
expandCollapseLink.setStyle("expanded"); | |
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.setTarget(target.toString()); | |
// add it so it can be remove in renderNodeEnd | |
currentNodeTrail.add(lastContentId); | |
} | |
renderLink(writer, context, expandCollapseLink); | |
} else if (!hasChildren) { | |
context.put("processChildren", Boolean.FALSE); | |
expandCollapseLink.setStyle("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"); | |
if (node.isRootNode()) { | |
renderEndingBoundaryComment(writer, "Tree Widget", node.getModelTree()); | |
} | |
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()); | |
} | |
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.getParameterList(), 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()); | |
} | |
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(writer, sr.toString()); | |
} | |
public ScreenStringRenderer getScreenStringRenderer(Map<String, Object> context) { | |
ScreenRenderer screenRenderer = (ScreenRenderer)context.get("screens"); | |
if (screenRenderer != null) { | |
this.screenStringRenderer = screenRenderer.getScreenStringRenderer(); | |
} | |
return this.screenStringRenderer; | |
} | |
} |