blob: bdc033992dad0b958f30a19242820eb26aa9ba9d [file] [log] [blame]
/*******************************************************************************
* 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("&nbsp;+&nbsp;");
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("&nbsp;-&nbsp;");
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;
}
}