1 | package pro.verron.officestamper.preset.processors.table; | |
2 | ||
3 | import jakarta.xml.bind.JAXBElement; | |
4 | import org.docx4j.XmlUtils; | |
5 | import org.docx4j.openpackaging.packages.WordprocessingMLPackage; | |
6 | import org.docx4j.wml.ContentAccessor; | |
7 | import org.docx4j.wml.Tbl; | |
8 | import org.docx4j.wml.Tc; | |
9 | import org.docx4j.wml.Tr; | |
10 | import org.springframework.lang.Nullable; | |
11 | import pro.verron.officestamper.api.*; | |
12 | import pro.verron.officestamper.core.PlaceholderReplacer; | |
13 | import pro.verron.officestamper.preset.CommentProcessorFactory; | |
14 | import pro.verron.officestamper.preset.StampTable; | |
15 | import pro.verron.officestamper.utils.WmlFactory; | |
16 | ||
17 | import java.util.Collections; | |
18 | import java.util.HashMap; | |
19 | import java.util.List; | |
20 | import java.util.Map; | |
21 | import java.util.function.Function; | |
22 | ||
23 | import static pro.verron.officestamper.api.OfficeStamperException.throwing; | |
24 | ||
25 | /** | |
26 | * TableResolver class. | |
27 | * | |
28 | * @author Joseph Verron | |
29 | * @version ${version} | |
30 | * @since 1.6.2 | |
31 | */ | |
32 | public class TableResolver | |
33 | extends AbstractCommentProcessor | |
34 | implements CommentProcessorFactory.ITableResolver { | |
35 | private final Map<Tbl, StampTable> cols = new HashMap<>(); | |
36 | private final Function<Tbl, List<Object>> nullSupplier; | |
37 | ||
38 | private TableResolver( | |
39 | ParagraphPlaceholderReplacer placeholderReplacer, Function<Tbl, List<Object>> nullSupplier | |
40 | ) { | |
41 | super(placeholderReplacer); | |
42 | this.nullSupplier = nullSupplier; | |
43 | } | |
44 | ||
45 | /** | |
46 | * Generate a new {@link TableResolver} instance where value is replaced by an empty list when <code>null</code> | |
47 | * | |
48 | * @param pr a {@link PlaceholderReplacer} instance | |
49 | * | |
50 | * @return a new {@link TableResolver} instance | |
51 | */ | |
52 | public static CommentProcessor newInstance(ParagraphPlaceholderReplacer pr) { | |
53 |
1
1. newInstance : replaced return value with null for pro/verron/officestamper/preset/processors/table/TableResolver::newInstance → KILLED |
return new TableResolver(pr, table -> Collections.emptyList()); |
54 | } | |
55 | ||
56 | /** | |
57 | * {@inheritDoc} | |
58 | */ | |
59 | @Override public void resolveTable(@Nullable StampTable givenTable) { | |
60 | var tbl = this.getParagraph() | |
61 | .parent(Tbl.class) | |
62 | .orElseThrow(throwing("Paragraph is not within a table!")); | |
63 | cols.put(tbl, givenTable); | |
64 | } | |
65 | ||
66 | /** | |
67 | * {@inheritDoc} | |
68 | */ | |
69 | @Override public void commitChanges(DocxPart document) { | |
70 | for (Map.Entry<Tbl, StampTable> entry : cols.entrySet()) { | |
71 | Tbl wordTable = entry.getKey(); | |
72 | ||
73 | StampTable stampedTable = entry.getValue(); | |
74 | ||
75 |
1
1. commitChanges : negated conditional → KILLED |
if (stampedTable != null) { |
76 |
1
1. commitChanges : removed call to pro/verron/officestamper/preset/processors/table/TableResolver::replaceTableInplace → KILLED |
replaceTableInplace(wordTable, stampedTable); |
77 | } | |
78 | else { | |
79 | List<Object> tableParentContent = ((ContentAccessor) wordTable.getParent()).getContent(); | |
80 | int tablePosition = tableParentContent.indexOf(wordTable); | |
81 | List<Object> toInsert = nullSupplier.apply(wordTable); | |
82 | tableParentContent.set(tablePosition, toInsert); | |
83 | } | |
84 | } | |
85 | } | |
86 | ||
87 | @Override public void commitChanges(WordprocessingMLPackage document) { | |
88 | throw new OfficeStamperException("Should not be called, since deprecation"); | |
89 | } | |
90 | ||
91 | /** | |
92 | * {@inheritDoc} | |
93 | */ | |
94 | @Override public void reset() { | |
95 |
1
1. reset : removed call to java/util/Map::clear → KILLED |
cols.clear(); |
96 | } | |
97 | ||
98 | private void replaceTableInplace(Tbl wordTable, StampTable stampedTable) { | |
99 | var headers = stampedTable.headers(); | |
100 | ||
101 | var rows = wordTable.getContent(); | |
102 | var headerRow = (Tr) rows.get(0); | |
103 | var firstDataRow = (Tr) rows.get(1); | |
104 | ||
105 |
1
1. replaceTableInplace : removed call to pro/verron/officestamper/preset/processors/table/TableResolver::growAndFillRow → KILLED |
growAndFillRow(headerRow, headers); |
106 | ||
107 |
1
1. replaceTableInplace : negated conditional → KILLED |
if (stampedTable.isEmpty()) rows.remove(firstDataRow); |
108 | else { | |
109 |
1
1. replaceTableInplace : removed call to pro/verron/officestamper/preset/processors/table/TableResolver::growAndFillRow → KILLED |
growAndFillRow(firstDataRow, stampedTable.getFirst()); |
110 | for (var rowContent : stampedTable.subList(1, stampedTable.size())) | |
111 | rows.add(copyRowFromTemplate(firstDataRow, rowContent)); | |
112 | } | |
113 | } | |
114 | ||
115 | private void growAndFillRow(Tr row, List<String> values) { | |
116 | List<Object> cellRowContent = row.getContent(); | |
117 | ||
118 | //Replace text in first cell | |
119 | JAXBElement<Tc> cell0 = (JAXBElement<Tc>) cellRowContent.getFirst(); | |
120 | Tc cell0tc = cell0.getValue(); | |
121 |
2
1. growAndFillRow : removed call to pro/verron/officestamper/preset/processors/table/TableResolver::setCellText → KILLED 2. growAndFillRow : negated conditional → KILLED |
setCellText(cell0tc, values.isEmpty() ? "" : values.getFirst()); |
122 | ||
123 |
2
1. growAndFillRow : changed conditional boundary → SURVIVED 2. growAndFillRow : negated conditional → KILLED |
if (values.size() > 1) { |
124 | //Copy the first cell and replace content for each remaining value | |
125 | for (String cellContent : values.subList(1, values.size())) { | |
126 | JAXBElement<Tc> xmlCell = XmlUtils.deepCopy(cell0); | |
127 |
1
1. growAndFillRow : removed call to pro/verron/officestamper/preset/processors/table/TableResolver::setCellText → KILLED |
setCellText(xmlCell.getValue(), cellContent); |
128 | cellRowContent.add(xmlCell); | |
129 | } | |
130 | } | |
131 | } | |
132 | ||
133 | private Tr copyRowFromTemplate(Tr firstDataRow, List<String> rowContent) { | |
134 | Tr newXmlRow = XmlUtils.deepCopy(firstDataRow); | |
135 | List<Object> xmlRow = newXmlRow.getContent(); | |
136 |
2
1. copyRowFromTemplate : negated conditional → KILLED 2. copyRowFromTemplate : changed conditional boundary → KILLED |
for (int i = 0; i < rowContent.size(); i++) { |
137 | String cellContent = rowContent.get(i); | |
138 | Tc xmlCell = ((JAXBElement<Tc>) xmlRow.get(i)).getValue(); | |
139 |
1
1. copyRowFromTemplate : removed call to pro/verron/officestamper/preset/processors/table/TableResolver::setCellText → KILLED |
setCellText(xmlCell, cellContent); |
140 | } | |
141 |
1
1. copyRowFromTemplate : replaced return value with null for pro/verron/officestamper/preset/processors/table/TableResolver::copyRowFromTemplate → KILLED |
return newXmlRow; |
142 | } | |
143 | ||
144 | private void setCellText(Tc tableCell, String content) { | |
145 | var tableCellContent = tableCell.getContent(); | |
146 |
1
1. setCellText : removed call to java/util/List::clear → KILLED |
tableCellContent.clear(); |
147 | tableCellContent.add(WmlFactory.newParagraph(new String[]{content})); | |
148 | } | |
149 | } | |
Mutations | ||
53 |
1.1 |
|
75 |
1.1 |
|
76 |
1.1 |
|
95 |
1.1 |
|
105 |
1.1 |
|
107 |
1.1 |
|
109 |
1.1 |
|
121 |
1.1 2.2 |
|
123 |
1.1 2.2 |
|
127 |
1.1 |
|
136 |
1.1 2.2 |
|
139 |
1.1 |
|
141 |
1.1 |
|
146 |
1.1 |