]> source.dussan.org Git - poi.git/commitdiff
Add support for HSLF metro blobs
authorAndreas Beeker <kiwiwings@apache.org>
Sun, 8 Nov 2015 23:13:28 +0000 (23:13 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sun, 8 Nov 2015 23:13:28 +0000 (23:13 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1713318 13f79535-47bb-0310-9956-ffa450edef68

src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFMetroShape.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java
src/scratchpad/src/org/apache/poi/hslf/model/HSLFMetroShape.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlide.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextBox.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java
test-data/slideshow/bug52297.ppt [new file with mode: 0644]

index ae9c8bac661ca6416937083e092436ed6b717410..5f66e9fca1330d5f37b0500766d4e59c04601230 100644 (file)
@@ -61,7 +61,7 @@ implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
 \r
     protected XSLFGroupShape(CTGroupShape shape, XSLFSheet sheet){\r
         super(shape,sheet);\r
-        _shapes = sheet.buildShapes(shape);\r
+        _shapes = XSLFSheet.buildShapes(shape, sheet);\r
         _grpSpPr = shape.getGrpSpPr();\r
     }\r
 \r
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFMetroShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFMetroShape.java
new file mode 100644 (file)
index 0000000..87278f7
--- /dev/null
@@ -0,0 +1,60 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+\r
+package org.apache.poi.xslf.usermodel;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;\r
+import org.apache.poi.openxml4j.opc.OPCPackage;\r
+import org.apache.poi.openxml4j.opc.PackagePart;\r
+import org.apache.poi.openxml4j.opc.PackagePartName;\r
+import org.apache.poi.openxml4j.opc.PackagingURIHelper;\r
+import org.apache.poi.sl.usermodel.Shape;\r
+import org.apache.poi.util.Internal;\r
+import org.apache.xmlbeans.XmlException;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;\r
+\r
+/**\r
+ * Experimental class for metro blobs, i.e. an alternative escher property\r
+ * containing an ooxml representation of the shape.\r
+ * This is the helper class for HSLFMetroShape to dive into OOXML classes\r
+ */\r
+@Internal\r
+public class XSLFMetroShape {\r
+    /*\r
+     * parses the metro bytes to a XSLF shape\r
+     */\r
+    public static Shape<?,?> parseShape(byte metroBytes[])\r
+    throws InvalidFormatException, IOException, XmlException {\r
+        PackagePartName shapePN = PackagingURIHelper.createPartName("/drs/shapexml.xml");\r
+        OPCPackage pkg = null;\r
+        try {\r
+            pkg = OPCPackage.open(new ByteArrayInputStream(metroBytes));\r
+            PackagePart shapePart = pkg.getPart(shapePN);\r
+            CTGroupShape gs = CTGroupShape.Factory.parse(shapePart.getInputStream());\r
+            XSLFGroupShape xgs = new XSLFGroupShape(gs, null);\r
+            return xgs.getShapes().get(0);               \r
+        } finally {\r
+            if (pkg != null) {\r
+                pkg.close();\r
+            }\r
+        }\r
+    }\r
+}\r
index daca97131d1a3fbc00e4b8f80e642b48ee48c50e..547e01fe8a51a28a7e30e8c216f9df341478383d 100644 (file)
@@ -90,20 +90,20 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
         throw new IllegalStateException("SlideShow was not found");
     }
 
-    protected List<XSLFShape> buildShapes(CTGroupShape spTree){
+    protected static List<XSLFShape> buildShapes(CTGroupShape spTree, XSLFSheet sheet){
         List<XSLFShape> shapes = new ArrayList<XSLFShape>();
         for(XmlObject ch : spTree.selectPath("*")){
             if(ch instanceof CTShape){ // simple shape
-                XSLFAutoShape shape = XSLFAutoShape.create((CTShape)ch, this);
+                XSLFAutoShape shape = XSLFAutoShape.create((CTShape)ch, sheet);
                 shapes.add(shape);
             } else if (ch instanceof CTGroupShape){
-                shapes.add(new XSLFGroupShape((CTGroupShape)ch, this));
+                shapes.add(new XSLFGroupShape((CTGroupShape)ch, sheet));
             } else if (ch instanceof CTConnector){
-                shapes.add(new XSLFConnectorShape((CTConnector)ch, this));
+                shapes.add(new XSLFConnectorShape((CTConnector)ch, sheet));
             } else if (ch instanceof CTPicture){
-                shapes.add(new XSLFPictureShape((CTPicture)ch, this));
+                shapes.add(new XSLFPictureShape((CTPicture)ch, sheet));
             } else if (ch instanceof CTGraphicalObjectFrame){
-                XSLFGraphicFrame shape = XSLFGraphicFrame.create((CTGraphicalObjectFrame)ch, this);
+                XSLFGraphicFrame shape = XSLFGraphicFrame.create((CTGraphicalObjectFrame)ch, sheet);
                 shapes.add(shape);
             }
         }
@@ -156,7 +156,7 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
             _drawing = new XSLFDrawing(this, cgs);
         }
         if (_shapes == null) {
-            _shapes = buildShapes(cgs);
+            _shapes = buildShapes(cgs, this);
         }
     }
 
index 18632ffbf0857dff8717c4acc2843d719b21783c..c8a1aeebd5c914051d40dba3a6a31d683f3a8f18 100644 (file)
@@ -25,10 +25,15 @@ import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;\r
 \r
 import java.awt.Color;\r
+import java.io.File;\r
 import java.io.IOException;\r
 import java.util.List;\r
 \r
+import org.apache.poi.POIDataSamples;\r
+import org.apache.poi.hslf.usermodel.HSLFTextShape;\r
 import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;\r
+import org.apache.poi.sl.usermodel.SlideShow;\r
+import org.apache.poi.sl.usermodel.SlideShowFactory;\r
 import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;\r
 import org.apache.poi.sl.usermodel.VerticalAlignment;\r
 import org.apache.poi.xslf.XSLFTestDataSamples;\r
@@ -40,9 +45,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;\r
 \r
-/**\r
- * @author Yegor Kozlov\r
- */\r
 public class TestXSLFTextShape {\r
 \r
     @Test\r
@@ -913,4 +915,16 @@ public class TestXSLFTextShape {
         \r
         ppt.close();\r
     }\r
+    \r
+    @Test\r
+    public void metroBlob() throws IOException {\r
+        File f = POIDataSamples.getSlideShowInstance().getFile("bug52297.ppt");\r
+        SlideShow<?,?> ppt = SlideShowFactory.create(f);\r
+        HSLFTextShape sh = (HSLFTextShape)ppt.getSlides().get(1).getShapes().get(3);\r
+        XSLFAutoShape xsh = (XSLFAutoShape)sh.getMetroShape();\r
+        String textExp = " ___ ___ ___ ________ __  _______ ___  ___________  __________ __ _____ ___ ___ ___ _______ ____ ______ ___________  _____________ ___ _______ ______  ____ ______ __ ___________  __________ ___ _________  _____ ________ __________  ___ _______ __________ ";\r
+        String textAct = xsh.getText();\r
+        ppt.close();\r
+        assertEquals(textExp, textAct);\r
+    }\r
 }
\ No newline at end of file
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFMetroShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFMetroShape.java
new file mode 100644 (file)
index 0000000..e5d9f93
--- /dev/null
@@ -0,0 +1,83 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.model;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+import org.apache.poi.ddf.AbstractEscherOptRecord;\r
+import org.apache.poi.ddf.EscherComplexProperty;\r
+import org.apache.poi.ddf.EscherProperties;\r
+import org.apache.poi.ddf.EscherTertiaryOptRecord;\r
+import org.apache.poi.hslf.usermodel.HSLFShape;\r
+import org.apache.poi.sl.usermodel.Shape;\r
+import org.apache.poi.util.Internal;\r
+import org.apache.poi.util.POILogFactory;\r
+import org.apache.poi.util.POILogger;\r
+\r
+/**\r
+ * Experimental class for metro blobs, i.e. an alternative escher property\r
+ * containing an ooxml representation of the shape\r
+ */\r
+@Internal\r
+public class HSLFMetroShape<T extends Shape<?,?>> {\r
+    private static final POILogger LOGGER = POILogFactory.getLogger(HSLFMetroShape.class);\r
+    \r
+    private final HSLFShape shape;\r
+\r
+    public HSLFMetroShape(HSLFShape shape) {\r
+        this.shape = shape;\r
+    }\r
+    \r
+    /**\r
+     * @return the bytes of the metro blob, which are bytes of an OPCPackage, i.e. a zip stream \r
+     */\r
+    public byte[] getMetroBytes() {\r
+        AbstractEscherOptRecord opt = shape.getEscherChild(EscherTertiaryOptRecord.RECORD_ID);\r
+        if (opt != null) {\r
+            EscherComplexProperty ep = (EscherComplexProperty)opt.lookup(EscherProperties.GROUPSHAPE__METROBLOB);\r
+            if (ep != null) {\r
+                return ep.getComplexData();\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+    \r
+    /**\r
+     * @return the metro blob shape or null if either there's no metro blob or the ooxml classes\r
+     * aren't in the classpath\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public T getShape() {\r
+        byte metroBytes[] = getMetroBytes();\r
+        if (metroBytes == null) {\r
+            return null;\r
+        }\r
+        \r
+        // org.apache.poi.xslf.usermodel.XSLFMetroShape\r
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();\r
+        try {\r
+            Class<?> ms = cl.loadClass("org.apache.poi.xslf.usermodel.XSLFMetroShape");\r
+            Method m = ms.getMethod("parseShape", byte[].class);\r
+            return (T)m.invoke(null, new Object[]{metroBytes});\r
+        } catch (Exception e) {\r
+            LOGGER.log(POILogger.ERROR, "can't process metro blob, check if all dependencies for POI OOXML are in the classpath.", e);\r
+            return null;\r
+        }\r
+    }\r
+}\r
+\r
index 8e94421c5d9386ab31587cc7f00901390b3bb2c0..1e485de9ff64095287189d6740b4282008f69455 100644 (file)
@@ -499,4 +499,9 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe
         // TODO Auto-generated method stub
 
     }
+    
+    @Override
+    public boolean getFollowMasterGraphics() {
+        return getFollowMasterObjects();
+    }
 }
index 792928d1ea235526a04458ad8e75189805682462..3872ecf5b884998b547ef36fbef7fa53911bf62b 100644 (file)
 
 package org.apache.poi.hslf.usermodel;
 
-import org.apache.poi.ddf.*;
-import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.sl.usermodel.ShapeContainer;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.TextBox;
+import org.apache.poi.sl.usermodel.VerticalAlignment;
 
 /**
  * Represents a TextFrame shape in PowerPoint.
@@ -88,5 +92,4 @@ public class HSLFTextBox extends HSLFTextShape implements TextBox<HSLFShape,HSLF
         setVerticalAlignment(VerticalAlignment.TOP);
         setEscherProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20002);
     }
-
 }
index bc8ac93c6ee308732a990cb5e5aa2c95b32876ab..f15cea208543710945a5235a1d4e29219e3b5c6d 100644 (file)
@@ -993,6 +993,15 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
         }\r
         return sb.toString();\r
     }\r
+    \r
+    @Override\r
+    public String toString() {\r
+        StringBuilder sb = new StringBuilder();\r
+        for (HSLFTextRun r : getTextRuns()) {\r
+            sb.append(r.getRawText());\r
+        }\r
+        return toExternalString(sb.toString(), getRunType());\r
+    }\r
 \r
     /**\r
      * Returns a new string with line breaks converted into internal ppt\r
index f24173e20428bb13be9d7fb0d7deacbbcec45222..cee75686f77400b401f5994bae1ae6bd6adad388 100644 (file)
@@ -34,6 +34,7 @@ import org.apache.poi.ddf.EscherProperties;
 import org.apache.poi.ddf.EscherSimpleProperty;
 import org.apache.poi.ddf.EscherTextboxRecord;
 import org.apache.poi.hslf.exceptions.HSLFException;
+import org.apache.poi.hslf.model.HSLFMetroShape;
 import org.apache.poi.hslf.record.EscherTextboxWrapper;
 import org.apache.poi.hslf.record.InteractiveInfo;
 import org.apache.poi.hslf.record.InteractiveInfoAtom;
@@ -102,7 +103,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
      */
     public static final int WrapThrough = 4;
 
-    
+
     /**
      * TextRun object which holds actual text and format data
      */
@@ -116,11 +117,11 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
 
     /**
      * This setting is used for supporting a deprecated alignment
-     * 
+     *
      * @see <a href=""></a>
      */
     boolean alignToBaseline = false;
-    
+
     /**
      * Used to calculate text bounds
      */
@@ -176,11 +177,11 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
         super.afterInsert(sh);
 
         storeText();
-        
+
         EscherTextboxWrapper thisTxtbox = getEscherTextboxWrapper();
         if(thisTxtbox != null){
             _escherContainer.addChildRecord(thisTxtbox.getEscherRecord());
-            
+
             PPDrawing ppdrawing = sh.getPPDrawing();
             ppdrawing.addTextboxWrapper(thisTxtbox);
             // Ensure the escher layer knows about the added records
@@ -199,10 +200,10 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
 
     protected EscherTextboxWrapper getEscherTextboxWrapper(){
         if(_txtbox != null) return _txtbox;
-        
+
         EscherTextboxRecord textRecord = getEscherChild(EscherTextboxRecord.RECORD_ID);
         if (textRecord == null) return null;
-        
+
         HSLFSheet sheet = getSheet();
         if (sheet != null) {
             PPDrawing drawing = sheet.getPPDrawing();
@@ -219,7 +220,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
                 }
             }
         }
-        
+
         _txtbox = new EscherTextboxWrapper(textRecord);
         return _txtbox;
     }
@@ -236,15 +237,15 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
             anchor.setSize(200, (int)anchor.getHeight());
             setAnchor(anchor);
         }
-        double height = getTextHeight(); 
+        double height = getTextHeight();
         height += 1; // add a pixel to compensate rounding errors
-        
+
         anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height);
         setAnchor(anchor);
-        
+
         return anchor;
-    }   
-    
+    }
+
     /**
     * Returns the type of the text, from the TextHeaderAtom.
     * Possible values can be seen from TextHeaderAtom
@@ -271,7 +272,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
             paras.get(0).setRunType(type);
         }
     }
-    
+
     /**
      * Returns the type of vertical alignment for the text.
      * One of the <code>Anchor*</code> constants defined in this class.
@@ -310,7 +311,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
 
         alignToBaseline = (align == AnchorBottomBaseline || align == AnchorBottomCenteredBaseline
             || align == AnchorTopBaseline || align == AnchorTopCenteredBaseline);
-        
+
         return align;
     }
 
@@ -334,15 +335,15 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
             align = new int[]{AnchorBottom, AnchorBottomCentered, AnchorBottomBaseline, AnchorBottomCenteredBaseline};
             break;
         }
-        
+
         int align2 = align[(isCentered ? 1 : 0)+(alignToBaseline ? 2 : 0)];
-        
+
         setEscherProperty(EscherProperties.TEXT__ANCHORTEXT, align2);
     }
-    
+
     /**
      * @return true, if vertical alignment is relative to baseline
-     * this is only used for older versions less equals Office 2003 
+     * this is only used for older versions less equals Office 2003
      */
     public boolean isAlignToBaseline() {
         getAlignment();
@@ -358,7 +359,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
         this.alignToBaseline = alignToBaseline;
         setAlignment(isHorizontalCentered(), getVerticalAlignment());
     }
