001: // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
002: // Released under the terms of the GNU General Public License version 2 or later.
003: package fitnesse.wikitext.widgets;
004:
005: import fitnesse.wikitext.WikiWidget;
006: import fitnesse.wiki.*;
007: import fitnesse.html.*;
008:
009: import java.util.*;
010:
011: public class ContentsTreeWidget extends WikiWidget {
012: public static final String NODE_DIV_CLASS = "contentsTreeDiv";
013:
014: public static final String OUTER_DIV_CLASS = "contentsTreeOuterDiv";
015:
016: public static final String COLLAPSIBLE_NODE_CLASS = "collapsibleNode";
017:
018: public static final String HIDDEN_NODE_CLASS = "hiddenNode";
019:
020: public static final String STATIC_IMAGE_CLASS = "contentsTreeStaticImage";
021:
022: public static final String TOGGLE_IMAGE_CLASS = "contentsTreeToggleImage";
023:
024: public static final String MINUS_IMAGE = "/files/images/treeview/minus.gif";
025:
026: public static final String PLUS_IMAGE = "/files/images/treeview/plus.gif";
027:
028: public static final String LINK_IMAGE = "/files/images/treeview/link_blank.gif";
029:
030: public static final String LAST_LINK_IMAGE = "/files/images/treeview/lastlink_blank.gif";
031:
032: public static final String STIQ_TEST_IMAGE = "/files/images/treeview/test.png";
033:
034: public static final String STIQ_SUITE_IMAGE = "/files/images/treeview/tsuite.png";
035:
036: public static final String STIQ_COMPONENT_IMAGE = "/files/images/treeview/file.png";
037:
038: public static final String STIQ_CONTAINER_IMAGE = "/files/images/treeview/folder.gif";
039:
040: public static final int STIQ_ICON_WIDTH = 22;
041: public static final int STIQ_ICON_HEIGHT = 16;
042:
043: private static final Map IMAGES_FOR_TYPE;
044: static {
045: Map map = new HashMap();
046: map.put(WikiPage.STIQ_TEST, STIQ_TEST_IMAGE);
047: map.put(WikiPage.STIQ_SUITE, STIQ_SUITE_IMAGE);
048: map.put(WikiPage.STIQ_COMPONENT, STIQ_COMPONENT_IMAGE);
049: map.put(WikiPage.STIQ_CONTAINER, STIQ_CONTAINER_IMAGE);
050: IMAGES_FOR_TYPE = Collections.unmodifiableMap(map);
051: }
052:
053: public static final String REGEXP = "(?:^!contentstree[ \t]*$)|(?:^!contentstree -RC?[ \t]*$)";
054:
055: private static final Random random = new Random(System
056: .currentTimeMillis());
057:
058: private boolean collapsed;
059:
060: private boolean recursive;
061:
062: public ContentsTreeWidget(ParentWidget parent, String text) {
063: super (parent);
064: setRecursive(text);
065: setStartCollapsed(text);
066: }
067:
068: private void setRecursive(String text) {
069: recursive = (text.indexOf("-R") > -1);
070: }
071:
072: private void setStartCollapsed(String text) {
073: collapsed = (text.indexOf("-RC") > -1);
074: }
075:
076: public String render() throws Exception {
077: HtmlTag outerDiv = makeOuterDivTag();
078: addChildDivs(getWikiPage(), outerDiv);
079: return outerDiv.html();
080: }
081:
082: private void addChildDivs(WikiPage parentWikiPage, HtmlTag parentDiv)
083: throws Exception {
084: for (Iterator iterator = buildListOfChildPages(parentWikiPage)
085: .iterator(); iterator.hasNext();) {
086: HtmlTag mainDiv = HtmlUtil.makeDivTag(NODE_DIV_CLASS);
087: WikiPage currentPage = (WikiPage) iterator.next();
088: String uniqueID = getUniqueID();
089:
090: boolean isLastChild = (iterator.hasNext() == false);
091: HtmlTag nodeImage = getNodeImage(currentPage, uniqueID,
092: isLastChild);
093: mainDiv.add(nodeImage);
094: mainDiv.add(getNodeTitleLink(currentPage, uniqueID));
095:
096: // Add div below which will hold children and collapse
097: HtmlTag innerDiv = makeDivTag(uniqueID);
098: mainDiv.add(innerDiv);
099: parentDiv.add(mainDiv);
100:
101: if (isRecursive()
102: && buildListOfChildPages(currentPage).size() > 0) {
103: addChildDivs(currentPage, innerDiv);
104: }
105: }
106: }
107:
108: private HtmlTag getNodeImage(WikiPage wikiPage, String uniqueID,
109: boolean isLastChild) {
110: HtmlTag img = getImageTag(wikiPage, uniqueID, isLastChild);
111: if (img.getAttribute("class") == TOGGLE_IMAGE_CLASS) {
112: HtmlTag anchor = new HtmlTag("a", img);
113: anchor.setAddNewlineAfter(false);
114: anchor.addAttribute("href", "javascript:toggleTreeNode('"
115: + uniqueID + "');");
116: return anchor;
117: }
118: return img;
119: }
120:
121: private HtmlTag getImageTag(WikiPage wikiPage, String uniqueID,
122: boolean isLastChild) {
123: HtmlTag img = new HtmlTag("img");
124: img.addAttribute("id", "img" + uniqueID);
125:
126: String imageClass = getImageClass(wikiPage);
127: img.addAttribute("class", imageClass);
128: if (isLastChild && imageClass != TOGGLE_IMAGE_CLASS) {
129: img.addAttribute("src", LAST_LINK_IMAGE);
130: } else {
131: img.addAttribute("src", getImageSrc(wikiPage));
132: }
133: return img;
134: }
135:
136: private String getImageSrc(WikiPage wikiPage) {
137: if (pageHasChildren(wikiPage)) {
138: if (startCollapsed()) {
139: return PLUS_IMAGE;
140: } else {
141: return MINUS_IMAGE;
142: }
143: } else {
144: return LINK_IMAGE;
145: }
146: }
147:
148: private boolean pageHasChildren(WikiPage wikiPage) {
149: boolean hasChildren = false;
150: try {
151: if (wikiPage.getChildren().size() > 0) {
152: hasChildren = true;
153: }
154: } catch (Exception e1) {
155: hasChildren = false;
156: }
157: return hasChildren;
158: }
159:
160: private String getImageClass(WikiPage wikiPage) {
161: String imageClass = STATIC_IMAGE_CLASS;
162: try {
163: if (wikiPage.getChildren().size() > 0) {
164: imageClass = TOGGLE_IMAGE_CLASS;
165: }
166: } catch (Exception e1) {
167: imageClass = STATIC_IMAGE_CLASS;
168: }
169: return imageClass;
170: }
171:
172: private HtmlTag getNodeTitleLink(WikiPage currentPage,
173: String uniqueID) throws Exception {
174: HtmlTag anchor = new HtmlTag("a");
175: anchor.addAttribute("href", getHref(currentPage));
176: anchor.setAddNewlineAfter(false);
177:
178: HtmlTag img = new HtmlTag("img");
179: String pageType = getTypeOfPage(currentPage);
180: String imgFilename = (String) IMAGES_FOR_TYPE.get(pageType);
181: img.addAttribute("src", imgFilename);
182: img.addAttribute("width", String.valueOf(STIQ_ICON_WIDTH));
183: img.addAttribute("height", String.valueOf(STIQ_ICON_HEIGHT));
184: img.addAttribute("class", "treeIcon");
185: img.addAttribute("alt", pageType);
186: anchor.add(img);
187:
188: anchor.add(currentPage.getName());
189: return anchor;
190: }
191:
192: private String getTypeOfPage(WikiPage currentPage) throws Exception {
193: if (currentPage.getData().hasAttribute(WikiPage.STIQ_TEST)) {
194: return WikiPage.STIQ_TEST;
195: } else if (currentPage.getData().hasAttribute(
196: WikiPage.STIQ_SUITE)) {
197: return WikiPage.STIQ_SUITE;
198: } else if (currentPage.getData().hasAttribute(
199: WikiPage.STIQ_COMPONENT)) {
200: return WikiPage.STIQ_COMPONENT;
201: }
202: return WikiPage.STIQ_CONTAINER;
203: }
204:
205: private String getUniqueID() {
206: return "" + random.nextLong();
207: }
208:
209: private List buildListOfChildPages(WikiPage wikiPage)
210: throws Exception {
211: List childPageList = new ArrayList(wikiPage.getChildren());
212: if (wikiPage.hasExtension(VirtualCouplingExtension.NAME)) {
213: VirtualCouplingExtension extension = (VirtualCouplingExtension) wikiPage
214: .getExtension(VirtualCouplingExtension.NAME);
215: WikiPage virtualCoupling = extension.getVirtualCoupling();
216: childPageList.addAll(virtualCoupling.getChildren());
217: }
218: Collections.sort(childPageList);
219: return childPageList;
220: }
221:
222: private HtmlTag makeDivTag(String id) {
223: String nodeClass = COLLAPSIBLE_NODE_CLASS;
224: if (startCollapsed()) {
225: nodeClass = HIDDEN_NODE_CLASS;
226: }
227: HtmlTag htmlTag = HtmlUtil.makeDivTag(nodeClass);
228:
229: htmlTag.addAttribute("id", id);
230: return htmlTag;
231: }
232:
233: private HtmlTag makeOuterDivTag() {
234: HtmlTag htmlTag = HtmlUtil.makeDivTag(OUTER_DIV_CLASS);
235: return htmlTag;
236: }
237:
238: public boolean isRecursive() {
239: return recursive;
240: }
241:
242: public boolean startCollapsed() {
243: return collapsed;
244: }
245: }
|