1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/TeXFormatter.java Sun Apr 06 23:32:54 2014 +0200
1.3 @@ -0,0 +1,205 @@
1.4 +/**
1.5 + * SQL-DK
1.6 + * Copyright © 2014 František Kučera (frantovo.cz)
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, either version 3 of the License, or
1.11 + * (at your option) any later version.
1.12 + *
1.13 + * This program is distributed in the hope that it will be useful,
1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.16 + * GNU General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU General Public License
1.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
1.20 + */
1.21 +package info.globalcode.sql.dk.formatting;
1.22 +
1.23 +import info.globalcode.sql.dk.ColorfulPrintWriter;
1.24 +import info.globalcode.sql.dk.Constants;
1.25 +import java.util.Collections;
1.26 +import java.util.HashMap;
1.27 +import java.util.List;
1.28 +import java.util.Map;
1.29 +
1.30 +/**
1.31 + * Outputs result sets in (La)TeX format.
1.32 + *
1.33 + * @author Ing. František Kučera (frantovo.cz)
1.34 + */
1.35 +public class TeXFormatter extends AbstractFormatter {
1.36 +
1.37 + public static final String NAME = "tex"; // bash-completion:formatter
1.38 + public static final String PROPERTY_COLORFUL = "color";
1.39 + private static final ColorfulPrintWriter.TerminalColor COMMAND_COLOR = ColorfulPrintWriter.TerminalColor.Magenta;
1.40 + private static final ColorfulPrintWriter.TerminalColor OPTIONS_COLOR = ColorfulPrintWriter.TerminalColor.Yellow;
1.41 + private static final Map<Character, String> TEX_ESCAPE_MAP;
1.42 + private final ColorfulPrintWriter out;
1.43 +
1.44 + static {
1.45 + Map<Character, String> replacements = new HashMap<>();
1.46 +
1.47 + replacements.put('\\', "\\textbackslash{}");
1.48 + replacements.put('{', "\\{{}");
1.49 + replacements.put('}', "\\}{}");
1.50 + replacements.put('_', "\\_{}");
1.51 + replacements.put('^', "\\textasciicircum{}");
1.52 + replacements.put('#', "\\#{}");
1.53 + replacements.put('&', "\\&{}");
1.54 + replacements.put('$', "\\${}");
1.55 + replacements.put('%', "\\%{}");
1.56 + replacements.put('~', "\\textasciitilde{}");
1.57 + replacements.put('-', "{-}");
1.58 +
1.59 + TEX_ESCAPE_MAP = Collections.unmodifiableMap(replacements);
1.60 + }
1.61 +
1.62 + public TeXFormatter(FormatterContext formatterContext) {
1.63 + super(formatterContext);
1.64 + boolean colorful = formatterContext.getProperties().getBoolean(PROPERTY_COLORFUL, false);
1.65 + out = new ColorfulPrintWriter(formatterContext.getOutputStream(), false, colorful);
1.66 + }
1.67 +
1.68 + @Override
1.69 + public void writeStartBatch() {
1.70 + super.writeStartBatch();
1.71 +
1.72 + printCommand("documentclass", "a4paper,twoside", "article", true);
1.73 + printCommand("usepackage", "T1", "fontenc", true);
1.74 + printCommand("usepackage", "utf8x", "inputenc", true);
1.75 + printCommand("usepackage", "pdfauthor={" + Constants.WEBSITE + "}, bookmarks=true,unicode,colorlinks=true,linkcolor=black,urlcolor=blue,citecolor=blue", "hyperref", true);
1.76 + printBegin("document");
1.77 + }
1.78 +
1.79 + @Override
1.80 + public void writeEndBatch() {
1.81 + super.writeEndBatch();
1.82 + printEnd("document");
1.83 + }
1.84 +
1.85 + @Override
1.86 + public void writeColumnValue(Object value) {
1.87 + super.writeColumnValue(value);
1.88 + // TODO: arrays, numbers, booleans, nulls etc.:
1.89 + out.print(escapeTex(toString(value)));
1.90 +
1.91 + if (!isCurrentColumnLast()) {
1.92 + printColumnSeparator();
1.93 + }
1.94 + }
1.95 +
1.96 + @Override
1.97 + public void writeEndRow() {
1.98 + super.writeEndRow();
1.99 + printEndRow();
1.100 + }
1.101 +
1.102 + @Override
1.103 + public void writeStartResultSet(ColumnsHeader header) {
1.104 + super.writeStartResultSet(header);
1.105 + printCommand("begin", null, "tabular", false);
1.106 +
1.107 + List<ColumnDescriptor> columnDescriptors = header.getColumnDescriptors();
1.108 +
1.109 + StringBuilder columnAlignments = new StringBuilder();
1.110 + for (ColumnDescriptor cd : columnDescriptors) {
1.111 + if (cd.isNumeric() || cd.isBoolean()) {
1.112 + columnAlignments.append('r');
1.113 + } else {
1.114 + columnAlignments.append('l');
1.115 + }
1.116 + }
1.117 +
1.118 + printCommand(null, null, columnAlignments.toString(), true);
1.119 + printCommand("hline", null, null, true);
1.120 +
1.121 + for (ColumnDescriptor cd : columnDescriptors) {
1.122 + printCommand("textbf", null, cd.getLabel(), false);
1.123 + if (cd.isLastColumn()) {
1.124 + printEndRow();
1.125 + } else {
1.126 + printColumnSeparator();
1.127 + }
1.128 + }
1.129 +
1.130 + printCommand("hline", null, null, true);
1.131 + }
1.132 +
1.133 + @Override
1.134 + public void writeEndResultSet() {
1.135 + super.writeEndResultSet();
1.136 + printCommand("hline", null, null, true);
1.137 + printEnd("tabular");
1.138 + }
1.139 +
1.140 + private String escapeTex(String text) {
1.141 + if (text == null) {
1.142 + return null;
1.143 + } else {
1.144 + StringBuilder result = new StringBuilder(text.length() * 2);
1.145 +
1.146 + for (char ch : text.toCharArray()) {
1.147 + String replacement = TEX_ESCAPE_MAP.get(ch);
1.148 + result.append(replacement == null ? ch : replacement);
1.149 + }
1.150 +
1.151 + return result.toString();
1.152 + }
1.153 + }
1.154 +
1.155 + protected String toString(Object value) {
1.156 + return String.valueOf(value);
1.157 + }
1.158 +
1.159 + private void printColumnSeparator() {
1.160 + out.print(COMMAND_COLOR, " & ");
1.161 + }
1.162 +
1.163 + private void printEndRow() {
1.164 + out.println(COMMAND_COLOR, " \\\\");
1.165 + out.flush();
1.166 + }
1.167 +
1.168 + /**
1.169 + *
1.170 + * @param command will not be escaped – should contain just a valid TeX command name
1.171 + * @param options will not be escaped – should be properly formatted to be printed inside [
1.172 + * and ]
1.173 + * @param value will be escaped
1.174 + * @param println whether to print line end and flush
1.175 + */
1.176 + private void printCommand(String command, String options, String value, boolean println) {
1.177 +
1.178 + if (command != null) {
1.179 + out.print(COMMAND_COLOR, "\\" + command);
1.180 + }
1.181 +
1.182 + if (options != null) {
1.183 + out.print(COMMAND_COLOR, "[");
1.184 + out.print(OPTIONS_COLOR, options);
1.185 + out.print(COMMAND_COLOR, "]");
1.186 + }
1.187 +
1.188 + if (value != null) {
1.189 + out.print(COMMAND_COLOR, "{");
1.190 + out.print(escapeTex(value));
1.191 + out.print(COMMAND_COLOR, "}");
1.192 + }
1.193 +
1.194 + if (println) {
1.195 + out.println();
1.196 + out.flush();
1.197 + }
1.198 + }
1.199 +
1.200 + private void printBegin(String environment) {
1.201 + printCommand("begin", null, environment, true);
1.202 + }
1.203 +
1.204 + private void printEnd(String environment) {
1.205 + printCommand("end", null, environment, true);
1.206 + }
1.207 +
1.208 +}