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 lineCount) throws 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 writer) throws 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 1 + (int) Math.floor(Math.log10(maxValue));
246 }
247 }
|