-    
+
     @Override
     public boolean isHorizontalCentered() {
         int va = getAlignment();
@@ -378,7 +379,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
     public void setHorizontalCentered(Boolean isCentered) {
         setAlignment(isCentered, getVerticalAlignment());
     }
-    
+
     @Override
     public VerticalAlignment getVerticalAlignment() {
         int va = getAlignment();
@@ -492,7 +493,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
      * Returns the distance (in points) between the edge of the text frame
      * and the edge of the inscribed rectangle of the shape that contains the text.
      * Default value is 1/20 inch.
-     * 
+     *
      * @param propId the id of the inset edge
      * @return the inset in points
      */
@@ -500,7 +501,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
         AbstractEscherOptRecord opt = getEscherOptRecord();
         EscherSimpleProperty prop = getEscherProperty(opt, propId);
         int val = prop == null ? (int)(Units.toEMU(Units.POINT_DPI)*defaultInch) : prop.getPropertyValue();
-        return Units.toPoints(val);        
+        return Units.toPoints(val);
     }
 
     /**
@@ -509,8 +510,8 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
      */
     private void setInset(short propId, double margin){
         setEscherProperty(propId, Units.toEMU(margin));
-    }    
-    
+    }
+
     /**
      * Returns the value indicating word wrap.
      *
@@ -524,7 +525,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
         EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
         return prop == null ? WrapSquare : prop.getPropertyValue();
     }
-    
+
     /**
      *  Specifies how the text should be wrapped
      *
@@ -545,7 +546,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
     public void setWordWrap(boolean wrap) {
         setWordWrapEx(wrap ? WrapSquare : WrapNone);
     }
-    
+
     /**
      * @return id for the text.
      */
