]> source.dussan.org Git - poi.git/commitdiff
Updates from Yegor: New shape and picture stuff (see bug 39256)
authorNick Burch <nick@apache.org>
Wed, 12 Apr 2006 18:48:53 +0000 (18:48 +0000)
committerNick Burch <nick@apache.org>
Wed, 12 Apr 2006 18:48:53 +0000 (18:48 +0000)
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@393576 13f79535-47bb-0310-9956-ffa450edef68

20 files changed:
src/scratchpad/src/org/apache/poi/hslf/model/AutoShape.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/model/Line.java
src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java
src/scratchpad/src/org/apache/poi/hslf/model/Picture.java
src/scratchpad/src/org/apache/poi/hslf/model/Rectangle.java
src/scratchpad/src/org/apache/poi/hslf/model/Shape.java
src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java
src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java
src/scratchpad/src/org/apache/poi/hslf/model/ShapeTypes.java
src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java
src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java
src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/record/EscherTextboxWrapper.java
src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
src/scratchpad/src/org/apache/poi/hslf/record/TextBytesAtom.java
src/scratchpad/src/org/apache/poi/hslf/record/TextHeaderAtom.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/PictureData.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPictures.java

diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/AutoShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/AutoShape.java
new file mode 100644 (file)
index 0000000..e546217
--- /dev/null
@@ -0,0 +1,65 @@
+/* ====================================================================\r
+   Copyright 2002-2004   Apache Software Foundation\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   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 org.apache.poi.ddf.*;\r
+\r
+import java.awt.*;\r
+\r
+/**\r
+ * Represents a autoshape in a PowerPoint drawing\r
+ *\r
+ *  @author Yegor Kozlov\r
+ */\r
+public class AutoShape extends SimpleShape {\r
+\r
+    protected AutoShape(EscherContainerRecord escherRecord, Shape parent){\r
+        super(escherRecord, parent);\r
+    }\r
+\r
+    public AutoShape(int type, Shape parent){\r
+        super(null, parent);\r
+        _escherContainer = createSpContainer(type, parent instanceof ShapeGroup);\r
+    }\r
+\r
+    public AutoShape(int type){\r
+        this(type, null);\r
+    }\r
+\r
+    protected EscherContainerRecord createSpContainer(int shapeType, boolean isChild){\r
+        EscherContainerRecord spcont = super.createSpContainer(isChild);\r
+\r
+        EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);\r
+        short type = (short)((shapeType << 4) | 0x2);\r
+        spRecord.setOptions(type);\r
+\r
+        //set default properties for a line\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);\r
+\r
+        opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__FILLCOLOR, 134217732));\r
+        opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__FILLBACKCOLOR, 134217728));\r
+        opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__NOFILLHITTEST, 1048592));\r
+        opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__COLOR, 134217729));\r
+        opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 524296));\r
+        opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.SHADOWSTYLE__COLOR, 134217730));\r
+\r
+        opt.sortProperties();\r
+\r
+        return spcont;\r
+    }\r
+\r
+}\r
index d6ea230cd93e36a7dae190a94bd05581ba34750a..a94130ed39cc719fcf154124fea9d31bfb745cf4 100644 (file)
@@ -107,13 +107,12 @@ public class Line extends SimpleShape {
         EscherContainerRecord spcont = super.createSpContainer(isChild);\r
 \r
         EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);\r
-        short type = (ShapeTypes.Line << 4) 2;\r
+        short type = (ShapeTypes.Line << 4) | 0x2;\r
         spRecord.setOptions(type);\r
   \r
         //set default properties for a line\r
         EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);\r
 \r
-        //opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 4));\r
         opt.sortProperties();\r
 \r
         return spcont;\r
index f84d968d2152daad19178a7bd9bd06dde86dff17..80f97416cd931e1394e4b2c868d9cdb4e12f8fe0 100644 (file)
@@ -139,6 +139,34 @@ public class PPGraphics2D extends Graphics2D {
     }\r
 \r
     public void drawString(String string, float x, float y){\r
+\r
+         TextBox txt = new TextBox(group);\r
+         txt.setMarginBottom(0);\r
+         txt.setMarginTop(0);\r
+         txt.setMarginLeft(0);\r
+         txt.setMarginRight(0);\r
+         txt.setText(string);\r
+         txt.setWordWrap(TextBox.WrapNone);\r
+        \r
+         if (font != null){\r
+             txt.setFontSize(font.getSize());\r
+             txt.setFontName(font.getName());\r
+             //if(getColor() != null) txt.setFontColor(getColor());\r
+             if (font.isBold()) txt.setBold(true);\r
+             if (font.isItalic()) txt.setItalic(true);\r
+         }\r
+\r
+         txt.resizeToFitText();\r
+         int height = (int)txt.getAnchor().getHeight();\r
+\r
+         /*\r
+           In powerpoint anchor of a shape is its top left corner.\r
+           Java graphics sets string coordinates by the baseline of the first character\r
+           so we need to shift down by the height of the textbox\r
+         */\r
+        txt.moveTo((int)x, (int)(y - height));\r
+\r
+        group.addShape(txt);\r
     }\r
 \r
     public void fill(Shape shape){\r
@@ -212,7 +240,7 @@ public class PPGraphics2D extends Graphics2D {
     }\r
 \r
     public void drawOval(int x, int y, int width, int height) {\r
-        Ellipse ellipse = new Ellipse();\r
+        AutoShape ellipse = new AutoShape(ShapeTypes.Ellipse);\r
         ellipse.setAnchor(new java.awt.Rectangle(x-width/2, y-height/2, width, height));\r
         if (stroke instanceof BasicStroke){\r
             BasicStroke bs = (BasicStroke)stroke;\r
index 5e74988ae9197ffde09037e326fae52f19e2bcfd..28e8e3f72918c718778812ee342873a23ac917a6 100644 (file)
@@ -3,11 +3,14 @@ package org.apache.poi.hslf.model;
 import org.apache.poi.ddf.*;\r
 import org.apache.poi.hslf.usermodel.PictureData;\r
 import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hslf.record.Document;\r
 \r
 import javax.imageio.ImageIO;\r
 import java.awt.image.BufferedImage;\r
 import java.io.ByteArrayInputStream;\r
 import java.io.IOException;\r
+import java.util.List;\r
+import java.util.Arrays;\r
 \r
 \r
 /**\r
@@ -122,16 +125,49 @@ public class Picture extends SimpleShape {
     }\r
 \r
     /**\r
-     * Set default size of the picture\r
-     *\r
-     * @param ppt presentation which holds the picture\r
+     * Resize this picture to the default size.\r
      */\r
-    public void setDefaultSize(SlideShow ppt) throws IOException {\r
-        int idx = getPictureIndex();\r
+    public void setDefaultSize(){\r
+        PictureData pict = getPictureData();\r
+        try {\r
+            BufferedImage img = ImageIO.read(new ByteArrayInputStream(pict.getData()));\r
+            setAnchor(new java.awt.Rectangle(0, 0, img.getWidth(), img.getHeight()));\r
+        } catch (IOException e){\r
+            throw new RuntimeException(e);\r
+        }\r
+    }\r
 \r
-        PictureData pict = ppt.getPictures()[idx-1];\r
-        BufferedImage img = ImageIO.read(new ByteArrayInputStream(pict.getData()));\r
+    /**\r
+     * Returns the picture data for this picture.\r
+     *\r
+     * @return the picture data for this picture.\r
+     */\r
+    public PictureData getPictureData(){\r
+        SlideShow ppt = getSheet().getSlideShow();\r
+        PictureData[] pict = ppt.getPictureData();\r
+        Document doc = ppt.getDocumentRecord();\r
+        EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();\r
+        EscherContainerRecord bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);\r
+\r
+        List lst = bstore.getChildRecords();\r
+        int idx = getPictureIndex()-1;\r
+        EscherBSERecord bse = (EscherBSERecord)lst.get(idx);\r
+        for ( int i = 0; i < pict.length; i++ ) {\r
+            if (Arrays.equals(bse.getUid(), pict[i].getUID())){\r
+                return pict[i];\r
+            }\r
+        }\r
+        return null;\r
+    }\r
 \r
-        setAnchor(new java.awt.Rectangle(0, 0, img.getWidth()*6, img.getHeight()*6));\r
+    /**\r
+     * By default set the orininal image size\r
+     */\r
+    protected void afterInsert(Sheet sh){\r
+        java.awt.Rectangle anchor = getAnchor();\r
+        if (anchor.equals(new java.awt.Rectangle())){\r
+            setDefaultSize();\r
+        }\r
     }\r
+\r
 }\r
index 2c5d69d22fc8c3d12b83faec70f0164ad9972051..1d69c47a44f2c38763484e0cda12f9ec715d0788 100644 (file)
@@ -21,39 +21,31 @@ import org.apache.poi.ddf.*;
 import java.awt.*;\r
 \r
 /**\r
- * Represents a line in a PowerPoint drawing\r
+ * Represents a rectangle shae in a PowerPoint drawing\r
  *\r
  *  @author Yegor Kozlov\r
  */\r
-public class Rectangle extends SimpleShape {\r
+public class Rectangle extends TextBox {\r
 \r
     protected Rectangle(EscherContainerRecord escherRecord, Shape parent){\r
         super(escherRecord, parent);\r
     }\r
 \r
     public Rectangle(Shape parent){\r
-        super(null, parent);\r
-        _escherContainer = createSpContainer(parent instanceof ShapeGroup);\r
+        super(parent);\r
     }\r
 \r
     public Rectangle(){\r
-        this(null);\r
+        super();\r
     }\r
 \r
     protected EscherContainerRecord createSpContainer(boolean isChild){\r
         EscherContainerRecord spcont = super.createSpContainer(isChild);\r
-        spcont.setOptions((short)15);\r
 \r
         EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);\r
         short type = (ShapeTypes.Rectangle << 4) + 2;\r
         spRecord.setOptions(type);\r
 \r
-        //set default properties for a rectangle\r
-        EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);\r
-\r
-        opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 4));\r
-        opt.sortProperties();\r
-\r
         return spcont;\r
     }\r
 \r
