001 package de.java2html.converter;
002 
003 import java.io.BufferedWriter;
004 import java.io.IOException;
005 
006 import de.java2html.Version;
007 import de.java2html.javasource.SourceRun;
008 import de.java2html.javasource.SourceType;
009 import de.java2html.javasource.TypedSource;
010 import de.java2html.javasource.TypedSourceIterator;
011 import de.java2html.options.JavaSourceConversionOptions;
012 import de.java2html.options.JavaSourceStyleTable;
013 import de.java2html.util.RGB;
014 
015 /**
016  * Algorithm and stuff for converting a
017  {@link de.java2html.javasource.TypedSource} object to to a TeX string
018  * representation (experimental!).
019  
020  * For questions, suggestions, bug-reports, enhancement-requests etc. I may be
021  * contacted at: <a href="mailto:markus@jave.de">markus@jave.de</a>
022  
023  * The Java2html home page is located at: <a href="http://www.java2html.de">
024  * http://www.java2html.de</a>
025  
026  @author <a href="mailto:markus@jave.de">Markus Gebhard</a>
027  @version 2.0, 05/07/02
028  
029  * Copyright (C) Markus Gebhard 2000-2002
030  
031  * This program is free software; you can redistribute it and/or modify it
032  * under the terms of the GNU General Public License as published by the Free
033  * Software Foundation; either version 2 of the License, or (at your option)
034  * any later version.
035  
036  * This program is distributed in the hope that it will be useful, but WITHOUT
037  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
038  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
039  * more details.
040  
041  * You should have received a copy of the GNU General Public License along with
042  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
043  * Place - Suite 330, Boston, MA 02111-1307, USA.
044  */
045 public class JavaSource2TeXConverter extends AbstractJavaSourceConverter {
046   private static String[] texFormats;
047   static {
048     final SourceType[] allTypes = SourceType.getAll();
049     texFormats = new String[allTypes.length];
050     for (int i = 0; i < allTypes.length; ++i) {
051       texFormats[i"\\jttstyle" (char) ('a' + i" ";
052     }
053   }
054 
055   private String createFormatDefinition(JavaSourceStyleTable styleTable) {
056     final StringBuffer sb = new StringBuffer();
057     sb.append("%Java2TeX style definitions\n");
058     sb.append("%You can modify them to fit your needs\n");
059 
060     final SourceType[] allTypes = SourceType.getAll();
061     for (int i = 0; i < allTypes.length; ++i) {
062       sb.append("%");
063       sb.append(allTypes[i].getName());
064       sb.append(':');
065       sb.append('\n');
066 
067       final char styleIndexChar = (char) ('a' + i);
068 
069       // "\\definecolor{colorjttq}{rgb}{.392,.392,.392}\n" //$NON-NLS-1$
070       sb.append("\\definecolor{colorjtt");
071       sb.append(styleIndexChar);
072       sb.append("}{rgb}{");
073       final RGB color = styleTable.get(allTypes[i]).getColor();
074       final float[] cs = new float[]{
075           color.getRed() 255.0f,
076           color.getGreen() 255.0f,
077           color.getBlue() 255.0f};
078       sb.append(floatToCharArray(cs[0]));
079       sb.append(',');
080       sb.append(floatToCharArray(cs[1]));
081       sb.append(',');
082       sb.append(floatToCharArray(cs[2]));
083       sb.append("}\n");
084 
085       //+ "\\newcommand{\\jttstyleq}{\\color{colorjttq}}\n" //$NON-NLS-1$
086       sb.append("\\newcommand{\\jttstyle");
087       sb.append(styleIndexChar);
088       sb.append("}{\\color{colorjtt");
089       sb.append(styleIndexChar);
090       sb.append("}}");
091       sb.append('\n');
092     }
093     sb.append('\n');
094     return sb.toString();
095   }
096 
097   /** Document header */
098   private final static String DOCUMENT_FOOTER = "\\end{document}";
099 
100   /** Block seperator for between two blocks of converted source code */
101   private final static String DOCUMENT_BLOCK_SEPARATOR = "\n\n";
102 
103   private final static String BLOCK_HEADER = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"
104       "%  Java Sourcecode to TeX automatically converted code\n"
105       "%  "
106       + Version.getJava2HtmlConverterTitle()
107       " "
108       + Version.getBuildDate()
109       " by Markus Gebhard  markus@jave.de\n"
110       "%     Further information: http://www.java2html.de\n";
111 
112   public JavaSource2TeXConverter() {
113     super(new ConverterMetaData("tex""TeX""tex"));
114   }
115 
116   private final static char[] floatToCharArray(float f) {
117     if (f >= 1.0) {
118       return new char[]{ '1''.''0''0' };
119     }
120 
121     return new char[]{ '.'(char) ('0' + f * 10)(char) ('0' + f * 100 10)(char) ('0' + f * 1000 10) };
122   }
123 
124   @Override
125   public String getDocumentHeader(JavaSourceConversionOptions options, String title) {
126     return "\\documentclass[11pt,a4paper]{article}\n"
127         "\n"
128         "\\usepackage{color}\n"
129         "\n"
130         + createFormatDefinition(options.getStyleTable())
131         "\\begin{document}\n"
132         "\n";
133   }
134 
135   @Override
136   public String getDocumentFooter(JavaSourceConversionOptions options) {
137     return DOCUMENT_FOOTER;
138   }
139 
140   @Override
141   public String getBlockSeparator(JavaSourceConversionOptions options) {
142     return DOCUMENT_BLOCK_SEPARATOR;
143   }
144 
145   /**
146    * Converts the parsed source code to HTML by adding color information,
147    * adding line breaks and replacing characters as needed for HTML. Also adds
148    * a table with line numbers etc.
149    */
150   @Override
151   public void convert(TypedSource source, JavaSourceConversionOptions options, BufferedWriter writer)
152       throws IOException {
153     if (source == null) {
154       throw new IllegalStateException("Trying to write out converted code without having source set.");
155     }
156 
157     writer.write(BLOCK_HEADER);
158 
159     //1) Header with filename if available
160     if (options.isShowFileName() && source.getFileName() != null) {
161       //TODO: Pretty print file name
162     }
163 
164     writer.write("\n")//$NON-NLS-1$
165     writer.write("\\noindent \\ttfamily");
166     writer.write("\n")//$NON-NLS-1$
167 
168     final int lineCount = source.getLineCount();
169     int lineNumber = 1;
170     final TypedSourceIterator iterator = source.getIterator();
171     while (iterator.hasNext()) {
172       final SourceRun run = iterator.getNext();
173       if (run.isAtStartOfLine() && options.isShowLineNumbers()) {
174         writeLineNumber(writer, lineNumber++, lineCount);
175       }
176       toTeX(run, writer);
177       if (run.isAtEndOfLine()) {
178         writer.write("\\\\");
179         writer.write("\n")//$NON-NLS-1$
180       }
181     }
182 
183     writer.write("\n")//$NON-NLS-1$
184   }
185 
186   public void writeLineNumber(BufferedWriter writer, int lineNumber, int lineCountthrows IOException {
187     writer.write(texFormats[SourceType.LINE_NUMBERS.getID()]);
188     writer.write(createIndent(lineNumber, lineCount));
189     writer.write(String.valueOf(lineNumber));
190     writer.write('~');
191   }
192 
193   private void toTeX(SourceRun run, BufferedWriter writerthrows IOException {
194     writer.write(texFormats[run.getType().getID()]);
195 
196     //Replace white space by non-breaking space and line breaks by \\
197     //Also enclose special characters in \\verb# #
198     final String text = run.getCode();
199     for (int i = 0; i < text.length(); ++i) {
200       final char ch = text.charAt(i);
201       if (ch == ' ') {
202         writer.write('~');
203       }
204       else if (ch == '_'
205           || ch == '\\'
206           || ch == '^'
207           || ch == '~'
208           || ch == '\"'
209           || ch == '|'
210           || ch == '<'
211           || ch == '>'
212           || ch == '*') {
213         writer.write("\\verb#" + ch + "#");
214       }
215       else if (ch == '{' || ch == '}' || ch == '_' || ch == '&' || ch == '%' || ch == '$' || ch == '#') {
216         writer.write("\\" + ch);
217       }
218       else {
219         writer.write(ch);
220       }
221     }
222   }
223 
224   private final static String[] WHITESPACES = """~""~~""~~~""~~~~"};
225 
226   private final static String whiteSpace(int size) {
227     if (size < WHITESPACES.length) {
228       return WHITESPACES[size];
229     }
230 
231     final char[] result = new char[size];
232     while (size > 0) {
233       result[--size'~';
234     }
235 
236     return new String(result);
237   }
238 
239   public final static String createIndent(int number, int maxValue) {
240     final int count = getCifferCount(maxValue- getCifferCount(number);
241     return whiteSpace(count);
242   }
243 
244   public static int getCifferCount(int maxValue) {
245     return (intMath.floor(Math.log10(maxValue));
246   }
247 }