]> source.dussan.org Git - poi.git/commitdiff
#64036 - Replace reflection calls in factories for Java 9+
authorAndreas Beeker <kiwiwings@apache.org>
Sat, 16 Oct 2021 00:00:50 +0000 (00:00 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sat, 16 Oct 2021 00:00:50 +0000 (00:00 +0000)
use ServiceLoader for HSLF Metro Shapes

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1894298 13f79535-47bb-0310-9956-ffa450edef68

17 files changed:
poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFMetroShape.java
poi-ooxml/src/main/java9/module-info.class
poi-ooxml/src/main/java9/module-info.java
poi-ooxml/src/main/resources/META-INF/services/org.apache.poi.sl.usermodel.MetroShapeProvider [new file with mode: 0644]
poi-ooxml/src/test/java/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java
poi-ooxml/src/test/java9/module-info.class
poi-ooxml/src/test/java9/module-info.java
poi-scratchpad/src/main/java/org/apache/poi/hslf/model/HSLFMetroShape.java
poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFTextRun.java
poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFTextShape.java
poi-scratchpad/src/main/java9/module-info.class
poi-scratchpad/src/main/java9/module-info.java
poi-scratchpad/src/test/java9/module-info.class
poi-scratchpad/src/test/java9/module-info.java
poi/src/main/java/org/apache/poi/sl/usermodel/MetroShapeProvider.java [new file with mode: 0644]
poi/src/test/java9/module-info.class
poi/src/test/java9/module-info.java

index 69931a2e91ef5fe2fa3019642eb00bdd75079715..5912d0574523c9d6b603b1df39a206e67defa518 100644 (file)
@@ -28,7 +28,7 @@ import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.openxml4j.opc.PackagePartName;
 import org.apache.poi.openxml4j.opc.PackagingURIHelper;
-import org.apache.poi.sl.usermodel.Shape;
+import org.apache.poi.sl.usermodel.MetroShapeProvider;
 import org.apache.poi.util.Internal;
 import org.apache.xmlbeans.XmlException;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
@@ -39,18 +39,21 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
  * This is the helper class for HSLFMetroShape to dive into OOXML classes
  */
 @Internal
-public class XSLFMetroShape {
-    /*
-     * parses the metro bytes to a XSLF shape
-     */
-    public static Shape<?,?> parseShape(byte[] metroBytes)
-    throws InvalidFormatException, IOException, XmlException {
-        PackagePartName shapePN = PackagingURIHelper.createPartName("/drs/shapexml.xml");
+public class XSLFMetroShape implements MetroShapeProvider {
+    /** parses the metro bytes to a XSLF shape */
+    @Override
+    public XSLFShape parseShape(byte[] metroBytes) throws IOException {
         try (OPCPackage pkg = OPCPackage.open(new UnsynchronizedByteArrayInputStream(metroBytes))) {
+            PackagePartName shapePN = PackagingURIHelper.createPartName("/drs/shapexml.xml");
             PackagePart shapePart = pkg.getPart(shapePN);
+            if (shapePart == null) {
+                return null;
+            }
             CTGroupShape gs = CTGroupShape.Factory.parse(shapePart.getInputStream(), DEFAULT_XML_OPTIONS);
             XSLFGroupShape xgs = new XSLFGroupShape(gs, null);
             return xgs.getShapes().get(0);
+        } catch (InvalidFormatException | XmlException e) {
+            throw new IOException("can't parse metro shape", e);
         }
     }
 }
index f4db29c6148bb418b977c028df8257512d4751e3..d79f2de6431f38013e21697e5598c837378448fc 100644 (file)
Binary files a/poi-ooxml/src/main/java9/module-info.class and b/poi-ooxml/src/main/java9/module-info.class differ
index b11e2a9ebed0713889ce4447e87024aeca6986c0..51533acbd6ae422268845a6a265adebd2d29e48f 100644 (file)
@@ -34,6 +34,7 @@ module org.apache.poi.ooxml {
     provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.xssf.usermodel.XSSFWorkbookFactory;
     provides org.apache.poi.sl.usermodel.SlideShowProvider with org.apache.poi.xslf.usermodel.XSLFSlideShowFactory;
     provides org.apache.poi.sl.draw.ImageRenderer with org.apache.poi.xslf.draw.SVGImageRenderer;
+    provides org.apache.poi.sl.usermodel.MetroShapeProvider with org.apache.poi.xslf.usermodel.XSLFMetroShape;
 
     exports org.apache.poi.xwpf.extractor;
     exports org.apache.poi.xwpf.usermodel;
diff --git a/poi-ooxml/src/main/resources/META-INF/services/org.apache.poi.sl.usermodel.MetroShapeProvider b/poi-ooxml/src/main/resources/META-INF/services/org.apache.poi.sl.usermodel.MetroShapeProvider
new file mode 100644 (file)
index 0000000..ba99414
--- /dev/null
@@ -0,0 +1,18 @@
+# ====================================================================
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+# ====================================================================
+
+org.apache.poi.xslf.usermodel.XSLFMetroShape
\ No newline at end of file
index 372e0216f4a22b3c0fb3722b1877c34461f067c9..397db98d12c64acc4596f09b012e52a585d70d66 100644 (file)
 package org.apache.poi.xslf.usermodel;
 
 import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
+import static org.apache.poi.sl.usermodel.TextRun.FieldType.DATE_TIME;
+import static org.apache.poi.sl.usermodel.TextRun.FieldType.SLIDE_NUMBER;
 import static org.apache.poi.xslf.usermodel.TestXSLFSimpleShape.getSpPr;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -27,17 +30,23 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assumptions.assumeFalse;
 
 import java.awt.Color;
-import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 import org.apache.poi.POIDataSamples;
+import org.apache.poi.sl.usermodel.MasterSheet;
 import org.apache.poi.sl.usermodel.Placeholder;
 import org.apache.poi.sl.usermodel.Shape;
 import org.apache.poi.sl.usermodel.SlideShow;
 import org.apache.poi.sl.usermodel.SlideShowFactory;
+import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
+import org.apache.poi.sl.usermodel.TextRun;
+import org.apache.poi.sl.usermodel.TextRun.FieldType;
+import org.apache.poi.sl.usermodel.TextShape;
 import org.apache.poi.sl.usermodel.VerticalAlignment;
 import org.apache.poi.xddf.usermodel.text.XDDFBodyProperties;
 import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
@@ -66,19 +75,19 @@ class TestXSLFTextShape {
 
     @Test
     void testLayouts() throws IOException {
-        XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("layouts.pptx");
+        try (XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("layouts.pptx")) {
 
-        List<XSLFSlide> slide = ppt.getSlides();
+            List<XSLFSlide> slide = ppt.getSlides();
 
-        verifySlide1(slide.get(0));
-        verifySlide2(slide.get(1));
-        verifySlide3(slide.get(2));
-        verifySlide4(slide.get(3));
-        verifySlide7(slide.get(6));
-        verifySlide8(slide.get(7));
-        verifySlide10(slide.get(9));
+            verifySlide1(slide.get(0));
+            verifySlide2(slide.get(1));
+            verifySlide3(slide.get(2));
+            verifySlide4(slide.get(3));
+            verifySlide7(slide.get(6));
+            verifySlide8(slide.get(7));
+            verifySlide10(slide.get(9));
 
-        ppt.close();
+        }
     }
 
     void verifySlide1(XSLFSlide slide){
@@ -90,7 +99,7 @@ class TestXSLFTextShape {
         XDDFTextBody tb1 = shape1.getTextBody();
         XDDFBodyProperties tbp1 = tb1.getBodyProperties();
         CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false);
-        assertEquals(STPlaceholderType.CTR_TITLE, ph1.getType());
+        assertSame(STPlaceholderType.CTR_TITLE, ph1.getType());
         // anchor is not defined in the shape
         assertNull(getSpPr(shape1).getXfrm());
 
@@ -129,7 +138,7 @@ class TestXSLFTextShape {
         XDDFTextBody tb2 = shape2.getTextBody();
         XDDFBodyProperties tbp2 = tb2.getBodyProperties();
         CTPlaceholder ph2 = shape2.getPlaceholderDetails().getCTPlaceholder(false);
-        assertEquals(STPlaceholderType.SUB_TITLE, ph2.getType());
+        assertSame(STPlaceholderType.SUB_TITLE, ph2.getType());
         // anchor is not defined in the shape
         assertNull(getSpPr(shape2).getXfrm());
 
@@ -171,7 +180,7 @@ class TestXSLFTextShape {
 
         XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0);
         CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false);
-        assertEquals(STPlaceholderType.TITLE, ph1.getType());
+        assertSame(STPlaceholderType.TITLE, ph1.getType());
         // anchor is not defined in the shape
         assertNull(getSpPr(shape1).getXfrm());
 
@@ -284,7 +293,7 @@ class TestXSLFTextShape {
 
         XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0);
         CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false);
-        assertEquals(STPlaceholderType.TITLE, ph1.getType());
+        assertSame(STPlaceholderType.TITLE, ph1.getType());
         // anchor is not defined in the shape
         assertNull(getSpPr(shape1).getXfrm());
 
@@ -318,7 +327,7 @@ class TestXSLFTextShape {
 
         XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
         CTPlaceholder ph2 = shape2.getPlaceholderDetails().getCTPlaceholder(false);
-        assertEquals(STPlaceholderType.BODY, ph2.getType());
+        assertSame(STPlaceholderType.BODY, ph2.getType());
         // anchor is not defined in the shape
         assertNull(getSpPr(shape2).getXfrm());
 
@@ -355,7 +364,7 @@ class TestXSLFTextShape {
 
         XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0);
         CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false);
-        assertEquals(STPlaceholderType.TITLE, ph1.getType());
+        assertSame(STPlaceholderType.TITLE, ph1.getType());
         // anchor is not defined in the shape
         assertNull(getSpPr(shape1).getXfrm());
 
@@ -470,7 +479,7 @@ class TestXSLFTextShape {
 
         XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0);
         CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false);
-        assertEquals(STPlaceholderType.TITLE, ph1.getType());
+        assertSame(STPlaceholderType.TITLE, ph1.getType());
         // anchor is not defined in the shape
         assertNull(getSpPr(shape1).getXfrm());
 
@@ -538,7 +547,7 @@ class TestXSLFTextShape {
 
         XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0);
         CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false);
-        assertEquals(STPlaceholderType.TITLE, ph1.getType());
+        assertSame(STPlaceholderType.TITLE, ph1.getType());
         // anchor is not defined in the shape
         assertNull(getSpPr(shape1).getXfrm());
 
@@ -664,301 +673,313 @@ class TestXSLFTextShape {
 
     @Test
     void testTitleStyles() throws IOException {
-        XMLSlideShow ppt = new XMLSlideShow();
-
-        XSLFSlideMaster master = ppt.getSlideMasters().get(0);
-        XSLFTheme theme = master.getTheme();
-        XSLFSlideLayout layout = master.getLayout(SlideLayout.TITLE);
-        XSLFSlide slide = ppt.createSlide(layout) ;
-        assertSame(layout, slide.getSlideLayout());
-        assertSame(master, slide.getSlideMaster());
-
-        XSLFTextShape titleShape = slide.getPlaceholder(0);
-        titleShape.setText("Apache POI");
-        XSLFTextParagraph paragraph = titleShape.getTextParagraphs().get(0);
-        XSLFTextRun textRun = paragraph.getTextRuns().get(0);
-
-        // level 1 : default title style on the master slide
-        // /p:sldMaster/p:txStyles/p:titleStyle/a:lvl1pPr
-        CTTextParagraphProperties lv1PPr = master.getXmlObject().getTxStyles().getTitleStyle().getLvl1PPr();
-        CTTextCharacterProperties lv1CPr = lv1PPr.getDefRPr();
-        assertEquals(4400, lv1CPr.getSz());
-        assertEquals(44.0, textRun.getFontSize(), 0);
-        assertEquals("+mj-lt", lv1CPr.getLatin().getTypeface());
-        assertEquals("Calibri", theme.getMajorFont());
-        assertEquals("Calibri", textRun.getFontFamily());
-        lv1CPr.setSz(3200);
-        assertEquals(32.0, textRun.getFontSize(), 0);
-        lv1CPr.getLatin().setTypeface("Arial");
-        assertEquals("Arial", textRun.getFontFamily());
-        assertEquals(STTextAlignType.CTR, lv1PPr.getAlgn());
-        assertEquals(TextAlign.CENTER, paragraph.getTextAlign());
-        lv1PPr.setAlgn(STTextAlignType.L);
-        assertEquals(TextAlign.LEFT, paragraph.getTextAlign());
-
-        // level 2: title placeholder on the master slide
-        // /p:sldMaster/p:cSld/p:spTree/p:sp/p:nvPr/p:ph[@type="title"]
-        XSLFTextShape tx2 = master.getPlaceholder(0);
-        CTTextParagraphProperties lv2PPr = tx2.getTextBody(true).getLstStyle().addNewLvl1PPr();
-        CTTextCharacterProperties lv2CPr = lv2PPr.addNewDefRPr();
-        lv2CPr.setSz(3300);
-        assertEquals(33.0, textRun.getFontSize(), 0);
-        lv2CPr.addNewLatin().setTypeface("Times");
-        assertEquals("Times", textRun.getFontFamily());
-        lv2PPr.setAlgn(STTextAlignType.R);
-        assertEquals(TextAlign.RIGHT, paragraph.getTextAlign());
-
-
-        // level 3: title placeholder on the slide layout
-        // /p:sldLayout /p:cSld/p:spTree/p:sp/p:nvPr/p:ph[@type="ctrTitle"]
-        XSLFTextShape tx3 = layout.getPlaceholder(0);
-        CTTextParagraphProperties lv3PPr = tx3.getTextBody(true).getLstStyle().addNewLvl1PPr();
-        CTTextCharacterProperties lv3CPr = lv3PPr.addNewDefRPr();
-        lv3CPr.setSz(3400);
-        assertEquals(34.0, textRun.getFontSize(), 0);
-        lv3CPr.addNewLatin().setTypeface("Courier New");
-        assertEquals("Courier New", textRun.getFontFamily());
-        lv3PPr.setAlgn(STTextAlignType.CTR);
-        assertEquals(TextAlign.CENTER, paragraph.getTextAlign());
-
-        // level 4: default text properties in the shape itself
-        // ./p:sp/p:txBody/a:lstStyle/a:lvl1pPr
-        CTTextParagraphProperties lv4PPr = titleShape.getTextBody(true).getLstStyle().addNewLvl1PPr();
-        CTTextCharacterProperties lv4CPr = lv4PPr.addNewDefRPr();
-        lv4CPr.setSz(3500);
-        assertEquals(35.0, textRun.getFontSize(), 0);
-        lv4CPr.addNewLatin().setTypeface("Arial");
-        assertEquals("Arial", textRun.getFontFamily());
-        lv4PPr.setAlgn(STTextAlignType.L);
-        assertEquals(TextAlign.LEFT, paragraph.getTextAlign());
-
-        // level 5: text properties are defined in the text run
-        CTTextParagraphProperties lv5PPr = paragraph.getXmlObject().addNewPPr();
-        CTTextCharacterProperties lv5CPr = textRun.getRPr(false);
-        lv5CPr.setSz(3600);
-        assertEquals(36.0, textRun.getFontSize(), 0);
-        lv5CPr.addNewLatin().setTypeface("Calibri");
-        assertEquals("Calibri", textRun.getFontFamily());
-        lv5PPr.setAlgn(STTextAlignType.CTR);
-        assertEquals(TextAlign.CENTER, paragraph.getTextAlign());
-
-        ppt.close();
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+
+            XSLFSlideMaster master = ppt.getSlideMasters().get(0);
+            XSLFTheme theme = master.getTheme();
+            XSLFSlideLayout layout = master.getLayout(SlideLayout.TITLE);
+            XSLFSlide slide = ppt.createSlide(layout);
+            assertSame(layout, slide.getSlideLayout());
+            assertSame(master, slide.getSlideMaster());
+
+            XSLFTextShape titleShape = slide.getPlaceholder(0);
+            titleShape.setText("Apache POI");
+            XSLFTextParagraph paragraph = titleShape.getTextParagraphs().get(0);
+            XSLFTextRun textRun = paragraph.getTextRuns().get(0);
+
+            // level 1 : default title style on the master slide
+            // /p:sldMaster/p:txStyles/p:titleStyle/a:lvl1pPr
+            CTTextParagraphProperties lv1PPr = master.getXmlObject().getTxStyles().getTitleStyle().getLvl1PPr();
+            CTTextCharacterProperties lv1CPr = lv1PPr.getDefRPr();
+            assertEquals(4400, lv1CPr.getSz());
+            assertEquals(44.0, textRun.getFontSize(), 0);
+            assertEquals("+mj-lt", lv1CPr.getLatin().getTypeface());
+            assertEquals("Calibri", theme.getMajorFont());
+            assertEquals("Calibri", textRun.getFontFamily());
+            lv1CPr.setSz(3200);
+            assertEquals(32.0, textRun.getFontSize(), 0);
+            lv1CPr.getLatin().setTypeface("Arial");
+            assertEquals("Arial", textRun.getFontFamily());
+            assertSame(STTextAlignType.CTR, lv1PPr.getAlgn());
+            assertEquals(TextAlign.CENTER, paragraph.getTextAlign());
+            lv1PPr.setAlgn(STTextAlignType.L);
+            assertEquals(TextAlign.LEFT, paragraph.getTextAlign());
+
+            // level 2: title placeholder on the master slide
+            // /p:sldMaster/p:cSld/p:spTree/p:sp/p:nvPr/p:ph[@type="title"]
+            XSLFTextShape tx2 = master.getPlaceholder(0);
+            CTTextParagraphProperties lv2PPr = tx2.getTextBody(true).getLstStyle().addNewLvl1PPr();
+            CTTextCharacterProperties lv2CPr = lv2PPr.addNewDefRPr();
+            lv2CPr.setSz(3300);
+            assertEquals(33.0, textRun.getFontSize(), 0);
+            lv2CPr.addNewLatin().setTypeface("Times");
+            assertEquals("Times", textRun.getFontFamily());
+            lv2PPr.setAlgn(STTextAlignType.R);
+            assertEquals(TextAlign.RIGHT, paragraph.getTextAlign());
+
+
+            // level 3: title placeholder on the slide layout
+            // /p:sldLayout /p:cSld/p:spTree/p:sp/p:nvPr/p:ph[@type="ctrTitle"]
+            XSLFTextShape tx3 = layout.getPlaceholder(0);
+            CTTextParagraphProperties lv3PPr = tx3.getTextBody(true).getLstStyle().addNewLvl1PPr();
+            CTTextCharacterProperties lv3CPr = lv3PPr.addNewDefRPr();
+            lv3CPr.setSz(3400);
+            assertEquals(34.0, textRun.getFontSize(), 0);
+            lv3CPr.addNewLatin().setTypeface("Courier New");
+            assertEquals("Courier New", textRun.getFontFamily());
+            lv3PPr.setAlgn(STTextAlignType.CTR);
+            assertEquals(TextAlign.CENTER, paragraph.getTextAlign());
+
+            // level 4: default text properties in the shape itself
+            // ./p:sp/p:txBody/a:lstStyle/a:lvl1pPr
+            CTTextParagraphProperties lv4PPr = titleShape.getTextBody(true).getLstStyle().addNewLvl1PPr();
+            CTTextCharacterProperties lv4CPr = lv4PPr.addNewDefRPr();
+            lv4CPr.setSz(3500);
+            assertEquals(35.0, textRun.getFontSize(), 0);
+            lv4CPr.addNewLatin().setTypeface("Arial");
+            assertEquals("Arial", textRun.getFontFamily());
+            lv4PPr.setAlgn(STTextAlignType.L);
+            assertEquals(TextAlign.LEFT, paragraph.getTextAlign());
+
+            // level 5: text properties are defined in the text run
+            CTTextParagraphProperties lv5PPr = paragraph.getXmlObject().addNewPPr();
+            CTTextCharacterProperties lv5CPr = textRun.getRPr(false);
+            lv5CPr.setSz(3600);
+            assertEquals(36.0, textRun.getFontSize(), 0);
+            lv5CPr.addNewLatin().setTypeface("Calibri");
+            assertEquals("Calibri", textRun.getFontFamily());
+            lv5PPr.setAlgn(STTextAlignType.CTR);
+            assertEquals(TextAlign.CENTER, paragraph.getTextAlign());
+        }
     }
 
     @Test
     void testBodyStyles() throws IOException {
-        XMLSlideShow ppt = new XMLSlideShow();
-
-        XSLFSlideMaster master = ppt.getSlideMasters().get(0);
-        XSLFTheme theme = master.getTheme();
-        XSLFSlideLayout layout = master.getLayout(SlideLayout.TITLE_AND_CONTENT);
-        XSLFSlide slide = ppt.createSlide(layout) ;
-        assertSame(layout, slide.getSlideLayout());
-        assertSame(master, slide.getSlideMaster());
-
-        XSLFTextShape tx1 = slide.getPlaceholder(1);
-        tx1.clearText();
-
-        XSLFTextParagraph p1 = tx1.addNewTextParagraph();
-        assertEquals(0, p1.getIndentLevel());
-        XSLFTextRun r1 = p1.addNewTextRun();
-        r1.setText("Apache POI");
-
-        XSLFTextParagraph p2 = tx1.addNewTextParagraph();
-        p2.setIndentLevel(1);
-        assertEquals(1, p2.getIndentLevel());
-        XSLFTextRun r2 = p2.addNewTextRun();
-        r2.setText("HSLF");
-
-        XSLFTextParagraph p3 = tx1.addNewTextParagraph();
-        p3.setIndentLevel(2);
-        assertEquals(2, p3.getIndentLevel());
-        XSLFTextRun r3 = p3.addNewTextRun();
-        r3.setText("XSLF");
-
-        // level 1 : default title style on the master slide
-        // /p:sldMaster/p:txStyles/p:bodyStyle/a:lvl1pPr
-        CTTextParagraphProperties lv1PPr = master.getXmlObject().getTxStyles().getBodyStyle().getLvl1PPr();
-        CTTextCharacterProperties lv1CPr = lv1PPr.getDefRPr();
-        CTTextParagraphProperties lv2PPr = master.getXmlObject().getTxStyles().getBodyStyle().getLvl2PPr();
-        CTTextCharacterProperties lv2CPr = lv2PPr.getDefRPr();
-        CTTextParagraphProperties lv3PPr = master.getXmlObject().getTxStyles().getBodyStyle().getLvl3PPr();
-        CTTextCharacterProperties lv3CPr = lv3PPr.getDefRPr();
-        // lv1
-        assertEquals(3200, lv1CPr.getSz());
-        assertEquals(32.0, r1.getFontSize(), 0);
-        assertEquals("+mn-lt", lv1CPr.getLatin().getTypeface());
-        assertEquals("Calibri", theme.getMinorFont());
-        assertEquals("Calibri", r1.getFontFamily());
-        lv1CPr.setSz(3300);
-        assertEquals(33.0, r1.getFontSize(), 0);
-        lv1CPr.getLatin().setTypeface("Arial");
-        assertEquals("Arial", r1.getFontFamily());
-        assertEquals(STTextAlignType.L, lv1PPr.getAlgn());
-        assertEquals(TextAlign.LEFT, p1.getTextAlign());
-        lv1PPr.setAlgn(STTextAlignType.R);
-        assertEquals(TextAlign.RIGHT, p1.getTextAlign());
-        //lv2
-        assertEquals(2800, lv2CPr.getSz());
-        assertEquals(28.0, r2.getFontSize(), 0);
-        lv2CPr.setSz(3300);
-        assertEquals(33.0, r2.getFontSize(), 0);
-        lv2CPr.getLatin().setTypeface("Times");
-        assertEquals("Times", r2.getFontFamily());
-        assertEquals(STTextAlignType.L, lv2PPr.getAlgn());
-        assertEquals(TextAlign.LEFT, p2.getTextAlign());
-        lv2PPr.setAlgn(STTextAlignType.R);
-        assertEquals(TextAlign.RIGHT, p2.getTextAlign());
-        //lv3
-        assertEquals(2400, lv3CPr.getSz());
-        assertEquals(24.0, r3.getFontSize(), 0);
-        lv3CPr.setSz(2500);
-        assertEquals(25.0, r3.getFontSize(), 0);
-        lv3CPr.getLatin().setTypeface("Courier New");
-        assertEquals("Courier New", r3.getFontFamily());
-        assertEquals(STTextAlignType.L, lv3PPr.getAlgn());
-        assertEquals(TextAlign.LEFT, p3.getTextAlign());
-        lv3PPr.setAlgn(STTextAlignType.R);
-        assertEquals(TextAlign.RIGHT, p3.getTextAlign());
-
-
-        // level 2: body placeholder on the master slide
-        // /p:sldMaster/p:cSld/p:spTree/p:sp/p:nvPr/p:ph[@type="body"]
-        XSLFTextShape tx2 = master.getPlaceholder(1);
-        assertEquals(Placeholder.BODY, tx2.getTextType());
-
-        lv1PPr = tx2.getTextBody(true).getLstStyle().addNewLvl1PPr();
-        lv1CPr = lv1PPr.addNewDefRPr();
-        lv2PPr = tx2.getTextBody(true).getLstStyle().addNewLvl2PPr();
-        lv2CPr = lv2PPr.addNewDefRPr();
-        lv3PPr = tx2.getTextBody(true).getLstStyle().addNewLvl3PPr();
-        lv3CPr = lv3PPr.addNewDefRPr();
-
-        lv1CPr.setSz(3300);
-        assertEquals(33.0, r1.getFontSize(), 0);
-        lv1CPr.addNewLatin().setTypeface("Times");
-        assertEquals("Times", r1.getFontFamily());
-        lv1PPr.setAlgn(STTextAlignType.L);
-        assertEquals(TextAlign.LEFT, p1.getTextAlign());
-
-        lv2CPr.setSz(3300);
-        assertEquals(33.0, r2.getFontSize(), 0);
-        lv2CPr.addNewLatin().setTypeface("Times");
-        assertEquals("Times", r2.getFontFamily());
-        lv2PPr.setAlgn(STTextAlignType.L);
-        assertEquals(TextAlign.LEFT, p2.getTextAlign());
-
-        lv3CPr.setSz(3300);
-        assertEquals(33.0, r3.getFontSize(), 0);
-        lv3CPr.addNewLatin().setTypeface("Times");
-        assertEquals("Times", r3.getFontFamily());
-        lv3PPr.setAlgn(STTextAlignType.L);
-        assertEquals(TextAlign.LEFT, p3.getTextAlign());
-
-        // level 3: body placeholder on the slide layout
-        // /p:sldLayout /p:cSld/p:spTree/p:sp/p:nvPr/p:ph[@type="ctrTitle"]
-        XSLFTextShape tx3 = layout.getPlaceholder(1);
-        assertEquals(Placeholder.BODY, tx2.getTextType());
-        lv1PPr = tx3.getTextBody(true).getLstStyle().addNewLvl1PPr();
-        lv1CPr = lv1PPr.addNewDefRPr();
-        lv2PPr = tx3.getTextBody(true).getLstStyle().addNewLvl2PPr();
-        lv2CPr = lv2PPr.addNewDefRPr();
-        lv3PPr = tx3.getTextBody(true).getLstStyle().addNewLvl3PPr();
-        lv3CPr = lv3PPr.addNewDefRPr();
-
-        lv1CPr.setSz(3400);
-        assertEquals(34.0, r1.getFontSize(), 0);
-        lv1CPr.addNewLatin().setTypeface("Courier New");
-        assertEquals("Courier New", r1.getFontFamily());
-        lv1PPr.setAlgn(STTextAlignType.CTR);
-        assertEquals(TextAlign.CENTER, p1.getTextAlign());
-
-        lv2CPr.setSz(3400);
-        assertEquals(34.0, r2.getFontSize(), 0);
-        lv2CPr.addNewLatin().setTypeface("Courier New");
-        assertEquals("Courier New", r2.getFontFamily());
-        lv2PPr.setAlgn(STTextAlignType.CTR);
-        assertEquals(TextAlign.CENTER, p2.getTextAlign());
-
-        lv3CPr.setSz(3400);
-        assertEquals(34.0, r3.getFontSize(), 0);
-        lv3CPr.addNewLatin().setTypeface("Courier New");
-        assertEquals("Courier New", r3.getFontFamily());
-        lv3PPr.setAlgn(STTextAlignType.CTR);
-        assertEquals(TextAlign.CENTER, p3.getTextAlign());
-
-        // level 4: default text properties in the shape itself
-        // ./p:sp/p:txBody/a:lstStyle/a:lvl1pPr
-        lv1PPr = tx1.getTextBody(true).getLstStyle().addNewLvl1PPr();
-        lv1CPr = lv1PPr.addNewDefRPr();
-        lv2PPr = tx1.getTextBody(true).getLstStyle().addNewLvl2PPr();
-        lv2CPr = lv2PPr.addNewDefRPr();
-        lv3PPr = tx1.getTextBody(true).getLstStyle().addNewLvl3PPr();
-        lv3CPr = lv3PPr.addNewDefRPr();
-
-        lv1CPr.setSz(3500);
-        assertEquals(35.0, r1.getFontSize(), 0);
-        lv1CPr.addNewLatin().setTypeface("Arial");
-        assertEquals("Arial", r1.getFontFamily());
-        lv1PPr.setAlgn(STTextAlignType.L);
-        assertEquals(TextAlign.LEFT, p1.getTextAlign());
-
-        lv2CPr.setSz(3500);
-        assertEquals(35.0, r2.getFontSize(), 0);
-        lv2CPr.addNewLatin().setTypeface("Arial");
-        assertEquals("Arial", r2.getFontFamily());
-        lv2PPr.setAlgn(STTextAlignType.L);
-        assertEquals(TextAlign.LEFT, p2.getTextAlign());
-
-        lv3CPr.setSz(3500);
-        assertEquals(35.0, r3.getFontSize(), 0);
-        lv3CPr.addNewLatin().setTypeface("Arial");
-        assertEquals("Arial", r3.getFontFamily());
-        lv3PPr.setAlgn(STTextAlignType.L);
-        assertEquals(TextAlign.LEFT, p3.getTextAlign());
-
-        // level 5: text properties are defined in the text run
-        lv1PPr = p1.getXmlObject().isSetPPr() ? p1.getXmlObject().getPPr() : p1.getXmlObject().addNewPPr();
-        lv1CPr = r1.getRPr(false);
-        lv2PPr = p2.getXmlObject().isSetPPr() ? p2.getXmlObject().getPPr() : p2.getXmlObject().addNewPPr();
-        lv2CPr = r2.getRPr(false);
-        lv3PPr = p3.getXmlObject().isSetPPr() ? p3.getXmlObject().getPPr() : p3.getXmlObject().addNewPPr();
-        lv3CPr = r3.getRPr(false);
-
-        lv1CPr.setSz(3600);
-        assertEquals(36.0, r1.getFontSize(), 0);
-        lv1CPr.addNewLatin().setTypeface("Calibri");
-        assertEquals("Calibri", r1.getFontFamily());
-        lv1PPr.setAlgn(STTextAlignType.CTR);
-        assertEquals(TextAlign.CENTER, p1.getTextAlign());
-
-        lv2CPr.setSz(3600);
-        assertEquals(36.0, r2.getFontSize(), 0);
-        lv2CPr.addNewLatin().setTypeface("Calibri");
-        assertEquals("Calibri", r2.getFontFamily());
-        lv2PPr.setAlgn(STTextAlignType.CTR);
-        assertEquals(TextAlign.CENTER, p2.getTextAlign());
-
-        lv3CPr.setSz(3600);
-        assertEquals(36.0, r3.getFontSize(), 0);
-        lv3CPr.addNewLatin().setTypeface("Calibri");
-        assertEquals("Calibri", r3.getFontFamily());
-        lv3PPr.setAlgn(STTextAlignType.CTR);
-        assertEquals(TextAlign.CENTER, p3.getTextAlign());
-
-        ppt.close();
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+
+            XSLFSlideMaster master = ppt.getSlideMasters().get(0);
+            XSLFTheme theme = master.getTheme();
+            XSLFSlideLayout layout = master.getLayout(SlideLayout.TITLE_AND_CONTENT);
+            XSLFSlide slide = ppt.createSlide(layout);
+            assertSame(layout, slide.getSlideLayout());
+            assertSame(master, slide.getSlideMaster());
+
+            XSLFTextShape tx1 = slide.getPlaceholder(1);
+            tx1.clearText();
+
+            XSLFTextParagraph p1 = tx1.addNewTextParagraph();
+            assertEquals(0, p1.getIndentLevel());
+            XSLFTextRun r1 = p1.addNewTextRun();
+            r1.setText("Apache POI");
+
+            XSLFTextParagraph p2 = tx1.addNewTextParagraph();
+            p2.setIndentLevel(1);
+            assertEquals(1, p2.getIndentLevel());
+            XSLFTextRun r2 = p2.addNewTextRun();
+            r2.setText("HSLF");
+
+            XSLFTextParagraph p3 = tx1.addNewTextParagraph();
+            p3.setIndentLevel(2);
+            assertEquals(2, p3.getIndentLevel());
+            XSLFTextRun r3 = p3.addNewTextRun();
+            r3.setText("XSLF");
+
+            // level 1 : default title style on the master slide
+            // /p:sldMaster/p:txStyles/p:bodyStyle/a:lvl1pPr
+            CTTextParagraphProperties lv1PPr = master.getXmlObject().getTxStyles().getBodyStyle().getLvl1PPr();
+            CTTextCharacterProperties lv1CPr = lv1PPr.getDefRPr();
+            CTTextParagraphProperties lv2PPr = master.getXmlObject().getTxStyles().getBodyStyle().getLvl2PPr();
+            CTTextCharacterProperties lv2CPr = lv2PPr.getDefRPr();
+            CTTextParagraphProperties lv3PPr = master.getXmlObject().getTxStyles().getBodyStyle().getLvl3PPr();
+            CTTextCharacterProperties lv3CPr = lv3PPr.getDefRPr();
+            // lv1
+            assertEquals(3200, lv1CPr.getSz());
+            assertEquals(32.0, r1.getFontSize(), 0);
+            assertEquals("+mn-lt", lv1CPr.getLatin().getTypeface());
+            assertEquals("Calibri", theme.getMinorFont());
+            assertEquals("Calibri", r1.getFontFamily());
+            lv1CPr.setSz(3300);
+            assertEquals(33.0, r1.getFontSize(), 0);
+            lv1CPr.getLatin().setTypeface("Arial");
+            assertEquals("Arial", r1.getFontFamily());
+            assertSame(STTextAlignType.L, lv1PPr.getAlgn());
+            assertEquals(TextAlign.LEFT, p1.getTextAlign());
+            lv1PPr.setAlgn(STTextAlignType.R);
+            assertEquals(TextAlign.RIGHT, p1.getTextAlign());
+            //lv2
+            assertEquals(2800, lv2CPr.getSz());
+            assertEquals(28.0, r2.getFontSize(), 0);
+            lv2CPr.setSz(3300);
+            assertEquals(33.0, r2.getFontSize(), 0);
+            lv2CPr.getLatin().setTypeface("Times");
+            assertEquals("Times", r2.getFontFamily());
+            assertSame(STTextAlignType.L, lv2PPr.getAlgn());
+            assertEquals(TextAlign.LEFT, p2.getTextAlign());
+            lv2PPr.setAlgn(STTextAlignType.R);
+            assertEquals(TextAlign.RIGHT, p2.getTextAlign());
+            //lv3
+            assertEquals(2400, lv3CPr.getSz());
+            assertEquals(24.0, r3.getFontSize(), 0);
+            lv3CPr.setSz(2500);
+            assertEquals(25.0, r3.getFontSize(), 0);
+            lv3CPr.getLatin().setTypeface("Courier New");
+            assertEquals("Courier New", r3.getFontFamily());
+            assertSame(STTextAlignType.L, lv3PPr.getAlgn());
+            assertEquals(TextAlign.LEFT, p3.getTextAlign());
+            lv3PPr.setAlgn(STTextAlignType.R);
+            assertEquals(TextAlign.RIGHT, p3.getTextAlign());
+
+
+            // level 2: body placeholder on the master slide
+            // /p:sldMaster/p:cSld/p:spTree/p:sp/p:nvPr/p:ph[@type="body"]
+            XSLFTextShape tx2 = master.getPlaceholder(1);
+            assertEquals(Placeholder.BODY, tx2.getTextType());
+
+            lv1PPr = tx2.getTextBody(true).getLstStyle().addNewLvl1PPr();
+            lv1CPr = lv1PPr.addNewDefRPr();
+            lv2PPr = tx2.getTextBody(true).getLstStyle().addNewLvl2PPr();
+            lv2CPr = lv2PPr.addNewDefRPr();
+            lv3PPr = tx2.getTextBody(true).getLstStyle().addNewLvl3PPr();
+            lv3CPr = lv3PPr.addNewDefRPr();
+
+            lv1CPr.setSz(3300);
+            assertEquals(33.0, r1.getFontSize(), 0);
+            lv1CPr.addNewLatin().setTypeface("Times");
+            assertEquals("Times", r1.getFontFamily());
+            lv1PPr.setAlgn(STTextAlignType.L);
+            assertEquals(TextAlign.LEFT, p1.getTextAlign());
+
+            lv2CPr.setSz(3300);
+            assertEquals(33.0, r2.getFontSize(), 0);
+            lv2CPr.addNewLatin().setTypeface("Times");
+            assertEquals("Times", r2.getFontFamily());
+            lv2PPr.setAlgn(STTextAlignType.L);
+            assertEquals(TextAlign.LEFT, p2.getTextAlign());
+
+            lv3CPr.setSz(3300);
+            assertEquals(33.0, r3.getFontSize(), 0);
+            lv3CPr.addNewLatin().setTypeface("Times");
+            assertEquals("Times", r3.getFontFamily());
+            lv3PPr.setAlgn(STTextAlignType.L);
+            assertEquals(TextAlign.LEFT, p3.getTextAlign());
+
+            // level 3: body placeholder on the slide layout
+            // /p:sldLayout /p:cSld/p:spTree/p:sp/p:nvPr/p:ph[@type="ctrTitle"]
+            XSLFTextShape tx3 = layout.getPlaceholder(1);
+            assertEquals(Placeholder.BODY, tx2.getTextType());
+            lv1PPr = tx3.getTextBody(true).getLstStyle().addNewLvl1PPr();
+            lv1CPr = lv1PPr.addNewDefRPr();
+            lv2PPr = tx3.getTextBody(true).getLstStyle().addNewLvl2PPr();
+            lv2CPr = lv2PPr.addNewDefRPr();
+            lv3PPr = tx3.getTextBody(true).getLstStyle().addNewLvl3PPr();
+            lv3CPr = lv3PPr.addNewDefRPr();
+
+            lv1CPr.setSz(3400);
+            assertEquals(34.0, r1.getFontSize(), 0);
+            lv1CPr.addNewLatin().setTypeface("Courier New");
+            assertEquals("Courier New", r1.getFontFamily());
+            lv1PPr.setAlgn(STTextAlignType.CTR);
+            assertEquals(TextAlign.CENTER, p1.getTextAlign());
+
+            lv2CPr.setSz(3400);
+            assertEquals(34.0, r2.getFontSize(), 0);
+            lv2CPr.addNewLatin().setTypeface("Courier New");
+            assertEquals("Courier New", r2.getFontFamily());
+            lv2PPr.setAlgn(STTextAlignType.CTR);
+            assertEquals(TextAlign.CENTER, p2.getTextAlign());
+
+            lv3CPr.setSz(3400);
+            assertEquals(34.0, r3.getFontSize(), 0);
+            lv3CPr.addNewLatin().setTypeface("Courier New");
+            assertEquals("Courier New", r3.getFontFamily());
+            lv3PPr.setAlgn(STTextAlignType.CTR);
+            assertEquals(TextAlign.CENTER, p3.getTextAlign());
+
+            // level 4: default text properties in the shape itself
+            // ./p:sp/p:txBody/a:lstStyle/a:lvl1pPr
+            lv1PPr = tx1.getTextBody(true).getLstStyle().addNewLvl1PPr();
+            lv1CPr = lv1PPr.addNewDefRPr();
+            lv2PPr = tx1.getTextBody(true).getLstStyle().addNewLvl2PPr();
+            lv2CPr = lv2PPr.addNewDefRPr();
+            lv3PPr = tx1.getTextBody(true).getLstStyle().addNewLvl3PPr();
+            lv3CPr = lv3PPr.addNewDefRPr();
+
+            lv1CPr.setSz(3500);
+            assertEquals(35.0, r1.getFontSize(), 0);
+            lv1CPr.addNewLatin().setTypeface("Arial");
+            assertEquals("Arial", r1.getFontFamily());
+            lv1PPr.setAlgn(STTextAlignType.L);
+            assertEquals(TextAlign.LEFT, p1.getTextAlign());
+
+            lv2CPr.setSz(3500);
+            assertEquals(35.0, r2.getFontSize(), 0);
+            lv2CPr.addNewLatin().setTypeface("Arial");
+            assertEquals("Arial", r2.getFontFamily());
+            lv2PPr.setAlgn(STTextAlignType.L);
+            assertEquals(TextAlign.LEFT, p2.getTextAlign());
+
+            lv3CPr.setSz(3500);
+            assertEquals(35.0, r3.getFontSize(), 0);
+            lv3CPr.addNewLatin().setTypeface("Arial");
+            assertEquals("Arial", r3.getFontFamily());
+            lv3PPr.setAlgn(STTextAlignType.L);
+            assertEquals(TextAlign.LEFT, p3.getTextAlign());
+
+            // level 5: text properties are defined in the text run
+            lv1PPr = p1.getXmlObject().isSetPPr() ? p1.getXmlObject().getPPr() : p1.getXmlObject().addNewPPr();
+            lv1CPr = r1.getRPr(false);
+            lv2PPr = p2.getXmlObject().isSetPPr() ? p2.getXmlObject().getPPr() : p2.getXmlObject().addNewPPr();
+            lv2CPr = r2.getRPr(false);
+            lv3PPr = p3.getXmlObject().isSetPPr() ? p3.getXmlObject().getPPr() : p3.getXmlObject().addNewPPr();
+            lv3CPr = r3.getRPr(false);
+
+            lv1CPr.setSz(3600);
+            assertEquals(36.0, r1.getFontSize(), 0);
+            lv1CPr.addNewLatin().setTypeface("Calibri");
+            assertEquals("Calibri", r1.getFontFamily());
+            lv1PPr.setAlgn(STTextAlignType.CTR);
+            assertEquals(TextAlign.CENTER, p1.getTextAlign());
+
+            lv2CPr.setSz(3600);
+            assertEquals(36.0, r2.getFontSize(), 0);
+            lv2CPr.addNewLatin().setTypeface("Calibri");
+            assertEquals("Calibri", r2.getFontFamily());
+            lv2PPr.setAlgn(STTextAlignType.CTR);
+            assertEquals(TextAlign.CENTER, p2.getTextAlign());
+
+            lv3CPr.setSz(3600);
+            assertEquals(36.0, r3.getFontSize(), 0);
+            lv3CPr.addNewLatin().setTypeface("Calibri");
+            assertEquals("Calibri", r3.getFontFamily());
+            lv3PPr.setAlgn(STTextAlignType.CTR);
+            assertEquals(TextAlign.CENTER, p3.getTextAlign());
+        }
     }
 
     @Test
     void metroBlob() throws IOException, ReflectiveOperationException {
         assumeFalse(xslfOnly);
-        File f = POIDataSamples.getSlideShowInstance().getFile("bug52297.ppt");
-        SlideShow<?,?> ppt = SlideShowFactory.create(f);
-        Shape<?, ?> sh = ppt.getSlides().get(1).getShapes().get(3);
-        XSLFAutoShape xsh = (XSLFAutoShape)sh.getClass().getMethod("getMetroShape").invoke(sh);
-        String textExp = " ___ ___ ___ ________ __  _______ ___  ___________  __________ __ _____ ___ ___ ___ _______ ____ ______ ___________  _____________ ___ _______ ______  ____ ______ __ ___________  __________ ___ _________  _____ ________ __________  ___ _______ __________ ";
-        String textAct = xsh.getText();
-        ppt.close();
-        assertEquals(textExp, textAct);
+        POIDataSamples samples = POIDataSamples.getSlideShowInstance();
+        String textAct;
+        try (InputStream is = samples.openResourceAsStream("bug52297.ppt");
+             SlideShow<?,?> ppt = SlideShowFactory.create(is)) {
+            // check metro shapes on master sheet
+            MasterSheet<?, ?> master = ppt.getSlideMasters().get(0);
+            FieldType[] tl = master.getShapes().stream().
+                filter(f -> f instanceof TextShape).map(f -> (TextShape<?,?>)f).
+                flatMap(f -> ((List<? extends TextParagraph<?, ?, ? extends TextRun>>) f.getTextParagraphs()).stream()).
+                flatMap(f -> f.getTextRuns().stream()).
+                map(TextRun::getFieldType).
+                filter(Objects::nonNull).
+                toArray(FieldType[]::new);
+            assertArrayEquals(new FieldType[]{DATE_TIME, SLIDE_NUMBER, SLIDE_NUMBER}, tl);
+
+            // check metro shapes on slides
+            Shape<?, ?> sh = ppt.getSlides().get(1).getShapes().get(3);
+            XSLFAutoShape xsh = (XSLFAutoShape) sh.getClass().getMethod("getMetroShape").invoke(sh);
+            String textExp = " ___ ___ ___ ________ __  _______ ___  ___________  __________ __ _____ ___ ___ ___ _______ ____ ______ ___________  _____________ ___ _______ ______  ____ ______ __ ___________  __________ ___ _________  _____ ________ __________  ___ _______ __________ ";
+            textAct = xsh.getText();
+            assertEquals(textExp, textAct);
+        }
     }
 }
\ No newline at end of file
index 2cd55eb942abe5e2d34493e2f899c32212601558..75444a4c92c5a626ecc49f8c0d56ef5eae49908e 100644 (file)
Binary files a/poi-ooxml/src/test/java9/module-info.class and b/poi-ooxml/src/test/java9/module-info.class differ
index 3bb546f87fd4cf703c75641345f47ab67612efc2..a6a78d6e4e388a2656a6593486ad3079826ee62f 100644 (file)
@@ -32,6 +32,7 @@ module org.apache.poi.ooxml {
     provides org.apache.poi.ss.usermodel.WorkbookProvider with org.apache.poi.xssf.usermodel.XSSFWorkbookFactory;
     provides org.apache.poi.sl.usermodel.SlideShowProvider with org.apache.poi.xslf.usermodel.XSLFSlideShowFactory;
     provides org.apache.poi.sl.draw.ImageRenderer with org.apache.poi.xslf.draw.SVGImageRenderer;
+    provides org.apache.poi.sl.usermodel.MetroShapeProvider with org.apache.poi.xslf.usermodel.XSLFMetroShape;
 
     exports org.apache.poi.xwpf.extractor;
     exports org.apache.poi.xwpf.usermodel;
index 54495aab2a475860910465983e40abaf838d1a42..cc64c4c82fa11cb92cff0ca0023b3a8da3984e9a 100644 (file)
@@ -17,7 +17,8 @@
 
 package org.apache.poi.hslf.model;
 
-import java.lang.reflect.Method;
+import java.io.IOException;
+import java.util.ServiceLoader;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -26,7 +27,10 @@ import org.apache.poi.ddf.EscherComplexProperty;
 import org.apache.poi.ddf.EscherPropertyTypes;
 import org.apache.poi.ddf.EscherTertiaryOptRecord;
 import org.apache.poi.hslf.usermodel.HSLFShape;
+import org.apache.poi.sl.usermodel.MetroShapeProvider;
 import org.apache.poi.sl.usermodel.Shape;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.sl.usermodel.TextRun;
 import org.apache.poi.util.Internal;
 
 /**
@@ -34,7 +38,10 @@ import org.apache.poi.util.Internal;
  * containing an ooxml representation of the shape
  */
 @Internal
-public class HSLFMetroShape<T extends Shape<?,?>> {
+public class HSLFMetroShape<
+    S extends Shape<S,P>,
+    P extends TextParagraph<S,P,? extends TextRun>
+> {
     private static final Logger LOGGER = LogManager.getLogger(HSLFMetroShape.class);
 
     private final HSLFShape shape;
@@ -42,9 +49,9 @@ public class HSLFMetroShape<T extends Shape<?,?>> {
     public HSLFMetroShape(HSLFShape shape) {
         this.shape = shape;
     }
-    
+
     /**
-     * @return the bytes of the metro blob, which are bytes of an OPCPackage, i.e. a zip stream 
+     * @return the bytes of the metro blob, which are bytes of an OPCPackage, i.e. a zip stream
      */
     public byte[] getMetroBytes() {
         EscherComplexProperty ep = getMetroProp();
@@ -57,33 +64,36 @@ public class HSLFMetroShape<T extends Shape<?,?>> {
     public boolean hasMetroBlob() {
         return getMetroProp() != null;
     }
-    
+
     private EscherComplexProperty getMetroProp() {
         AbstractEscherOptRecord opt = shape.getEscherChild(EscherTertiaryOptRecord.RECORD_ID);
         return (opt == null) ? null : (EscherComplexProperty)opt.lookup(EscherPropertyTypes.GROUPSHAPE__METROBLOB.propNumber);
     }
-    
+
     /**
      * @return the metro blob shape or null if either there's no metro blob or the ooxml classes
      * aren't in the classpath
      */
     @SuppressWarnings("unchecked")
-    public T getShape() {
+    public Shape<S,P> getShape() {
         byte[] metroBytes = getMetroBytes();
         if (metroBytes == null) {
             return null;
         }
-        
-        // org.apache.poi.xslf.usermodel.XSLFMetroShape
-        ClassLoader cl = getClass().getClassLoader();
-        try {
-            Class<?> ms = cl.loadClass("org.apache.poi.xslf.usermodel.XSLFMetroShape");
-            Method m = ms.getMethod("parseShape", byte[].class);
-            return (T)m.invoke(null, new Object[]{metroBytes});
-        } catch (Exception e) {
-            LOGGER.atError().withThrowable(e).log("can't process metro blob, check if all dependencies for POI OOXML are in the classpath.");
-            return null;
+
+        ClassLoader cl = HSLFMetroShape.class.getClassLoader();
+        IOException lastError = null;
+        for (MetroShapeProvider msp : ServiceLoader.load(MetroShapeProvider.class, cl)) {
+            try {
+                return (Shape<S, P>) msp.parseShape(metroBytes);
+            } catch (IOException ex) {
+                lastError = ex;
+                break;
+            }
         }
+
+        LOGGER.atError().withThrowable(lastError).log("can't process metro blob, check if all dependencies for POI OOXML are in the classpath.");
+        return null;
     }
 }
 
index f69ee6e432be46a00ee128a706109278f2309dae..a30281eeeb0ab8edc1ff33aa203e0edc4ac1eb01 100644 (file)
@@ -19,6 +19,7 @@ package org.apache.poi.hslf.usermodel;
 
 import java.awt.Color;
 import java.util.List;
+import java.util.stream.Stream;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -35,6 +36,7 @@ import org.apache.poi.sl.usermodel.MasterSheet;
 import org.apache.poi.sl.usermodel.PaintStyle;
 import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
 import org.apache.poi.sl.usermodel.Placeholder;
+import org.apache.poi.sl.usermodel.Shape;
 import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextRun;
 import org.apache.poi.sl.usermodel.TextShape;
@@ -506,16 +508,14 @@ public final class HSLFTextRun implements TextRun {
             }
         }
 
-        if (ts.getSheet() instanceof MasterSheet) {
-            TextShape<?,? extends TextParagraph<?,?,? extends TextRun>> ms = ts.getMetroShape();
-            if (ms == null || ms.getTextParagraphs().isEmpty()) {
-                return null;
-            }
-            List<? extends TextRun> trList = ms.getTextParagraphs().get(0).getTextRuns();
-            if (trList.isEmpty()) {
-                return null;
-            }
-            return trList.get(0).getFieldType();
+        Shape<?,?> ms = (ts.getSheet() instanceof MasterSheet) ? ts.getMetroShape() : null;
+        if (ms instanceof TextShape) {
+            return Stream.of((TextShape<?,?>)ms).
+                flatMap(tsh -> ((List<? extends TextParagraph<?,?,? extends TextRun>>)tsh.getTextParagraphs()).stream()).
+                flatMap(tph -> tph.getTextRuns().stream()).
+                findFirst().
+                map(TextRun::getFieldType).
+                orElse(null);
         }
 
         return null;
index 9a60a2e8ae324a514513246fded5a9de40e58268..8efa7cadb1b1ca347990302e927c9112bbeb6c2c 100644 (file)
@@ -51,6 +51,7 @@ import org.apache.poi.sl.draw.DrawFactory;
 import org.apache.poi.sl.draw.DrawTextShape;
 import org.apache.poi.sl.usermodel.Insets2D;
 import org.apache.poi.sl.usermodel.Placeholder;
+import org.apache.poi.sl.usermodel.Shape;
 import org.apache.poi.sl.usermodel.ShapeContainer;
 import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextRun;
@@ -153,7 +154,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
     /**
      * Create a TextBox object and initialize it from the supplied Record container.
      *
-     * @param escherRecord       <code>EscherSpContainer</code> container which holds information about this shape
+     * @param escherRecord       {@code EscherSpContainer} container which holds information about this shape
      * @param parent    the parent of the shape
      */
     protected HSLFTextShape(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
@@ -192,7 +193,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
 
     /**
      * When a textbox is added to  a sheet we need to tell upper-level
-     * <code>PPDrawing</code> about it.
+     * {@code PPDrawing} about it.
      *
      * @param sh the sheet we are adding to
      */
@@ -403,7 +404,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
 
     /**
      * Sets the type of alignment for the text.
-     * One of the <code>Anchor*</code> constants defined in this class.
+     * One of the {@code Anchor*} constants defined in this class.
      *
      * @param isCentered horizontal centered?
      * @param vAlign vertical alignment
@@ -572,7 +573,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
      * Returns the value indicating word wrap.
      *
      * @return the value indicating word wrap.
-     *  Must be one of the <code>Wrap*</code> constants defined in this class.
+     *  Must be one of the {@code Wrap*} constants defined in this class.
      *
      * @see <a href="https://msdn.microsoft.com/en-us/library/dd948168(v=office.12).aspx">MSOWRAPMODE</a>
      */
@@ -586,7 +587,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
      *  Specifies how the text should be wrapped
      *
      * @param wrap  the value indicating how the text should be wrapped.
-     *  Must be one of the <code>Wrap*</code> constants defined in this class.
+     *  Must be one of the {@code Wrap*} constants defined in this class.
      */
     public void setWordWrapEx(int wrap){
         setEscherProperty(EscherPropertyTypes.TEXT__WRAPTEXT, wrap);
@@ -841,7 +842,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
     /**
      * Returns the array of all hyperlinks in this text run
      *
-     * @return the array of all hyperlinks in this text run or <code>null</code>
+     * @return the array of all hyperlinks in this text run or {@code null}
      *         if not found.
      */
     public List<HSLFHyperlink> getHyperlinks() {
@@ -904,8 +905,10 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
      *
      * @return null, if there's no alternative representation, otherwise the text shape
      */
-    public TextShape<?,? extends TextParagraph<?,?,? extends TextRun>> getMetroShape() {
-        HSLFMetroShape<TextShape<?,? extends TextParagraph<?,?,? extends TextRun>>> mbs = new HSLFMetroShape<>(this);
-        return mbs.getShape();
+    public <
+        S extends Shape<S,P>,
+        P extends TextParagraph<S,P,? extends TextRun>
+    > Shape<S,P> getMetroShape() {
+        return new HSLFMetroShape<S,P>(this).getShape();
     }
 }
\ No newline at end of file
index 72189ac318dd5fdfbb0c5ec62efaff1fb5a610cb..1c076d2f61d18824bc169cce38b053e0018182af 100644 (file)
Binary files a/poi-scratchpad/src/main/java9/module-info.class and b/poi-scratchpad/src/main/java9/module-info.class differ
index f2b2732ec5281d2dec7b5a05fc70944d4d59b2e4..ea505f6c1ceeb96323004e56baa1c43970cdf82d 100644 (file)
@@ -23,6 +23,8 @@ module org.apache.poi.scratchpad {
     requires org.apache.commons.codec;
     requires org.apache.logging.log4j;
 
+    uses org.apache.poi.sl.usermodel.MetroShapeProvider;
+
     provides org.apache.poi.extractor.ExtractorProvider with org.apache.poi.extractor.ole2.OLE2ScratchpadExtractorFactory;
     provides org.apache.poi.sl.usermodel.SlideShowProvider with org.apache.poi.hslf.usermodel.HSLFSlideShowFactory;
     provides org.apache.poi.sl.draw.ImageRenderer with org.apache.poi.hwmf.draw.HwmfImageRenderer, org.apache.poi.hemf.draw.HemfImageRenderer;
index f5349bb241c60277f72502fdbfef92b958413333..91bc9fc6b8d666de861f65b8c043c0371e044c03 100644 (file)
Binary files a/poi-scratchpad/src/test/java9/module-info.class and b/poi-scratchpad/src/test/java9/module-info.class differ
index aa1e3d76c8664490969d7ca664276ecc01e46c74..0d6ba80e5b787a61cff3d03f0782d1acdc81191f 100644 (file)
@@ -21,6 +21,8 @@ module org.apache.poi.scratchpad {
     requires commons.math3;
     requires org.apache.logging.log4j;
 
+    uses org.apache.poi.sl.usermodel.MetroShapeProvider;
+
     provides org.apache.poi.extractor.ExtractorProvider with org.apache.poi.extractor.ole2.OLE2ScratchpadExtractorFactory;
     provides org.apache.poi.sl.usermodel.SlideShowProvider with org.apache.poi.hslf.usermodel.HSLFSlideShowFactory;
     provides org.apache.poi.sl.draw.ImageRenderer with org.apache.poi.hwmf.draw.HwmfImageRenderer, org.apache.poi.hemf.draw.HemfImageRenderer;
diff --git a/poi/src/main/java/org/apache/poi/sl/usermodel/MetroShapeProvider.java b/poi/src/main/java/org/apache/poi/sl/usermodel/MetroShapeProvider.java
new file mode 100644 (file)
index 0000000..e89a14d
--- /dev/null
@@ -0,0 +1,31 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.sl.usermodel;
+
+import java.io.IOException;
+
+import org.apache.poi.util.Internal;
+
+/**
+ * Experimental provider / loader for metro shapes.
+ * Metro shapes are xslf fragments stored in hslf shapes.
+ */
+@Internal
+public interface MetroShapeProvider {
+    Shape<?,?> parseShape(byte[] metroBytes) throws IOException;
+}
index 028b943d0ae7577c19f08d4b20ce352134f4f685..438e778ab515b0d480b1fb79ccaffeeafa4e55c6 100644 (file)
Binary files a/poi/src/test/java9/module-info.class and b/poi/src/test/java9/module-info.class differ
index 58ac2220c59952ace4fda46ea49914e271e8e0af..7b9cf162cfb2414f76429f844e9f2f7ac96b0729 100644 (file)
@@ -24,6 +24,8 @@ module org.apache.poi.poi {
     requires java.logging;
     requires java.desktop;
 
+    uses org.apache.poi.sl.usermodel.MetroShapeProvider;
+
     /* needed for CleanerUtil */
     requires jdk.unsupported;