index aa1b200e64d54b749d750f930098ba1d7e5cac3a..666568bfd62d91e92df0c4f48f64c96f0c0bc177 100644 (file)
@@ -22,13 +22,47 @@ import java.awt.*;
 import java.util.Iterator;\r
 \r
 /**\r
+ *  <p>\r
   * Represents a Shape which is the elemental object that composes a drawing.\r
+ *  This class is a wrapper around EscherSpContainer which holds all information\r
+ *  about a shape in PowerPoint document.\r
+ *  </p>\r
+ *  <p>\r
+ *  When you add a shape, you usually specify the dimensions of the shape and the position\r
+ *  of the upper�left corner of the bounding box for the shape relative to the upper�left\r
+ *  corner of the page, worksheet, or slide. Distances in the drawing layer are measured\r
+ *  in points (72 points = 1 inch).\r
+ *  </p>\r
+ * <p>\r
   *\r
   * @author Yegor Kozlov\r
  */\r
 public abstract class Shape {\r
 \r
+    /**\r
+     * In Escher absolute distances are specified in\r
+     * English Metric Units (EMUs), occasionally referred to as A units;\r
+     * there are 360000 EMUs per centimeter, 914400 EMUs per inch, 12700 EMUs per point.\r
+     */\r
+    public static final int EMU_PER_INCH = 914400;\r
     public static final int EMU_PER_POINT = 12700;\r
+    public static final int EMU_PER_CENTIMETER = 360000;\r
+\r
+    /**\r
+     * Master DPI (576 pixels per inch).\r
+     * Used by the reference coordinate system in PowerPoint.\r
+     */\r
+    public static final int MASTER_DPI = 576;\r
+\r
+    /**\r
+     * Pixels DPI (96 pixels per inch)\r
+     */\r
+    public static final int PIXEL_DPI = 96;\r
+\r
+    /**\r
+     * Points DPI (72 pixels per inch)\r
+     */\r
+    public static final int POINT_DPI = 72;\r
 \r
     /**\r
      * Either EscherSpContainer or EscheSpgrContainer record\r
@@ -42,6 +76,11 @@ public abstract class Shape {
      */\r
     protected Shape _parent;\r
 \r
+    /**\r
+     * The <code>Sheet</code> this shape belongs to\r
+     */\r
+    protected Sheet _sheet;\r
+\r
     /**\r
      * Create a Shape object. This constructor is used when an existing Shape is read from from a PowerPoint document.\r
      *\r
@@ -86,25 +125,25 @@ public abstract class Shape {
         if ((flags & EscherSpRecord.FLAG_CHILD) != 0){\r
             EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);\r
             anchor = new java.awt.Rectangle();\r
-            anchor.x = rec.getDx1();\r
-            anchor.y = rec.getDy1();\r
-            anchor.width = rec.getDx2() - anchor.x;\r
-            anchor.height = rec.getDy2() - anchor.y;\r
+            anchor.x = rec.getDx1()*POINT_DPI/MASTER_DPI;\r
+            anchor.y = rec.getDy1()*POINT_DPI/MASTER_DPI;\r
+            anchor.width = (rec.getDx2() - anchor.x)*POINT_DPI/MASTER_DPI;\r
+            anchor.height = (rec.getDy2() - anchor.y)*POINT_DPI/MASTER_DPI;\r
         }\r
         else {\r
             EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);\r
             anchor = new java.awt.Rectangle();\r
-            anchor.y = rec.getFlag();\r
-            anchor.x = rec.getCol1();\r
-            anchor.width = rec.getDx1() - anchor.x;\r
-            anchor.height = rec.getRow1() - anchor.y;\r
+            anchor.y = rec.getFlag()*POINT_DPI/MASTER_DPI;\r
+            anchor.x = rec.getCol1()*POINT_DPI/MASTER_DPI;\r
+            anchor.width = (rec.getDx1() - rec.getCol1())*POINT_DPI/MASTER_DPI;\r
+            anchor.height = (rec.getRow1() - rec.getFlag())*POINT_DPI/MASTER_DPI;\r
         }\r
         return anchor;\r
     }\r
 \r
     /**\r
      * Sets the anchor (the bounding box rectangle) of this shape.\r
-     * All coordinates should be expressed in Master units (576 dpi).\r
+     * All coordinates should be expressed in poitns (72 dpi).\r
      *\r
      * @param anchor new anchor\r
      */\r
@@ -113,17 +152,17 @@ public abstract class Shape {
         int flags = spRecord.getFlags();\r
         if ((flags & EscherSpRecord.FLAG_CHILD) != 0){\r
             EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);\r
-            rec.setDx1(anchor.x);\r
-            rec.setDy1(anchor.y);\r
-            rec.setDx2(anchor.width + anchor.x);\r
-            rec.setDy2(anchor.height + anchor.y);\r
+            rec.setDx1(anchor.x*MASTER_DPI/POINT_DPI);\r
+            rec.setDy1(anchor.y*MASTER_DPI/POINT_DPI);\r
+            rec.setDx2((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI);\r
+            rec.setDy2((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI);\r
         }\r
         else {\r
             EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);\r
-            rec.setFlag((short)anchor.y);\r
-            rec.setCol1((short)anchor.x);\r
-            rec.setDx1((short)(anchor.width + anchor.x));\r
-            rec.setRow1((short)(anchor.height + anchor.y));\r
+            rec.setFlag((short)(anchor.y*MASTER_DPI/POINT_DPI));\r
+            rec.setCol1((short)(anchor.x*MASTER_DPI/POINT_DPI));\r
+            rec.setDx1((short)((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI));\r
+            rec.setRow1((short)((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI));\r
         }\r
 \r
     }\r
@@ -171,11 +210,11 @@ public abstract class Shape {
     }\r
 \r
     /**\r
-     * Set an escher property in the opt record.\r
+     * Set an escher property for this shape.\r
      *\r
      * @param opt       The opt record to set the properties to.\r
      * @param propId    The id of the property. One of the constants defined in EscherOptRecord.\r
-     * @param value     value of the property\r
+     * @param value     value of the property. If value = -1 then the property is removed.\r
      */\r
      public static void setEscherProperty(EscherOptRecord opt, short propId, int value){\r
         java.util.List props = opt.getEscherProperties();\r
@@ -198,4 +237,33 @@ public abstract class Shape {
     public EscherContainerRecord getSpContainer(){\r
         return _escherContainer;\r
     }\r
+\r
+    /**\r
+     * Event which fires when a shape is inserted in the sheet.\r
+     * In some cases we need to propagate changes to upper level containers.\r
+     * <br>\r
+     * Default implementation does nothing.\r
+     *\r
+     * @param sh - owning shape\r
+     */\r
+    protected void afterInsert(Sheet sh){\r
+\r
+    }\r
+\r
+    /**\r
+     *  @return the <code>SlideShow</code> this shape belongs to\r
+     */\r
+    public Sheet getSheet(){\r
+        return _sheet;\r
+    }\r
+\r
+    /**\r
+     * Assign the <code>SlideShow</code> this shape belongs to\r
+     *\r
+     * @param sheet owner of this shape\r
+     */\r
+    public void setSheet(Sheet sheet){\r
+        _sheet = sheet;\r
+    }\r
+\r
 }\r
index c886638c3ca92b145b40bb46370ae34d12554b1e..5c7f1c89a94543f47c8530d8e2f3758197e32ff1 100644 (file)
@@ -25,6 +25,9 @@ import org.apache.poi.ddf.EscherContainerRecord;
  */\r
 public class ShapeFactory {\r
 \r
+    /**\r
+     * Create a new shape from the data provided.  \r
+     */\r
     public static Shape createShape(EscherContainerRecord spContainer, Shape parent){\r
         if (spContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){\r
             return new ShapeGroup(spContainer, parent);\r
@@ -36,6 +39,8 @@ public class ShapeFactory {
         int type = spRecord.getOptions() >> 4;\r
         switch (type){\r
             case ShapeTypes.TextBox:\r
+                shape = new TextBox(spContainer, parent);\r
+                break;\r
             case ShapeTypes.Rectangle:\r
                 shape = new Rectangle(spContainer, parent);\r
                 break;\r
@@ -45,14 +50,11 @@ public class ShapeFactory {
             case ShapeTypes.Line:\r
                 shape = new Line(spContainer, parent);\r
                 break;\r
-            case ShapeTypes.Ellipse:\r
-                shape = new Ellipse(spContainer, parent);\r
-                break;\r
             case ShapeTypes.NotPrimitive:\r
                 shape = new ShapeGroup(spContainer, parent);\r
                 break;\r
             default:\r
-                shape = new SimpleShape(spContainer, parent);\r
+                shape = new AutoShape(spContainer, parent);\r
                 break;\r
         }\r
         return shape;\r
index 0d2d61e95a90482ad654fb0cecb4ec6f9530ad27..a3f6584b2856cb2841cd1b4f905ee0566fd290ab 100644 (file)
@@ -27,11 +27,21 @@ import java.util.List;
  */\r
 public class ShapeGroup extends Shape{\r
 \r
+    /**\r
+      * Create a new ShapeGroup. This constructor is used when a new shape is created.\r
+      *\r
+      */\r
     public ShapeGroup(){\r
         this(null, null);\r
         _escherContainer = createSpContainer(false);\r
     }\r
 \r
+    /**\r
+      * Create a ShapeGroup object and initilize it from the supplied Record container.\r
+      *\r
+      * @param escherRecord       <code>EscherSpContainer</code> container which holds information about this shape\r
+      * @param parent    the parent of the shape\r
+      */\r
     protected ShapeGroup(EscherContainerRecord escherRecord, Shape parent){\r
         super(escherRecord, parent);\r
     }\r
index fd571c1818601a7980a527cfeb0d233661de7b05..30966d5865241431a60d651b6da74e40bddc93fc 100644 (file)
@@ -82,9 +82,9 @@ public class ShapeTypes {
     public static final int Chevron = 55;\r
     public static final int Pentagon = 56;\r
     public static final int NoSmoking = 57;\r
-    public static final int Seal8 = 58;\r
-    public static final int Seal16 = 59;\r
-    public static final int Seal32 = 60;\r
+    public static final int Star8 = 58;\r
+    public static final int Star16 = 59;\r
+    public static final int Star32 = 60;\r
     public static final int WedgeRectCallout = 61;\r
     public static final int WedgeRRectCallout = 62;\r
     public static final int WedgeEllipseCallout = 63;\r
@@ -116,7 +116,7 @@ public class ShapeTypes {
     public static final int LeftUpArrow = 89;\r
     public static final int BentUpArrow = 90;\r
     public static final int BentArrow = 91;\r
-    public static final int Seal24 = 92;\r
+    public static final int Star24 = 92;\r
     public static final int StripedRightArrow = 93;\r
     public static final int NotchedRightArrow = 94;\r
     public static final int BlockArc = 95;\r
@@ -211,7 +211,7 @@ public class ShapeTypes {
     public static final int Moon = 184;\r
     public static final int BracketPair = 185;\r
     public static final int BracePair = 186;\r
-    public static final int Seal4 = 187;\r
+    public static final int Star4 = 187;\r
     public static final int DoubleWave = 188;\r
     public static final int ActionButtonBlank = 189;\r
     public static final int ActionButtonHome = 190;\r
index e1c95d747c593e740ae764d97846d9bc544f0ff8..35353e9c8856f180499482dbfe12eb5d4ca2eacb 100644 (file)
@@ -23,6 +23,7 @@ import org.apache.poi.ddf.EscherContainerRecord;
 import org.apache.poi.ddf.EscherDgRecord;
 import org.apache.poi.ddf.EscherRecord;
 import org.apache.poi.hslf.record.*;
+import org.apache.poi.hslf.usermodel.SlideShow;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -38,6 +39,11 @@ import java.util.Vector;
 
 public abstract class Sheet
 {
+  /**
+   * The <code>SlideShow</code> we belong to
+   */
+  private SlideShow _slideShow; 
+  
   /**
    * Returns an array of all the TextRuns in the sheet.
    */
@@ -59,7 +65,19 @@ public abstract class Sheet
    * Fetch the PPDrawing from the underlying record
    */
   protected abstract PPDrawing getPPDrawing();
+  
+  
+  /**
+   * Fetch the SlideShow we're attached to
+   */
+  public SlideShow getSlideShow() { return _slideShow; }
+  
+  /**
+   * Set the SlideShow we're attached to
+   */
+  public void setSlideShow(SlideShow ss) { _slideShow = ss; }
 
+  
   /**
    * For a given PPDrawing, grab all the TextRuns
    */
@@ -149,7 +167,9 @@ public abstract class Sheet
        ArrayList shapes = new ArrayList();
        for (int i=1;i<ch.size();i++) {
                EscherContainerRecord sp = (EscherContainerRecord)ch.get(i);
-               shapes.add(ShapeFactory.createShape(sp, null));
+               Shape sh = ShapeFactory.createShape(sp, null);
+               sh.setSheet(this);
+               shapes.add(sh);
        }
        
        return (Shape[])shapes.toArray(new Shape[shapes.size()]);
@@ -169,5 +189,8 @@ public abstract class Sheet
 
        EscherDgRecord dg = (EscherDgRecord)Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
        dg.setNumShapes(dg.getNumShapes()+1);
+       
+       shape.setSheet(this);
+       shape.afterInsert(this);
   }
 } 
index 787780dcf53100ea7eeb6f271beeb07a2c10731e..038f00e5b90c81498f2aa13c4b7792754704d8ba 100644 (file)
@@ -29,6 +29,12 @@ import java.awt.*;
  */\r
 public class SimpleShape extends Shape {\r
 \r
+    /**\r
+     * Create a SimpleShape object and initialize it from the supplied Record container.\r
+     *\r
+     * @param escherRecord    <code>EscherSpContainer</code> container which holds information about this shape\r
+     * @param parent    the parent of the shape\r
+     */\r
     protected SimpleShape(EscherContainerRecord escherRecord, Shape parent){\r
         super(escherRecord, parent);\r
     }\r
@@ -102,12 +108,12 @@ public class SimpleShape extends Shape {
     }\r
 \r
     /**\r
-     * @return color of the line\r
+     * @return color of the line. If color is not set returns <code>java.awt.Color.black</code>\r
      */\r
     public Color getLineColor(){\r
         EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
         EscherRGBProperty prop = (EscherRGBProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__COLOR);\r
-        Color color = null;\r
+        Color color = Color.black;\r
         if (prop != null){\r
             Color swp = new Color(prop.getRgbColor());\r
             color = new Color(swp.getBlue(), swp.getGreen(), swp.getRed());\r
@@ -136,6 +142,11 @@ public class SimpleShape extends Shape {
         return prop == null ? Line.LineSolid : prop.getPropertyValue();\r
     }\r
 \r
+    /**\r
+     * The color used to fill this shape.\r
+     *\r
+     * @param color the background color\r
+     */\r
     public void setFillColor(Color color){\r
         EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
         int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB();\r
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java
new file mode 100644 (file)
index 0000000..5584ab1
--- /dev/null
@@ -0,0 +1,490 @@
+\r
+/* ====================================================================\r
+   Copyright 2002-2004   Apache Software Foundation\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   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 org.apache.poi.ddf.*;\r
+import org.apache.poi.hslf.record.*;\r
+import org.apache.poi.hslf.usermodel.RichTextRun;\r
+\r
+import java.awt.*;\r
+import java.awt.font.FontRenderContext;\r
+import java.awt.font.TextLayout;\r
+import java.io.IOException;\r
+\r
+/**\r
+ * Represents a TextFrame shape in PowerPoint.\r
+ * <p>\r
+ * Contains the text in a text frame as well as the properties and methods\r
+ * that control alignment and anchoring of the text.\r
+ * </p>\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TextBox extends SimpleShape {\r
+\r
+    /**\r
+     * How to anchor the text\r
+     */\r
+    public static final int AnchorTop = 0;\r
+    public static final int AnchorMiddle = 1;\r
+    public static final int AnchorBottom = 2;\r
+    public static final int AnchorTopCentered = 3;\r
+    public static final int AnchorMiddleCentered = 4;\r
+    public static final int AnchorBottomCentered = 5;\r
+    public static final int AnchorTopBaseline = 6;\r
+    public static final int AnchorBottomBaseline = 7;\r
+    public static final int AnchorTopCenteredBaseline = 8;\r
+    public static final int AnchorBottomCenteredBaseline = 9;\r
+\r
+    /**\r
+     * How to wrap the text\r
+     */\r
+    public static final int WrapSquare = 0;\r
+    public static final int WrapByPoints = 1;\r
+    public static final int WrapNone = 2;\r
+    public static final int WrapTopBottom = 3;\r
+    public static final int WrapThrough = 4;\r
+\r
+    /**\r
+     * How to align the text\r
+     */\r
+    public static final int AlignLeft = 0;\r
+    public static final int AlignCenter = 1;\r
+    public static final int AlignRight = 2;\r
+    public static final int AlignJustify = 3;\r
+\r
+    /**\r
+     * Default font size\r
+     */\r
+    public static final int DefaultFontSize = 24;\r
+\r
+    /**\r
+     * Low-level object which holds actual text and format data\r
+     */\r
+    protected TextRun _txtrun;\r
+\r
+    /**\r
+     * Escher container which holds text attributes such as\r
+     * TextHeaderAtom, TextBytesAtom ot TextCharsAtom, StyleTextPropAtom etc.\r
+     */\r
+    protected EscherTextboxWrapper _txtbox;\r
+\r
+    /**\r
+     * Create a TextBox object and initialize it from the supplied Record container.\r
+     *\r
+     * @param escherRecord       <code>EscherSpContainer</code> container which holds information about this shape\r
+     * @param parent    the parent of the shape\r
+     */\r
+   protected TextBox(EscherContainerRecord escherRecord, Shape parent){\r
+        super(escherRecord, parent);\r
+\r
+        EscherTextboxRecord textbox = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);\r
+        _txtbox = new EscherTextboxWrapper(textbox);\r
+\r
+        TextHeaderAtom tha = null;\r
+        TextBytesAtom tba = null;\r
+        StyleTextPropAtom sta = null;\r
+        Record[] child = _txtbox.getChildRecords();\r
+        for (int i = 0; i < child.length; i++) {\r
+            if (child[i] instanceof TextHeaderAtom) tha = (TextHeaderAtom)child[i];\r
+            else if (child[i] instanceof TextBytesAtom) tba = (TextBytesAtom)child[i];\r
+            else if (child[i] instanceof StyleTextPropAtom) sta = (StyleTextPropAtom)child[i];\r
+        }\r
+\r
+        _txtrun = new TextRun(tha,tba,sta);\r
+    }\r
+\r
+    /**\r
+     * Create a new TextBox. This constructor is used when a new shape is created.\r
+     *\r
+     * @param parent    the parent of this Shape. For example, if this text box is a cell\r
+     * in a table then the parent is Table.\r
+     */\r
+    public TextBox(Shape parent){\r
+        super(null, parent);\r
+        _escherContainer = createSpContainer(parent instanceof ShapeGroup);\r
+    }\r
+\r
+    /**\r
+     * Create a new TextBox. This constructor is used when a new shape is created.\r
+     *\r
+     */\r
+    public TextBox(){\r
+        this(null);\r
+    }\r
+\r
+    /**\r
+     * Create a new textBox and initialize internal structures\r
+     *\r
+     * @return the created <code>EscherContainerRecord</code> which holds shape data\r
+     */\r
+    protected EscherContainerRecord createSpContainer(boolean isChild){\r
+        EscherContainerRecord spcont = super.createSpContainer(isChild);\r
+\r
+        EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);\r
+        short type = (ShapeTypes.TextBox << 4) | 0x2;\r
+        spRecord.setOptions(type);\r
+\r
+        //set default properties for a textbox\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);\r
+        setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);\r
+\r
+        setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, 134217732);\r
+        setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, 134217728);\r
+        setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 1048576);\r
+        setEscherProperty(opt, EscherProperties.LINESTYLE__COLOR, 134217729);\r
+        setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 524288);\r
+        setEscherProperty(opt, EscherProperties.SHADOWSTYLE__COLOR, 134217730);\r
+\r
+        opt.sortProperties();\r
+\r
+        //create EscherTextboxWrapper\r
+        _txtbox = new EscherTextboxWrapper();\r
+\r
+        TextHeaderAtom tha = new TextHeaderAtom();\r
+        _txtbox.appendChildRecord(tha);\r
+\r
+        TextBytesAtom tba = new TextBytesAtom();\r
+        _txtbox.appendChildRecord(tba);\r
+\r
+        StyleTextPropAtom sta = new StyleTextPropAtom(0);\r
+        _txtbox.appendChildRecord(sta);\r
+\r
+        _txtrun = new TextRun(tha,tba,sta);\r
+        _txtrun.setText("");\r
+        spcont.addChildRecord(_txtbox.getEscherRecord());\r
+\r
+        return spcont;\r
+    }\r
+\r
+    /**\r
+     * Returns the text contained in this text frame.\r
+     *\r
+     * @return the text string for this textbox.\r
+     */\r
+     public String getText(){\r
+        return _txtrun.getText();        \r
+    }\r
+\r
+    /**\r
+     * Sets the text contained in this text frame.\r
+     *\r
+     * @param text the text string used by this object.\r
+     */\r
+    public void setText(String text){\r
+        _txtrun.setText(text);\r
+    }\r
+\r
+    /**\r
+     * When a textbox is added to  a sheet we need to tell upper-level\r
+     * <code>PPDrawing</code> about it.\r
+     *\r
+     * @param sh the sheet we are adding to\r
+     */\r
+    protected void afterInsert(Sheet sh){\r
+        PPDrawing ppdrawing = sh.getPPDrawing();\r
+        ppdrawing.addTextboxWrapper(_txtbox);\r
+        // Ensure the escher layer knows about the added records \r
+        try {\r
+            _txtbox.writeOut(null);\r
+        } catch (IOException e){\r
+            throw new RuntimeException(e);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns the bounds of this <code>TextFrame</code>.\r
+     * <code>Note</b>, this is very primitive estimation, the precision is poor.\r
+     *\r
+     * @return  the bounds of this <code>TextFrame</code>.\r
+     */\r
+    protected Dimension getTextSize(){\r
+        FontRenderContext frc = new FontRenderContext(null, true, true);\r
+        RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
+        int size = rt.getFontSize();\r
+        if (size == -1) size = TextBox.DefaultFontSize;\r
+        int style = 0;\r
+        if (rt.isBold()) style |= Font.BOLD;\r
+        if (rt.isItalic()) style |= Font.ITALIC;\r
+        String fntname = rt.getFontName();\r
+        if (fntname == null) //get the default font from Document.Environment.FontCollection\r
+            fntname = getSheet().getSlideShow().getDocumentRecord().getEnvironment().getFontCollection().getFontWithId(0);\r
+        Font font = new Font(fntname, style, size);\r
+\r
+        TextLayout layout = new TextLayout(getText(), font, frc);\r
+        int width = Math.round(layout.getAdvance());\r
+        width += getMarginLeft() + getMarginRight();\r
+        int height = Math.round(layout.getAscent());\r
+        height += getMarginTop() + getMarginBottom();\r
+        return new Dimension(width, height);\r
+    }\r
+\r
+    /**\r
+     * Adjust the size of the TextBox so it encompasses the text inside it.\r
+     */\r
+    public void resizeToFitText(){\r
+        Dimension size = getTextSize();\r
+        java.awt.Rectangle anchor = getAnchor();\r
+        anchor.setSize(size);\r
+        setAnchor(anchor);\r
+    }\r
+\r
+    /**\r
+     * Returns the type of vertical alignment for the text.\r
+     * One of the <code>Anchor*</code> constants defined in this class.\r
+     *\r
+     * @return the type of alignment\r
+     */\r
+    public int getVerticalAlignment(){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);\r
+        return prop == null ? AlignCenter : prop.getPropertyValue();\r
+    }\r
+\r
+    /**\r
+     * Sets the type of vertical alignment for the text.\r
+     * One of the <code>Anchor*</code> constants defined in this class.\r
+     *\r
+     * @param align - the type of alignment\r
+     */\r
+    public void setVerticalAlignment(int align){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        setEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT, align);\r
+    }\r
+    /**\r
+     * Returns the distance (in points) between the bottom of the text frame\r
+     * and the bottom of the inscribed rectangle of the shape that contains the text.\r
+     * Default value is 1/20 inch.\r
+     *\r
+     * @return the botom margin\r
+     */\r
+    public int getMarginBottom(){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);\r
+        int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();\r
+        return val/EMU_PER_POINT;\r
+    }\r
+\r
+    /**\r
+     * Sets the botom margin.\r
+     * @see #getMarginBottom()\r
+     *\r
+     * @param margin    the bottom margin\r
+     */\r
+    public void setMarginBottom(int margin){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        setEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM, margin*EMU_PER_POINT);\r
+    }\r
+\r
+    /**\r
+     *  Returns the distance (in EMUs) between the left edge of the text frame\r
+     *  and the left edge of the inscribed rectangle of the shape that contains\r
+     *  the text.\r
+     *  Default value is 1/10 inch.\r
+     *\r
+     * @return the left margin\r
+     */\r
+    public int getMarginLeft(){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);\r
+        int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();\r
+        return val/EMU_PER_POINT;\r
+    }\r
+\r
+    /**\r
+     * Sets the left margin.\r
+     * @see #getMarginLeft()\r
+     *\r
+     * @param margin    the left margin\r
+     */\r
+    public void setMarginLeft(int margin){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        setEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT, margin*EMU_PER_POINT);\r
+    }\r
+\r
+    /**\r
+     *  Returns the distance (in EMUs) between the right edge of the\r
+     *  text frame and the right edge of the inscribed rectangle of the shape\r
+     *  that contains the text.\r
+     *  Default value is 1/10 inch.\r
+     *\r
+     * @return the right margin\r
+     */\r
+    public int getMarginRight(){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);\r
+        int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();\r
+        return val/EMU_PER_POINT;\r
+    }\r
+\r
+    /**\r
+     * Sets the right margin.\r
+     * @see #getMarginRight()\r
+     *\r
+     * @param margin    the right margin\r
+     */\r
+    public void setMarginRight(int margin){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        setEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT, margin*EMU_PER_POINT);\r
+    }\r
+\r
+     /**\r
+     *  Returns the distance (in EMUs) between the top of the text frame\r
+     *  and the top of the inscribed rectangle of the shape that contains the text.\r
+     *  Default value is 1/20 inch.\r
+     *\r
+     * @return the top margin\r
+     */\r
+    public int getMarginTop(){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);\r
+        int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();\r
+        return val/EMU_PER_POINT;\r
+    }\r
+\r
+   /**\r
+     * Sets the top margin.\r
+     * @see #getMarginTop()\r
+     *\r
+     * @param margin    the top margin\r
+     */\r
+    public void setMarginTop(int margin){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        setEscherProperty(opt, EscherProperties.TEXT__TEXTTOP, margin*EMU_PER_POINT);\r
+    }\r
+\r
+\r
+    /**\r
+     * Returns the value indicating word wrap.\r
+     * One of the <code>Wrap*</code> constants defined in this class.\r
+     *\r
+     * @return the value indicating word wrap\r
+     */\r
+    public int getWordWrap(){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);\r
+        return prop == null ? WrapSquare : prop.getPropertyValue();\r
+    }\r
+\r
+    /**\r
+     *  Specifies how the text should be wrapped\r
+     *\r
+     * @param wrap  the value indicating how the text should be wrapped\r
+     */\r
+    public void setWordWrap(int wrap){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        setEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT, wrap);\r
+    }\r
+\r
+    /**\r
+     * @return id for the text.\r
+     */\r
+    public int getTextId(){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTID);\r
+        return prop == null ? 0 : prop.getPropertyValue();\r
+    }\r
+\r
+    /**\r
+     * Sets text ID\r
+     *\r
+     * @param id of the text\r
+     */\r
+    public void setTextId(int id){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        setEscherProperty(opt, EscherProperties.TEXT__TEXTID, id);\r
+    }\r
+\r
+    /**\r
+     * The color used to fill this shape.\r
+     *\r
+     * @param color the background color\r
+     */\r
+    public void setBackgroundColor(Color color){\r
+        EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+        int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB();\r
+        setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, rgb);\r
+    }\r
+\r
+    /**\r
+      * @return  array of RichTextRun objects which control text formatting in this text box\r
+      */\r
+     public RichTextRun[] getRichTextRuns(){\r
+         return _txtrun.getRichTextRuns();\r
+     }\r
+\r
+    /**\r
+     * Sets the <code>Font</code> object for this text frame\r
+     *\r
+     * @param size  the size of the font\r
+     */\r
+    public void setFontSize(int size){\r
+        RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
+        rt.setFontSize(size);\r
+    }\r
+\r
+    /**\r
+     *\r
+     * @return  the size of the font applied to this text shape\r
+     */\r
+    public int getFontSize(){\r
+        RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
+        return rt.getFontSize();\r
+    }\r
+\r
+    /**\r
+     * Set whether to use bold or not\r
+     *\r
+     * @param bold  <code>true</code>   if the text should be bold, <code>false</code>  otherwise\r
+     */\r
+    public void setBold(boolean bold){\r
+        RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
+        rt.setBold(bold);\r
+    }\r
+\r
+    /**\r
+     * Set whether to use italic or not\r
+     *\r
+     * @param italic  <code>true</code>   if the text should be italic, <code>false</code>  otherwise\r
+     */\r
+    public void setItalic(boolean italic){\r
+        RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
+        rt.setItalic(italic);\r
+    }\r
+\r
+    /**\r
+     * Set whether to use underline or not\r
+     *\r
+     * @param underline  <code>true</code>   if the text should be underlined, <code>false</code>  otherwise\r
+     */\r
+    public void setUnderline(boolean underline){\r
+        RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
+        rt.setUnderlined(underline);\r
+    }\r
+\r
+    /**\r
+     *  Sets the font of this text shape\r
+     *\r
+     * @param name  the name of the font to be applied to this text shape\r
+     */\r
+    public void setFontName(String name){\r
+        RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
+        rt.setFontName(name);\r
+    }\r
+    \r
+}\r
index c07291f21ea96d9390fda07c517aa11ce19fe3f8..67acf239103ee36bf2f73512917c24c54744b6c3 100644 (file)
@@ -47,7 +47,7 @@ public class EscherTextboxWrapper extends RecordContainer
        /** 
         * Creates the wrapper for the given DDF Escher Record and children
         */
