feat(#35): Handle wide tables better in PDF preview

This commit is contained in:
2026-01-21 06:29:33 +01:00
parent 753d90dc64
commit 8350a1bd5d
3 changed files with 60 additions and 8 deletions

View File

@@ -77,11 +77,14 @@ class ApplicationFormFormatService(
subtitle = LatexEscaper.escape(subsection.subtitle ?: ""),
elements =
subsection.elements.map { element ->
val isTable = element.type.name == "TABLE"
val tableInfo = if (isTable) renderTableValue(element) else null
LatexFormElement(
title = LatexEscaper.escape(element.title ?: ""),
description = LatexEscaper.escape(element.description ?: ""),
value = renderElementValue(element),
isTable = element.type.name == "TABLE",
value = tableInfo?.first ?: renderElementValue(element),
isTable = isTable,
isWideTable = tableInfo?.second ?: false,
)
},
)
@@ -131,13 +134,17 @@ class ApplicationFormFormatService(
if (element.options.any { it.value == "true" }) "Ja" else "Nein"
}
"TABLE" -> {
renderTableValue(element)
renderTableValue(element).first
}
else -> "Keine Auswahl getroffen"
}
private fun renderTableValue(element: FormElementSnapshotDto): String {
if (element.options.isEmpty()) return "Keine Daten"
/**
* Renders a table element to LaTeX.
* @return Pair of (LaTeX string, isWideTable flag)
*/
private fun renderTableValue(element: FormElementSnapshotDto): Pair<String, Boolean> {
if (element.options.isEmpty()) return "Keine Daten" to false
val objectMapper = jacksonObjectMapper()
val headers = element.options.map { LatexEscaper.escape(it.label ?: "") }
@@ -152,10 +159,15 @@ class ApplicationFormFormatService(
}
val rowCount = columnData.maxOfOrNull { col -> col.size } ?: 0
if (rowCount == 0) return "Keine Daten"
if (rowCount == 0) return "Keine Daten" to false
val columnCount = headers.size
val isWideTable = columnCount > WIDE_TABLE_COLUMN_THRESHOLD
// Use tabularx with Y columns (auto-wrapping) for flexible width distribution
// Y is defined as >{\raggedright\arraybackslash}X in the template
// For wide tables, use \linewidth (works correctly inside landscape environment)
val tableWidth = if (isWideTable) "\\linewidth" else "\\textwidth"
val columnSpec = headers.joinToString("") { "Y" }
val headerRow = headers.joinToString(" & ") { "\\textbf{$it}" }
val dataRows =
@@ -166,8 +178,13 @@ class ApplicationFormFormatService(
}
}
return buildString {
appendLine("\\begin{tabularx}{\\textwidth}{$columnSpec}")
val latexContent = buildString {
if (isWideTable) {
// Use smaller font and tighter column spacing for wide tables
appendLine("\\footnotesize")
appendLine("\\setlength{\\tabcolsep}{2pt}")
}
appendLine("\\begin{tabularx}{$tableWidth}{$columnSpec}")
appendLine("\\toprule")
appendLine("$headerRow \\\\")
appendLine("\\midrule")
@@ -176,7 +193,19 @@ class ApplicationFormFormatService(
}
appendLine("\\bottomrule")
appendLine("\\end{tabularx}")
if (isWideTable) {
// Reset to normal settings after the table
appendLine("\\normalsize")
appendLine("\\setlength{\\tabcolsep}{6pt}")
}
}
return latexContent to isWideTable
}
companion object {
/** Tables with more than this number of columns are rendered in landscape mode */
private const val WIDE_TABLE_COLUMN_THRESHOLD = 6
}
private fun filterVisibleElements(snapshot: ApplicationFormSnapshotDto): ApplicationFormSnapshotDto {

View File

@@ -29,4 +29,5 @@ data class LatexFormElement(
val description: String?,
val value: String,
val isTable: Boolean = false,
val isWideTable: Boolean = false,
)

View File

@@ -18,10 +18,16 @@
\usepackage{tabularx}
\usepackage{array}
\usepackage{booktabs}
\usepackage{pdflscape}
\usepackage{scrlayer-scrpage}
\usepackage{geometry}
% Define column type for auto-wrapping text
\newcolumntype{Y}{>{\raggedright\arraybackslash}X}
% Page style for landscape pages - no header/footer to maximize table space
\newpagestyle{landscapestyle}{}{}
\hypersetup{
colorlinks=true,
linkcolor=black,
@@ -74,6 +80,21 @@ Dieses Dokument enthält die Details der Betriebsvereinbarung "[[${applicationFo
[/]
[# th:each="element : ${subsection.elements}"]
[# th:if="${element.isTable && element.isWideTable}"]
\newgeometry{left=1cm,right=1cm,top=1cm,bottom=1cm}
\begin{landscape}
\thispagestyle{landscapestyle}
\paragraph{[[${element.title}]]}
[# th:if="${element.description}"]
\textit{\small [[${element.description}]]}
[/]
\vspace{0.5em}
\noindent
[(${element.value})]
\end{landscape}
\restoregeometry
[/]
[# th:if="${!(element.isTable && element.isWideTable)}"]
\paragraph{[[${element.title}]]}
[# th:if="${element.description}"]
\textit{\small [[${element.description}]]}
@@ -95,6 +116,7 @@ Dieses Dokument enthält die Details der Betriebsvereinbarung "[[${applicationFo
[/]
[/]
[/]
[/]
\vspace{3cm}