WmlFactory.java

1
package pro.verron.officestamper.utils.wml;
2
3
import jakarta.xml.bind.JAXBElement;
4
import jakarta.xml.bind.JAXBException;
5
import org.docx4j.UnitsOfMeasurement;
6
import org.docx4j.XmlUtils;
7
import org.docx4j.dml.wordprocessingDrawing.Inline;
8
import org.docx4j.model.structure.PageDimensions;
9
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
10
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
11
import org.docx4j.openpackaging.parts.WordprocessingML.CommentsPart;
12
import org.docx4j.relationships.Relationship;
13
import org.docx4j.wml.*;
14
import org.docx4j.wml.Comments.Comment;
15
import pro.verron.officestamper.utils.UtilsException;
16
17
import java.awt.geom.Dimension2D;
18
import java.math.BigInteger;
19
import java.util.*;
20
21
import static java.util.Arrays.asList;
22
import static java.util.stream.Collectors.toCollection;
23
24
/// Utility class for creating and configuring various WordML (WML) elements.
25
/// Provides static methods to generate paragraphs, runs, comments, text, and
26
///  other WML structures. This is intended for handling Office Open XML
27
/// documents programmatically.
28
public class WmlFactory {
29
    private static final Random RANDOM = new Random();
30
31
    private WmlFactory() {
32
        throw new UtilsException("Utility class shouldn't be instantiated");
33
    }
34
35
    /// Creates a new comment with the provided value.
36
    ///
37
    /// @param id    The ID to assign to the comment.
38
    /// @param value The string value to be included in the comment.
39
    ///
40
    /// @return A new [Comment] object containing the provided value.
41
    public static Comment newComment(BigInteger id, String value) {
42
        var comment = new Comment();
43 1 1. newComment : removed call to org/docx4j/wml/Comments$Comment::setId → NO_COVERAGE
        comment.setId(id);
44
        var commentContent = comment.getContent();
45
        commentContent.add(newParagraph(value));
46 1 1. newComment : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newComment → NO_COVERAGE
        return comment;
47
    }
48
49
    /// Creates a new paragraph containing the provided string value.
50
    ///
51
    /// @param value The string value to be added to the new paragraph.
52
    ///
53
    /// @return A new [P] containing the provided string value.
54
    public static P newParagraph(String value) {
55 1 1. newParagraph : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newParagraph → NO_COVERAGE
        return newParagraph(newRun(value));
56
    }
57
58
    /// Creates a new paragraph containing the provided run.
59
    ///
60
    /// @param run The [R] object (run) to be included in the new paragraph.
61
    ///
62
    /// @return A new [P] containing the provided run.
63
    public static P newParagraph(R run) {
64 1 1. newParagraph : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newParagraph → NO_COVERAGE
        return newParagraph(List.of(run));
65
    }
66
67
    /// Creates a new run containing the provided string value.
68
    ///
69
    /// @param value The string value to be included in the new run.
70
    ///
71
    /// @return A new [R] containing the provided string value.
72
    public static R newRun(String value) {
73 1 1. newRun : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newRun → NO_COVERAGE
        return newRun(newText(value));
74
    }
75
76
    /// Creates a new paragraph containing the provided list of values.
77
    ///
78
    /// @param values A list of objects to be added to the new paragraph. These
79
    /// objects populate the content of the paragraph.
80
    ///
81
    /// @return A new [P] containing the provided values.
82
    public static P newParagraph(List<?> values) {
83
        var paragraph = new P();
84
        var paragraphContent = paragraph.getContent();
85
        paragraphContent.addAll(values);
86 1 1. newParagraph : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newParagraph → NO_COVERAGE
        return paragraph;
87
    }
88
89
    /// Creates a new run containing a single text object.
90
    ///
91
    /// @param value The [Text] object to be included in the new run.
92
    ///
93
    /// @return A new [R] encapsulating the provided text object.
94
    public static R newRun(Text value) {
95 1 1. newRun : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newRun → NO_COVERAGE
        return newRun(List.of(value));
96
    }
97
98
    /// Creates a new [Text] object with the specified value, preserving spaces.
99
    ///
100
    /// @param value The string value to be set in the new [Text] object.
101
    ///
102
    /// @return A new [Text] object containing the provided value with space
103
    /// preserved.
104
    public static Text newText(String value) {
105
        var text = new Text();
106 1 1. newText : removed call to org/docx4j/wml/Text::setValue → NO_COVERAGE
        text.setValue(value);
107 1 1. newText : removed call to org/docx4j/wml/Text::setSpace → NO_COVERAGE
        text.setSpace("preserve");
108 1 1. newText : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newText → NO_COVERAGE
        return text;
109
    }
110
111
    /// Creates a new run containing the provided values deemed worth keeping.
112
    ///
113
    /// @param values A list of objects to be added to the new run. Objects are
114
    /// filtered based on a predefined criteria to determine if they are
115
    /// worth keeping.
116
    ///
117
    /// @return A new [R] containing the filtered values.
118
    public static R newRun(List<Object> values) {
119
        var run = new R();
120
        var runContent = run.getContent();
121
        runContent.addAll(values.stream()
122
                                .filter(WmlFactory::worthKeeping)
123
                                .collect(toCollection(ArrayList::new)));
124 1 1. newRun : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newRun → NO_COVERAGE
        return run;
125
    }
126
127
    private static boolean worthKeeping(Object o) {
128 3 1. worthKeeping : negated conditional → NO_COVERAGE
2. worthKeeping : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlFactory::worthKeeping → NO_COVERAGE
3. worthKeeping : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlFactory::worthKeeping → NO_COVERAGE
        if (o instanceof Text text) return worthKeeping(text);
129 1 1. worthKeeping : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlFactory::worthKeeping → NO_COVERAGE
        else return true;
130
    }
131
132
    private static boolean worthKeeping(Text text) {
133
        var textValue = text.getValue();
134 2 1. worthKeeping : negated conditional → NO_COVERAGE
2. worthKeeping : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlFactory::worthKeeping → NO_COVERAGE
        return !textValue.isEmpty();
135
    }
136
137
    /// Creates a new [Body] object containing the provided elements.
138
    ///
139
    /// @param elements A list of objects to be added to the new [Body].
140
    ///
141
    /// @return A new [Body] containing the provided elements.
142
    public static Body newBody(List<Object> elements) {
143
        Body body = new Body();
144
        var bodyContent = body.getContent();
145
        bodyContent.addAll(elements);
146 1 1. newBody : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newBody → NO_COVERAGE
        return body;
147
    }
148
149
    /// Creates a new paragraph containing the provided text values.
150
    ///
151
    /// @param texts The array of string values to be included in the new
152
    /// paragraph.
153
    ///
154
    /// @return A new [P] containing the provided text values.
155
    public static P newParagraph(String... texts) {
156 1 1. newParagraph : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newParagraph → NO_COVERAGE
        return newParagraph(Arrays.stream(texts)
157
                                  .map(WmlFactory::newRun)
158
                                  .toList());
159
    }
160
161
    /// Creates a new [PPr] (paragraph properties) object.
162
    ///
163
    /// @return A new [PPr] object.
164
    public static PPr newPPr() {
165 1 1. newPPr : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newPPr → NO_COVERAGE
        return new PPr();
166
    }
167
168
    /// Creates a new [Comments] object and populates it with a list of
169
    /// [Comment] objects.
170
    ///
171
    /// @param list A list of [Comment] objects to be added to the new
172
    ///  [Comments] object.
173
    ///
174
    /// @return A new [Comments] object containing the provided [Comment]
175
    ///  objects.
176
    public static Comments newComments(List<Comment> list) {
177
        Comments comments = new Comments();
178
        List<Comment> commentList = comments.getComment();
179
        commentList.addAll(list);
180 1 1. newComments : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newComments → NO_COVERAGE
        return comments;
181
    }
182
183
    /// Creates a new Inline object representing an image with the specified
184
    /// parameters, properly formatted for use in Word documents. The image
185
    /// is defined using WordprocessingML and associated relationships.
186
    ///
187
    /// @param relationship The relationship object that provides the
188
    /// relationship ID for the image.
189
    /// @param filenameHint A hint for the file name of the image, used to set
190
    /// display names in the document.
191
    /// @param altText      The alternate text for the image, used for
192
    /// accessibility purposes.
193
    /// @param scale        The scale object that defines the dimensions (cx,
194
    /// cy) of the image in EMUs (English Metric Units).
195
    ///
196
    /// @return An Inline object that represents the formatted image element to
197
    /// be embedded in the document.
198
    ///
199
    /// @throws UtilsException If any error occurs during the creation of the
200
    ///  Inline object.
201
    public static Inline newImgInline(
202
            Relationship relationship,
203
            String filenameHint,
204
            String altText,
205
            Scale scale
206
    ) {
207
        // creating random ids assuming unicity, id must not be too large
208
        // otherwise Word cannot open the document
209
        var id1 = RANDOM.nextLong(100_000L);
210
        var id2 = RANDOM.nextInt(100_000);
211
        try {
212
            String ml = """
213
                    <wp:inline distT="0" distB="0" distL="0" distR="0"
214
                      xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
215
                      xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
216
                      xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">
217
                      <wp:extent cx="${cx}" cy="${cy}"/>
218
                      <wp:effectExtent l="0" t="0" r="0" b="0"/>
219
                      <wp:docPr id="${id1}" name="${filenameHint}" descr="${altText}"/>
220
                      <wp:cNvGraphicFramePr>
221
                        <a:graphicFrameLocks noChangeAspect="1"
222
                          xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"/>
223
                      </wp:cNvGraphicFramePr>
224
                      <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
225
                        <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
226
                          <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
227
                            <pic:nvPicPr>
228
                              <pic:cNvPr id="${id2}" name="${filenameHint}"/>
229
                              <pic:cNvPicPr/>
230
                            </pic:nvPicPr>
231
                            <pic:blipFill><a:blip r:embed="${rEmbedId}"/>
232
                                <a:stretch><a:fillRect/></a:stretch>
233
                            </pic:blipFill>
234
                            <pic:spPr>
235
                              <a:xfrm>
236
                                <a:off x="0" y="0"/>
237
                                <a:ext cx="${cx}" cy="${cy}"/>
238
                              </a:xfrm>
239
                              <a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
240
                            </pic:spPr>
241
                          </pic:pic>
242
                        </a:graphicData>
243
                      </a:graphic>
244
                    </wp:inline>""";
245
            var mappings = new HashMap<String, String>();
246
            mappings.put("cx", Long.toString(scale.cx()));
247
            mappings.put("cy", Long.toString(scale.cy()));
248
            mappings.put("filenameHint", filenameHint);
249
            mappings.put("altText", altText);
250
            mappings.put("rEmbedId", relationship.getId());
251
            mappings.put("id1", Long.toString(id1));
252
            mappings.put("id2", Integer.toString(id2));
253
            var jaxbElement = (JAXBElement<?>) XmlUtils.unmarshallFromTemplate(
254
                    ml,
255
                    mappings);
256 1 1. newImgInline : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newImgInline → NO_COVERAGE
            return (Inline) jaxbElement.getValue();
257
        } catch (Exception e) {
258
            throw new UtilsException(e);
259
        }
260
    }
261
262
    /// Computes a scaling factor for an image to fit within the writable width
263
    /// of a page.
264
    ///
265
    /// @param pageDimensions the dimensions of the page, including the
266
    /// writable width
267
    /// @param maxWidth       an optional maximum width in twips; if greater
268
    /// than zero, this value will limit the writable width
269
    /// @param dpx            the dimensions of the image in pixels
270
    ///
271
    /// @return a Scale object containing the width (cx) and height (cy) in EMUs
272
    public static Scale computeScale(
273
            PageDimensions pageDimensions,
274
            Integer maxWidth,
275
            Dimension2D dpx
276
    ) {
277
        double writableWidthTwips = pageDimensions.getWritableWidthTwips();
278 4 1. computeScale : changed conditional boundary → NO_COVERAGE
2. computeScale : negated conditional → NO_COVERAGE
3. computeScale : changed conditional boundary → NO_COVERAGE
4. computeScale : negated conditional → NO_COVERAGE
        if (maxWidth > 0 && maxWidth < writableWidthTwips)
279
            writableWidthTwips = maxWidth;
280
        double imageWidthTwips =
281
                UnitsOfMeasurement.pxToTwipDouble(dpx.getWidth());
282
        double imageHeightTwips =
283
                UnitsOfMeasurement.pxToTwipDouble(dpx.getHeight());
284
        long cx;
285
        long cy;
286 2 1. computeScale : changed conditional boundary → NO_COVERAGE
2. computeScale : negated conditional → NO_COVERAGE
        if (imageWidthTwips > writableWidthTwips) {
287
            cx = UnitsOfMeasurement.twipToEMU(writableWidthTwips);
288 2 1. computeScale : Replaced double division with multiplication → NO_COVERAGE
2. computeScale : Replaced double multiplication with division → NO_COVERAGE
            cy = UnitsOfMeasurement.twipToEMU(
289
                    imageHeightTwips * writableWidthTwips / imageWidthTwips);
290
        }
291
        else {
292
            cx = UnitsOfMeasurement.twipToEMU(imageWidthTwips);
293
            cy = UnitsOfMeasurement.twipToEMU(imageHeightTwips);
294
        }
295 1 1. computeScale : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::computeScale → NO_COVERAGE
        return new Scale(cx, cy);
296
    }
297
298
    /// Creates a new run containing a single drawing.
299
    ///
300
    /// @param value The [Drawing] object to be included in the new run.
301
    ///
302
    /// @return A new [R] encapsulating the provided drawing.
303
    public static R newRun(Drawing value) {
304 1 1. newRun : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newRun → NO_COVERAGE
        return newRun(List.of(value));
305
    }
306
307
    /// Creates a new [Drawing] object containing the provided [Inline] object.
308
    ///
309
    /// @param inline The [Inline] object to be contained within the new
310
    ///  [Drawing].
311
    ///
312
    /// @return A new [Drawing] object encapsulating the provided inline object.
313
    public static Drawing newDrawing(Inline inline) {
314
        var drawing = new Drawing();
315
        var anchorOrInline = drawing.getAnchorOrInline();
316
        anchorOrInline.add(inline);
317 1 1. newDrawing : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newDrawing → NO_COVERAGE
        return drawing;
318
    }
319
320
    /// Creates a new [CommentRangeStart] object with the specified ID and
321
    /// parent.
322
    ///
323
    /// @param id     The unique identifier for the [CommentRangeStart] object.
324
    /// @param parent The parent element ([P]) to which this
325
    ///  [CommentRangeStart] belongs.
326
    ///
327
    /// @return A new [CommentRangeStart] object with the specified ID and
328
    /// parent.
329
    public static CommentRangeStart newCommentRangeStart(
330
            BigInteger id,
331
            ContentAccessor parent
332
    ) {
333
        var commentRangeStart = new CommentRangeStart();
334 1 1. newCommentRangeStart : removed call to org/docx4j/wml/CommentRangeStart::setId → NO_COVERAGE
        commentRangeStart.setId(id);
335 1 1. newCommentRangeStart : removed call to org/docx4j/wml/CommentRangeStart::setParent → NO_COVERAGE
        commentRangeStart.setParent(parent);
336 1 1. newCommentRangeStart : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCommentRangeStart → NO_COVERAGE
        return commentRangeStart;
337
    }
338
339
    /// Creates a new [CommentRangeEnd] object with the specified ID and parent.
340
    ///
341
    /// @param id     The unique identifier for the [CommentRangeEnd] object.
342
    /// @param parent The parent element ([P]) to which this
343
    ///  [CommentRangeEnd] belongs.
344
    ///
345
    /// @return A new [CommentRangeEnd] object with the specified ID and parent.
346
    public static CommentRangeEnd newCommentRangeEnd(
347
            BigInteger id,
348
            ContentAccessor parent
349
    ) {
350
        var commentRangeEnd = new CommentRangeEnd();
351 1 1. newCommentRangeEnd : removed call to org/docx4j/wml/CommentRangeEnd::setId → NO_COVERAGE
        commentRangeEnd.setId(id);
352 1 1. newCommentRangeEnd : removed call to org/docx4j/wml/CommentRangeEnd::setParent → NO_COVERAGE
        commentRangeEnd.setParent(parent);
353 1 1. newCommentRangeEnd : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCommentRangeEnd → NO_COVERAGE
        return commentRangeEnd;
354
    }
355
356
    /// Creates a new [R.CommentReference] object with the specified ID and
357
    /// parent.
358
    ///
359
    /// @param id     The unique identifier for the [R.CommentReference].
360
    /// @param parent The parent element ([P]) to which this
361
    ///  [R.CommentReference] belongs.
362
    ///
363
    /// @return A new [R.CommentReference] object with the specified ID and
364
    /// parent.
365
    public static R.CommentReference newCommentReference(
366
            BigInteger id,
367
            ContentAccessor parent
368
    ) {
369
        var commentReference = new R.CommentReference();
370 1 1. newCommentReference : removed call to org/docx4j/wml/R$CommentReference::setId → NO_COVERAGE
        commentReference.setId(id);
371 1 1. newCommentReference : removed call to org/docx4j/wml/R$CommentReference::setParent → NO_COVERAGE
        commentReference.setParent(parent);
372 1 1. newCommentReference : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCommentReference → NO_COVERAGE
        return commentReference;
373
    }
374
375
    /// Creates a new table object.
376
    ///
377
    /// @return A new instance of [Tbl].
378
    public static Tbl newTbl() {
379 1 1. newTbl : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newTbl → NO_COVERAGE
        return new Tbl();
380
    }
381
382
    /// Creates a new cell object.
383
    ///
384
    /// @return A new instance of [Tc].
385
    public static Tc newCell() {
386 1 1. newCell : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCell → NO_COVERAGE
        return new Tc();
387
    }
388
389
    /// Creates a new row object.
390
    ///
391
    /// @return A new instance of [Tr].
392
    public static Tr newRow() {
393 1 1. newRow : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newRow → NO_COVERAGE
        return new Tr();
394
    }
395
396
    /// Creates a new [WordprocessingMLPackage] object initialized with a main
397
    /// document part, and an empty comments part.
398
    ///
399
    /// @return A new instance of [WordprocessingMLPackage].
400
    public static WordprocessingMLPackage newWord() {
401
        try {
402
            var aPackage = WordprocessingMLPackage.createPackage();
403
            var mainDocumentPart = aPackage.getMainDocumentPart();
404
            var cp = newCommentsPart();
405 1 1. newWord : removed call to org/docx4j/openpackaging/parts/WordprocessingML/CommentsPart::init → NO_COVERAGE
            cp.init();
406 1 1. newWord : removed call to org/docx4j/openpackaging/parts/WordprocessingML/CommentsPart::setJaxbElement → NO_COVERAGE
            cp.setJaxbElement(newComments());
407
            mainDocumentPart.addTargetPart(cp);
408 1 1. newWord : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newWord → NO_COVERAGE
            return aPackage;
409
        } catch (InvalidFormatException e) {
410
            throw new UtilsException(e);
411
        }
412
    }
413
414
    /// Creates a new [CommentsPart] object. This method attempts to create a
415
    /// new instance of [CommentsPart]. If an [InvalidFormatException] occurs
416
    ///  during the creation process, it wraps the exception in an
417
    ///  [UtilsException] and throws it.
418
    ///
419
    /// @return A new instance of [CommentsPart].
420
    public static CommentsPart newCommentsPart() {
421
        try {
422 1 1. newCommentsPart : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCommentsPart → NO_COVERAGE
            return new CommentsPart();
423
        } catch (InvalidFormatException e) {
424
            throw new UtilsException(e);
425
        }
426
    }
427
428
    private static Comments newComments() {
429 1 1. newComments : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newComments → NO_COVERAGE
        return new Comments();
430
    }
431
432
    /// Creates a new [Br] (break) object with text wrapping enabled.
433
    ///
434
    /// @return A new [Br] object with text wrapping type and no clear
435
    /// attribute set.
436
    public static Br newBr() {
437
        var br = new Br();
438 1 1. newBr : removed call to org/docx4j/wml/Br::setType → NO_COVERAGE
        br.setType(STBrType.TEXT_WRAPPING);
439 1 1. newBr : removed call to org/docx4j/wml/Br::setClear → NO_COVERAGE
        br.setClear(null);
440 1 1. newBr : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newBr → NO_COVERAGE
        return br;
441
    }
442
443
    /// Creates a new smart tag run with the specified element, run and
444
    /// attribute.
445
    ///
446
    /// @param element   The element name for the smart tag.
447
    /// @param attribute The [CTAttr] to add to the smart tag properties.
448
    /// @param object    The content objects to add to the smart tag.
449
    ///
450
    /// @return A new [CTSmartTagRun] object configured with the specified
451
    /// parameters.
452
    public static CTSmartTagRun newSmartTag(
453
            String element,
454
            CTAttr attribute,
455
            Object... object
456
    ) {
457
        var smartTag = new CTSmartTagRun();
458 1 1. newSmartTag : removed call to org/docx4j/wml/CTSmartTagRun::setElement → NO_COVERAGE
        smartTag.setElement(element);
459
460
        var smartTagPr = new CTSmartTagPr();
461 1 1. newSmartTag : removed call to org/docx4j/wml/CTSmartTagRun::setSmartTagPr → NO_COVERAGE
        smartTag.setSmartTagPr(smartTagPr);
462
463
        var smartTagPrAttr = smartTagPr.getAttr();
464
        smartTagPrAttr.add(attribute);
465
466
        var smartTagContent = smartTag.getContent();
467
        smartTagContent.addAll(asList(object));
468 1 1. newSmartTag : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newSmartTag → NO_COVERAGE
        return smartTag;
469
    }
470
471
    /// Creates a new [CTAttr] object with the specified name and value.
472
    ///
473
    /// @param name  The name of the attribute.
474
    /// @param value The value of the attribute.
475
    ///
476
    /// @return A new [CTAttr] object with the specified name and value.
477
    public static CTAttr newCtAttr(String name, String value) {
478
        var ctAttr = new CTAttr();
479 1 1. newCtAttr : removed call to org/docx4j/wml/CTAttr::setName → NO_COVERAGE
        ctAttr.setName(name);
480 1 1. newCtAttr : removed call to org/docx4j/wml/CTAttr::setVal → NO_COVERAGE
        ctAttr.setVal(value);
481 1 1. newCtAttr : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCtAttr → NO_COVERAGE
        return ctAttr;
482
    }
483
484
    /// Creates a new [Pict] object containing the provided inner object.
485
    ///
486
    /// @param innerObj The object to be included in the new pict element.
487
    ///
488
    /// @return A new [Pict] object containing the provided inner object.
489
    public static Object newPict(Object innerObj) {
490
        var pict = new Pict();
491
        pict.getAnyAndAny()
492
            .add(innerObj);
493 1 1. newPict : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newPict → KILLED
        return pict;
494
    }
495
496
    /// Creates a new [SdtBlock] object containing the provided inner object.
497
    ///
498
    /// @param innerObj The object to be included in the new structured
499
    /// document tag block.
500
    ///
501
    /// @return A new [SdtBlock] object containing the provided inner object.
502
    public static SdtBlock newSdtBlock(Object innerObj) {
503
        var block = new SdtContentBlock();
504
        var blockContent = block.getContent();
505
        blockContent.add(innerObj);
506
        var sdtBlock = new SdtBlock();
507 1 1. newSdtBlock : removed call to org/docx4j/wml/SdtBlock::setSdtContent → KILLED
        sdtBlock.setSdtContent(block);
508 1 1. newSdtBlock : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newSdtBlock → KILLED
        return sdtBlock;
509
    }
510
511
    /// Creates a new [SdtRun] object containing the provided inner object.
512
    ///
513
    /// @param innerObj The object to be included in the new structured
514
    /// document tag run.
515
    ///
516
    /// @return A new [SdtRun] object containing the provided inner object.
517
    public static SdtRun newSdtRun(Object innerObj) {
518
        var sdtContentRun = new CTSdtContentRun();
519
        var sdtContentRunContent = sdtContentRun.getContent();
520
        sdtContentRunContent.add(innerObj);
521
        var sdtRun = new SdtRun();
522 1 1. newSdtRun : removed call to org/docx4j/wml/SdtRun::setSdtContent → KILLED
        sdtRun.setSdtContent(sdtContentRun);
523 1 1. newSdtRun : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newSdtRun → KILLED
        return sdtRun;
524
    }
525
526
    /// Creates a new SVG inline object for use in a WordprocessingML document.
527
    ///
528
    /// @param relationship The relationship object containing the unique
529
    /// identifier of the resource to be embedded.
530
    /// @param altText      The alternative text for the SVG image, used for
531
    /// accessibility purposes.
532
    /// @param filenameHint The suggested filename for the SVG image.
533
    /// @param scale        The scale dimensions (cx and cy) for the SVG image,
534
    /// defining its size in the document.
535
    ///
536
    /// @return A new instance of `Inline` containing the SVG image data.
537
    ///
538
    /// @throws JAXBException If there is an error during the marshalling or
539
    /// unmarshalling of XML.
540
    public static Inline newSVGInline(
541
            Relationship relationship,
542
            String altText,
543
            String filenameHint,
544
            Scale scale
545
    )
546
            throws JAXBException {
547
        String template = """
548
                <wp:inline distB="0" distL="0" distR="0" distT="0"
549
                xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
550
                                  xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
551
                                  xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
552
                                  xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"
553
                                  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
554
                  <wp:extent cx="${cx}" cy="${cy}"/>
555
                  <wp:effectExtent b="0" l="0" r="0" t="0"/>
556
                  <wp:docPr id="${id1}" name="${filenameHint}" descr="${altText}"/>
557
                  <wp:cNvGraphicFramePr>
558
                    <a:graphicFrameLocks noChangeAspect="true"/>
559
                  </wp:cNvGraphicFramePr>
560
                  <a:graphic>
561
                    <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
562
                      <pic:pic>
563
                        <pic:nvPicPr>
564
                          <pic:cNvPr id="${id2}" name="${filenameHint}"/>
565
                          <pic:cNvPicPr/>
566
                        </pic:nvPicPr>
567
                        <pic:blipFill>
568
                          <a:blip>
569
                            <a:extLst>
570
                              <a:ext uri="{96DAC541-7B7A-43D3-8B79-37D633B846F1}">
571
                                <asvg:svgBlip
572
                                  xmlns:asvg="http://schemas.microsoft.com/office/drawing/2016/SVG/main"
573
                                  r:embed="${relId}"/>
574
                              </a:ext>
575
                            </a:extLst>
576
                          </a:blip>
577
                          <a:stretch><a:fillRect/></a:stretch>
578
                        </pic:blipFill>
579
                        <pic:spPr>
580
                          <a:xfrm>
581
                            <a:off x="0" y="0"/>
582
                            <a:ext cx="${cx}" cy="${cy}"/>
583
                          </a:xfrm>
584
                          <a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
585
                        </pic:spPr>
586
                      </pic:pic>
587
                    </a:graphicData>
588
                  </a:graphic>
589
                </wp:inline>
590
                """;
591
592
        var id1 = RANDOM.nextLong(100_000L);
593
        var id2 = RANDOM.nextInt(100_000);
594
595
        var mappings = new HashMap<String, String>();
596
        mappings.put("cx", Long.toString(scale.cx()));
597
        mappings.put("cy", Long.toString(scale.cy()));
598
        mappings.put("id1", Long.toString(id1));
599
        mappings.put("id2", Integer.toString(id2));
600
        mappings.put("filenameHint", filenameHint);
601
        mappings.put("altText", altText);
602
        mappings.put("relId", relationship.getId());
603
604
        var jaxbElement = (JAXBElement<?>) XmlUtils.unmarshallFromTemplate(
605
                template,
606
                mappings);
607 1 1. newSVGInline : replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newSVGInline → NO_COVERAGE
        return (Inline) jaxbElement.getValue();
608
    }
609
610
    /// Represents a scale with two long values as its center coordinates.
611
    /// The scale is defined by its x-coordinate (cx) and y-coordinate (cy).
612
    /// This record class is immutable and encapsulates the coordinate data.
613
    ///
614
    /// @param cx The x-coordinate of the scale's center.
615
    /// @param cy The y-coordinate of the scale's center.
616
    public record Scale(long cx, long cy) {}
617
}