-       protected EscherTextboxWrapper(EscherTextboxRecord textbox) {
+       public EscherTextboxWrapper(EscherTextboxRecord textbox) {
                _escherRecord = textbox;
                _type = (long)_escherRecord.getRecordId();
 
@@ -55,7 +55,18 @@ public class EscherTextboxWrapper extends RecordContainer
                byte[] data = _escherRecord.getData();
                _children = Record.findChildRecords(data,0,data.length);
        }
+       
+       /**
+        * Creates a new, empty wrapper for DDF Escher Records and their children
+        */
+       public EscherTextboxWrapper() {
+               _escherRecord = new EscherTextboxRecord();
+               _escherRecord.setRecordId(EscherTextboxRecord.RECORD_ID);
+               _escherRecord.setOptions((short)15);
 
+               _children = new Record[0];
+       }
+       
 
        /**
         * Return the type of the escher record (normally in the 0xFnnn range)
index 4cbcca00bf6ba30e9a4e5709231c0861dc4a96f0..1967fc2116a5734900b5c214d4283e5beb00ea62 100644 (file)
@@ -262,4 +262,15 @@ public class PPDrawing extends RecordAtom
                        dgContainer
                };
        }
+       
+       /**
+        * Add a new EscherTextboxWrapper to this <code>PPDrawing</code>.
+        */
+       public void addTextboxWrapper(EscherTextboxWrapper txtbox){
+               EscherTextboxWrapper[] tw = new EscherTextboxWrapper[textboxWrappers.length + 1];
+               System.arraycopy(textboxWrappers, 0, tw, 0, textboxWrappers.length);
+               
+               tw[textboxWrappers.length] = txtbox;
+               textboxWrappers = tw;
+       }
 }
