001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2007
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.war.javascript.tree;
034:
035: import com.flexive.faces.RequestRelativeUriMapper;
036: import com.flexive.faces.components.TreeRenderer;
037: import com.flexive.faces.javascript.tree.TreeNodeWriter;
038: import static com.flexive.faces.javascript.tree.TreeNodeWriter.Node;
039: import com.flexive.shared.EJBLookup;
040: import com.flexive.shared.exceptions.FxApplicationException;
041: import com.flexive.shared.tree.FxTreeMode;
042: import com.flexive.shared.tree.FxTreeNode;
043: import org.apache.commons.logging.Log;
044: import org.apache.commons.logging.LogFactory;
045:
046: import javax.servlet.http.HttpServletRequest;
047: import java.io.IOException;
048: import java.io.Serializable;
049: import java.io.StringWriter;
050: import java.util.*;
051:
052: /**
053: * Renders the content tree for the current user, either in the live
054: * or edit version.
055: *
056: * @author Daniel Lichtenberger (daniel.lichtenberger@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
057: * @version $Rev: 1 $
058: */
059: public class ContentTreeWriter implements Serializable {
060: private static final long serialVersionUID = -8810546022515615892L;
061: private static final Log LOG = LogFactory
062: .getLog(ContentTreeWriter.class);
063:
064: private static final String DOCTYPE_NODE = "ContentNode";
065: private static final String DOCTYPE_CONTENT = "ContentObject";
066:
067: /**
068: * Render the content tree beginning at the given node up to maxDepth levels deep.
069: * To be called via JSON-RPC-Java.
070: *
071: * @param request the current request, auto-variable set by JSON-RPC-Java
072: * @param startNodeId the start node for the content tree (1 or null to get the whole tree)
073: * @param maxDepth the maximum depth to be rendered
074: * @param liveTree true if the live tree should be rendered, false for the edit tree
075: * @param pathMode true if node labels should be paths instead of content captions
076: * @return the resulting tree
077: */
078: public String renderContentTree(HttpServletRequest request,
079: Long startNodeId, int maxDepth, boolean liveTree,
080: boolean pathMode) {
081: StringWriter localWriter = null;
082: try {
083: // if embedded in a tree component, use the component's tree writer
084: TreeNodeWriter writer = (TreeNodeWriter) request
085: .getAttribute(TreeRenderer.PROP_NODEWRITER);
086: if (writer == null) {
087: // otherwise return the tree nodes in the response
088: localWriter = new StringWriter();
089: writer = new TreeNodeWriter(localWriter,
090: new RequestRelativeUriMapper(request),
091: TreeNodeWriter.FORMAT_CONTENTTREE);
092: }
093: writeContentTree(writer, startNodeId != null ? startNodeId
094: : FxTreeNode.ROOT_NODE, maxDepth, liveTree,
095: pathMode);
096: if (localWriter != null) {
097: writer.finishResponse();
098: }
099: } catch (Throwable e) {
100: LOG.error("Failed to render content tree: "
101: + e.getMessage(), e);
102: }
103: return localWriter != null ? localWriter.toString() : "";
104: }
105:
106: /**
107: * Render the content tree beginning at the given node up to maxDepth levels deep.
108: *
109: * @param writer the tree node writer to be used
110: * @param startNodeId the start node for the content tree (1 to get the whole tree)
111: * @param maxDepth the maximum depth to be rendered
112: * @param liveTree true if the live tree should be rendered, false for the edit tree
113: * @param pathMode true if node labels should be paths instead of content captions
114: * @throws java.io.IOException if an I/O error occured
115: * @throws FxApplicationException if an tree error occured while accessing the tree
116: */
117: private void writeContentTree(TreeNodeWriter writer,
118: long startNodeId, int maxDepth, boolean liveTree,
119: boolean pathMode) throws FxApplicationException,
120: IOException {
121: FxTreeNode root = EJBLookup.getTreeEngine().getTree(
122: liveTree ? FxTreeMode.Live : FxTreeMode.Edit,
123: startNodeId, maxDepth);
124: writeContentNode(writer, root, new HashMap<String, Object>(),
125: new ArrayList<String>(), pathMode);
126: }
127:
128: private void writeContentNode(TreeNodeWriter writer,
129: FxTreeNode node, Map<String, Object> properties,
130: List<String> actionsDisabled, boolean pathMode)
131: throws IOException {
132: properties.clear();
133: actionsDisabled.clear();
134: properties.put("objectId", node.getId());
135: properties.put("widgetId", "node_" + node.getId());
136: properties.put("isDirty", node.isDirty());
137: properties.put("mayEdit", node.isMayEdit());
138: if (node.hasReference())
139: properties.put("referenceId", node.getReference().getId());
140:
141: setAllowedActions(actionsDisabled, node);
142: if (actionsDisabled.size() > 0)
143: properties.put("actionsDisabled", actionsDisabled);
144:
145: final String docType = node.hasReference() ? DOCTYPE_CONTENT
146: : DOCTYPE_NODE;
147: final String label = pathMode ? node.getName() : node
148: .getLabel().getBestTranslation();
149: properties.put("nodeText", label);
150: if (node.isLeaf()) {
151: writer.writeNode(new Node(String.valueOf(node.getId()),
152: label, docType, properties));
153: } else {
154: if (node.getChildren().size() == 0
155: && node.getDirectChildCount() > 0) {
156: properties.put("isFolder", true);
157: }
158: writer.startNode(new Node(String.valueOf(node.getId()),
159: label + " [" + node.getTotalChildCount() + "]",
160: docType, properties));
161: writer.startChildren();
162: for (FxTreeNode child : node.getChildren())
163: writeContentNode(writer, child, properties,
164: actionsDisabled, pathMode);
165: writer.closeChildren();
166: writer.closeNode();
167: }
168: }
169:
170: /**
171: * Set the allowed context menu actions depending on the given node.
172: *
173: * @param actionsDisabled list of disabled actions
174: * @param node the node to be processed
175: */
176: private void setAllowedActions(List<String> actionsDisabled,
177: FxTreeNode node) {
178: final boolean contentAvailable = node.hasReference();
179: enableAction(actionsDisabled, contentAvailable
180: && node.isMayDelete(), "removeContent");
181: enableAction(actionsDisabled, contentAvailable
182: && node.isMayEdit(), "editContent", "rename");
183: enableAction(actionsDisabled, node.isMayEdit(), "editNode",
184: "cutNode");
185: enableAction(actionsDisabled, node.getDirectChildCount() > 0,
186: "searchSubtree");
187: enableAction(actionsDisabled, !node.isLive()
188: && node.isMayEdit(), "activateNode",
189: "activateNodeAndChildren", "removeNode");
190: enableAction(actionsDisabled, !node.isLive(), "createContent",
191: "createFolder");
192: enableAction(actionsDisabled, node.isLive(), "deactivateNode",
193: "deactivateNodeAndChildren");
194: }
195:
196: /**
197: * Shortcut for enabling/disabling a tree action.
198: *
199: * @param actionsDisabled list of disabled actions
200: * @param enable true to enable the action, false to disable it
201: * @param actions the action(s) to be enabled or disabled
202: */
203: private void enableAction(List<String> actionsDisabled,
204: boolean enable, String... actions) {
205: if (!enable) {
206: actionsDisabled.addAll(Arrays.asList(actions));
207: }
208: }
209: }
|