Mutations

43

1.1
Location : newComment
Killed by : none
removed call to org/docx4j/wml/Comments$Comment::setId → NO_COVERAGE

46

1.1
Location : newComment
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newComment → NO_COVERAGE

55

1.1
Location : newParagraph
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newParagraph → NO_COVERAGE

64

1.1
Location : newParagraph
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newParagraph → NO_COVERAGE

73

1.1
Location : newRun
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newRun → NO_COVERAGE

86

1.1
Location : newParagraph
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newParagraph → NO_COVERAGE

95

1.1
Location : newRun
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newRun → NO_COVERAGE

106

1.1
Location : newText
Killed by : none
removed call to org/docx4j/wml/Text::setValue → NO_COVERAGE

107

1.1
Location : newText
Killed by : none
removed call to org/docx4j/wml/Text::setSpace → NO_COVERAGE

108

1.1
Location : newText
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newText → NO_COVERAGE

124

1.1
Location : newRun
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newRun → NO_COVERAGE

128

1.1
Location : worthKeeping
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : worthKeeping
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlFactory::worthKeeping → NO_COVERAGE

3.3
Location : worthKeeping
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlFactory::worthKeeping → NO_COVERAGE

129

1.1
Location : worthKeeping
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlFactory::worthKeeping → NO_COVERAGE

