Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export: Delete delete/reused datasets tables when empty #138

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;
import java.text.SimpleDateFormat;

Expand Down Expand Up @@ -35,7 +36,7 @@ public abstract class AbstractTemplateExportFunctions {
* @return
* @throws Exception
*/
public XWPFDocument loadTemplate (InputStream template, String startChar, String endChar) throws Exception{
public XWPFDocument loadTemplate(InputStream template, String startChar, String endChar) throws Exception {
//Extract document using Apache POI https://poi.apache.org/
XWPFDocument document = new XWPFDocument(template);

Expand Down Expand Up @@ -119,7 +120,7 @@ public void addReplacement(Map<String, String> replacements, String variable, Ob
* @throws XmlException
* @throws Exception
*/
public XWPFTableRow insertNewTableRow(XWPFTableRow sourceTableRow, int pos) throws XmlException, IOException {
public XWPFTableRow insertNewTableRow(XWPFTableRow sourceTableRow, int pos) throws XmlException, IOException {
XWPFTable table = sourceTableRow.getTable();
CTRow newCTRrow = CTRow.Factory.parse(sourceTableRow.getCtRow().newInputStream());
XWPFTableRow tableRow = new XWPFTableRow(newCTRrow, table);
Expand Down Expand Up @@ -152,7 +153,7 @@ static void insertTableCells(XWPFTable table, XWPFTableRow newRow, ArrayList<Str
* @param table
* @param replacements
*/
static void replaceTableVariables(XWPFTable table, Map<String, String> replacements){
static void replaceTableVariables(XWPFTable table, Map<String, String> replacements) {
//this replaces variables in tables (e.g. costcurrency)
List<XWPFTableRow> tableRows = table.getRows();
for (XWPFTableRow xwpfTableRow : tableRows) {
Expand Down Expand Up @@ -260,7 +261,7 @@ public XWPFDocument templateFormatting(XWPFDocument document, String startChar,
* @param startChar
* @param endChar
*/
public void formattingTable(List<XWPFTable> xwpfTables, String startChar, String endChar){
public void formattingTable(List<XWPFTable> xwpfTables, String startChar, String endChar) {
if (xwpfTables != null) {
for (XWPFTable xwpfTable : xwpfTables) {
for (XWPFTableRow row : xwpfTable.getRows()) {
Expand Down Expand Up @@ -297,20 +298,18 @@ public void formattingParagraph(List<XWPFParagraph> xwpfParagraphs, String start
if (!xwpfRunText.contains(endChar)) {
removeRunIndex.add(xwpfRuns.indexOf(xwpfRun));
mergeRun = true;
if (sb.length()>0) {
if (sb.length() > 0) {
sb.delete(0, sb.length());
}
sb.append(xwpfRunText);
}
}
else {
} else {
if (mergeRun) {
sb.append(xwpfRunText);
if (xwpfRunText.contains(endChar)) {
mergeRun = false;
xwpfRun.setText(sb.toString(),0);
}
else {
xwpfRun.setText(sb.toString(), 0);
} else {
removeRunIndex.add(xwpfRuns.indexOf(xwpfRun));
}
}
Expand All @@ -326,4 +325,108 @@ public void formattingParagraph(List<XWPFParagraph> xwpfParagraphs, String start
}
}
}

/**
* Removes a table inside a document or nested inside another table.
* For nested tables, this works only for depth 1.
* If the table is not to be found inside the doc or at depth 1, nothing happens.
*
* @param doc
* @param table
*/
public void removeTable(XWPFDocument doc, XWPFTable table) {
int pos = doc.getPosOfTable(table);
if (pos != -1) {
doc.removeBodyElement(pos);
} else { // table not found in document -> nestedTable
removeNestedTable(doc, table);
}
}

/**
* Removes a table which is nested inside another table. Max nested depth is 1.
*
* @param doc
* @param table
*/
private void removeNestedTable(XWPFDocument doc, XWPFTable table) {
for (XWPFTableCell cell : getAllOuterTableCells(doc)) {
for (XWPFTable nestedTable : cell.getTables()) {
if (nestedTable.equals(table)) {
int pos = cell.getTables().indexOf(nestedTable);
// dirty hack since POI XWPF does not offer functionality for removing nested tables
try {
Field beField = cell.getClass().getDeclaredField("tables");
beField.setAccessible(true);
((List<XWPFTable>) beField.get(cell)).remove(pos); // higher level representation
} catch (Exception ignored) {
}
cell.getCTTc().removeTbl(pos); // low level cell representation

return;
}
}
}
}

/**
* Removes a table inside a document or nested inside another table. Also removes the paragraph above it.
* For nested tables, this works only for depth 1.
* If the table is not to be found inside the doc or at depth 1, nothing happens.
* If the there is no paragraph above the table, only the table will be removed.
*
* @param doc
* @param table
*/
public void removeTableAndParagraphAbove(XWPFDocument doc, XWPFTable table) {
// paragraph above the table
if (doc.getPosOfTable(table) != -1) {
int paragraphPos = doc.getPosOfTable(table) - 1;
if (doc.getBodyElements().get(paragraphPos).getElementType().equals(BodyElementType.PARAGRAPH)) {
doc.removeBodyElement(paragraphPos);
}
} else {
for (XWPFTableCell cell : getAllOuterTableCells(doc)) {
for (XWPFTable nestedTable : cell.getTables()) {
if (nestedTable.equals(table)) {
int paragraphPos = cell.getBodyElements().indexOf(table) - 1;
if (cell.getBodyElements().get(paragraphPos).getElementType().equals(BodyElementType.PARAGRAPH)) {
XWPFParagraph paragraphToRemove = (XWPFParagraph) cell.getBodyElements().get(paragraphPos);
cell.removeParagraph(cell.getParagraphs().indexOf(paragraphToRemove));
}
}
}
}
}
// delete unnecessary table
removeTable(doc, table);
}

/**
* Returns a list of all table cells of non nested tables in the document.
*
* @param doc
*/
public List<XWPFTableCell> getAllOuterTableCells(XWPFDocument doc) {
List<XWPFTableCell> tableCells = new ArrayList<>();
for (XWPFTable outerTable : doc.getTables()) {
for (XWPFTableRow row : outerTable.getRows()) {
tableCells.addAll(row.getTableCells());
}
}
return tableCells;
}

/**
* Returns a list of all tables and nested tables with depth 1.
*
* @param doc
*/
public List<XWPFTable> getAllTables(XWPFDocument doc) {
ArrayList<XWPFTable> tables = new ArrayList<>(doc.getTables());
for (XWPFTableCell cell : getAllOuterTableCells(doc)) {
tables.addAll(cell.getTables());
}
return tables;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;

import java.lang.reflect.Field;
import java.text.NumberFormat;
import java.time.ZoneId;
import java.time.ZonedDateTime;
Expand Down Expand Up @@ -706,8 +707,9 @@ protected static String format(long number) {
}

//All tables variables replacement
public void tableContent(List<XWPFTable> xwpfTables) {
for (XWPFTable xwpfTable : xwpfTables) {
// Takes care of filling tables and deletes certain empty tables
public void tableContent(XWPFDocument document, List<XWPFTable> xwpfTables) {
for (XWPFTable xwpfTable : new ArrayList<>(xwpfTables)) {
XWPFTableRow tableIdentifierRow = xwpfTable.getRow(1);
if (tableIdentifierRow != null) {

Expand All @@ -728,7 +730,7 @@ public void tableContent(List<XWPFTable> xwpfTables) {
composeTableNewDatasets(xwpfTable);
break;
case ("[reusedDatasetTable]"):
composeTableReusedDatasets(xwpfTable);
composeTableReusedDatasets(document, xwpfTable);
break;
case ("[datasetAccessTable]"):
composeTableDataAccess(xwpfTable);
Expand All @@ -740,14 +742,20 @@ public void tableContent(List<XWPFTable> xwpfTables) {
composeTableDatasetRepository(xwpfTable);
break;
case ("[datasetDeleteTable]"):
composeTableDatasetDeletion(xwpfTable);
composeTableDatasetDeletion(document, xwpfTable);
break;
case ("[costTable]"):
composeTableCost(xwpfTable);
break;
default:
break;
}
}
replaceTableVariables(xwpfTable, replacements);
}

// prevents replacing table variables of deleted tables
for (XWPFTable table : getAllTables(document)) {
replaceTableVariables(table, replacements);
}
}

Expand Down Expand Up @@ -824,7 +832,7 @@ public List<Dataset> getReusedDatasets(){
return datasets.stream().filter(dataset -> dataset.getSource().equals(EDataSource.REUSED)).collect(Collectors.toList());
}

public void composeTableReusedDatasets(XWPFTable xwpfTable){
public void composeTableReusedDatasets(XWPFDocument document, XWPFTable xwpfTable){
log.debug("Export steps: Reused Dataset Table");

List<Dataset> reusedDatasets = getReusedDatasets();
Expand Down Expand Up @@ -877,13 +885,10 @@ public void composeTableReusedDatasets(XWPFTable xwpfTable){
insertTableCells(xwpfTable, newRow, docVar);
}
xwpfTable.removeRow(xwpfTable.getRows().size() - 1);
xwpfTable.removeRow(1);
} else {
//clean row
ArrayList<String> emptyContent = new ArrayList<String>(Arrays.asList("", "", "", "", "", ""));
insertTableCells(xwpfTable, xwpfTable.getRows().get(xwpfTable.getRows().size() - 1), emptyContent);
removeTableAndParagraphAbove(document, xwpfTable);
}
//end of dynamic table rows code
xwpfTable.removeRow(1);
}

public void composeTableDataAccess(XWPFTable xwpfTable){
Expand All @@ -902,6 +907,7 @@ public void composeTableDataAccess(XWPFTable xwpfTable){
insertTableCells(xwpfTable, xwpfTable.getRows().get(xwpfTable.getRows().size() - 1), emptyContent);
}
xwpfTable.removeRow(1);
replaceTableVariables(xwpfTable, replacements);
}

private void insertComposeTableDataAccess(XWPFTable xwpfTable, List<Dataset> currentDatasets){
Expand Down Expand Up @@ -1100,7 +1106,7 @@ public void composeTableDatasetRepository(XWPFTable xwpfTable){
commitTableRows(xwpfTable);
}

public void composeTableDatasetDeletion(XWPFTable xwpfTable){
public void composeTableDatasetDeletion(XWPFDocument document, XWPFTable xwpfTable){
log.debug("Export steps: Dataset Deletion Table");

if (deletedDatasets.size() > 0) {
Expand Down Expand Up @@ -1141,12 +1147,11 @@ public void composeTableDatasetDeletion(XWPFTable xwpfTable){
insertTableCells(xwpfTable, newRow, docVar);
}
xwpfTable.removeRow(xwpfTable.getRows().size() - 1);
xwpfTable.removeRow(1);
} else {
//clean row
ArrayList<String> emptyContent = new ArrayList<String>(Arrays.asList("", "", "", "", ""));
insertTableCells(xwpfTable, xwpfTable.getRows().get(xwpfTable.getRows().size() - 1), emptyContent);
removeTableAndParagraphAbove(document, xwpfTable);
}
xwpfTable.removeRow(1);

}

public void composeTableCost(XWPFTable xwpfTable){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ public XWPFDocument exportTemplate(long dmpId) {
//in FWF template this replaces paragraphs within the template table
replaceTableVariables(templateTable, replacements);
//this replaces the tables with the main template table
tableContent(templateXwpfTables);
tableContent(document, templateXwpfTables);

return document;
}

private List<XWPFTable> parseContentTables(XWPFTable templateTable) {
List<XWPFTable> templateXwpfTables = new ArrayList<>();
for (XWPFTableRow row : templateTable.getRows()){
if (row.getTableCells().size() > 1){
if (row.getTableCells().size() > 1) {
templateXwpfTables.addAll(row.getCell(1).getTables());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public XWPFDocument exportTemplate(long dmpId) {
// TO DO: combine the function with the first row generation to avoid double
// code of similar modification.
log.debug("Export steps: Replace in table");
tableContent(xwpfTables);
tableContent(document, xwpfTables);

// Fourth step of the export: modify the content of the document's footer
log.debug("Export steps: Replace in footer");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public XWPFDocument exportTemplate(long dmpId) {
//Third step of the export: dynamic table in all sections will be added from row number two until the end of data list.
//TO DO: combine the function with the first row generation to avoid double code of similar modification.
log.debug("Export steps: Replace in table");
tableContent(xwpfTables);
tableContent(document, xwpfTables);

//Fourth step of the export: modify the content of the document's footer
log.debug("Export steps: Replace in footer");
Expand Down
Loading