PptxIterator.java

1
package pro.verron.officestamper.utils.pml;
2
3
import org.docx4j.openpackaging.exceptions.Docx4JException;
4
import org.docx4j.openpackaging.packages.PresentationMLPackage;
5
import org.docx4j.openpackaging.parts.PresentationML.SlidePart;
6
import org.docx4j.wml.ContentAccessor;
7
import org.docx4j.wml.SdtBlock;
8
import org.docx4j.wml.SdtRun;
9
import org.jspecify.annotations.Nullable;
10
import org.pptx4j.Pptx4jException;
11
import org.pptx4j.pml.Shape;
12
import org.slf4j.Logger;
13
import org.slf4j.LoggerFactory;
14
import pro.verron.officestamper.utils.UtilsException;
15
import pro.verron.officestamper.utils.iterator.ResetableIterator;
16
17
import java.util.*;
18
import java.util.function.Supplier;
19
20
import static org.docx4j.XmlUtils.unwrap;
21
22
/// An iterator implementation for traversing PowerPoint presentation content. This class provides a way to iterate
23
/// through all content elements in a PowerPoint file, including slides, shapes, text blocks, and other document
24
/// structure elements.
25
///
26
/// The iterator handles the complex hierarchical structure of PowerPoint presentations and provides a flat iteration
27
/// interface over all content objects.
28
///
29
/// @author verron
30
/// @since 3.0
31
public class PptxIterator
32
        implements ResetableIterator<Object> {
33
34
    private static final Logger log = LoggerFactory.getLogger(PptxIterator.class);
35
    private final Supplier<Iterator<?>> supplier;
36
    private Queue<Iterator<?>> iteratorQueue;
37
    private @Nullable Object next;
38
39
    /// Constructs a new PptxIterator for the given presentation package.
40
    ///
41
    /// @param presentation the PowerPoint presentation package to iterate through
42
    /// @throws UtilsException if there is an error accessing the presentation structure
43
    public PptxIterator(PresentationMLPackage presentation) {
44
        try {
45
            var mainPresentationPart = presentation.getMainPresentationPart();
46
            var slideParts = mainPresentationPart.getSlideParts();
47
            supplier = slideParts::iterator;
48
        } catch (Pptx4jException e) {
49
            throw new UtilsException(e);
50
        }
51
        var startingIterator = supplier.get();
52
        this.iteratorQueue = Collections.asLifoQueue(new ArrayDeque<>());
53
        this.iteratorQueue.add(startingIterator);
54 1 1. <init> : negated conditional → NO_COVERAGE
        this.next = startingIterator.hasNext() ? unwrap(startingIterator.next()) : null;
55
    }
56
57
    @Override
58
    public void reset() {
59
        var startingIterator = supplier.get();
60
        this.iteratorQueue = Collections.asLifoQueue(new ArrayDeque<>());
61
        this.iteratorQueue.add(startingIterator);
62 1 1. reset : negated conditional → NO_COVERAGE
        this.next = startingIterator.hasNext() ? unwrap(startingIterator.next()) : null;
63
    }
64
65
    @Override
66
    public boolean hasNext() {
67 2 1. hasNext : replaced boolean return with true for pro/verron/officestamper/utils/pml/PptxIterator::hasNext → NO_COVERAGE
2. hasNext : negated conditional → NO_COVERAGE
        return next != null;
68
    }
69
70
    @Override
71
    public Object next() {
72 1 1. next : negated conditional → NO_COVERAGE
        if (next == null) throw new NoSuchElementException("No more elements to iterate");
73
74
        var result = next;
75
        next = null;
76
        switch (result) {
77
            case ContentAccessor contentAccessor -> {
78
                var content = contentAccessor.getContent();
79
                iteratorQueue.add(content.iterator());
80
            }
81
            case SdtRun sdtRun -> {
82
                var sdtContent = sdtRun.getSdtContent();
83
                var content = sdtContent.getContent();
84
                iteratorQueue.add(content.iterator());
85
            }
86
            case SdtBlock sdtBlock -> {
87
                var sdtContent = sdtBlock.getSdtContent();
88
                var content = sdtContent.getContent();
89
                iteratorQueue.add(content.iterator());
90
            }
91
            case SlidePart slidePart -> {
92
                List<Object> content;
93
                try {
94
                    content = slidePart.getContents()
95
                                       .getCSld()
96
                                       .getSpTree()
97
                                       .getSpOrGrpSpOrGraphicFrame();
98
                } catch (Docx4JException e) {
99
                    throw new UtilsException(e);
100
                }
101
                iteratorQueue.add(content.iterator());
102
            }
103
            case Shape shape -> {
104 1 1. next : negated conditional → NO_COVERAGE
                if (shape.getTxBody() != null) {
105
                    var content = shape.getTxBody()
106
                                       .getP();
107
                    iteratorQueue.add(content.iterator());
108
                }
109
            }
110
            default -> log.debug("Unknown type: {}", result.getClass());
111
        }
112 2 1. next : negated conditional → NO_COVERAGE
2. next : negated conditional → NO_COVERAGE
        while (!iteratorQueue.isEmpty() && next == null) {
113
            var nextIterator = iteratorQueue.poll();
114 1 1. next : negated conditional → NO_COVERAGE
            if (nextIterator.hasNext()) {
115
                next = unwrap(nextIterator.next());
116
                iteratorQueue.add(nextIterator);
117
            }
118
        }
119 1 1. next : replaced return value with null for pro/verron/officestamper/utils/pml/PptxIterator::next → NO_COVERAGE
        return result;
120
    }
121
}

Mutations

54

1.1
Location : <init>
Killed by : none
negated conditional → NO_COVERAGE

62

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

67

1.1
Location : hasNext
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/pml/PptxIterator::hasNext → NO_COVERAGE

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

72

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

104

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

112

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

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

114

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

119

1.1
Location : next
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/pml/PptxIterator::next → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.25.5 support