From 3c02ed472cf50189689ec89dee6eee6e7b9aa815 Mon Sep 17 00:00:00 2001 From: Quang Truong Date: Wed, 13 May 2026 10:01:46 +0200 Subject: [PATCH 1/3] Export footnote to excel --- .../export/pdf/TableToTableDocument.xtend | 2 +- .../export/xlsx/ExcelExportBuilder.java | 95 ++++++++++++++++++- .../extensions/TableExtensions.xtend | 37 +++++--- 3 files changed, 117 insertions(+), 17 deletions(-) diff --git a/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/pdf/TableToTableDocument.xtend b/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/pdf/TableToTableDocument.xtend index f4d9728199..68519ecfa3 100644 --- a/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/pdf/TableToTableDocument.xtend +++ b/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/pdf/TableToTableDocument.xtend @@ -66,7 +66,7 @@ class TableToTableDocument { public static val String FOOTNOTE_INLINE_TEXT_SEPARATOR = String. format("%n") - static val String FOOTNOTE_MARK_SEPRATOR = ", " + public static val String FOOTNOTE_MARK_SEPRATOR = ", " val Document doc var String tablename diff --git a/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java b/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java index 6b31bd8243..10ffd79a7a 100644 --- a/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java +++ b/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java @@ -19,7 +19,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.apache.poi.ss.usermodel.BorderStyle; @@ -38,9 +40,13 @@ import org.eclipse.set.basis.constants.ExportType; import org.eclipse.set.basis.constants.TableType; import org.eclipse.set.basis.exceptions.FileExportException; +import org.eclipse.set.feature.export.pdf.TableToTableDocument; +import org.eclipse.set.model.tablemodel.FootnoteContainer; +import org.eclipse.set.model.tablemodel.SimpleFootnoteContainer; import org.eclipse.set.model.tablemodel.Table; import org.eclipse.set.model.tablemodel.TableRow; import org.eclipse.set.model.tablemodel.extensions.TableExtensions; +import org.eclipse.set.model.tablemodel.extensions.TableExtensions.FootnoteInfo; import org.eclipse.set.model.tablemodel.extensions.TableRowExtensions; import org.eclipse.set.model.titlebox.Titlebox; import org.eclipse.set.services.export.TableExport; @@ -49,6 +55,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.collect.Streams; + /** * {@link TableExport} implementation for Excel with template files. * @@ -63,6 +71,7 @@ public class ExcelExportBuilder implements TableExport { .getLogger(ExcelExportBuilder.class); private static final String TEMPLATE_DIR = "./data/export/excel"; //$NON-NLS-1$ + private static final String FOONOTE_SHEET_NAME = "Bermerkungen"; //$NON-NLS-1$ private static int getFirstRowForContent(final Sheet sheet) { return getHeaderLastRowIndex(sheet) + 1; @@ -104,6 +113,8 @@ public void export(final Map tables, final OverwriteHandling overwriteHandling) throws FileExportException { final Table table = getTableToBeExported(tables); + final boolean isInlineFootnote = TableExtensions + .isInlineFootnote(table); // IMPROVE: this is only a temporary situation for the table // Sskp_dm final String tableShortcut = shortcut.equals("sskp_dm") ? "sskp" //$NON-NLS-1$//$NON-NLS-2$ @@ -135,7 +146,13 @@ public void export(final Map tables, final List rows = TableExtensions.getTableRows(table); // Fill sheet - fillSheet(sheet, rows, rowIndex, columnCount); + fillSheet(sheet, rows, rowIndex, columnCount, isInlineFootnote); + + if (!isInlineFootnote) { + final Sheet footnoteSheet = workbook + .createSheet(FOONOTE_SHEET_NAME); + fillFootnoteSheet(footnoteSheet, table); + } // Create spans addTableSpans(sheet, rows, rowIndex, columnCount); @@ -160,13 +177,54 @@ public void export(final Map tables, } } + @SuppressWarnings("boxing") + private static void fillFootnoteSheet(final Sheet footnoteSheet, + final Table table) { + final List allFootnotes = new ArrayList<>( + Streams.stream(TableExtensions.getAllFootnotes(table)) + .toList()); + if (allFootnotes.isEmpty()) { + return; + } + footnoteSheet.autoSizeColumn(1); + allFootnotes.sort( + (first, second) -> Integer.compare(first.index, second.index)); + for (int i = 0; i < allFootnotes.size(); i++) { + final Row row = footnoteSheet.createRow(i + 1); + final Cell fnIndexCell = row.createCell(0); + final FootnoteInfo footnoteInfo = allFootnotes.get(i); + // Currently export only the FINAL-State table to excel, therefore + // no need to handle cell style + fnIndexCell.setCellValue(String.format("*%d", footnoteInfo.index) //$NON-NLS-1$ + ); + final Cell fnContentCell = row.createCell(1); + fnContentCell.setCellValue(footnoteInfo.toText()); + + } + } + private static void fillSheet(final Sheet sheet, final List rows, - final int rowIndex, final int columnCount) { + final int rowIndex, final int columnCount, + final boolean inlineFootnote) { + if (rows.isEmpty()) { + return; + } + final Table table = TableRowExtensions.getTable(rows.getFirst()); + final List allFootnotes = Streams + .stream(TableExtensions.getAllFootnotes(table)) + .toList(); int contentRowIndex = rowIndex; + for (final TableRow row : rows) { final Row sheetRow = contentRowIndex == rowIndex ? sheet.getRow(contentRowIndex) : createNewRow(sheet, contentRowIndex, columnCount); + final FootnoteContainer footnotes = row.getFootnotes(); + // Currently export only FINAL-Table to excel, therefore the + // FootnoteContainer should be SimpleFootnoteContainer + if (!(footnotes instanceof SimpleFootnoteContainer)) { + throw new IllegalArgumentException(); + } for (int i = 0; i < columnCount; i++) { final String content = TableRowExtensions .getPlainStringValue(row, i); @@ -175,7 +233,12 @@ private static void fillSheet(final Sheet sheet, final List rows, if (cell == null) { cell = sheetRow.createCell(i + 1); } - + if (i == columnCount - 1 + && footnotes instanceof final SimpleFootnoteContainer simpleContainer) { + fillFootnoteCell(cell, content, allFootnotes, + simpleContainer, inlineFootnote); + continue; + } cell.setCellValue(content); } // Auto adjust row height @@ -184,6 +247,32 @@ private static void fillSheet(final Sheet sheet, final List rows, } } + private static void fillFootnoteCell(final Cell cell, + final String cellContent, final List allFootnotes, + final SimpleFootnoteContainer fnContainer, + final boolean inlineFootnote) { + final List fnInfo = fnContainer.getFootnotes() + .stream() + .map(fn -> TableExtensions.getFootnoteInfo(allFootnotes, fn)) + .filter(Objects::nonNull) + .toList(); + final StringBuilder builder = new StringBuilder(); + if (!cellContent.isEmpty() && !cellContent.isBlank()) { + builder.append(cellContent); + builder.append(TableToTableDocument.FOOTNOTE_INLINE_TEXT_SEPARATOR); + } + final String footnoteValue = inlineFootnote ? fnInfo.stream() + .map(FootnoteInfo::toText) + .collect(Collectors.joining( + TableToTableDocument.FOOTNOTE_INLINE_TEXT_SEPARATOR)) + : fnInfo.stream() + .map(fn -> "*" + fn.index) //$NON-NLS-1$ + .collect(Collectors.joining( + TableToTableDocument.FOOTNOTE_MARK_SEPRATOR)); + builder.append(footnoteValue); + cell.setCellValue(builder.toString()); + } + @SuppressWarnings("resource") private static Row createNewRow(final Sheet sheet, final int rowIndex, final int maxColIndex) { diff --git a/java/bundles/org.eclipse.set.model.tablemodel.extensions/src/org/eclipse/set/model/tablemodel/extensions/TableExtensions.xtend b/java/bundles/org.eclipse.set.model.tablemodel.extensions/src/org/eclipse/set/model/tablemodel/extensions/TableExtensions.xtend index 1ac69c1e4b..c921124102 100644 --- a/java/bundles/org.eclipse.set.model.tablemodel.extensions/src/org/eclipse/set/model/tablemodel/extensions/TableExtensions.xtend +++ b/java/bundles/org.eclipse.set.model.tablemodel.extensions/src/org/eclipse/set/model/tablemodel/extensions/TableExtensions.xtend @@ -41,6 +41,7 @@ import static extension org.eclipse.set.ppmodel.extensions.EObjectExtensions.* import static extension org.eclipse.set.ppmodel.extensions.UrObjectExtensions.* import static extension org.eclipse.set.ppmodel.extensions.utils.IterableExtensions.* import static extension org.eclipse.set.utils.StringExtensions.* +import org.eclipse.set.model.tablemodel.extensions.TableExtensions.FootnoteInfo /** * Extensions for {@link Table}. @@ -485,6 +486,29 @@ class TableExtensions { static def FootnoteInfo getFootnoteInfo(Table table, Bearbeitungsvermerk bv) { val allNotes = table.allFootnotes.toList + return allNotes.getFootnoteInfo(bv) + } + + static def FootnoteInfo getFootnoteInfo(EObject tableContent, Footnote fn) { + return getFootnoteInfo(tableContent, fn.bearbeitungsvermerk) + } + + static def FootnoteInfo getFootnoteInfo(EObject tableContent, + Bearbeitungsvermerk bv) { + var object = tableContent + while (!(object instanceof Table)) { + object = object.eContainer + } + return getFootnoteInfo(object as Table, bv) + } + + static def FootnoteInfo getFootnoteInfo(Iterable allNotes, + Footnote fn) { + return getFootnoteInfo(allNotes, fn.bearbeitungsvermerk) + } + + static def FootnoteInfo getFootnoteInfo(Iterable allNotes, + Bearbeitungsvermerk bv) { val sameId = allNotes.filter [ bearbeitungsvermerk?.identitaet?.wert == bv.identitaet?.wert ] @@ -506,19 +530,6 @@ class TableExtensions { return sameId.firstOrNull } - static def FootnoteInfo getFootnoteInfo(EObject tableContent, Footnote fn) { - return getFootnoteInfo(tableContent, fn.bearbeitungsvermerk) - } - - static def FootnoteInfo getFootnoteInfo(EObject tableContent, - Bearbeitungsvermerk bv) { - var object = tableContent - while (!(object instanceof Table)) { - object = object.eContainer - } - return getFootnoteInfo(object as Table, bv) - } - static def boolean isTableEmpty(Table table) { return table.tableRows.nullOrEmpty } From 3456b1308b483c471598f255f170e83bf5eebe34 Mon Sep 17 00:00:00 2001 From: Marius Heine Date: Tue, 26 May 2026 23:35:33 +0200 Subject: [PATCH 2/3] fix typo --- .../eclipse/set/feature/export/xlsx/ExcelExportBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java b/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java index 10ffd79a7a..2cf6a2f81b 100644 --- a/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java +++ b/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java @@ -71,7 +71,7 @@ public class ExcelExportBuilder implements TableExport { .getLogger(ExcelExportBuilder.class); private static final String TEMPLATE_DIR = "./data/export/excel"; //$NON-NLS-1$ - private static final String FOONOTE_SHEET_NAME = "Bermerkungen"; //$NON-NLS-1$ + private static final String FOOTNOTE_SHEET_NAME = "Bemerkungen"; //$NON-NLS-1$ private static int getFirstRowForContent(final Sheet sheet) { return getHeaderLastRowIndex(sheet) + 1; @@ -150,7 +150,7 @@ public void export(final Map tables, if (!isInlineFootnote) { final Sheet footnoteSheet = workbook - .createSheet(FOONOTE_SHEET_NAME); + .createSheet(FOOTNOTE_SHEET_NAME); fillFootnoteSheet(footnoteSheet, table); } From c2bdc37f9c691ca51886fdb7778f1bccb260a529 Mon Sep 17 00:00:00 2001 From: Marius Heine Date: Tue, 26 May 2026 23:37:29 +0200 Subject: [PATCH 3/3] fix exporting of footnotes in tables with merging rows e.g. sskg --- .../export/xlsx/ExcelExportBuilder.java | 28 ++++++++++--------- .../extensions/TableExtensions.xtend | 13 ++++++--- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java b/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java index 2cf6a2f81b..158ad95547 100644 --- a/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java +++ b/java/bundles/org.eclipse.set.feature.export/src/org/eclipse/set/feature/export/xlsx/ExcelExportBuilder.java @@ -41,6 +41,8 @@ import org.eclipse.set.basis.constants.TableType; import org.eclipse.set.basis.exceptions.FileExportException; import org.eclipse.set.feature.export.pdf.TableToTableDocument; +import org.eclipse.set.model.tablemodel.CompareFootnoteContainer; +import org.eclipse.set.model.tablemodel.Footnote; import org.eclipse.set.model.tablemodel.FootnoteContainer; import org.eclipse.set.model.tablemodel.SimpleFootnoteContainer; import org.eclipse.set.model.tablemodel.Table; @@ -220,11 +222,6 @@ private static void fillSheet(final Sheet sheet, final List rows, ? sheet.getRow(contentRowIndex) : createNewRow(sheet, contentRowIndex, columnCount); final FootnoteContainer footnotes = row.getFootnotes(); - // Currently export only FINAL-Table to excel, therefore the - // FootnoteContainer should be SimpleFootnoteContainer - if (!(footnotes instanceof SimpleFootnoteContainer)) { - throw new IllegalArgumentException(); - } for (int i = 0; i < columnCount; i++) { final String content = TableRowExtensions .getPlainStringValue(row, i); @@ -233,10 +230,9 @@ private static void fillSheet(final Sheet sheet, final List rows, if (cell == null) { cell = sheetRow.createCell(i + 1); } - if (i == columnCount - 1 - && footnotes instanceof final SimpleFootnoteContainer simpleContainer) { - fillFootnoteCell(cell, content, allFootnotes, - simpleContainer, inlineFootnote); + if (i == columnCount - 1) { + fillFootnoteCell(cell, content, allFootnotes, footnotes, + inlineFootnote); continue; } cell.setCellValue(content); @@ -249,10 +245,16 @@ private static void fillSheet(final Sheet sheet, final List rows, private static void fillFootnoteCell(final Cell cell, final String cellContent, final List allFootnotes, - final SimpleFootnoteContainer fnContainer, - final boolean inlineFootnote) { - final List fnInfo = fnContainer.getFootnotes() - .stream() + final FootnoteContainer fnContainer, final boolean inlineFootnote) { + final List footnotes = switch (fnContainer) { + case final SimpleFootnoteContainer simpleContainer -> simpleContainer + .getFootnotes(); + case final CompareFootnoteContainer compareContainer -> compareContainer + .getUnchangedFootnotes() + .getFootnotes(); + default -> throw new IllegalArgumentException(); + }; + final List fnInfo = footnotes.stream() .map(fn -> TableExtensions.getFootnoteInfo(allFootnotes, fn)) .filter(Objects::nonNull) .toList(); diff --git a/java/bundles/org.eclipse.set.model.tablemodel.extensions/src/org/eclipse/set/model/tablemodel/extensions/TableExtensions.xtend b/java/bundles/org.eclipse.set.model.tablemodel.extensions/src/org/eclipse/set/model/tablemodel/extensions/TableExtensions.xtend index c921124102..d0c9e5981a 100644 --- a/java/bundles/org.eclipse.set.model.tablemodel.extensions/src/org/eclipse/set/model/tablemodel/extensions/TableExtensions.xtend +++ b/java/bundles/org.eclipse.set.model.tablemodel.extensions/src/org/eclipse/set/model/tablemodel/extensions/TableExtensions.xtend @@ -449,21 +449,26 @@ class TableExtensions { } static def Iterable getAllFootnotes(Table table) { - val common = (table.eAllContents.filter(SimpleFootnoteContainer).map [ + val simpleFootnoteContainer = table.eAllContents.filter( + SimpleFootnoteContainer).toList + val compareFootnoteContainer = table.eAllContents.filter( + CompareFootnoteContainer).toList + + val common = (simpleFootnoteContainer.map [ footnotes.map[new FootnoteInfo(it, FootnoteType.COMMON_FOOTNOTE)] - ] + table.eAllContents.filter(CompareFootnoteContainer).map [ + ] + compareFootnoteContainer.map [ unchangedFootnotes.footnotes.map [ new FootnoteInfo(it, FootnoteType.COMMON_FOOTNOTE) ] ]).toList.flatten - val old = table.eAllContents.filter(CompareFootnoteContainer).map [ + val old = compareFootnoteContainer.map [ oldFootnotes.footnotes.map [ new FootnoteInfo(it, FootnoteType.OLD_FOOTNOTE) ] ].toList.flatten - val newF = table.eAllContents.filter(CompareFootnoteContainer).map [ + val newF = compareFootnoteContainer.map [ newFootnotes.footnotes.map [ new FootnoteInfo(it, FootnoteType.NEW_FOOTNOTE)