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.html;
021 
022 import java.io.Reader;
023 
024 import com.javadoq.SourceFile;
025 import com.javadoq.jjtree.JavaCharStream;
026 import com.javadoq.jjtree.Token;
027 
028 /**
029  * <p>An abstract base class of transformers that perform transformation of source
030  * files to HTML files.</p>
031  * 
032  * @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>
033  */
034 public abstract class DoqHTMLSourceFile extends DoqHTMLBody
035 {
036     /**
037      * <p>The source file to transform.</p>
038      * @since 1.0
039      */
040     public final SourceFile file;
041 
042     private static final int TAB_SPACES = 4;
043 
044     /**
045      * <p>Constructs a {@link DoqHTMLSourceFile} transformer.</p>
046      * <p>This constructor invokes its super constructor to create or open the target file,
047      * open HTML and HTML body, and write the header.</p>
048      * @param file The source file to transform.
049      * @since 1.0
050      */
051     public DoqHTMLSourceFile(SourceFile file) {
052         super(
053                 file.pckg.jdoq,
054                 file.getTarget(),
055                 file.getFullName().text,
056                 file.pckg.getRoot() + STYLE_SHEET
057         );
058         this.file = file;
059         writeLine("<table id=\"header\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">");
060         writeLine("<tr>");
061         writeLine("<td colspan=\"2\" width=\"20%\">&nbsp;</td>");
062         writeLine("<td align=\"center\" colspan=\"2\" width=\"60%\">");
063         writeLine("<font size=\"4\"><a href=\"http://www.javadoq.com\" target=\"_blank\">JavaDoq</a>: " + file.name + "</font>");
064         writeLine("</td>");
065         writeLine("<td align=\"right\" colspan=\"2\" width=\"20%\">&nbsp;</td>");
066         writeLine("</tr>");
067         writeLine("</table>");
068         writeLine("<pre id=\"java-source\">");
069     }
070 
071     /**
072      * <p>Closes the target HTML body.</p>
073      * <p>This method writes the footer and invokes its super method to close HTML body, HTML 
074      * and the file.</p>
075      * @since 1.0
076      */
077     @Override
078     public void close() {
079         writeLine("</pre>");
080         writeLine("<table id=\"footer\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">");
081         writeLine("<tr>");
082         writeLine("<td colspan=\"2\" width=\"20%\">&nbsp;</td>");
083         writeLine("<td align=\"center\" colspan=\"2\" width=\"60%\">");
084         writeLine("<font size=\"4\"><a href=\"http://www.javadoq.com\" target=\"_blank\">JavaDoq</a>: " + file.name + "</font>");
085         writeLine("</td>");
086         writeLine("<td align=\"right\" colspan=\"2\" width=\"20%\">&nbsp;</td>");
087         writeLine("</tr>");
088         writeLine("</table>");
089         super.close();
090     }
091 
092     /**
093      * <p>The format of line numbers.</p>
094      * @since 1.0
095      */
096     protected String format = "%1$05d ";
097 
098     // Stores the current line number.
099     private int lines = 0;
100 
101     /**
102      * <p>Gets the current line number.</p>
103      * @return The HTML text for the current line number.
104      * @since 1.0
105      */
106     protected String getLineNumber() {
107         lines++;
108         return "<font id=\"line-number\">" + String.format(format, lines) + 
109                 "</font><a name=\"" + lines + "\"></a>";
110     }
111 
112     // Temporary variables for writeHTML(char).
113     private int skips = 0, chars = 0;
114 
115     /**
116      * <p>Writes a char to the target file as HTML text.</p>
117      * @param c The char to parse and write.
118      * @since 1.0
119      */
120     public void writeHTML(char c) {
121         switch (c) {
122             case '&':
123                 write("&amp;");
124                 chars++;
125                 break;
126             case '<':
127                 write("&lt;");
128                 chars++;
129                 break;
130             case '>':
131                 write("&gt;");
132                 chars++;
133                 break;
134             case '\r':
135                 chars = 0;
136                 write(LINE_SEPARATOR);
137                 write(getLineNumber());
138                 skips = 2;
139                 break;
140             case '\n':
141                 chars = 0;
142                 if (skips == 0) {
143                     write(LINE_SEPARATOR);
144                     write(getLineNumber());
145                 }
146                 break;
147             case '\t':
148                 int t = TAB_SPACES - chars % TAB_SPACES;
149                 while (t > 0) {
150                     write(' '); t--; chars++;
151                 }
152                 break;
153             default:
154                 write(c);
155                 chars++;
156                 break;
157         }
158         if (skips > 0) {
159             skips--;
160         }
161     }
162 
163     /**
164      * <p>Writes a string to the target file as HTML text.</p>
165      * @param str The string to parse and write.
166      * @since 1.0
167      */
168     public void writeHTML(String str) {
169         for (int i = 0; i < str.length(); i++) {
170             writeHTML(str.charAt(i));
171         }
172     }
173 
174     /**
175      * <p>Writes a {@link Token} to the target file as HTML text.</p>
176      * @param t The {@link Token} to parse and write.
177      * @since 1.0
178      */
179     public void writeHTML(Token t) {
180         int j = t.beginColumn + 5;
181         for (int i = 0; i < t.image.length(); i++, j++) {
182             char ch = t.image.charAt(i);
183             String s = escapes.get(j + "," + t.beginLine);
184             if (s != null) {
185                 writeHTML(s);
186                 j += 5;
187             }
188             else {
189                 writeHTML(ch);
190             }
191         }
192     }
193 
194     //A map of escapable unicodes.
195     private final java.util.Map<String, String> escapes = new java.util.HashMap<String, String>();
196 
197     /**
198      * <p>A {@link JavaCharStream} filter to escape unicodes.</p>
199      * 
200      * @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>
201      */
202     protected class CharStream extends JavaCharStream
203     {
204         /**
205          * <p>Constructs a {@link CharStream}.</p>
206          * @param reader A reader for input.
207          * @since 1.0
208          */
209         public CharStream(Reader reader) {
210             super(reader);
211         }
212 
213         /**
214          * <p>Reads a byte from the input reader for the char stream.</p>
215          * <p>This method invokes its super method to read a byte and then 
216          * performs necessary filtering.</p>
217          * @return The read byte as a char.
218          * @since 1.0
219          */
220         @Override
221         protected char ReadByte() throws java.io.IOException {
222             char c = super.ReadByte();
223             if (buf.length() > 5) {
224                 buf.setLength(0);
225             }
226             int len = buf.length();
227             if (len == 0 && c != '\\') {
228                 return c;
229             }
230             if (len == 1) {
231                 if (c == '\\') {
232                     return c;
233                 }
234                 if (c != 'u') {
235                     buf.setLength(0);
236                     return c;
237                 }
238             }
239             buf.append(c);
240             return c;
241         }
242 
243         // A string buffer.
244         private final StringBuilder buf = new StringBuilder();
245 
246         /**
247          * <p>Reads a char from the char stream.</p>
248          * <p>This method invokes its super method to read a char and then 
249          * performs necessary filtering.</p>
250          * @return The read char.
251          * @since 1.0
252          */
253         @Override
254         public char readChar() throws java.io.IOException {
255             int n = column;
256             char c = super.readChar();
257             if (column > n + 5) {
258                 String s = buf.toString();
259                 if (s.length() == 6) {
260                     escapes.put(column + "," + line, s);
261                 }
262             }
263             return c;
264         }
265     }
266 }