1.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java Sun Apr 06 17:53:36 2014 +0200
1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java Sun Apr 06 23:32:54 2014 +0200
1.3 @@ -24,6 +24,7 @@
1.4 import info.globalcode.sql.dk.formatting.TabularFormatter;
1.5 import info.globalcode.sql.dk.formatting.TabularPrefetchingFormatter;
1.6 import info.globalcode.sql.dk.formatting.TabularWrappingFormatter;
1.7 +import info.globalcode.sql.dk.formatting.TeXFormatter;
1.8 import info.globalcode.sql.dk.formatting.XhtmlFormatter;
1.9 import info.globalcode.sql.dk.formatting.XmlFormatter;
1.10 import java.util.ArrayList;
1.11 @@ -68,6 +69,7 @@
1.12 l.add(new FormatterDefinition(TabularFormatter.NAME, TabularFormatter.class.getName()));
1.13 l.add(new FormatterDefinition(TabularPrefetchingFormatter.NAME, TabularPrefetchingFormatter.class.getName()));
1.14 l.add(new FormatterDefinition(TabularWrappingFormatter.NAME, TabularWrappingFormatter.class.getName()));
1.15 + l.add(new FormatterDefinition(TeXFormatter.NAME, TeXFormatter.class.getName()));
1.16 buildInFormatters = Collections.unmodifiableCollection(l);
1.17 }
1.18
2.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/ColumnDescriptor.java Sun Apr 06 17:53:36 2014 +0200
2.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/ColumnDescriptor.java Sun Apr 06 23:32:54 2014 +0200
2.3 @@ -17,6 +17,8 @@
2.4 */
2.5 package info.globalcode.sql.dk.formatting;
2.6
2.7 +import java.sql.Types;
2.8 +
2.9 /**
2.10 *
2.11 * @author Ing. František Kučera (frantovo.cz)
2.12 @@ -96,4 +98,25 @@
2.13 public void setColumnNumber(int columnNumber) {
2.14 this.columnNumber = columnNumber;
2.15 }
2.16 +
2.17 + public boolean isBoolean() {
2.18 + return type == Types.BOOLEAN;
2.19 + }
2.20 +
2.21 + public boolean isNumeric() {
2.22 + switch (type) {
2.23 + case Types.BIGINT:
2.24 + case Types.DECIMAL:
2.25 + case Types.DOUBLE:
2.26 + case Types.FLOAT:
2.27 + case Types.INTEGER:
2.28 + case Types.NUMERIC:
2.29 + case Types.REAL:
2.30 + case Types.SMALLINT:
2.31 + case Types.TINYINT:
2.32 + return true;
2.33 + default:
2.34 + return false;
2.35 + }
2.36 + }
2.37 }
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/TeXFormatter.java Sun Apr 06 23:32:54 2014 +0200
3.3 @@ -0,0 +1,205 @@
3.4 +/**
3.5 + * SQL-DK
3.6 + * Copyright © 2014 František Kučera (frantovo.cz)
3.7 + *
3.8 + * This program is free software: you can redistribute it and/or modify
3.9 + * it under the terms of the GNU General Public License as published by
3.10 + * the Free Software Foundation, either version 3 of the License, or
3.11 + * (at your option) any later version.
3.12 + *
3.13 + * This program is distributed in the hope that it will be useful,
3.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.16 + * GNU General Public License for more details.
3.17 + *
3.18 + * You should have received a copy of the GNU General Public License
3.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
3.20 + */
3.21 +package info.globalcode.sql.dk.formatting;
3.22 +
3.23 +import info.globalcode.sql.dk.ColorfulPrintWriter;
3.24 +import info.globalcode.sql.dk.Constants;
3.25 +import java.util.Collections;
3.26 +import java.util.HashMap;
3.27 +import java.util.List;
3.28 +import java.util.Map;
3.29 +
3.30 +/**
3.31 + * Outputs result sets in (La)TeX format.
3.32 + *
3.33 + * @author Ing. František Kučera (frantovo.cz)
3.34 + */
3.35 +public class TeXFormatter extends AbstractFormatter {
3.36 +
3.37 + public static final String NAME = "tex"; // bash-completion:formatter
3.38 + public static final String PROPERTY_COLORFUL = "color";
3.39 + private static final ColorfulPrintWriter.TerminalColor COMMAND_COLOR = ColorfulPrintWriter.TerminalColor.Magenta;
3.40 + private static final ColorfulPrintWriter.TerminalColor OPTIONS_COLOR = ColorfulPrintWriter.TerminalColor.Yellow;
3.41 + private static final Map<Character, String> TEX_ESCAPE_MAP;
3.42 + private final ColorfulPrintWriter out;
3.43 +
3.44 + static {
3.45 + Map<Character, String> replacements = new HashMap<>();
3.46 +
3.47 + replacements.put('\\', "\\textbackslash{}");
3.48 + replacements.put('{', "\\{{}");
3.49 + replacements.put('}', "\\}{}");
3.50 + replacements.put('_', "\\_{}");
3.51 + replacements.put('^', "\\textasciicircum{}");
3.52 + replacements.put('#', "\\#{}");
3.53 + replacements.put('&', "\\&{}");
3.54 + replacements.put('$', "\\${}");
3.55 + replacements.put('%', "\\%{}");
3.56 + replacements.put('~', "\\textasciitilde{}");
3.57 + replacements.put('-', "{-}");
3.58 +
3.59 + TEX_ESCAPE_MAP = Collections.unmodifiableMap(replacements);
3.60 + }
3.61 +
3.62 + public TeXFormatter(FormatterContext formatterContext) {
3.63 + super(formatterContext);
3.64 + boolean colorful = formatterContext.getProperties().getBoolean(PROPERTY_COLORFUL, false);
3.65 + out = new ColorfulPrintWriter(formatterContext.getOutputStream(), false, colorful);
3.66 + }
3.67 +
3.68 + @Override
3.69 + public void writeStartBatch() {
3.70 + super.writeStartBatch();
3.71 +
3.72 + printCommand("documentclass", "a4paper,twoside", "article", true);
3.73 + printCommand("usepackage", "T1", "fontenc", true);
3.74 + printCommand("usepackage", "utf8x", "inputenc", true);
3.75 + printCommand("usepackage", "pdfauthor={" + Constants.WEBSITE + "}, bookmarks=true,unicode,colorlinks=true,linkcolor=black,urlcolor=blue,citecolor=blue", "hyperref", true);
3.76 + printBegin("document");
3.77 + }
3.78 +
3.79 + @Override
3.80 + public void writeEndBatch() {
3.81 + super.writeEndBatch();
3.82 + printEnd("document");
3.83 + }
3.84 +
3.85 + @Override
3.86 + public void writeColumnValue(Object value) {
3.87 + super.writeColumnValue(value);
3.88 + // TODO: arrays, numbers, booleans, nulls etc.:
3.89 + out.print(escapeTex(toString(value)));
3.90 +
3.91 + if (!isCurrentColumnLast()) {
3.92 + printColumnSeparator();
3.93 + }
3.94 + }
3.95 +
3.96 + @Override
3.97 + public void writeEndRow() {
3.98 + super.writeEndRow();
3.99 + printEndRow();
3.100 + }
3.101 +
3.102 + @Override
3.103 + public void writeStartResultSet(ColumnsHeader header) {
3.104 + super.writeStartResultSet(header);
3.105 + printCommand("begin", null, "tabular", false);
3.106 +
3.107 + List<ColumnDescriptor> columnDescriptors = header.getColumnDescriptors();
3.108 +
3.109 + StringBuilder columnAlignments = new StringBuilder();
3.110 + for (ColumnDescriptor cd : columnDescriptors) {
3.111 + if (cd.isNumeric() || cd.isBoolean()) {
3.112 + columnAlignments.append('r');
3.113 + } else {
3.114 + columnAlignments.append('l');
3.115 + }
3.116 + }
3.117 +
3.118 + printCommand(null, null, columnAlignments.toString(), true);
3.119 + printCommand("hline", null, null, true);
3.120 +
3.121 + for (ColumnDescriptor cd : columnDescriptors) {
3.122 + printCommand("textbf", null, cd.getLabel(), false);
3.123 + if (cd.isLastColumn()) {
3.124 + printEndRow();
3.125 + } else {
3.126 + printColumnSeparator();
3.127 + }
3.128 + }
3.129 +
3.130 + printCommand("hline", null, null, true);
3.131 + }
3.132 +
3.133 + @Override
3.134 + public void writeEndResultSet() {
3.135 + super.writeEndResultSet();
3.136 + printCommand("hline", null, null, true);
3.137 + printEnd("tabular");
3.138 + }
3.139 +
3.140 + private String escapeTex(String text) {
3.141 + if (text == null) {
3.142 + return null;
3.143 + } else {
3.144 + StringBuilder result = new StringBuilder(text.length() * 2);
3.145 +
3.146 + for (char ch : text.toCharArray()) {
3.147 + String replacement = TEX_ESCAPE_MAP.get(ch);
3.148 + result.append(replacement == null ? ch : replacement);
3.149 + }
3.150 +
3.151 + return result.toString();
3.152 + }
3.153 + }
3.154 +
3.155 + protected String toString(Object value) {
3.156 + return String.valueOf(value);
3.157 + }
3.158 +
3.159 + private void printColumnSeparator() {
3.160 + out.print(COMMAND_COLOR, " & ");
3.161 + }
3.162 +
3.163 + private void printEndRow() {
3.164 + out.println(COMMAND_COLOR, " \\\\");
3.165 + out.flush();
3.166 + }
3.167 +
3.168 + /**
3.169 + *
3.170 + * @param command will not be escaped – should contain just a valid TeX command name
3.171 + * @param options will not be escaped – should be properly formatted to be printed inside [
3.172 + * and ]
3.173 + * @param value will be escaped
3.174 + * @param println whether to print line end and flush
3.175 + */
3.176 + private void printCommand(String command, String options, String value, boolean println) {
3.177 +
3.178 + if (command != null) {
3.179 + out.print(COMMAND_COLOR, "\\" + command);
3.180 + }
3.181 +
3.182 + if (options != null) {
3.183 + out.print(COMMAND_COLOR, "[");
3.184 + out.print(OPTIONS_COLOR, options);
3.185 + out.print(COMMAND_COLOR, "]");
3.186 + }
3.187 +
3.188 + if (value != null) {
3.189 + out.print(COMMAND_COLOR, "{");
3.190 + out.print(escapeTex(value));
3.191 + out.print(COMMAND_COLOR, "}");
3.192 + }
3.193 +
3.194 + if (println) {
3.195 + out.println();
3.196 + out.flush();
3.197 + }
3.198 + }
3.199 +
3.200 + private void printBegin(String environment) {
3.201 + printCommand("begin", null, environment, true);
3.202 + }
3.203 +
3.204 + private void printEnd(String environment) {
3.205 + printCommand("end", null, environment, true);
3.206 + }
3.207 +
3.208 +}