]> source.dussan.org Git - poi.git/commitdiff
improved rendering of indented text in XSLF, also improved import content from extern...
authorYegor Kozlov <yegor@apache.org>
Thu, 10 Nov 2011 13:59:16 +0000 (13:59 +0000)
committerYegor Kozlov <yegor@apache.org>
Thu, 10 Nov 2011 13:59:16 +0000 (13:59 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1200330 13f79535-47bb-0310-9956-ffa450edef68

15 files changed:
src/ooxml/java/org/apache/poi/xslf/usermodel/LineCap.java
src/ooxml/java/org/apache/poi/xslf/usermodel/RenderableShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java [new file with mode: 0755]
test-data/slideshow/themes.pptx

index f2bfba99fdc70ae9613ed5bc2813642a871ce866..55b4c8492fe543b0ceadb19930ab46288ba3809e 100644 (file)
 package org.apache.poi.xslf.usermodel;\r
 \r
 /**\r
+ * \r
+ *\r
  * @author Yegor Kozlov\r
  */\r
 public enum LineCap {\r
     /**\r
-     *  Rounded ends - the default\r
+     *  Rounded ends\r
      */\r
     ROUND,\r
     /**\r
index bbd0de9ea6a4885d26a9196e273c16d6df097604..82a29756a4bb6cfd75609c53e0cf5f4e728cc947 100644 (file)
@@ -469,10 +469,19 @@ class RenderableShape {
 \r
         // first fill\r
         Paint fill = getFillPaint(graphics);\r
+        Paint line = getLinePaint(graphics);\r
+        applyStroke(graphics); // the stroke applies both to the shadow and the shape\r
+\r
+        // first paint the shadow\r
+        if(shadow != null) for(Outline o : elems){\r
+            if(o.getPath().isFilled()){\r
+                if(fill != null) shadow.fill(graphics, o.getOutline());\r
+                if(line != null) shadow.draw(graphics, o.getOutline());\r
+            }\r
+        }\r
+        // then fill the shape interior\r
         if(fill != null) for(Outline o : elems){\r
             if(o.getPath().isFilled()){\r
-                if(shadow != null) shadow.fill(graphics, o.getOutline());\r
-\r
                 graphics.setPaint(fill);\r
                 graphics.fill(o.getOutline());\r
             }\r
@@ -482,13 +491,8 @@ class RenderableShape {
         _shape.drawContent(graphics);\r
 \r
         // then stroke the shape outline\r
-        Paint line = getLinePaint(graphics);\r
         if(line != null) for(Outline o : elems){\r
             if(o.getPath().isStroked()){\r
-                applyStroke(graphics); // the stroke applies both to the shadow and the shape\r
-\r
-                if(shadow != null) shadow.draw(graphics, o.getOutline());\r
-\r
                 graphics.setPaint(line);\r
                 graphics.draw(o.getOutline());\r
             }\r
index 647b414c538da070eeb750348fd50289e6a542f5..b7f1f3d389fee00aeeb44c08c30be97afeb288e8 100644 (file)
@@ -331,4 +331,12 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
         return lst;\r
     }\r
 \r
+    /**\r
+     * YK: dashing of lines is suppressed for now.\r
+     * @return\r
+     */\r
+    @Override\r
+    public XSLFShadow getShadow() {\r
+        return null;\r
+    }\r
 }
\ No newline at end of file
index 445c16e9b0820a826f865c006e480cfe0b2b3405..1b5bbea2e42981f49a99c490b2998efc10b93d88 100644 (file)
@@ -22,6 +22,7 @@ package org.apache.poi.xslf.usermodel;
 import org.apache.poi.POIXMLException;\r
 import org.apache.poi.openxml4j.opc.PackagePart;\r
 import org.apache.poi.openxml4j.opc.PackageRelationship;\r
+import org.apache.poi.openxml4j.opc.TargetMode;\r
 import org.apache.poi.util.Beta;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;\r
@@ -97,8 +98,7 @@ public class XSLFPictureShape extends XSLFSimpleShape {
 \r
     public XSLFPictureData getPictureData() {\r
         if(_data == null){\r
-            CTPicture ct = (CTPicture)getXmlObject();\r
-            String blipId = ct.getBlipFill().getBlip().getEmbed();\r
+            String blipId = getBlipId();\r
 \r
             PackagePart p = getSheet().getPackagePart();\r
             PackageRelationship rel = p.getRelationship(blipId);\r
@@ -115,6 +115,11 @@ public class XSLFPictureShape extends XSLFSimpleShape {
         return _data;\r
     }\r
 \r
+    private String getBlipId(){\r
+        CTPicture ct = (CTPicture)getXmlObject();\r
+        return ct.getBlipFill().getBlip().getEmbed();\r
+    }\r
+\r
     @Override\r
     public void drawContent(Graphics2D graphics) {\r
 \r
@@ -126,4 +131,19 @@ public class XSLFPictureShape extends XSLFSimpleShape {
 \r
         renderer.drawImage(graphics, data, getAnchor());\r
     }\r
+\r
+\r
+    @Override\r
+    void copy(XSLFShape sh){\r
+        super.copy(sh);\r
+\r
+        XSLFPictureShape p = (XSLFPictureShape)sh;\r
+        String blipId = p.getBlipId();\r
+        String relId = getSheet().importBlip(blipId, p.getSheet().getPackagePart());\r
+\r
+        CTPicture ct = (CTPicture)getXmlObject();\r
+        CTBlip blip = ct.getBlipFill().getBlip();\r
+        blip.setEmbed(relId);\r
+\r
+    }\r
 }\r
index 70d42ce5c33f16fdecad4ed00445ac99e2163028..7c2128e8fbd2f129f868feca21d3b879569bc8c1 100644 (file)
@@ -32,6 +32,7 @@ import java.awt.geom.Rectangle2D;
  * @author Yegor Kozlov\r
  */\r
 public class XSLFShadow extends XSLFSimpleShape {\r
+\r
     private XSLFSimpleShape _parent;\r
 \r
     /* package */XSLFShadow(CTOuterShadowEffect shape, XSLFSimpleShape parentShape) {\r
index 9ff619257cf9406c5459ec81e01f15e16bb3350f..00191df6f0bc8dc641d35b3cd3ac6f5e9cd2a3ce 100644 (file)
@@ -20,6 +20,7 @@
 package org.apache.poi.xslf.usermodel;\r
 \r
 import org.apache.poi.util.Beta;\r
+import org.apache.poi.util.Internal;\r
 import org.apache.xmlbeans.XmlObject;\r
 \r
 import java.awt.Graphics2D;\r
@@ -34,27 +35,23 @@ import java.awt.geom.Rectangle2D;
 public abstract class XSLFShape {\r
 \r
     /**\r
-     *\r
      * @return the position of this shape within the drawing canvas.\r
-     * The coordinates are expressed in points\r
+     *         The coordinates are expressed in points\r
      */\r
     public abstract Rectangle2D getAnchor();\r
 \r
     /**\r
-     *\r
      * @param anchor the position of this shape within the drawing canvas.\r
-     * The coordinates are expressed in points\r
+     *               The coordinates are expressed in points\r
      */\r
     public abstract void setAnchor(Rectangle2D anchor);\r
 \r
     /**\r
-     *\r
      * @return the xml bean holding this shape's data\r
      */\r
     public abstract XmlObject getXmlObject();\r
 \r
     /**\r
-     *\r
      * @return human-readable name of this shape, e.g. "Rectange 3"\r
      */\r
     public abstract String getShapeName();\r
@@ -64,8 +61,8 @@ public abstract class XSLFShape {
      * This ID may be used to assist in uniquely identifying this object so that it can\r
      * be referred to by other parts of the document.\r
      * <p>\r
-     *     If multiple objects within the same document share the same id attribute value,\r
-     *     then the document shall be considered non-conformant.\r
+     * If multiple objects within the same document share the same id attribute value,\r
+     * then the document shall be considered non-conformant.\r
      * </p>\r
      *\r
      * @return unique id of this shape\r
@@ -82,7 +79,7 @@ public abstract class XSLFShape {
      * @param theta the rotation angle in degrees.\r
      */\r
     public abstract void setRotation(double theta);\r
-   \r
+\r
     /**\r
      * Rotation angle in degrees\r
      * <p>\r
@@ -105,7 +102,7 @@ public abstract class XSLFShape {
      * @param flip whether the shape is vertically flipped\r
      */\r
     public abstract void setFlipVertical(boolean flip);\r
-    \r
+\r
     /**\r
      * Whether the shape is horizontally flipped\r
      *\r
@@ -132,15 +129,15 @@ public abstract class XSLFShape {
      *\r
      * @param graphics the graphics whos transform matrix will be modified\r
      */\r
-    protected void applyTransform(Graphics2D graphics){\r
+    protected void applyTransform(Graphics2D graphics) {\r
         Rectangle2D anchor = getAnchor();\r
 \r
         // rotation\r
         double rotation = getRotation();\r
-        if(rotation != 0.) {\r
-               // PowerPoint rotates shapes relative to the geometric center\r
-            double centerX = anchor.getX() + anchor.getWidth()/2;\r
-            double centerY = anchor.getY() + anchor.getHeight()/2;\r
+        if (rotation != 0.) {\r
+            // PowerPoint rotates shapes relative to the geometric center\r
+            double centerX = anchor.getX() + anchor.getWidth() / 2;\r
+            double centerY = anchor.getY() + anchor.getHeight() / 2;\r
 \r
             graphics.translate(centerX, centerY);\r
             graphics.rotate(Math.toRadians(rotation));\r
@@ -148,18 +145,34 @@ public abstract class XSLFShape {
         }\r
 \r
         //flip horizontal\r
-        if(getFlipHorizontal()){\r
+        if (getFlipHorizontal()) {\r
             graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY());\r
             graphics.scale(-1, 1);\r
-            graphics.translate(-anchor.getX() , -anchor.getY());\r
+            graphics.translate(-anchor.getX(), -anchor.getY());\r
         }\r
 \r
         //flip vertical\r
-        if(getFlipVertical()){\r
+        if (getFlipVertical()) {\r
             graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());\r
             graphics.scale(1, -1);\r
             graphics.translate(-anchor.getX(), -anchor.getY());\r
         }\r
     }\r
 \r
+    /**\r
+     * Set the contents of this shape to be a copy of the source shape.\r
+     * This method is called recursively for each shape when merging slides\r
+     *\r
+     * @param  sh the source shape\r
+     * @see org.apache.poi.xslf.usermodel.XSLFSlide#importContent(XSLFSheet)\r
+     */\r
+    @Internal\r
+    void copy(XSLFShape sh) {\r
+        if (!getClass().isInstance(sh)) {\r
+            throw new IllegalArgumentException(\r
+                    "Can't copy " + sh.getClass().getSimpleName() + " into " + getClass().getSimpleName());\r
+        }\r
+\r
+        setAnchor(sh.getAnchor());\r
+    }\r
 }
\ No newline at end of file
index 964df2df9687f369f3e0d832d8c7aaba301d3666..a5baed5312a84de821c738d3b8f50c81cfd8be7a 100644 (file)
 package org.apache.poi.xslf.usermodel;
 
 import org.apache.poi.POIXMLDocumentPart;
+import org.apache.poi.POIXMLException;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.openxml4j.opc.PackageRelationship;
 import org.apache.poi.openxml4j.opc.TargetMode;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
 import org.apache.xmlbeans.XmlObject;
@@ -270,14 +272,29 @@ public abstract class XSLFSheet extends POIXMLDocumentPart implements Iterable<X
 
     /**
      * Set the contents of this sheet to be a copy of the source sheet.
+     * This method erases any existing shapes and replaces them with
+     * object from the source sheet.
      *
      * @param src the source sheet to copy data from
+     * @return modified 'this'
      */
-    public void copy(XSLFSheet src){
+    public XSLFSheet importContent(XSLFSheet src){
         _shapes = null;
         _spTree = null;
         _drawing = null;
+        // first copy the source xml
         getXmlObject().set(src.getXmlObject());
+
+        // recursively update each shape 
+        List<XSLFShape> tgtShapes = getShapeList();
+        List<XSLFShape> srcShapes = src.getShapeList();
+        for(int i = 0; i < tgtShapes.size(); i++){
+            XSLFShape s1 = srcShapes.get(i);
+            XSLFShape s2 = tgtShapes.get(i);
+
+            s2.copy(s1);
+        }
+        return this;
     }
 
     /**
@@ -423,4 +440,32 @@ public abstract class XSLFSheet extends POIXMLDocumentPart implements Iterable<X
 
         }
     }
+
+    /**
+     * Import a picture data from another document.
+     *
+     * @param blipId        ID of the package relationship to retrieve.
+     * @param packagePart   package part containing the data to import
+     * @return ID of the created relationship
+     */
+    String importBlip(String blipId, PackagePart packagePart) {
+        PackageRelationship blipRel = packagePart.getRelationship(blipId);
+        PackagePart blipPart;
+        try {
+            blipPart = packagePart.getRelatedPart(blipRel);
+        } catch (InvalidFormatException e){
+            throw new POIXMLException(e);
+        }
+        XSLFPictureData data = new XSLFPictureData(blipPart, null);
+
+        XMLSlideShow ppt = getSlideShow();
+        int pictureIdx = ppt.addPicture(data.getData(), data.getPictureType());
+        PackagePart pic = ppt.getAllPictures().get(pictureIdx).getPackagePart();
+
+        PackageRelationship rel = getPackagePart().addRelationship(
+                pic.getPartName(), TargetMode.INTERNAL, blipRel.getRelationshipType());
+        addRelation(rel.getId(), new XSLFPictureData(pic, rel));
+
+        return rel.getId();
+    }
 }
\ No newline at end of file
index c67f39e7932e6f425cdc8b36c8c6b2f3a6c30c57..5e62ec87eab8a13ae360436f01b984580c621f3d 100644 (file)
@@ -29,6 +29,11 @@ import org.apache.poi.xslf.model.geom.IAdjustableShape;
 import org.apache.poi.xslf.model.geom.Outline;\r
 import org.apache.poi.xslf.model.geom.Path;\r
 import org.apache.poi.xslf.model.geom.PresetGeometries;\r
+import org.apache.poi.openxml4j.opc.PackageRelationship;\r
+import org.apache.poi.openxml4j.opc.PackagePart;\r
+import org.apache.poi.openxml4j.opc.TargetMode;\r
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;\r
+import org.apache.poi.POIXMLException;\r
 import org.apache.xmlbeans.XmlObject;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;\r
@@ -48,8 +53,10 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
 import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;\r
 \r
 import java.awt.Color;\r
 import java.awt.Graphics2D;\r
@@ -69,6 +76,7 @@ import java.util.List;
  */\r
 @Beta\r
 public abstract class XSLFSimpleShape extends XSLFShape {\r
+    private static CTOuterShadowEffect NO_SHADOW = CTOuterShadowEffect.Factory.newInstance();\r
 \r
     private final XmlObject _shape;\r
     private final XSLFSheet _sheet;\r
@@ -285,6 +293,11 @@ public abstract class XSLFSimpleShape extends XSLFShape {
             CTSolidColorFillProperties fill = ln.isSetSolidFill() ? ln\r
                     .getSolidFill() : ln.addNewSolidFill();\r
             fill.setSrgbClr(rgb);\r
+            if(fill.isSetHslClr()) fill.unsetHslClr();\r
+            if(fill.isSetPrstClr()) fill.unsetPrstClr();\r
+            if(fill.isSetSchemeClr()) fill.unsetSchemeClr();\r
+            if(fill.isSetScrgbClr()) fill.unsetScrgbClr();\r
+            if(fill.isSetSysClr()) fill.unsetSysClr();\r
         }\r
     }\r
 \r
@@ -483,6 +496,11 @@ public abstract class XSLFSimpleShape extends XSLFShape {
                     (byte) color.getGreen(), (byte) color.getBlue()});\r
 \r
             fill.setSrgbClr(rgb);\r
+            if(fill.isSetHslClr()) fill.unsetHslClr();\r
+            if(fill.isSetPrstClr()) fill.unsetPrstClr();\r
+            if(fill.isSetSchemeClr()) fill.unsetSchemeClr();\r
+            if(fill.isSetScrgbClr()) fill.unsetScrgbClr();\r
+            if(fill.isSetSysClr()) fill.unsetSysClr();\r
         }\r
     }\r
 \r
@@ -508,7 +526,7 @@ public abstract class XSLFSimpleShape extends XSLFShape {
                 CTShapeProperties spPr = shape.getSpPr();\r
                 if (spPr.isSetEffectLst()) {\r
                     CTOuterShadowEffect obj = spPr.getEffectLst().getOuterShdw();\r
-                    setValue(obj);\r
+                    setValue(obj == null ? NO_SHADOW : obj);\r
                     return true;\r
                 }\r
                 return false;\r
@@ -530,7 +548,7 @@ public abstract class XSLFSimpleShape extends XSLFShape {
                 }\r
             }\r
         }\r
-        return obj == null ? null : new XSLFShadow(obj, this);\r
+        return (obj == null || obj == NO_SHADOW) ? null : new XSLFShadow(obj, this);\r
     }\r
 \r
     @Override\r
@@ -640,4 +658,50 @@ public abstract class XSLFSimpleShape extends XSLFShape {
     public void drawContent(Graphics2D graphics){\r
 \r
     }\r
+\r
+    @Override\r
+    void copy(XSLFShape sh){\r
+        super.copy(sh);\r
+\r
+        XSLFSimpleShape s = (XSLFSimpleShape)sh;\r
+\r
+        Color srsSolidFill = s.getFillColor();\r
+        Color tgtSoliFill = getFillColor();\r
+        if(srsSolidFill != null && !srsSolidFill.equals(tgtSoliFill)){\r
+            setFillColor(srsSolidFill);\r
+        }\r
+\r
+        if(getSpPr().isSetBlipFill()){\r
+            CTBlip blip = getSpPr().getBlipFill().getBlip();\r
+            String blipId = blip.getEmbed();\r
+\r
+            String relId = getSheet().importBlip(blipId, s.getSheet().getPackagePart());\r
+            blip.setEmbed(relId);\r
+        }\r
+        \r
+        Color srcLineColor = s.getLineColor();\r
+        Color tgtLineColor = getLineColor();\r
+        if(srcLineColor != null && !srcLineColor.equals(tgtLineColor)) {\r
+            setLineColor(srcLineColor);\r
+        }\r
+\r
+        double srcLineWidth = s.getLineWidth();\r
+        double tgtLineWidth = getLineWidth();\r
+        if(srcLineWidth != tgtLineWidth) {\r
+            setLineWidth(srcLineWidth);\r
+        }\r
+\r
+        LineDash srcLineDash = s.getLineDash();\r
+        LineDash tgtLineDash = getLineDash();\r
+        if(srcLineDash != null && srcLineDash != tgtLineDash) {\r
+            setLineDash(srcLineDash);\r
+        }\r
+\r
+        LineCap srcLineCap = s.getLineCap();\r
+        LineCap tgtLineCap = getLineCap();\r
+        if(srcLineCap != null && srcLineCap != tgtLineCap) {\r
+            setLineCap(srcLineCap);\r
+        }\r
+\r
+    }\r
 }\r
index 598baaeee4d9fdd0b9f2803849fe398258d26991..aee9ef0020a29711e6e1f74f698dd7a35b784d3b 100644 (file)
@@ -26,11 +26,13 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupTransform2D;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
 import org.openxmlformats.schemas.presentationml.x2006.main.SldDocument;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground;
 
 import java.awt.Graphics2D;
 import java.io.IOException;
@@ -228,4 +230,21 @@ public final class XSLFSlide extends XSLFSheet {
     }
 
 
+    @Override
+    public XSLFSlide importContent(XSLFSheet src){
+        super.importContent(src);
+
+        CTBackground bg = ((CTSlide)src.getXmlObject()).getCSld().getBg();
+        if(bg != null) {
+            if(bg.isSetBgPr() && bg.getBgPr().isSetBlipFill()){
+                CTBlip blip = bg.getBgPr().getBlipFill().getBlip();
+                String blipId = blip.getEmbed();
+
+                String relId = importBlip(blipId, src.getPackagePart());
+                blip.setEmbed(relId);
+            }
+        }
+        return this;
+    }
+
 }
index 669fa366193cb3abc1111bc8c7af17acdbc8b5d9..4358288ee009bb3b049d5874a36e0804ad2211fd 100644 (file)
@@ -27,6 +27,12 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharBullet;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePoint;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;\r
 \r
@@ -56,20 +62,33 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
     private final XSLFTextShape _shape;\r
     private List<TextFragment> _lines;\r
     private TextFragment _bullet;\r
+    /**\r
+     * the highest line in this paragraph. Used for line spacing.\r
+     */\r
+    private double _maxLineHeight;\r
 \r
     XSLFTextParagraph(CTTextParagraph p, XSLFTextShape shape){\r
         _p = p;\r
         _runs = new ArrayList<XSLFTextRun>();\r
         _shape = shape;\r
 \r
-        for (CTRegularTextRun r : _p.getRList()) {\r
-            _runs.add(new XSLFTextRun(r, this));\r
-        }\r
-\r
-        for (CTTextField f : _p.getFldList()) {\r
-            CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();\r
-            r.setT(f.getT());\r
-            _runs.add(new XSLFTextRun(r, this));\r
+        for(XmlObject ch : _p.selectPath("*")){\r
+            if(ch instanceof CTRegularTextRun){\r
+                CTRegularTextRun r = (CTRegularTextRun)ch;\r
+                _runs.add(new XSLFTextRun(r, this));\r
+            } else if (ch instanceof CTTextLineBreak){\r
+                CTTextLineBreak br = (CTTextLineBreak)ch;\r
+                CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();\r
+                r.setRPr(br.getRPr());\r
+                r.setT("\n");\r
+                _runs.add(new XSLFTextRun(r, this));\r
+            } else if (ch instanceof CTTextField){\r
+                CTTextField f = (CTTextField)ch;\r
+                CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();\r
+                r.setRPr(f.getRPr());\r
+                r.setT(f.getT());\r
+                _runs.add(new XSLFTextRun(r, this));\r
+            }\r
         }\r
     }\r
 \r
@@ -81,19 +100,10 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
         return out.toString();\r
     }\r
 \r
-    private String getVisibleText(){\r
+    String getRenderableText(){\r
         StringBuilder out = new StringBuilder();\r
         for (XSLFTextRun r : _runs) {\r
-            String txt = r.getText();\r
-            switch (r.getTextCap()){\r
-                case ALL:\r
-                    txt = txt.toUpperCase();\r
-                    break;\r
-                case SMALL:\r
-                    txt = txt.toLowerCase();\r
-                    break;\r
-            }\r
-            out.append(txt);\r
+            out.append(r.getRenderableText());\r
         }\r
         return out.toString();\r
     }\r
@@ -183,6 +193,12 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
         return fetcher.getValue();\r
     }\r
 \r
+    public void setBulletFont(String typeface){\r
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
+        CTTextFont font = pr.isSetBuFont() ? pr.getBuFont() : pr.addNewBuFont();\r
+        font.setTypeface(typeface);\r
+    }\r
+\r
     /**\r
      * @return the character to be used in place of the standard bullet point\r
      */\r
@@ -200,6 +216,12 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
         return fetcher.getValue();\r
     }\r
 \r
+    public void setBulletCharacter(String str){\r
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
+        CTTextCharBullet c = pr.isSetBuChar() ? pr.getBuChar() : pr.addNewBuChar();\r
+        c.setChar(str);\r
+    }\r
+\r
     public Color getBulletFontColor(){\r
         final XSLFTheme theme = getParentShape().getSheet().getTheme();\r
         ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getLevel()){\r
@@ -216,6 +238,13 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
         return fetcher.getValue();\r
     }\r
 \r
+    public void setBulletFontColor(Color color){\r
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
+        CTColor c = pr.isSetBuClr() ? pr.getBuClr() : pr.addNewBuClr();\r
+        CTSRgbColor clr = c.isSetSrgbClr() ? c.getSrgbClr() : c.addNewSrgbClr();\r
+        clr.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()});\r
+    }\r
+\r
     public double getBulletFontSize(){\r
         ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){\r
             public boolean fetch(CTTextParagraphProperties props){\r
@@ -234,11 +263,17 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
         return fetcher.getValue() == null ? 100 : fetcher.getValue();\r
     }\r
 \r
+    public void setBulletFontSize(double size){\r
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
+        CTTextBulletSizePoint pt = pr.isSetBuSzPts() ? pr.getBuSzPts() : pr.addNewBuSzPts();\r
+        pt.setVal((int)(size*1000));\r
+        if(pr.isSetBuSzPct()) pr.unsetBuSzPct();\r
+    }\r
+\r
     /**\r
      * Specifies the indent size that will be applied to the first line of text in the paragraph.\r
      *\r
-     * @param value the indent in points. The value of -1 unsets the indent attribute\r
-     * from the underlying xml bean.\r
+     * @param value the indent in points. \r
      */\r
     public void setIndent(double value){\r
         CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
@@ -297,7 +332,8 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
             }\r
         };\r
         fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue() == null ? 0 : fetcher.getValue();\r
+        // if the marL attribute is omitted, then a value of 347663 is implied\r
+        return fetcher.getValue() == null ? Units.toPoints(347663) : fetcher.getValue();\r
     }\r
 \r
     /**\r
@@ -512,7 +548,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
 \r
     /**\r
      *\r
-     * @param isBullet whether text in this paragraph has bullets\r
+     * @param flag whether text in this paragraph has bullets\r
      */\r
     public void setBullet(boolean flag) {\r
         if(isBullet() == flag) return;\r
@@ -535,38 +571,117 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
         return _lines;\r
     }\r
 \r
+    /**\r
+     * Returns wrapping width to break lines in this paragraph\r
+     *\r
+     * @param firstLine whether the first line is breaking\r
+     *\r
+     * @return  wrapping width in points\r
+     */\r
+    double getWrappingWidth(boolean firstLine){\r
+        // internal margins for the text box\r
+        double leftInset = _shape.getLeftInset();\r
+        double rightInset = _shape.getRightInset();\r
+\r
+        Rectangle2D anchor = _shape.getAnchor();\r
+\r
+        double leftMargin = getLeftMargin();\r
+        double indent = getIndent();\r
+\r
+        double width;\r
+        if(!_shape.getWordWrap()) {\r
+            // if wordWrap == false then we return the advance to the right border of the sheet\r
+            width = _shape.getSheet().getSlideShow().getPageSize().getWidth() - anchor.getX();\r
+        } else {\r
+            width = anchor.getWidth() -  leftInset - rightInset - leftMargin;\r
+            if(firstLine) {\r
+                if(isBullet()){\r
+                    width -= Math.abs(indent);\r
+                } else {\r
+                    if(indent > 0) width -= indent; // first line indentation\r
+                    else if (indent < 0) { // hanging indentation: the first line start at the left margin\r
+                        width += leftMargin;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        return width;\r
+    }\r
+\r
     public double draw(Graphics2D graphics, double x, double y){\r
-        double marginLeft = _shape.getLeftInset();\r
-        double marginRight = _shape.getRightInset();\r
+        double leftInset = _shape.getLeftInset();\r
+        double rightInset = _shape.getRightInset();\r
         Rectangle2D anchor = _shape.getAnchor();\r
         double penY = y;\r
 \r
-        double textOffset = getLeftMargin();\r
+        double leftMargin = getLeftMargin();\r
         boolean firstLine = true;\r
+        double indent = getIndent();\r
         for(TextFragment line : _lines){\r
             double penX = x;\r
+\r
+            if(firstLine) {\r
+\r
+                if(_bullet != null){\r
+                    if(indent < 0) {\r
+                        // a negative value means "Hanging" indentation and\r
+                        // indicates the position of the actual bullet character.\r
+                        // (the bullet is shifted to right relative to the text)\r
+                        _bullet.draw(graphics, penX,  penY);\r
+                        penX -= indent;\r
+                    } else if(indent > 0){\r
+                        penX += leftMargin;\r
+                        // a positive value means the "First Line" indentation:\r
+                        // the first line is indented and other lines start at the bullet ofset\r
+                        _bullet.draw(graphics, penX,  penY);\r
+                        penX += indent;\r
+                    } else {\r
+                        // no special indent. The first line behaves like all others\r
+                        penX += leftMargin;\r
+\r
+                        // a zero indent means that the bullet and text have the same offset\r
+                        _bullet.draw(graphics, penX,  penY);\r
+\r
+                        // don't let text overlay the bullet and advance by the bullet width\r
+                        penX += _bullet._layout.getAdvance() + 1;\r
+                    }\r
+                } else {\r
+                    if(indent < 0) {\r
+                        // if bullet=false and indentation=hanging then the first line\r
+                        // starts at the left offset (penX is not incremented)\r
+                    } else if(indent > 0) {\r
+                        // first line indent shifts penX\r
+                        penX += indent + leftMargin;\r
+                    }  else {\r
+                        // no special indent. The first line behaves like all others\r
+                        penX += leftMargin;\r
+                    }\r
+                }\r
+            } else {\r
+                penX += leftMargin;\r
+            }\r
+\r
+\r
             switch (getTextAlign()) {\r
                 case CENTER:\r
-                    penX += textOffset + (anchor.getWidth() - textOffset - line.getWidth() - marginLeft - marginRight) / 2;\r
+                    penX += (anchor.getWidth() - leftMargin - line.getWidth() - leftInset - rightInset) / 2;\r
                     break;\r
                 case RIGHT:\r
-                    penX += (anchor.getWidth() - line.getWidth() - marginLeft - marginRight);\r
+                    penX += (anchor.getWidth() - line.getWidth() - leftInset - rightInset);\r
                     break;\r
                 default:\r
-                    penX = x + textOffset;\r
+                    //penX += leftInset;\r
                     break;\r
             }\r
 \r
-            if(_bullet != null && firstLine){\r
-                _bullet.draw(graphics, penX  + getIndent(),  penY);\r
-            }\r
             line.draw(graphics, penX,  penY);\r
 \r
             //The vertical line spacing\r
             double spacing = getLineSpacing();\r
             if(spacing > 0) {\r
                 // If linespacing >= 0, then linespacing is a percentage of normal line height.\r
-                penY += spacing*0.01*line.getHeight();\r
+                penY += spacing*0.01* _maxLineHeight;\r
             } else {\r
                 // positive value means absolute spacing in points\r
                 penY += -spacing;\r
@@ -607,13 +722,13 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
     }\r
 \r
     AttributedString getAttributedString(Graphics2D graphics){\r
-        String text = getVisibleText();\r
+        String text = getRenderableText();\r
 \r
         AttributedString string = new AttributedString(text);\r
 \r
         int startIndex = 0;\r
         for (XSLFTextRun run : _runs){\r
-            int length = run.getText().length();\r
+            int length = run.getRenderableText().length();\r
             if(length == 0) {\r
                 // skip empty runs\r
                 continue;\r
@@ -656,6 +771,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
     void breakText(Graphics2D graphics){\r
         _lines = new ArrayList<TextFragment>();\r
 \r
+        String text = getRenderableText();\r
         AttributedString at = getAttributedString(graphics);\r
         AttributedCharacterIterator it = at.getIterator();\r
         if(it.getBeginIndex() == it.getEndIndex()) {\r
@@ -664,12 +780,17 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
         LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext());\r
         for (;;) {\r
             int startIndex = measurer.getPosition();\r
-            double wrappingWidth = getWrappingWidth() + 1; // add a pixel to compensate rounding errors\r
-            TextLayout layout = measurer.nextLayout((float)wrappingWidth, it.getEndIndex(), true);\r
+            double wrappingWidth = getWrappingWidth(_lines.size() == 0) + 1; // add a pixel to compensate rounding errors\r
+\r
+\r
+            int nextBreak = text.indexOf('\n', startIndex + 1);\r
+            if(nextBreak == -1) nextBreak = it.getEndIndex();\r
+\r
+            TextLayout layout = measurer.nextLayout((float)wrappingWidth, nextBreak, true);\r
              if (layout == null) {\r
                  // layout can be null if the entire word at the current position\r
                  // does not fit within the wrapping width. Try with requireNextWord=false.\r
-                 layout = measurer.nextLayout((float)wrappingWidth, it.getEndIndex(), false);\r
+                 layout = measurer.nextLayout((float)wrappingWidth, nextBreak, false);\r
              }\r
 \r
             int endIndex = measurer.getPosition();\r
@@ -683,6 +804,8 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
             TextFragment line = new TextFragment(layout, str);\r
             _lines.add(line);\r
 \r
+            _maxLineHeight = Math.max(_maxLineHeight, line.getHeight());\r
+\r
             if(endIndex == it.getEndIndex()) break;\r
         }\r
 \r
@@ -714,17 +837,6 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
 \r
     }\r
 \r
-    double getWrappingWidth(){\r
-        double width;\r
-        if(!_shape.getWordWrap()) {\r
-            width = _shape.getSheet().getSlideShow().getPageSize().getWidth();\r
-        } else {\r
-            width = _shape.getAnchor().getWidth() -\r
-                    _shape.getLeftInset() - _shape.getRightInset() - getLeftMargin();\r
-        }\r
-        return width;\r
-    }\r
-\r
     CTTextParagraphProperties getDefaultStyle(){\r
         CTPlaceholder ph = _shape.getCTPlaceholder();\r
         String defaultStyleSelector;\r
@@ -782,4 +894,64 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
         return ok;\r
     }\r
 \r
+    void copy(XSLFTextParagraph p){\r
+        TextAlign srcAlign = p.getTextAlign();\r
+        if(srcAlign != getTextAlign()){\r
+            setTextAlign(srcAlign);\r
+        }\r
+\r
+        boolean isBullet = p.isBullet();\r
+        if(isBullet != isBullet()){\r
+            setBullet(isBullet);\r
+            if(isBullet) {\r
+                String buFont = p.getBulletFont();\r
+                if(buFont != null && !buFont.equals(getBulletFont())){\r
+                    setBulletFont(buFont);\r
+                }\r
+                String buChar = p.getBulletCharacter();\r
+                if(buChar != null && !buChar.equals(getBulletCharacter())){\r
+                    setBulletCharacter(buChar);\r
+                }\r
+                Color buColor = p.getBulletFontColor();\r
+                if(buColor != null && !buColor.equals(getBulletFontColor())){\r
+                    setBulletFontColor(buColor);\r
+                }\r
+                double buSize = p.getBulletFontSize();\r
+                if(buSize != getBulletFontSize()){\r
+                    setBulletFontSize(buSize);\r
+                }\r
+            }\r
+        }\r
+\r
+        double leftMargin = p.getLeftMargin();\r
+        if(leftMargin != getLeftMargin()){\r
+            setLeftMargin(leftMargin);\r
+        }\r
+\r
+        double indent = p.getIndent();\r
+        if(indent != getIndent()){\r
+            setIndent(indent);\r
+        }\r
+\r
+        double spaceAfter = p.getSpaceAfter();\r
+        if(spaceAfter != getSpaceAfter()){\r
+            setSpaceAfter(spaceAfter);\r
+        }\r
+        double spaceBefore = p.getSpaceBefore();\r
+        if(spaceBefore != getSpaceBefore()){\r
+            setSpaceBefore(spaceBefore);\r
+        }\r
+        double lineSpacing = p.getLineSpacing();\r
+        if(lineSpacing != getLineSpacing()){\r
+            setLineSpacing(lineSpacing);\r
+        }\r
+\r
+        List<XSLFTextRun> srcR = p.getTextRuns();\r
+        List<XSLFTextRun> tgtR = getTextRuns();\r
+        for(int i = 0; i < srcR.size(); i++){\r
+            XSLFTextRun r1 = srcR.get(i);\r
+            XSLFTextRun r2 = tgtR.get(i);\r
+            r2.copy(r1);\r
+        }\r
+    }\r
 }\r
index b4aa3ca8bf6ec9944087f0d0fbe118077aa96ca9..dc79e73c68f121d1ad8d4c05bb824faa8d0480ed 100644 (file)
@@ -56,6 +56,23 @@ public class XSLFTextRun {
         return _r.getT();\r
     }\r
 \r
+    String getRenderableText(){\r
+        String txt = _r.getT();\r
+        switch (getTextCap()){\r
+            case ALL:\r
+                txt = txt.toUpperCase();\r
+                break;\r
+            case SMALL:\r
+                txt = txt.toLowerCase();\r
+                break;\r
+        }\r
+        // TODO-1 is is the place to convert wingdings to unicode\r
+        \r
+        // TODO-2 this is a temporary hack. Rendering text with tabs is not yet supported.\r
+        // for now tabs are replaced with some number of spaces.\r
+        return txt.replace("\t", " ");\r
+    }\r
+\r
     public void setText(String text){\r
         _r.setT(text);\r
     }\r
@@ -69,6 +86,13 @@ public class XSLFTextRun {
         CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill();\r
         CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr();\r
         clr.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()});\r
+\r
+        if(fill.isSetHslClr()) fill.unsetHslClr();\r
+        if(fill.isSetPrstClr()) fill.unsetPrstClr();\r
+        if(fill.isSetSchemeClr()) fill.unsetSchemeClr();\r
+        if(fill.isSetScrgbClr()) fill.unsetScrgbClr();\r
+        if(fill.isSetSysClr()) fill.unsetSysClr();\r
+\r
     }\r
 \r
     public Color getFontColor(){\r
@@ -393,4 +417,32 @@ public class XSLFTextRun {
         return ok;\r
     }\r
 \r
+    void copy(XSLFTextRun r){\r
+        String srcFontFamily = r.getFontFamily();\r
+        if(srcFontFamily != null && !srcFontFamily.equals(getFontFamily())){\r
+            setFontFamily(srcFontFamily);\r
+        }\r
+\r
+        Color srcFontColor = r.getFontColor();\r
+        if(srcFontColor != null && !srcFontColor.equals(getFontColor())){\r
+            setFontColor(srcFontColor);\r
+        }\r
+\r
+        double srcFontSize = r.getFontSize();\r
+        if(srcFontSize  != getFontSize()){\r
+            setFontSize(srcFontSize);\r
+        }\r
+\r
+        boolean bold = r.isBold();\r
+        if(bold != isBold()) setBold(bold);\r
+\r
+        boolean italic = r.isItalic();\r
+        if(italic != isItalic()) setItalic(italic);\r
+\r
+        boolean underline = r.isUnderline();\r
+        if(underline != isUnderline()) setUnderline(underline);\r
+\r
+        boolean strike = r.isStrikethrough();\r
+        if(strike != isStrikethrough()) setStrikethrough(strike);\r
+    }\r
 }\r
index dd49c316a09c6e77c65eac33476ec048a063c716..cce5a61e84fe49b3c750deca3d4ff61a884748a3 100644 (file)
@@ -202,7 +202,8 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements Iterable<
             }
         };
         fetchShapeProperty(fetcher);
-        return fetcher.getValue() == null ? 0 : fetcher.getValue();
+        // If this attribute is omitted, then a value of 0.05 inches is implied
+        return fetcher.getValue() == null ? 3.6 : fetcher.getValue();
     }
 
     /**
@@ -224,7 +225,8 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements Iterable<
             }
         };
         fetchShapeProperty(fetcher);
-        return fetcher.getValue() == null ? 0 : fetcher.getValue();
+        // If this attribute is omitted, then a value of 0.1 inches is implied
+        return fetcher.getValue() == null ? 7.2 : fetcher.getValue();
     }
 
     /**
@@ -246,7 +248,8 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements Iterable<
             }
         };
         fetchShapeProperty(fetcher);
-        return fetcher.getValue() == null ? 0 : fetcher.getValue();
+        // If this attribute is omitted, then a value of 0.1 inches is implied
+        return fetcher.getValue() == null ? 7.2 : fetcher.getValue();
     }
 
     /**
@@ -267,7 +270,8 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements Iterable<
             }
         };
         fetchShapeProperty(fetcher);
-        return fetcher.getValue() == null ? 0 : fetcher.getValue();
+        // If this attribute is omitted, then a value of 0.05 inches is implied
+        return fetcher.getValue() == null ? 3.6 : fetcher.getValue();
     }
 
     /**
@@ -521,4 +525,46 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements Iterable<
         return y - y0;
     }
 
+    @Override
+    void copy(XSLFShape sh){
+        super.copy(sh);
+
+        XSLFTextShape tsh = (XSLFTextShape)sh;
+
+        boolean srcWordWrap = tsh.getWordWrap();
+        if(srcWordWrap != getWordWrap()){
+            setWordWrap(srcWordWrap);
+        }
+
+        double leftInset = tsh.getLeftInset();
+        if(leftInset != getLeftInset()) {
+            setLeftInset(leftInset);
+        }
+        double rightInset = tsh.getRightInset();
+        if(rightInset != getRightInset()) {
+            setRightInset(rightInset);
+        }
+        double topInset = tsh.getTopInset();
+        if(topInset != getTopInset()) {
+            setTopInset(topInset);
+        }
+        double bottomInset = tsh.getBottomInset();
+        if(bottomInset != getBottomInset()) {
+            setBottomInset(bottomInset);
+        }
+
+        VerticalAlignment vAlign = tsh.getVerticalAlignment();
+        if(vAlign != getVerticalAlignment()) {
+            setVerticalAlignment(vAlign);
+        }
+
+        List<XSLFTextParagraph> srcP = tsh.getTextParagraphs();
+        List<XSLFTextParagraph> tgtP = getTextParagraphs();
+        for(int i = 0; i < srcP.size(); i++){
+            XSLFTextParagraph p1 = srcP.get(i);
+            XSLFTextParagraph p2 = tgtP.get(i);
+            p2.copy(p1);
+        }
+
+    }
 }
\ No newline at end of file
index d8cb5783e47765f8d4451f05b9bcde31295adc19..d5e7c61c2bf40fe0a1da951845bc89c3f60e4bec 100755 (executable)
@@ -19,6 +19,12 @@ package org.apache.poi.xslf.usermodel;
 import junit.framework.TestCase;\r
 \r
 import org.apache.poi.xslf.XSLFTestDataSamples;\r
+import org.apache.poi.openxml4j.opc.PackagePart;\r
+\r
+import java.awt.Color;\r
+import java.util.List;\r
+import java.util.Arrays;\r
+import java.util.regex.Pattern;\r
 \r
 /**\r
  * @author Yegor Kozlov\r
@@ -103,4 +109,58 @@ public class TestXSLFSlide extends TestCase {
         assertTrue(slide.getFollowMasterGraphics());\r
     }\r
 \r
+    public void testImportContent(){\r
+        XMLSlideShow ppt = new XMLSlideShow();\r
+\r
+        XMLSlideShow  src = XSLFTestDataSamples.openSampleDocument("themes.pptx");\r
+\r
+        // create a blank slide and import content from the 4th slide of themes.pptx\r
+        XSLFSlide slide1 = ppt.createSlide().importContent(src.getSlides()[3]);\r
+        XSLFShape[] shapes1 = slide1.getShapes();\r
+        assertEquals(2, shapes1.length);\r
+\r
+        XSLFTextShape sh1 = (XSLFTextShape)shapes1[0];\r
+        assertEquals("Austin Theme", sh1.getText());\r
+        XSLFTextRun r1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0);\r
+        assertEquals("Century Gothic", r1.getFontFamily());\r
+        assertEquals(40.0, r1.getFontSize());\r
+        assertTrue(r1.isBold());\r
+        assertTrue(r1.isItalic());\r
+        assertEquals(new Color(148, 198, 0), r1.getFontColor());\r
+        assertNull(sh1.getFillColor());\r
+        assertNull(sh1.getLineColor());\r
+\r
+        XSLFTextShape sh2 = (XSLFTextShape)shapes1[1];\r
+        assertEquals(\r
+                "Text in a autoshape is white\n" +\r
+                "Fill: RGB(148, 198,0)", sh2.getText());\r
+        XSLFTextRun r2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0);\r
+        assertEquals("Century Gothic", r2.getFontFamily());\r
+        assertEquals(18.0, r2.getFontSize());\r
+        assertFalse(r2.isBold());\r
+        assertFalse(r2.isItalic());\r
+        assertEquals(Color.white, r2.getFontColor());\r
+        assertEquals(new Color(148, 198, 0), sh2.getFillColor());\r
+        assertEquals(new Color(74, 99, 0), sh2.getLineColor()); // slightly different from PowerPoint!\r
+\r
+        // the 5th slide has a picture and a texture fill\r
+        XSLFSlide slide2 = ppt.createSlide().importContent(src.getSlides()[4]);\r
+        XSLFShape[] shapes2 = slide2.getShapes();\r
+        assertEquals(2, shapes2.length);\r
+\r
+        XSLFTextShape sh3 = (XSLFTextShape)shapes2[0];\r
+        assertEquals("This slide overrides master background with a texture fill", sh3.getText());\r
+        XSLFTextRun r3 = sh3.getTextParagraphs().get(0).getTextRuns().get(0);\r
+        assertEquals("Century Gothic", r3.getFontFamily());\r
+        //assertEquals(32.4.0, r3.getFontSize());\r
+        assertTrue(r3.isBold());\r
+        assertTrue(r3.isItalic());\r
+        assertEquals(new Color(148, 198, 0), r3.getFontColor());\r
+        assertNull(sh3.getFillColor());\r
+        assertNull(sh3.getLineColor());\r
+\r
+        XSLFPictureShape sh4 = (XSLFPictureShape)shapes2[1];\r
+        XSLFPictureShape srcPic = (XSLFPictureShape)src.getSlides()[4].getShapes()[1];\r
+        assertTrue(Arrays.equals(sh4.getPictureData().getData(), srcPic.getPictureData().getData()));\r
+    }\r
 }
\ No newline at end of file
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java
new file mode 100755 (executable)
index 0000000..c426fd1
--- /dev/null
@@ -0,0 +1,105 @@
+package org.apache.poi.xslf.usermodel;\r
+\r
+import junit.framework.TestCase;\r
+\r
+import java.awt.Rectangle;\r
+import java.awt.Color;\r
+import java.awt.geom.Rectangle2D;\r
+import java.io.FileOutputStream;\r
+\r
+import org.apache.poi.xssf.dev.XSSFDump;\r
+import org.apache.poi.xslf.util.PPTX2PNG;\r
+\r
+/**\r
+ * Created by IntelliJ IDEA.\r
+ * User: yegor\r
+ * Date: Nov 10, 2011\r
+ * Time: 1:43:25 PM\r
+ * To change this template use File | Settings | File Templates.\r
+ */\r
+public class TestXSLFTextParagraph extends TestCase {\r
+\r
+    public void testWrappingWidth() throws Exception {\r
+        XMLSlideShow ppt = new XMLSlideShow();\r
+        XSLFSlide slide = ppt.createSlide();\r
+        XSLFTextShape sh = slide.createAutoShape();\r
+        sh.setLineColor(Color.black);\r
+\r
+        XSLFTextParagraph p = sh.addNewTextParagraph();\r
+        p.addNewTextRun().setText(\r
+                "Paragraph formatting allows for more granular control " +\r
+                "of text within a shape. Properties here apply to all text " +\r
+                "residing within the corresponding paragraph.");\r
+\r
+        Rectangle2D anchor = new Rectangle(50, 50, 300, 200);\r
+        sh.setAnchor(anchor);\r
+\r
+        double leftInset = sh.getLeftInset();\r
+        double rightInset = sh.getRightInset();\r
+        assertEquals(7.2, leftInset);\r
+        assertEquals(7.2, rightInset);\r
+\r
+        double leftMargin = p.getLeftMargin();\r
+        assertEquals(0.0, leftMargin);\r
+\r
+        double indent = p.getIndent();\r
+        assertEquals(0.0, indent); // default\r
+\r
+        double expectedWidth;\r
+\r
+        // Case 1: bullet=false, leftMargin=0, indent=0.\r
+        expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin;\r
+        assertEquals(285.6, expectedWidth); // 300 - 7.2 - 7.2 - 0\r
+        assertEquals(expectedWidth, p.getWrappingWidth(true));\r
+        assertEquals(expectedWidth, p.getWrappingWidth(false));\r
+\r
+        p.setLeftMargin(36); // 0.5"\r
+        leftMargin = p.getLeftMargin();\r
+        assertEquals(36.0, leftMargin);\r
+        expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin;\r
+        assertEquals(249.6, expectedWidth, 1E-5); // 300 - 7.2 - 7.2 - 36\r
+        assertEquals(expectedWidth, p.getWrappingWidth(true));\r
+        assertEquals(expectedWidth, p.getWrappingWidth(false));\r
+\r
+        // increase insets, the wrapping width should get smaller\r
+        sh.setLeftInset(10);\r
+        sh.setRightInset(10);\r
+        leftInset = sh.getLeftInset();\r
+        rightInset = sh.getRightInset();\r
+        assertEquals(10.0, leftInset);\r
+        assertEquals(10.0, rightInset);\r
+        expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin;\r
+        assertEquals(244.0, expectedWidth); // 300 - 10 - 10 - 36\r
+        assertEquals(expectedWidth, p.getWrappingWidth(true));\r
+        assertEquals(expectedWidth, p.getWrappingWidth(false));\r
+\r
+        // set a positive indent of a 0.5 inch. This means "First Line" indentation:\r
+        // |<---  indent -->|Here goes first line of the text\r
+        // Here go other lines (second and subsequent)\r
+\r
+        p.setIndent(36.0);  // 0.5"\r
+        indent = p.getIndent();\r
+        assertEquals(36.0, indent);\r
+        expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin - indent;\r
+        assertEquals(208.0, expectedWidth); // 300 - 10 - 10 - 36 - 6.4\r
+        assertEquals(expectedWidth, p.getWrappingWidth(true)); // first line is indented\r
+        // other lines are not indented\r
+        expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin;\r
+        assertEquals(244.0, expectedWidth); // 300 - 10 - 10 - 36\r
+        assertEquals(expectedWidth, p.getWrappingWidth(false));\r
+\r
+        // set a negative indent of a 1 inch. This means "Hanging" indentation:\r
+        // Here goes first line of the text\r
+        // |<---  indent -->|Here go other lines (second and subsequent)\r
+        p.setIndent(-72.0);  // 1"\r
+        indent = p.getIndent();\r
+        assertEquals(-72.0, indent);\r
+        expectedWidth = anchor.getWidth() - leftInset - rightInset;\r
+        assertEquals(280.0, expectedWidth); // 300 - 10 - 10 \r
+        assertEquals(expectedWidth, p.getWrappingWidth(true)); // first line is NOT indented\r
+        // other lines are indented by leftMargin (the value of indent is not used)\r
+        expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin;\r
+        assertEquals(244.0, expectedWidth); // 300 - 10 - 10 - 36 \r
+        assertEquals(expectedWidth, p.getWrappingWidth(false));\r
+     }\r
+}\r
index ff39de3ed4067e312cde6964b91bea51c96a5fb3..5f2e751a77fa61cba20b8966d9b6c76ccffb31cb 100755 (executable)
Binary files a/test-data/slideshow/themes.pptx and b/test-data/slideshow/themes.pptx differ