134

1.1
Location : worthKeeping
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : worthKeeping
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlFactory::worthKeeping → NO_COVERAGE

146

1.1
Location : newBody
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newBody → NO_COVERAGE

156

1.1
Location : newParagraph
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newParagraph → NO_COVERAGE

165

1.1
Location : newPPr
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newPPr → NO_COVERAGE

180

1.1
Location : newComments
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newComments → NO_COVERAGE

256

1.1
Location : newImgInline
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newImgInline → NO_COVERAGE

278

1.1
Location : computeScale
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : computeScale
Killed by : none
negated conditional → NO_COVERAGE

3.3
Location : computeScale
Killed by : none
changed conditional boundary → NO_COVERAGE

4.4
Location : computeScale
Killed by : none
negated conditional → NO_COVERAGE

286

1.1
Location : computeScale
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : computeScale
Killed by : none
negated conditional → NO_COVERAGE

288

1.1
Location : computeScale
Killed by : none
Replaced double division with multiplication → NO_COVERAGE

2.2
Location : computeScale
Killed by : none
Replaced double multiplication with division → NO_COVERAGE

295

1.1
Location : computeScale
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::computeScale → NO_COVERAGE

304

1.1
Location : newRun
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newRun → NO_COVERAGE

317

1.1
Location : newDrawing
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newDrawing → NO_COVERAGE