index a0d421317e68259f7306ee19819cfe9cfa1b680f..eb11cf6734f85f7ac22a0072a13debff61155095 100644 (file)
@@ -71,6 +71,18 @@ public class TextBytesAtom extends RecordAtom
                _text = new byte[len-8];
                System.arraycopy(source,start+8,_text,0,len-8);
        }
+       
+       /**
+        * Create an empty TextBytes Atom
+        */
+       public TextBytesAtom() {
+               _header = new byte[8];
+               LittleEndian.putUShort(_header, 0, 0);
+               LittleEndian.putUShort(_header, 2, (int)_type);
+               LittleEndian.putInt(_header, 4, 0);
+
+               _text = new byte[]{};
+       }
 
        /**
         * We are of type 4008
index 7dddc529e711fa38060fa311a308ce25d416ad05..1e84a24ffa45b0ebbf996ddd840d67e1d54852c3 100644 (file)
@@ -75,6 +75,18 @@ public class TextHeaderAtom extends RecordAtom implements ParentAwareRecord
                // Grab the type
                textType = (int)LittleEndian.getInt(source,start+8);
        }
+       
+       /**
+        * Create a new TextHeader Atom, for an unknown type of text
+        */
+       public TextHeaderAtom() {
+               _header = new byte[8];
+               LittleEndian.putUShort(_header, 0, 0);
+               LittleEndian.putUShort(_header, 2, (int)_type);
+               LittleEndian.putInt(_header, 4, 4);
+
+               textType = OTHER_TYPE;
+       }
 
        /**
         * We are of type 3999
index 0d2eba10cbe7821558eeb4839e0b4ed257d9602f..2f37b72df6656bbb82c385f24182372615fe9a3c 100644 (file)
@@ -25,6 +25,7 @@ import java.security.NoSuchAlgorithmException;
 \r
 /**\r
  * A class that represents the image data contained in the Presentation.\r
+ * \r
  *\r
  *  @author Yegor Kozlov\r
  */\r
