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.faces.javascript.tree;
034:
035: import com.flexive.faces.javascript.RelativeUriMapper;
036: import com.flexive.war.JsonWriter;
037:
038: import java.io.IOException;
039: import java.io.Writer;
040: import java.util.HashMap;
041: import java.util.Map;
042: import java.util.Map.Entry;
043:
044: /**
045: * A basic writer for tree nodes for the Dojo tree (V3).
046: *
047: * @author Daniel Lichtenberger (daniel.lichtenberger@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
048: * @version $Rev: 1 $
049: */
050: public class TreeNodeWriter {
051: private final static Map<String, Object> EMPTY_MAP = new HashMap<String, Object>();
052:
053: /**
054: * A single tree node.
055: */
056: public static class Node {
057: /**
058: * Default class for nodes without children (leaves)
059: */
060: public static final String TITLE_CLASS_LEAF = "treeNodeV3Child";
061: /**
062: * Default class for nodes with children
063: */
064: public static final String TITLE_CLASS_NODE = "treeNodeV3Node";
065:
066: private String id;
067: private String title;
068: private String titleClass;
069: private String icon;
070: private String docType;
071: private String link;
072: private Map<String, ?> properties;
073:
074: /**
075: * Create a node without style infos. Formatting is based on the CSS class(es)
076: * corresponding to docType.
077: *
078: * @param title the node title
079: * @param docType the document type
080: * @param properties optional properties
081: */
082: public Node(String id, String title, String docType,
083: Map<String, ?> properties) {
084: this .id = id;
085: this .title = title;
086: this .docType = docType;
087: this .properties = properties;
088: }
089:
090: public Node(String id, String title, String titleClass,
091: String icon, Map<String, ?> properties) {
092: this .id = id;
093: this .title = title;
094: this .titleClass = titleClass;
095: this .icon = icon;
096: this .properties = properties != null ? properties
097: : EMPTY_MAP;
098: }
099:
100: public Node(String id, String title, String titleClass,
101: String icon) {
102: this (id, title, titleClass != null ? titleClass
103: : TITLE_CLASS_LEAF, icon, EMPTY_MAP);
104: }
105:
106: public Node(String id, String title, String titleClass,
107: String icon, String link) {
108: this (id, title, titleClass != null ? titleClass
109: : TITLE_CLASS_LEAF, icon, EMPTY_MAP);
110: this .link = link;
111: }
112:
113: public String getId() {
114: return id;
115: }
116:
117: public String getTitle() {
118: return title;
119: }
120:
121: public String getTitleClass() {
122: return titleClass;
123: }
124:
125: public String getIcon() {
126: return icon;
127: }
128:
129: public String getDocType() {
130: return docType;
131: }
132:
133: public String getLink() {
134: return link;
135: }
136: }
137:
138: /**
139: * Formats the label of a given tree node, e.g. adds
140: * HTML markup for formatting.
141: */
142: public static interface NodeFormatter {
143: String format(Node node, RelativeUriMapper uriMapper);
144: }
145:
146: /**
147: * Plain node formatter. Icons may be rendered using the
148: * TreeDocIconExtension and specifying matching CSS classes.
149: * Preferred to FORMAT_ADMINTREE if inline node editing is required.
150: */
151: public static final NodeFormatter FORMAT_PLAIN = new NodeFormatter() {
152: /** {@inheritDoc} */
153: public String format(Node node, RelativeUriMapper uriMapper) {
154: return node.title;
155: }
156: };
157:
158: /**
159: * Format the node using the default style for the admin backend trees.
160: */
161: public static final NodeFormatter FORMAT_ADMINTREE = new NodeFormatter() {
162: private static final String ICON_CLASS = "treeNodeV3Icon";
163: private static final String ICON_PATH = "adm/images/tree/";
164:
165: /** {@inheritDoc} */
166: public String format(Node node, RelativeUriMapper uriMapper) {
167: final String title = "<div class=\"" + node.titleClass
168: + "\">" + node.title + "</div>";
169: if (node.icon == null) {
170: return title;
171: } else {
172: final String icon = ICON_PATH + node.icon + ".png";
173: return "<img src=\"" + uriMapper.getAbsoluteUri(icon)
174: + "\" class=\"" + ICON_CLASS + "\">" + title;
175: }
176: }
177: };
178:
179: public static final NodeFormatter FORMAT_CONTENTTREE = new NodeFormatter() {
180: /** {@inheritDoc} */
181: public String format(Node node, RelativeUriMapper uriMapper) {
182: final StringBuilder style = new StringBuilder();
183: if ((Boolean) node.properties.get("isDirty")) {
184: style.append("dirty ");
185: }
186: if (!(Boolean) node.properties.get("mayEdit")) {
187: style.append("readonly ");
188: }
189: if (style.length() > 0) {
190: // add dirty node style
191: return "<span class=\"" + style + "\">" + node.title
192: + "</span>";
193: } else {
194: return node.title;
195: }
196: }
197: };
198:
199: private final JsonWriter out;
200: private final NodeFormatter formatter;
201: private final RelativeUriMapper uriMapper;
202:
203: /**
204: * Create a new TreeNodeWriter using an existing JsonWriter.
205: *
206: * @param out the JsonWriter instance to be used
207: * @param formatter the default formatter to be used
208: * @throws IOException if the output could not be written
209: */
210: public TreeNodeWriter(JsonWriter out, RelativeUriMapper uriMapper,
211: NodeFormatter formatter) throws IOException {
212: this .out = out;
213: this .formatter = formatter;
214: this .uriMapper = uriMapper;
215: out.startArray();
216: }
217:
218: /**
219: * Create a new TreeNodeWriter for the given output writer.
220: *
221: * @param out an output writer.
222: * @param formatter the default node formatter to be used
223: * @throws IOException if the output could not be written
224: */
225: public TreeNodeWriter(Writer out, RelativeUriMapper uriMapper,
226: NodeFormatter formatter) throws IOException {
227: this (new JsonWriter(out), uriMapper, formatter);
228: }
229:
230: /**
231: * Closes the tree structure. No nodes can be appended to the generated tree
232: * afterwards.
233: *
234: * @throws IOException if the output could not be written
235: */
236: public void finishResponse() throws IOException {
237: out.closeArray();
238: }
239:
240: /**
241: * Start a new node without closing it. Additional parameters
242: * and nested child nodes may be appended in subsequent calls. The node must be
243: * closed with a call to {@link TreeNodeWriter#closeNode()}.
244: *
245: * @param node the node to be written
246: * @throws IOException if the output could not be written
247: */
248: public void startNode(Node node) throws IOException {
249: out.startMap();
250: out.writeAttribute("title", formatter.format(node, uriMapper));
251: if (node.docType != null) {
252: out.writeAttribute("nodeDocType", node.docType);
253: }
254: if (node.link != null) {
255: out.writeAttribute("link", node.link);
256: }
257: for (Entry<String, ?> entry : node.properties.entrySet()) {
258: out.writeAttribute(entry.getKey(), entry.getValue());
259: }
260: }
261:
262: /**
263: * Close a node previously opened with
264: * {@link TreeNodeWriter#startNode(TreeNodeWriter.Node)}.
265: *
266: * @throws IOException if the output could not be written
267: */
268: public void closeNode() throws IOException {
269: out.closeMap();
270: }
271:
272: /**
273: * Render a leaf node.
274: *
275: * @param node the node to be rendered
276: * @throws IOException if the output could not be written
277: */
278: public void writeNode(Node node) throws IOException {
279: startNode(node);
280: closeNode();
281: }
282:
283: /**
284: * Prepare the current node (created with
285: * {@link TreeNodeWriter#startNode(TreeNodeWriter.Node)})
286: * for appending of nested child nodes.
287: *
288: * @throws IOException if the output could not be written
289: */
290: public void startChildren() throws IOException {
291: out.startAttribute("children");
292: out.startArray();
293: }
294:
295: /**
296: * Close the child nodes array previously created with
297: * {@link TreeNodeWriter#startChildren()}.
298: *
299: * @throws IOException if the output could not be written
300: */
301: public void closeChildren() throws IOException {
302: out.closeArray();
303: }
304:
305: }
|