This is an automated email from the ASF dual-hosted git repository.
fanningpj pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git
The following commit(s) were added to refs/heads/trunk by this push:
new 4b3c688d51 Add methods to manage first slide number(firstSlideNum)
(#968)
4b3c688d51 is described below
commit 4b3c688d51d03b8706d97d0589cc8985d661dd94
Author: hyun1024 <[email protected]>
AuthorDate: Sat Dec 13 21:06:04 2025 +0900
Add methods to manage first slide number(firstSlideNum) (#968)
* Add methods to manage first slide number(firstSlideNum)
Adds methods to manage the custom starting slide number in XSLF
(PowerPoint) presentations. This property is stored as the 'firstSlideNum'
attribute in ppt/presentation.xml.
The following methods are added to XMLSlideShow:
- getFirstSlideNumber(): Retrieves the current starting slide number
(default is 1).
- setFirstSlideNumber(int num): Sets the custom starting slide number.
- unsetFirstSlideNumber(): Removes the 'firstSlideNum' attribute, reverting
to the default (1).
Constraints:
The 'set' method enforces the bounds [0, 9999] as defined by Microsoft's
implementation specifications (MS-OI29500, Part 1, Section 19.2.1.26) to ensure
the creation of valid PowerPoint files.
Also includes TestXSLFSlideShow updates to cover the new functionality,
persistence, and validation checks.
* Review: Apply review feedback to firstSlideNumber feature
- Add @since 6.0.0 Javadoc tag to getFirstSlideNumber(),
setFirstSlideNumber(), and unsetFirstSlideNumber() methods in XMLSlideShow.
- Refactor TestXSLFSlideShow to use explicit static JUnit imports (e.g.,
assertEquals, assertThrows) instead of wildcard imports, adhering to project
coding style guidelines.
* whitespace
---------
Co-authored-by: PJ Fanning <[email protected]>
---
.../apache/poi/xslf/usermodel/XMLSlideShow.java | 47 ++++++++++
.../poi/xslf/usermodel/TestXSLFSlideShow.java | 102 ++++++++++++++++++++-
2 files changed, 145 insertions(+), 4 deletions(-)
diff --git
a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
index 63cea1a76c..44585f8b77 100644
--- a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
+++ b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
@@ -748,4 +748,51 @@ public class XMLSlideShow extends POIXMLDocument
RelationPart rp = target.addRelation(null, XSLFRelation.IMAGES,
pictureData);
return rp.getRelationship().getId();
}
+
+ /**
+ * Returns the number that shall be displayed on the first slide of the
presentation.
+ * Subsequent slides will be numbered sequentially from this number.
+ * The default value is 1 if the property is not set in the presentation
file.
+ *
+ * @return The starting number for the first slide (default is 1).
+ * @since 6.0.0
+ */
+ public int getFirstSlideNumber() {
+ // CTPresentation.getFirstSlideNum() returns the default value of 1
+ // if the 'firstSlideNum' attribute is not set, as per OOXML standard.
+ return getCTPresentation().getFirstSlideNum();
+ }
+
+ /**
+ * Sets the custom number that shall be displayed on the first slide of
the presentation.
+ * Subsequent slides will be numbered sequentially from this number.
+ *
+ * The value is restricted to the range [0, 9999] as defined in the
Microsoft Office
+ * Implementation Information for ISO/IEC 29500 (MS-OI29500), specifically
in
+ * Part 1, Section 19.2.1.26, presentation (Presentation), which restricts
the
+ * XML Schema int datatype.
+ *
+ * @param num The starting number for the first slide (must be between 0
and 9999).
+ * @throws IllegalArgumentException if the provided number is outside the
allowed range [0, 9999].
+ * @since 6.0.0
+ */
+ public void setFirstSlideNumber(int num) {
+ // We enforce the PowerPoint application constraint (0 <= num <= 9999)
+ // to ensure that a valid file, as rendered by PowerPoint, is created.
+ if (num < 0 || num > 9999) {
+ throw new IllegalArgumentException(
+ "First slide number must be between 0 and 9999
(inclusive), as required by MS-OI29500 (Part 1, Section 19.2.1.26).");
+ }
+ // Sets the attribute on the underlying CTPresentation object.
+ getCTPresentation().setFirstSlideNum(num);
+ }
+
+ /**
+ * Unsets the custom first slide number, reverting the numbering to the
default (1).
+ * This removes the 'firstSlideNum' attribute from presentation.xml.
+ * @since 6.0.0
+ */
+ public void unsetFirstSlideNumber() {
+ getCTPresentation().unsetFirstSlideNum();
+ }
}
diff --git
a/poi-ooxml/src/test/java/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java
b/poi-ooxml/src/test/java/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java
index 45e2aa31c2..312c804a3f 100644
---
a/poi-ooxml/src/test/java/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java
+++
b/poi-ooxml/src/test/java/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java
@@ -16,10 +16,6 @@
==================================================================== */
package org.apache.poi.xslf.usermodel;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertSame;
-
import java.awt.Dimension;
import java.awt.Rectangle;
import java.io.ByteArrayInputStream;
@@ -34,6 +30,12 @@ import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.xslf.XSLFTestDataSamples;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
class TestXSLFSlideShow {
@Test
void testCreateSlide() throws IOException {
@@ -327,4 +329,96 @@ class TestXSLFSlideShow {
}
}
}
+
+ /**
+ * Test getting the first slide number, which defaults to 1.
+ * The first slide number is stored in the presentation.xml part.
+ */
+ @Test
+ void testGetFirstSlideNumberDefault() throws IOException {
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ // Default value when attribute is not present should be 1 (as per
OOXML standard and CTPresentation logic)
+ assertEquals(1, ppt.getFirstSlideNumber());
+ }
+ }
+
+ /**
+ * Test setting, getting, and persisting the custom first slide number.
+ */
+ @Test
+ void testSetAndPersistFirstSlideNumber() throws IOException {
+ final int customStartNum = 5;
+ final int zeroStartNum = 0;
+ final int maxStartNum = 9999;
+
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ // 1. Set to a custom positive number (e.g., 5)
+ ppt.setFirstSlideNumber(customStartNum);
+ assertEquals(customStartNum, ppt.getFirstSlideNumber());
+
+ // Check persistence by writing out and reading back
+ try (XMLSlideShow ppt2 =
XSLFTestDataSamples.writeOutAndReadBack(ppt)) {
+ assertEquals(customStartNum, ppt2.getFirstSlideNumber(),
+ "The custom first slide number should persist after
save/load.");
+ }
+
+ // 2. Set to minimum valid number (0)
+ ppt.setFirstSlideNumber(zeroStartNum);
+ assertEquals(zeroStartNum, ppt.getFirstSlideNumber());
+
+ // 3. Set to maximum valid number (9999)
+ ppt.setFirstSlideNumber(maxStartNum);
+ assertEquals(maxStartNum, ppt.getFirstSlideNumber());
+ }
+ }
+
+ /**
+ * Test unsetting the first slide number, which should revert it to the
default (1).
+ */
+ @Test
+ void testUnsetFirstSlideNumber() throws IOException {
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ // 1. Set a custom number
+ ppt.setFirstSlideNumber(50);
+ assertEquals(50, ppt.getFirstSlideNumber());
+
+ // 2. Unset it
+ ppt.unsetFirstSlideNumber();
+
+ // It should return the default value (1) after unsetting
+ assertEquals(1, ppt.getFirstSlideNumber(),
+ "Unsetting the first slide number should revert it to the
default of 1.");
+
+ // Check persistence after unsetting
+ try (XMLSlideShow ppt2 =
XSLFTestDataSamples.writeOutAndReadBack(ppt)) {
+ assertEquals(1, ppt2.getFirstSlideNumber(),
+ "The first slide number should remain the default (1)
after unset and save/load.");
+ // Ensure the attribute is actually removed from the
CTPresentation object
+ // Note: We access the internal object to confirm removal,
which is acceptable in test code.
+ assertFalse(ppt2.getCTPresentation().isSetFirstSlideNum(),
+ "The 'firstSlideNum' attribute should be unset
(removed) in the XML.");
+ }
+ }
+ }
+
+ /**
+ * Test that setting an invalid first slide number (outside [0, 9999])
throws an exception.
+ */
+ @Test
+ void testSetFirstSlideNumberValidation() throws IOException {
+ try (XMLSlideShow ppt = new XMLSlideShow()) {
+ // Test case: Negative number
+ assertThrows(IllegalArgumentException.class, () ->
+ ppt.setFirstSlideNumber(-1),
+ "Negative number should throw IllegalArgumentException.");
+
+ // Test case: Number greater than 9999
+ assertThrows(IllegalArgumentException.class, () ->
+ ppt.setFirstSlideNumber(10000),
+ "Number greater than 9999 should throw
IllegalArgumentException.");
+
+ // Ensure the value hasn't changed from the default after failed
attempts
+ assertEquals(1, ppt.getFirstSlideNumber());
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]