334

1.1
Location : newCommentRangeStart
Killed by : none
removed call to org/docx4j/wml/CommentRangeStart::setId → NO_COVERAGE

335

1.1
Location : newCommentRangeStart
Killed by : none
removed call to org/docx4j/wml/CommentRangeStart::setParent → NO_COVERAGE

336

1.1
Location : newCommentRangeStart
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCommentRangeStart → NO_COVERAGE

351

1.1
Location : newCommentRangeEnd
Killed by : none
removed call to org/docx4j/wml/CommentRangeEnd::setId → NO_COVERAGE

352

1.1
Location : newCommentRangeEnd
Killed by : none
removed call to org/docx4j/wml/CommentRangeEnd::setParent → NO_COVERAGE

353

1.1
Location : newCommentRangeEnd
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCommentRangeEnd → NO_COVERAGE

370

1.1
Location : newCommentReference
Killed by : none
removed call to org/docx4j/wml/R$CommentReference::setId → NO_COVERAGE

371

1.1
Location : newCommentReference
Killed by : none
removed call to org/docx4j/wml/R$CommentReference::setParent → NO_COVERAGE

372

1.1
Location : newCommentReference
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCommentReference → NO_COVERAGE

379

1.1
Location : newTbl
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newTbl → NO_COVERAGE

