001: package fitnesse.wikitext.widgets;
002:
003: import java.util.Iterator;
004: import java.util.Set;
005: import java.util.*;
006: import java.util.regex.Matcher;
007: import java.util.regex.Pattern;
008:
009: import fitnesse.components.TagManager;
010: import fitnesse.html.HtmlTag;
011: import fitnesse.html.HtmlUtil;
012: import fitnesse.util.PropertiesUtil;
013: import fitnesse.wiki.PageCrawler;
014: import fitnesse.wiki.PathParser;
015: import fitnesse.wiki.VirtualEnabledPageCrawler;
016: import fitnesse.wiki.WikiPage;
017: import fitnesse.wikitext.WikiWidget;
018:
019: public class TagSuiteWidget extends WikiWidget {
020:
021: public static final String WIDGET_NAME = "TagSuite";
022:
023: public static final String WIDGET_TITLE = "Tag Suite";
024:
025: public static final String ERROR_INVALID_CHARACTERS = "invalid tag characters.";
026:
027: public static final String ANY_TAGS = "ANY";
028:
029: public static final String NO_TAGS = "NONE";
030:
031: public static final String SHOW_PARENT_IN_TAGSUITE_LINKS_PROPERTY = "ShowParentInTagsuiteLinks";
032:
033: public static final String SHOW_PARENT_IN_TAGSUITE_LINKS_DEFAULT = "true";
034:
035: public static final String DEFAULT_START_PAGE_PROPERTY = "TagsuiteStartPageDefault";
036:
037: public static final String DEFAULT_START_PAGE_DEFAULT = ".";
038:
039: public static final String DEFAULT_TAG_PROPERTY = "TagsuiteTagDefault";
040:
041: public static final String DEFAULT_TAG_DEFAULT = "integration";
042:
043: private boolean anyTags = false;
044:
045: private boolean noTags = false;
046:
047: // FIXME: A regex wizard can make this better...
048: private static String someWhitespace = "[ \t]+";
049:
050: private static String someWords = "[ \\t]+[\\d\\w \\t]+";
051:
052: private static String linebreak = LineBreakWidget.REGEXP;
053:
054: public static final String REGEXP = "(?:^!" + WIDGET_NAME
055: + someWhitespace + WikiWordWidget.REGEXP + someWords
056: + linebreak + "?)|" + "(?:^!" + WIDGET_NAME.toLowerCase()
057: + someWhitespace + WikiWordWidget.REGEXP + someWords
058: + linebreak + "?)|" + "(?:^!" + WIDGET_NAME
059: + someWhitespace + "\\." + someWords + linebreak + "?)|"
060: + "(?:^!" + WIDGET_NAME.toLowerCase() + someWhitespace
061: + "\\." + someWords + linebreak + "?)";
062:
063: private static final Pattern pattern = Pattern.compile("^!("
064: + WIDGET_NAME + "|" + WIDGET_NAME.toLowerCase() + ")"
065: + "[ \\t]+([\\d\\w\\.]+)[ \t]+([\\d\\w \\t]+)$");
066:
067: private String pageName = "";
068:
069: private String[] tags = null;
070:
071: private HtmlTag table;
072:
073: public TagSuiteWidget(ParentWidget parent, String text) {
074: super (parent);
075: String rawTags = null;
076: Matcher match = pattern.matcher(text);
077: if (match.find()) {
078: // The first group is the widget name; we use it to match lowercase
079: pageName = match.group(2).trim();
080: rawTags = match.group(3).trim();
081: setTags(rawTags);
082: }
083:
084: // Look for special tag values and set flags
085: if (text.indexOf(ANY_TAGS) != -1) {
086: anyTags = true;
087: }
088: if (text.indexOf(NO_TAGS) != -1) {
089: noTags = true;
090: }
091: }
092:
093: public String render() throws Exception {
094:
095: if ((tags == null) && (!anyTags) && (!noTags)) {
096: return "!" + WIDGET_NAME + " error: "
097: + ERROR_INVALID_CHARACTERS;
098: }
099:
100: WikiPage startPage = null;
101: WikiPage rootPage = getWikiPage();
102: try {
103:
104: // FIXME: Get the site root by walking up the tree; find a better way
105: while (!rootPage.getPageCrawler().isRoot(rootPage)) {
106: rootPage = rootPage.getParent();
107: }
108:
109: if (pageName.equals(".")) {
110: startPage = rootPage;
111: } else {
112: // Find our start page using a crawler
113: PageCrawler crawler = rootPage.getPageCrawler();
114: crawler
115: .setDeadEndStrategy(new VirtualEnabledPageCrawler());
116: startPage = crawler.getPage(rootPage, PathParser
117: .parse(pageName));
118: }
119:
120: if (startPage == null) {
121: return "!" + WIDGET_NAME + " error: Unable to locate ["
122: + pageName + "]";
123: }
124: } catch (Exception e) {
125: return "!" + WIDGET_NAME + " error: " + e.getMessage()
126: + " [" + pageName + " " + getTagsString() + "]";
127: }
128: final Set pages = getTagManager().pagesForTags(startPage, tags,
129: anyTags, noTags);
130: return buildContentsDiv(pages, 1).html();
131: }
132:
133: private TagManager getTagManager() {
134: return TagManager.INSTANCE;
135: }
136:
137: private HtmlTag buildContentsDiv(Set pages, int currentDepth)
138: throws Exception {
139: HtmlTag div = makeDivTag(currentDepth);
140: table = new HtmlTag("table");
141: table.addAttribute("class", "suite-table");
142: AddTableHeading();
143:
144: // Sort the set
145: Map map = new TreeMap();
146: String key = "";
147: WikiPage page;
148: for (Iterator iterator = pages.iterator(); iterator.hasNext();) {
149: page = (WikiPage) iterator.next();
150: if (getShowParentInTagsuiteLink().equals("true")) {
151: key = page.getParent().getName()
152: + getParentChildLinkSeparator()
153: + page.getName();
154: } else {
155: key = page.getName();
156: }
157: map.put(key, page);
158: }
159:
160: for (Iterator iter = map.keySet().iterator(); iter.hasNext();) {
161: addPageRow((WikiPage) map.get((String) iter.next()));
162: }
163: div.add(table);
164: return div;
165: }
166:
167: private void AddTableHeading() {
168: HtmlTag row = new HtmlTag("tr");
169: HtmlTag data = new HtmlTag("td");
170: data.add(getTableTitleHtml() + " " + getPageTitleHtml() + " "
171: + getTagsHtml());
172: row.add(data);
173: table.add(row);
174: }
175:
176: private void addPageRow(WikiPage wikiPage) throws Exception {
177: HtmlTag row = new HtmlTag("tr");
178: HtmlTag data = new HtmlTag("td");
179:
180: String linkText = wikiPage.getName();
181:
182: // We might include the parent
183: if (getShowParentInTagsuiteLink().equals("true")) {
184: linkText = wikiPage.getParent().getName()
185: + getParentChildLinkSeparator()
186: + wikiPage.getName();
187: }
188:
189: data.add(HtmlUtil.makeLink(getHref(wikiPage), linkText));
190: row.add(data);
191: table.add(row);
192: }
193:
194: private void setTags(String rawTags) {
195: String squashed = rawTags.replaceAll("\\t", " ");
196: squashed = squashed.replaceAll("\\s{2,}", " ");
197: tags = squashed.split("\\s+");
198: }
199:
200: private String getTagsString() {
201: String tagsString = "";
202: for (int i = 0; i < tags.length; i++) {
203: tagsString += tags[i] + " ";
204: }
205: return tagsString.trim();
206: }
207:
208: private String getTableTitleHtml() {
209: return "<span class=\"tagSuiteWidgetTitle\">" + WIDGET_TITLE
210: + ":</span>";
211: }
212:
213: private String getPageTitleHtml() {
214: return "<span class=\"tagSuiteWidgetPage\">" + pageName
215: + "</span>";
216: }
217:
218: private String getTagsHtml() {
219: String tagsString = "";
220: try {
221: for (int i = 0; i < tags.length; i++) {
222: tagsString += "<span class=\"tagSuiteWidgetTag\">"
223: + tags[i] + "</span>";
224: }
225: } catch (Exception e) {
226:
227: }
228: return tagsString.trim();
229: }
230:
231: private HtmlTag makeDivTag(int currentDepth) {
232: return HtmlUtil.makeDivTag(WIDGET_NAME + currentDepth);
233: }
234:
235: public String getShowParentInTagsuiteLink() {
236: return PropertiesUtil.getProperty(
237: SHOW_PARENT_IN_TAGSUITE_LINKS_PROPERTY,
238: SHOW_PARENT_IN_TAGSUITE_LINKS_DEFAULT).trim();
239: }
240: }
|