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.wiki.*;
006: import fitnesse.components.PageReferencer;
007: import fitnesse.wikitext.WidgetVisitor;
008: import java.util.regex.Pattern;
009:
010: public class WikiWordWidget extends TextWidget implements
011: PageReferencer {
012: public static final String SINGLE_WIKIWORD_REGEXP = "\\b[A-Z](?:[a-z0-9]+[A-Z][a-z0-9]*)+";
013:
014: public static final String REGEXP = "(?:\\^|\\./|(?:\\.\\./)+)?(?:[./]?"
015: + SINGLE_WIKIWORD_REGEXP + ")+\\b";
016:
017: public static final String NONEXISTENT_PAGE_TOKEN = "";
018:
019: public WikiPage parentPage;
020:
021: public WikiWordWidget(ParentWidget parent, String text)
022: throws Exception {
023: super (parent, text);
024: WikiPage wikiPage = getWikiPage();
025: parentPage = wikiPage.getParent();
026: }
027:
028: public String render() throws Exception {
029: WikiPagePath pathOfWikiWord = PathParser.parse(getWikiWord());
030: WikiPagePath fullPathOfWikiWord = parentPage.getPageCrawler()
031: .getFullPathOfChild(parentPage, pathOfWikiWord);
032: String qualifiedName = PathParser.render(fullPathOfWikiWord);
033: if (parentPage.getPageCrawler().pageExists(parentPage,
034: PathParser.parse(getWikiWord())))
035: return makeLinkToExistingWikiPage(qualifiedName);
036: else
037: return makeLinkToNonExistentWikiPage(qualifiedName);
038: }
039:
040: private String makeLinkToNonExistentWikiPage(String qualifiedName) {
041: StringBuffer html = new StringBuffer();
042: html.append(getText());
043: html.append("<a href=\"").append(qualifiedName);
044: html.append("?edit");
045: html.append("\">" + NONEXISTENT_PAGE_TOKEN + "</a>");
046: return html.toString();
047: }
048:
049: private String makeLinkToExistingWikiPage(String qualifiedName) {
050: StringBuffer html = new StringBuffer();
051: html.append("<a href=\"");
052: html.append(qualifiedName).append("\">");
053: html.append(getText()).append("</a>");
054: return html.toString();
055: }
056:
057: // If pageToRename is referenced somewhere in this wiki word (could be a
058: // parent, etc.),
059: // rename it to newName.
060: public void renamePageIfReferenced(WikiPage pageToRename,
061: String newName) throws Exception {
062: String qualifiedReference = getQualifiedWikiWord();
063: WikiPagePath targetPath = pageToRename.getPageCrawler()
064: .getFullPath(pageToRename);
065: targetPath.makeAbsolute();
066: String qualifiedTarget = PathParser.render(targetPath);
067:
068: if (refersTo(qualifiedReference, qualifiedTarget)) {
069: int oldNameLength = qualifiedTarget.length();
070: String newQualifiedTarget = "."
071: + rename(qualifiedTarget.substring(1), newName);
072: String newQualifiedReference = newQualifiedTarget
073: + qualifiedReference.substring(oldNameLength);
074: String renamedReference = makeRenamedRelativeReference(newQualifiedReference);
075: setText(renamedReference);
076: }
077: }
078:
079: public void renameMovedPageIfReferenced(WikiPage pageToBeMoved,
080: String newParentName) throws Exception {
081: WikiPagePath pathOfPageToBeMoved = pageToBeMoved
082: .getPageCrawler().getFullPath(pageToBeMoved);
083: pathOfPageToBeMoved.makeAbsolute();
084: String QualifiedNameOfPageToBeMoved = PathParser
085: .render(pathOfPageToBeMoved);
086: String reference = getQualifiedWikiWord();
087: if (refersTo(reference, QualifiedNameOfPageToBeMoved)) {
088: String referenceTail = reference
089: .substring(QualifiedNameOfPageToBeMoved.length());
090: String childPortionOfReference = pageToBeMoved.getName();
091: if (referenceTail.length() > 0)
092: childPortionOfReference += referenceTail;
093: String newQualifiedName;
094: if ("".equals(newParentName))
095: newQualifiedName = "." + childPortionOfReference;
096: else
097: newQualifiedName = "." + newParentName + "."
098: + childPortionOfReference;
099:
100: setText(newQualifiedName);
101: }
102: }
103:
104: public String makeRenamedRelativeReference(
105: String newQualifiedReference) throws Exception {
106: String rawReference = getText();
107: String renamedRawReference = rawReference;
108: try {
109: if (rawReference.startsWith(".")) // absolute reference
110: renamedRawReference = newQualifiedReference;
111: else // relative reference
112: {
113: WikiPagePath parentPath = parentPage.getPageCrawler()
114: .getFullPath(parentPage);
115: parentPath.makeAbsolute();
116: String qualifiedReferenceToParent = PathParser
117: .render(parentPath);
118:
119: boolean parentPrefixHasTrailingDot = !parentPage
120: .getPageCrawler().isRoot(parentPage);
121: String parentPrefix = qualifiedReferenceToParent
122: + (parentPrefixHasTrailingDot ? "." : "");
123: String referenceRemainder = newQualifiedReference
124: .substring(parentPrefix.length());
125: if (newQualifiedReference.startsWith(parentPrefix)) // It's not
126: // a
127: // component
128: // of the
129: // parent
130: // that is
131: // being
132: // renamed.
133: {
134: if (rawReference.startsWith("^"))
135: renamedRawReference = "^"
136: + referenceRemainder
137: .substring(referenceRemainder
138: .indexOf(".") + 1);
139: else
140: renamedRawReference = referenceRemainder;
141: }
142: }
143: } catch (StringIndexOutOfBoundsException e) {
144: // MDM Not quite sure why this happens but it causes trouble....
145: // I suppose it can't hurt too much to use the qualified name for
146: // the time being.
147: return newQualifiedReference;
148: }
149: return renamedRawReference;
150: }
151:
152: static boolean refersTo(String qualifiedReference,
153: String qualifiedTarget) {
154: if (qualifiedReference.equals(qualifiedTarget))
155: return true;
156: if (qualifiedReference.startsWith(qualifiedTarget + "."))
157: return true;
158: return false;
159: }
160:
161: private String getQualifiedWikiWord() throws Exception {
162: String pathName = expandUparrow(getText());
163: WikiPagePath expandedPath = PathParser.parse(pathName);
164: if (expandedPath == null)
165: return getText();
166: WikiPagePath fullPath = parentPage.getPageCrawler()
167: .getFullPathOfChild(parentPage, expandedPath);
168: return "." + PathParser.render(fullPath); // todo rcm 2/6/05 put that
169: // '.' into pathParser.
170: // Perhaps
171: // WikiPagePath.setAbsolute()
172: }
173:
174: private String rename(String oldQualifiedName, String newPageName) {
175: String newQualifiedName = oldQualifiedName;
176:
177: int lastDotIndex = oldQualifiedName.lastIndexOf(".");
178: if (lastDotIndex < 1)
179: newQualifiedName = newPageName;
180: else
181: newQualifiedName = oldQualifiedName.substring(0,
182: lastDotIndex + 1)
183: + newPageName;
184: return newQualifiedName;
185: }
186:
187: String getWikiWord() throws Exception {
188: String theWord = getText();
189: theWord = expandUparrow(theWord);
190: return theWord;
191: }
192:
193: public static boolean isWikiWord(String word) {
194: return Pattern.matches(REGEXP, word);
195: }
196:
197: protected String expandUparrow(String theWord) throws Exception {
198: if (theWord.charAt(0) == '^') {
199: theWord = getWikiPage().getName() + "."
200: + theWord.substring(1);
201: }
202: return theWord;
203: }
204:
205: public WikiPage getReferencedPage() throws Exception {
206: String theWord = getWikiWord();
207: return parentPage.getPageCrawler().getPage(parentPage,
208: PathParser.parse(theWord));
209: }
210:
211: public void acceptVisitor(WidgetVisitor visitor) throws Exception {
212: visitor.visit(this );
213: }
214:
215: public static boolean isSingleWikiWord(String s) {
216: return Pattern.matches(SINGLE_WIKIWORD_REGEXP, s);
217: }
218: }
|