@@ -35,6 +36,9 @@ public class PictureData {
        */\r
        public static final int HEADER_SIZE = 25;\r
 \r
+    protected static final int JPEG_HEADER = -266516832;\r
+    protected static final int PNG_HEADER = -266441216;\r
+\r
        /**\r
        * Binary data of the picture\r
        */\r
@@ -118,11 +122,27 @@ public class PictureData {
        */\r
        public void setType(int format){\r
         switch (format){\r
-            case Picture.JPEG: LittleEndian.putInt(header, 0, -266516832); break;\r
-            case Picture.PNG: LittleEndian.putInt(header, 0, -266441216); break;\r
+            case Picture.JPEG: LittleEndian.putInt(header, 0, PictureData.JPEG_HEADER); break;\r
+            case Picture.PNG: LittleEndian.putInt(header, 0, PictureData.PNG_HEADER); break;\r
         }\r
        }\r
 \r
+    /**\r
+     * Returns type of this picture.\r
+     * Must be one of the static constans defined in the <code>Picture<code> class.\r
+     *\r
+     * @return type of this picture.\r
+     */\r
+    public int getType(){\r
+        int format = 0;\r
+        int val = LittleEndian.getInt(header, 0);\r
+        switch (val){\r
+            case PictureData.JPEG_HEADER: format = Picture.JPEG; break;\r
+            case PictureData.PNG_HEADER: format = Picture.PNG; break;\r
+        }\r
+        return format;\r
+    }\r
+\r
     /**\r
      * Returns the header of the Picture\r
      *\r
index 5485c8043a282a1fb8616e8e6664ed63606a60c5..cef58ffe0f5b7fd35623da352dbf324678bc7ae8 100644 (file)
@@ -401,6 +401,7 @@ public class SlideShow
        _notes = new Notes[notesV.size()];
        for(int i=0; i<_notes.length; i++) {
                _notes[i] = (Notes)notesV.get(i);
+               _notes[i].setSlideShow(this);
                
                // Now supply ourselves to all the rich text runs
                //  of this note's TextRuns
@@ -418,6 +419,7 @@ public class SlideShow
        _slides = new Slide[slidesV.size()];
        for(int i=0; i<_slides.length; i++) {
                _slides[i] = (Slide)slidesV.get(i);
+               _slides[i].setSlideShow(this);
 
                // Now supply ourselves to all the rich text runs
                //  of this slide's TextRuns
@@ -472,9 +474,9 @@ public class SlideShow
        //public MetaSheet[] getMetaSheets() { return _msheets; }
 
        /**
-        * Returns all the pictures attached to the SlideShow
+        * Returns the data of all the pictures attached to the SlideShow
         */
-       public PictureData[] getPictures() throws IOException {
+       public PictureData[] getPictureData() {
                return _hslfSlideShow.getPictures();
        }
        
@@ -483,7 +485,20 @@ public class SlideShow
         */
        public Dimension getPageSize(){
                DocumentAtom docatom = _documentRecord.getDocumentAtom();
-               return new Dimension((int)docatom.getSlideSizeX(), (int)docatom.getSlideSizeY());
+               int pgx = (int)docatom.getSlideSizeX()*Shape.POINT_DPI/Shape.MASTER_DPI;
+               int pgy = (int)docatom.getSlideSizeY()*Shape.POINT_DPI/Shape.MASTER_DPI;
+               return new Dimension(pgx, pgy);
+       }
+       
+       /**
+        * Change the current page size
+        * 
+        * @param pgsize page size (in points)
+        */
+       public void setPageSize(Dimension pgsize){
+               DocumentAtom docatom = _documentRecord.getDocumentAtom();
+               docatom.setSlideSizeX(pgsize.width*Shape.MASTER_DPI/Shape.POINT_DPI);
+               docatom.setSlideSizeY(pgsize.height*Shape.MASTER_DPI/Shape.POINT_DPI);
        }
        
        /**
@@ -491,9 +506,9 @@ public class SlideShow
         */
        protected FontCollection getFontCollection() { return _fonts; }
        /**
-        * Helper method for usermodel: Get the document record
+        * Helper method for usermodel and model: Get the document record
         */
-       protected Document getDocumentRecord() { return _documentRecord; }
+       public Document getDocumentRecord() { return _documentRecord; }
 
        
        /* ===============================================================
@@ -607,6 +622,7 @@ public class SlideShow
                usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW);
                
                // All done and added
+               slide.setSlideShow(this);
                return slide;
        }
 
index 400a66c6ee2845914b2f1effca0bf55e0874bf9b..1ceaa9e00fc1095d2d5b03df064ae7bda4ba087f 100644 (file)
@@ -17,12 +17,14 @@ package org.apache.poi.hslf.model;
 \r
 import junit.framework.TestCase;\r
 import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hslf.usermodel.RichTextRun;\r
 import org.apache.poi.hslf.HSLFSlideShow;\r
 \r
 import java.awt.*;\r
 import java.awt.Rectangle;\r
 import java.io.ByteArrayOutputStream;\r
 import java.io.ByteArrayInputStream;\r
+import java.io.FileOutputStream;\r
 \r
 /**\r
  * Test drawing shapes via Graphics2D\r
@@ -36,21 +38,23 @@ public class TestShapes extends TestCase {
                String dirname = System.getProperty("HSLF.testdata.path");\r
                String filename = dirname + "/empty.ppt";\r
                ppt = new SlideShow(new HSLFSlideShow(filename));\r
-        getClass().getResourceAsStream("");\r
     }\r
 \r
     public void testGraphics() throws Exception {\r
         Slide slide = ppt.createSlide();\r
 \r
         Line line = new Line();\r
-        line.setAnchor(new Rectangle(1296, 2544, 1344, 528));\r
+        java.awt.Rectangle lineAnchor = new java.awt.Rectangle(100, 200, 50, 60);\r
+        line.setAnchor(lineAnchor);\r
+        System.out.println(line.getAnchor());\r
         line.setLineWidth(3);\r
         line.setLineStyle(Line.LineDashSys);\r
         line.setLineColor(Color.red);\r
         slide.addShape(line);\r
 \r
-        Ellipse ellipse = new Ellipse();\r
-        ellipse.setAnchor(new Rectangle(4000, 1000, 1000, 1000));\r
+        AutoShape ellipse = new AutoShape(ShapeTypes.Ellipse);\r
+        java.awt.Rectangle ellipseAnchor = new Rectangle(320, 154, 55, 111);\r
+        ellipse.setAnchor(ellipseAnchor);\r
         ellipse.setLineWidth(2);\r
         ellipse.setLineStyle(Line.LineSolid);\r
         ellipse.setLineColor(Color.green);\r
@@ -64,17 +68,103 @@ public class TestShapes extends TestCase {
         //read ppt from byte array\r
 \r
         ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())));\r
-        assertEquals(ppt.getSlides().length, 1);\r
+        assertEquals(1, ppt.getSlides().length);\r
 \r
         slide = ppt.getSlides()[0];\r
         Shape[] shape = slide.getShapes();\r
-        assertEquals(shape.length, 2);\r
+        assertEquals(2, shape.length);\r
 \r
         assertTrue(shape[0] instanceof Line); //group shape\r
-        assertEquals(shape[0].getAnchor(), new Rectangle(1296, 2544, 1344, 528)); //group shape\r
+        assertEquals(lineAnchor, shape[0].getAnchor()); //group shape\r
 \r
-        assertTrue(shape[1] instanceof Ellipse); //group shape\r
-        assertEquals(shape[1].getAnchor(), new Rectangle(4000, 1000, 1000, 1000)); //group shape\r
+        assertTrue(shape[1] instanceof AutoShape); //group shape\r
+        assertEquals(ellipseAnchor, shape[1].getAnchor()); //group shape\r
+    }\r
+\r
+    /**\r
+     * Verify that we can read TextBox shapes\r
+     * @throws Exception\r
+     */\r
+    public void testTextBoxRead() throws Exception {\r
+        String dirname = System.getProperty("HSLF.testdata.path");\r
+        String filename = dirname + "/with_textbox.ppt";\r
+        ppt = new SlideShow(new HSLFSlideShow(filename));\r
+        Slide sl = ppt.getSlides()[0];\r
+        Shape[] sh = sl.getShapes();\r
+        for (int i = 0; i < sh.length; i++) {\r
+            assertTrue(sh[i] instanceof TextBox);\r
+            TextBox txtbox = (TextBox)sh[i];\r
+            String text = txtbox.getText();\r
+            assertNotNull(text);\r
+\r
+            assertEquals(txtbox.getRichTextRuns().length, 1);\r
+            RichTextRun rt = txtbox.getRichTextRuns()[0];\r
+\r
+            if (text.equals("Hello, World!!!")){\r
+                assertEquals(32, rt.getFontSize());\r
+                assertTrue(rt.isBold());\r
+                assertTrue(rt.isItalic());\r
+            } else if (text.equals("I am just a poor boy")){\r
+                assertEquals(44, rt.getFontSize());\r
+                assertTrue(rt.isBold());\r
+            } else if (text.equals("This is Times New Roman")){\r
+                assertEquals(16, rt.getFontSize());\r
+                assertTrue(rt.isBold());\r
+                assertTrue(rt.isItalic());\r
+                assertTrue(rt.isUnderlined());\r
+            } else if (text.equals("Plain Text")){\r
+                assertEquals(18, rt.getFontSize());\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Verify that we can add TextBox shapes to a slide\r
+     * @throws Exception\r
+     */\r
+    public void testTextBoxWrite() throws Exception {\r
+        ppt = new SlideShow();\r
+        Slide sl = ppt.createSlide();\r
+\r
+        TextBox txtbox = new TextBox();\r
+        txtbox.setText("Hello, World!");\r
+        txtbox.setFontSize(42);\r
+        txtbox.setBold(true);\r
+        txtbox.setItalic(true);\r
+\r
+        sl.addShape(txtbox);\r
+\r
+        txtbox = new TextBox();\r
+        txtbox.setText("Plain text in default font");\r
+        sl.addShape(txtbox);\r
+\r
+        assertEquals(sl.getShapes().length, 2);\r
+        \r
+        //serialize and read again\r
+        ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+        ppt.write(out);\r
+        out.close();\r
+\r
+        ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())));\r
+        sl = ppt.getSlides()[0];\r
+        assertEquals(sl.getShapes().length, 2);\r
+\r
+        Shape[] sh = sl.getShapes();\r
+        for (int i = 0; i < sh.length; i++) {\r
+            assertTrue(sh[i] instanceof TextBox);\r
+            txtbox = (TextBox)sh[i];\r
+            String text = txtbox.getText();\r
+            assertNotNull(text);\r
+\r
+            assertEquals(txtbox.getRichTextRuns().length, 1);\r
+            RichTextRun rt = txtbox.getRichTextRuns()[0];\r
+\r
+            if (text.equals("Hello, World!")){\r
+                assertEquals(42, rt.getFontSize());\r
+                assertTrue(rt.isBold());\r
+                assertTrue(rt.isItalic());\r
+            }\r
+        }\r
     }\r
 \r
 }\r
index b4503eb017fdf16d104f8e7adf751e7ddc8a62f5..3a3133a952b90e03002cb4d89f2a8c6f11efd5ef 100644 (file)
@@ -50,10 +50,37 @@ public class TestPictures extends TestCase{
 \r
             BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));\r
             assertNotNull(img);\r
+            assertEquals(Picture.PNG, pict[i].getType());\r
         }\r
         ppt.close();\r
     }\r
 \r