386

1.1
Location : newCell
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCell → NO_COVERAGE

393

1.1
Location : newRow
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newRow → NO_COVERAGE

405

1.1
Location : newWord
Killed by : none
removed call to org/docx4j/openpackaging/parts/WordprocessingML/CommentsPart::init → NO_COVERAGE

406

1.1
Location : newWord
Killed by : none
removed call to org/docx4j/openpackaging/parts/WordprocessingML/CommentsPart::setJaxbElement → NO_COVERAGE

408

1.1
Location : newWord
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newWord → NO_COVERAGE

422

1.1
Location : newCommentsPart
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCommentsPart → NO_COVERAGE

429

1.1
Location : newComments
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newComments → NO_COVERAGE

438

1.1
Location : newBr
Killed by : none
removed call to org/docx4j/wml/Br::setType → NO_COVERAGE

439

1.1
Location : newBr
Killed by : none
removed call to org/docx4j/wml/Br::setClear → NO_COVERAGE

440

1.1
Location : newBr
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newBr → NO_COVERAGE

458

1.1
Location : newSmartTag
Killed by : none
removed call to org/docx4j/wml/CTSmartTagRun::setElement → NO_COVERAGE

461

1.1
Location : newSmartTag
Killed by : none
removed call to org/docx4j/wml/CTSmartTagRun::setSmartTagPr → NO_COVERAGE

468

1.1
Location : newSmartTag
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newSmartTag → NO_COVERAGE

479

1.1
Location : newCtAttr
Killed by : none
removed call to org/docx4j/wml/CTAttr::setName → NO_COVERAGE

480

1.1
Location : newCtAttr
Killed by : none
removed call to org/docx4j/wml/CTAttr::setVal → NO_COVERAGE

481

1.1
Location : newCtAttr
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newCtAttr → NO_COVERAGE

493

1.1
Location : newPict
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testNextHandlesPictStructure()]
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newPict → KILLED

507

1.1
Location : newSdtBlock
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testNextHandlesSdtBlockStructure()]
removed call to org/docx4j/wml/SdtBlock::setSdtContent → KILLED

508

1.1
Location : newSdtBlock
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testNextHandlesSdtBlockStructure()]
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newSdtBlock → KILLED

522

1.1
Location : newSdtRun
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testNextHandlesSdtRunStructure()]
removed call to org/docx4j/wml/SdtRun::setSdtContent → KILLED

523

1.1
Location : newSdtRun
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testNextHandlesSdtRunStructure()]
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newSdtRun → KILLED

607

1.1
Location : newSVGInline
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlFactory::newSVGInline → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.25.5 support