@@ -567,7 +568,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
     @Override
     public List<HSLFTextParagraph> getTextParagraphs(){
         if (!_paragraphs.isEmpty()) return _paragraphs;
-        
+
         _txtbox = getEscherTextboxWrapper();
         if (_txtbox == null) {
             _paragraphs.addAll(HSLFTextParagraph.createEmptyParagraph());
@@ -578,7 +579,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
                 // there are actually TextBoxRecords without extra data - see #54722
                 _paragraphs = HSLFTextParagraph.createEmptyParagraph(_txtbox);
             }
-                
+
             if (_paragraphs.isEmpty()) {
                 logger.log(POILogger.WARN, "TextRecord didn't contained any text lines");
             }
@@ -594,7 +595,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
         for (HSLFTextParagraph p : _paragraphs) {
             p.setParentShape(this);
         }
-        
+
         return _paragraphs;
     }
 
@@ -675,7 +676,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
         //  them to \n
         String text = rawText.replace('\r','\n').replace('\u000b', replChr);
      */
-    
+
     /**
      * Return <code>OEPlaceholderAtom</code>, the atom that describes a placeholder.
      *
@@ -777,13 +778,13 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
         return HSLFTextParagraph.toExternalString(rawText, getRunType());
     }
 
-    
+
     // Update methods follow
 
       /**
        * Adds the supplied text onto the end of the TextParagraphs,
        * creating a new RichTextRun for it to sit in.
-       * 
+       *
        * @param text the text string used by this object.
        */
       public HSLFTextRun appendText(String text, boolean newParagraph) {
@@ -800,7 +801,7 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
           setTextId(text.hashCode());
           return htr;
       }
-      
+
       /**
        * Saves the modified paragraphs/textrun to the records.
        * Also updates the styles to the correct text length.
@@ -813,7 +814,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>
      *         if not found.
      */
@@ -880,5 +881,15 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
         }
     }
 
-    
+
+    /**
+     * Get alternative representation of text shape stored as metro blob escher property.
+     * The returned shape is the first shape in stored group shape of the metro blob
+     *
+     * @return null, if there's no alternative representation, otherwise the text shape
+     */
+    public TextShape<?,?> getMetroShape() {
+        HSLFMetroShape<TextShape<?,?>> mbs = new HSLFMetroShape<TextShape<?,?>>(this);
+        return mbs.getShape();
+    }
 }
\ No newline at end of file
diff --git a/test-data/slideshow/bug52297.ppt b/test-data/slideshow/bug52297.ppt
new file mode 100644 (file)
index 0000000..79fd609
Binary files /dev/null and b/test-data/slideshow/bug52297.ppt differ