+    public void testReadPicturesForSlide() throws Exception {\r
+\r
+        SlideShow ppt = new SlideShow(new HSLFSlideShow(filename));\r
+\r
+        Slide[] slide = ppt.getSlides();\r
+        for (int i = 0; i < slide.length; i++) {\r
+            Slide sl = slide[i];\r
+            Shape[] sh = sl.getShapes();\r
+            for (int j = 0; j < sh.length; j++) {\r
+                Shape shape = sh[j];\r
+                if (shape instanceof Picture){\r
+                    Picture picture = (Picture)shape;\r
+\r
+                    PictureData pictdata = picture.getPictureData();\r
+                    assertEquals(Picture.PNG, pictdata.getType());\r
+\r
+                    //raw data.\r
+                    byte[] data = pictdata.getData();\r
+                    BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));\r
+                    assertNotNull(img);\r
+                }\r
+            }\r
+\r
+        }\r
+    }\r
+\r
     public void testSerializePictures() throws Exception {\r
         HSLFSlideShow ppt = new HSLFSlideShow(filename);\r
         PictureData[] pict = ppt.getPictures();\r
@@ -78,12 +105,10 @@ public class TestPictures extends TestCase{
         idx = ppt.addPicture(new File(dirname + "/clock.jpg"), Picture.JPEG);\r
         slide = ppt.createSlide();\r
         pict = new Picture(idx);\r
-        pict.setDefaultSize(ppt);\r
         slide.addShape(pict);\r
 \r
         idx = ppt.addPicture(new File(dirname + "/painting.png"), Picture.PNG);\r
         pict = new Picture(idx);\r
-        pict.setDefaultSize(ppt);\r
         slide.addShape(pict);\r
 \r
         ByteArrayOutputStream out = new ByteArrayOutputStream();\r
@@ -91,7 +116,7 @@ public class TestPictures extends TestCase{
         out.close();\r
 \r
         ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())));\r
-        assertTrue(ppt.getPictures().length == 2 );\r
+        assertTrue(ppt.getPictureData().length == 2 );\r
     }\r
 \r
 }\r