001 
002 /*
003  *  JavaDoq 1.0 - DOCUment JAVA In Source
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.javadoq.com>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package com.javadoq.jjtree.ast;
021 
022 import java.io.StringReader;
023 import java.util.ArrayList;
024 import java.util.List;
025 
026 import com.javadoq.JavaName;
027 import com.javadoq.JavaNestedType;
028 import com.javadoq.JavaPackage;
029 import com.javadoq.JavaType;
030 import com.javadoq.html.DoqHTMLSourceFile;
031 import com.javadoq.jjtree.ASTCompilationUnit;
032 import com.javadoq.jjtree.ASTGrammar;
033 import com.javadoq.jjtree.ASTName;
034 import com.javadoq.jjtree.ASTNewName;
035 import com.javadoq.jjtree.ASTNewType;
036 import com.javadoq.jjtree.ASTNode;
037 import com.javadoq.jjtree.ASTPackageName;
038 import com.javadoq.jjtree.Token;
039 
040 /**
041  * <p>Transforms JJTree nodes to HTML at token level.</p>
042  * 
043  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.javadoq.com" target="_blank">http://www.javadoq.com</a>
044  */
045 public class HTMLConversionVisitor extends HTMLColorizeVisitor
046 {
047     /**
048      * <p>The transformer.</p>
049      * @since 1.0
050      */
051     public final DoqHTMLSourceFile doq;
052 
053     /**
054      * <p>Constructs a {@link HTMLConversionVisitor}.</p>
055      * @param doq The transformer for this visitor.
056      * @since 1.0
057      */
058     public HTMLConversionVisitor(DoqHTMLSourceFile doq) {
059         this.doq = doq;
060     }
061 
062     /**
063      * <p>Visits a JJTree node with the specific type.</p>
064      * <p>This method visits all the children nodes and tokens.</p>
065      * @param node The JJTree node to visit.
066      * @param data Visitor data.
067      * @return A visitor data.
068      * @since 1.0
069      */
070     @Override
071     public Object visit(ASTGrammar node, Object data) {
072         return visitChildren(node, data);
073     }
074 
075     /**
076      * <p>Visits a JJTree node with the specific type.</p>
077      * <p>This method visits all the children nodes and tokens.</p>
078      * @param node The JJTree node to visit.
079      * @param data Visitor data.
080      * @return A visitor data.
081      * @since 1.0
082      */
083     @Override
084     public Object visit(ASTCompilationUnit node, Object data) {
085         if (!node.packageName.equals(doq.file.pckg.name.text)) {
086             return data;
087         }
088         return visitChildren(node, data);
089     }
090 
091     private List<JavaType> stack = new ArrayList<JavaType>();
092 
093     /**
094      * <p>Visits a JJTree node with the specific type.</p>
095      * <p>This method pushes the found new type into the stack before visiting children nodes and
096      * pop it after visiting the children nodes and tokens.</p>
097      * @param node The JJTree node to visit.
098      * @param data Visitor data.
099      * @return A visitor data.
100      * @since 1.0
101      */
102     @Override
103     public Object visit(ASTNewType node, Object data) {
104         JavaType t;
105         if (stack.isEmpty()) {
106             t = doq.file.pckg.types.get(node.name);
107         } else {
108             JavaType outer = stack.get(stack.size() - 1);
109             t = outer.inners.get(node.name);
110             
111         }
112         stack.add(t);
113         data = visitChildren(node, data);
114         stack.remove(stack.size() - 1);
115         return data;
116     }
117 
118     /**
119      * <p>Visits a JJTree node with the specific type.</p>
120      * <p>This method visits all the children nodes and tokens.</p>
121      * @param node The JJTree node to visit.
122      * @param data Visitor data.
123      * @return A visitor data.
124      * @since 1.0
125      */
126     @Override
127     protected Object visit(ASTNode node, Object data) {
128         if (node instanceof ASTCompilationUnit) {
129             return visit((ASTCompilationUnit)node, data);
130         } else if (node instanceof ASTGrammar) {
131             return visit((ASTGrammar)node, data);
132         } else if (node instanceof ASTName) {
133             return visit((ASTName)node, data);
134         } else if (node instanceof ASTNewType) {
135             return visit((ASTNewType)node, data);
136         } else {
137             return visitChildren(node, data);
138         }
139     }
140 
141     /**
142      * <p>Visits a JJTree node with the specific type.</p>
143      * <p>This method create hyper links for the found name.</p>
144      * @param node The JJTree node to visit.
145      * @param data Visitor data.
146      * @return A visitor data.
147      * @since 1.0
148      */
149     @Override
150     public Object visit(ASTName node, Object data) {
151         Token t = node.firstToken;
152         visitSpecial(t.specialToken);
153         String link = null;
154         JavaPackage pckg = doq.file.pckg;
155 
156         if (node instanceof ASTNewName) {
157             write("<a name=\"" + stack.get(stack.size() - 1).qname.merge(new JavaName(node.text)) + "\"></a>");
158         } else if (node instanceof ASTPackageName) {
159             link = pckg.getLink(pckg.jdoq.findPackage(new JavaName(node.text)));
160             if (link != null) {
161                 link += "\" target=\"package-frame";
162             }
163         } else if (node.text.endsWith(".*")) {
164             JavaPackage p = pckg.jdoq.findPackage(new JavaName(node.text).chopLast());
165             if (p != null && !p.isDefault) {
166                 link = pckg.getLink(p) + "\" target=\"package-frame";
167             }
168         } else {
169             JavaType current = stack.isEmpty() ? null : stack.get(stack.size() - 1);
170             JavaName name = new JavaName(node.text);
171             JavaType type = current != null ? current.searchType(name):
172                     doq.file.findType(name);
173             if (type != null) {
174                 name = type.qname.merge(name);
175                 if (!name.equals(type.qname)) {
176                     link = "#" + name;
177                     if (!type.equals(current)) {
178                         link = pckg.getLink(type.file) + link;
179                     }
180                 } else {
181                     if (type.equals(current)) {
182                         link = "#";
183                         if (type instanceof JavaNestedType) {
184                             link += type.qname;
185                         }
186                     } else {
187                         link = pckg.getLink(type.file);                 }
188                     if (type instanceof JavaNestedType) {
189                         link += "#" + type.qname;
190                     }
191                 }
192                 link += "\" target=\"source-frame";
193             }
194         }
195 
196         if (link != null) {
197             write("<a href=\"" + link + "\">");
198         }
199 
200         visitToken(t);
201 
202         if (t == node.lastToken) {
203             if (link != null) {
204                 write("</a>");
205             }
206             return data;
207         }
208         t = t.next;
209 
210         while (t != node.lastToken) {
211             visit(t);
212             t = t.next;
213         }
214         visit(t);
215         if (link != null) {
216             write("</a>");
217         }
218         return data;
219     }
220 
221     /**
222      * <p>Transforms a string{@link  DoqHTMLSourceFile#write(String)  }.</p>
223      * <p>This method invokes {@link DoqHTMLSourceFile#write(String)} to write the string to 
224      * the target HTML file.</p>
225      * @param s The string to output.
226      * @since 1.0
227      */
228     @Override
229     protected void write(String s) {
230         doq.write(s);
231     }
232 
233     /**
234      * <p>Transforms a token.</p>
235      * <p>This method invokes {@link DoqHTMLSourceFile#writeHTML(Token)} to write the token to 
236      * the target HTML file.</p>
237      * @param t The JJTree token to output.
238      * @since 1.0
239      */
240     @Override
241     protected void write(Token t) {
242         if (t.kind != FORMAL_COMMENT) {
243             doq.writeHTML(t);
244         } else {
245             StringReader reader = new StringReader(t.image);
246             com.javadoq.javadoc.JavadocParser parser = new com.javadoq.javadoc.JavadocParser(reader);
247             try {
248                 com.javadoq.javadoc.ASTCompilationUnit node = parser.CompilationUnit();
249                 for (com.javadoq.javadoc.Token tt = node.firstToken; tt != null; tt = tt.next) {
250                     switch (tt.kind) {
251                         case com.javadoq.javadoc.JavadocParserConstants.ANCHOR:
252                             doq.write("<a href=\"" + tt.image + "\" target=\"_blank\">");
253                             doq.writeHTML(tt.image);
254                             doq.write("</a>");
255                             break;
256                         case com.javadoq.javadoc.JavadocParserConstants.LINK:
257                         case com.javadoq.javadoc.JavadocParserConstants.SEE:
258                             JavaType current = stack.isEmpty() ? null : stack.get(stack.size() - 1);
259                             String[] names = tt.image.split("#");
260                             String link = null;
261                             if (names.length < 1) {
262                                 // Flow through to default
263                             } else if (names.length < 2) {
264                                 JavaName name = new JavaName(names[0]);
265                                 JavaType type = current != null ? current.findType(name) :
266                                     doq.file.findType(name);
267                                 if (type != null) {
268                                     if (type.equals(current)) {
269                                         link = "#";
270                                         if (type instanceof JavaNestedType) {
271                                             link += type.qname;
272                                         }
273                                     } else {
274                                         link = doq.file.pckg.getLink(type.file);
275                                         if (type instanceof JavaNestedType) {
276                                             link += "#" + type.qname;
277                                         }
278                                     }
279                                 }
280                             } else if (names[0].length() > 0) {
281                                 JavaName name = new JavaName(names[0]);
282                                 JavaType type = current != null ? current.findType(name) :
283                                     doq.file.findType(name);
284                                 if (type != null) {
285                                     if (names[1].length() > 0) {
286                                         link = "#" + type.qname.addLast(names[1]);
287                                         if (!type.equals(current)) {
288                                             link = doq.file.pckg.getLink(type.file) + link;
289                                         }
290                                     } else {
291                                         if (type.equals(current)) {
292                                             link = "#";
293                                             if (type instanceof JavaNestedType) {
294                                                 link += type.qname;
295                                             }
296                                         } else {
297                                             link = doq.file.pckg.getLink(type.file);
298                                             if (type instanceof JavaNestedType) {
299                                                 link += "#" + type.qname;
300                                             }
301                                         }
302                                     }
303                                 }
304                             } else if (current != null) {
305                                 link = "#";
306                                 if (names[1].length() > 0) {
307                                     link += current.qname.addLast(names[1]);
308                                 } else if (current instanceof JavaNestedType) {
309                                     link += current.qname;
310                                 }
311                             }
312                             if (link != null) {
313                                 doq.write("<a href=\"" + link + "\" target=\"source-frame\">");
314                                 doq.writeHTML(tt.image);
315                                 doq.write("</a>");
316                                 break; // Skip default
317                             }
318                         default:
319                             doq.writeHTML(tt.image);
320                     }
321                 }
322             } catch (Throwable thr) {
323                 doq.writeHTML(t);
324                 doq.close();
325                 throw new RuntimeException(thr);
326             }
327             reader.close();
328         }
329     }
330 }