feat(#35): Handle wide tables better in PDF preview
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -29,4 +29,5 @@ data class LatexFormElement(
|
||||
val description: String?,
|
||||
val value: String,
|
||||
val isTable: Boolean = false,
|
||||
val isWideTable: Boolean = false,
|
||||
)
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user