]> source.dussan.org Git - poi.git/commitdiff
more work on rendering ppt slides
authorYegor Kozlov <yegor@apache.org>
Wed, 30 Apr 2008 06:29:11 +0000 (06:29 +0000)
committerYegor Kozlov <yegor@apache.org>
Wed, 30 Apr 2008 06:29:11 +0000 (06:29 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@652298 13f79535-47bb-0310-9956-ffa450edef68

23 files changed:
src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java
src/scratchpad/src/org/apache/poi/hslf/model/Freeform.java
src/scratchpad/src/org/apache/poi/hslf/model/MasterSheet.java
src/scratchpad/src/org/apache/poi/hslf/model/Picture.java
src/scratchpad/src/org/apache/poi/hslf/model/Shape.java
src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.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/Slide.java
src/scratchpad/src/org/apache/poi/hslf/model/SlideMaster.java
src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java
src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java
src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java [new file with mode: 0755]
src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java
src/scratchpad/testcases/org/apache/poi/hslf/record/TestTextRulerAtom.java [new file with mode: 0755]
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestRichTextRun.java

index 5d345e6de4b0d51689c60819dbe0a4d1a9cec64e..1fc4ec9932c28f3787b2a3890447dbca2933cd36 100755 (executable)
@@ -369,5 +369,12 @@ public class AutoShapes {
             }\r
         };\r
 \r
+        shapes[ShapeTypes.StraightConnector1] = new ShapeOutline(){\r
+            public java.awt.Shape getOutline(Shape shape){\r
+                return new Line2D.Float(0, 0, 21600, 21600);\r
+            }\r
+        };\r
+\r
+\r
     }\r
 }\r
index d31237f8db1378ce96a436ae8d25ba7d730b1c77..fb3980a455b34bbf9ad56287e27b723414431820 100755 (executable)
@@ -19,6 +19,7 @@ package org.apache.poi.hslf.model;
 import org.apache.poi.ddf.*;\r
 import org.apache.poi.util.LittleEndian;\r
 import org.apache.poi.util.POILogger;\r
+import org.apache.poi.util.HexDump;\r
 \r
 import java.awt.geom.*;\r
 import java.util.ArrayList;\r
@@ -185,10 +186,6 @@ public class Freeform extends AutoShape {
             return null;\r
         }\r
 \r
-        Rectangle2D bounds = getAnchor2D();\r
-        float right = (float)bounds.getX();\r
-        float bottom = (float)bounds.getY();\r
-\r
         GeneralPath path = new GeneralPath();\r
         int numPoints = verticesProp.getNumberOfElementsInArray();\r
         int numSegments = segmentsProp.getNumberOfElementsInArray();\r
@@ -199,8 +196,8 @@ public class Freeform extends AutoShape {
                 short x = LittleEndian.getShort(p, 0);\r
                 short y = LittleEndian.getShort(p, 2);\r
                 path.moveTo(\r
-                        ((float)x*POINT_DPI/MASTER_DPI + right),\r
-                        ((float)y*POINT_DPI/MASTER_DPI + bottom));\r
+                        ((float)x*POINT_DPI/MASTER_DPI),\r
+                        ((float)y*POINT_DPI/MASTER_DPI));\r
             } else if (Arrays.equals(elem, SEGMENTINFO_CUBICTO) || Arrays.equals(elem, SEGMENTINFO_CUBICTO2)){\r
                 i++;\r
                 byte[] p1 = verticesProp.getElement(j++);\r
@@ -213,9 +210,9 @@ public class Freeform extends AutoShape {
                 short x3 = LittleEndian.getShort(p3, 0);\r
                 short y3 = LittleEndian.getShort(p3, 2);\r
                 path.curveTo(\r
-                        ((float)x1*POINT_DPI/MASTER_DPI + right), ((float)y1*POINT_DPI/MASTER_DPI + bottom),\r
-                        ((float)x2*POINT_DPI/MASTER_DPI + right), ((float)y2*POINT_DPI/MASTER_DPI + bottom),\r
-                        ((float)x3*POINT_DPI/MASTER_DPI + right), ((float)y3*POINT_DPI/MASTER_DPI + bottom));\r
+                        ((float)x1*POINT_DPI/MASTER_DPI), ((float)y1*POINT_DPI/MASTER_DPI),\r
+                        ((float)x2*POINT_DPI/MASTER_DPI), ((float)y2*POINT_DPI/MASTER_DPI),\r
+                        ((float)x3*POINT_DPI/MASTER_DPI), ((float)y3*POINT_DPI/MASTER_DPI));\r
 \r
             } else if (Arrays.equals(elem, SEGMENTINFO_LINETO)){\r
                 i++;\r
@@ -226,18 +223,26 @@ public class Freeform extends AutoShape {
                         short x = LittleEndian.getShort(p, 0);\r
                         short y = LittleEndian.getShort(p, 2);\r
                         path.lineTo(\r
-                                ((float)x*POINT_DPI/MASTER_DPI + right), ((float)y*POINT_DPI/MASTER_DPI + bottom));\r
+                                ((float)x*POINT_DPI/MASTER_DPI), ((float)y*POINT_DPI/MASTER_DPI));\r
                     }\r
                 } else if (Arrays.equals(pnext, SEGMENTINFO_CLOSE)){\r
                     path.closePath();\r
                 }\r
             }\r
         }\r
-\r
         return path;\r
     }\r
 \r
     public java.awt.Shape getOutline(){\r
-        return getPath();\r
+        GeneralPath path =  getPath();\r
+        Rectangle2D anchor = getAnchor2D();\r
+        Rectangle2D bounds = path.getBounds2D();\r
+        AffineTransform at = new AffineTransform();\r
+        at.translate(anchor.getX(), anchor.getY());\r
+        at.scale(\r
+                anchor.getWidth()/bounds.getWidth(),\r
+                anchor.getHeight()/bounds.getHeight()\r
+        );\r
+        return at.createTransformedShape(path);\r
     }\r
 }\r
index 5b1b1016e4f3487875d03a2a6ac8665003cd0db2..d01136d87ee90ee876453ea6239ed168b035a7ab 100644 (file)
@@ -67,4 +67,21 @@ public abstract class MasterSheet extends Sheet {
         }
         return false;
     }
+
+    /**
+     * Return placeholder by text type
+     */
+    public TextShape getPlaceholder(int type){
+        Shape[] shape = getShapes();
+        for (int i = 0; i < shape.length; i++) {
+            if(shape[i] instanceof TextShape){
+                TextShape tx = (TextShape)shape[i];
+                TextRun run = tx.getTextRun();
+                if(run != null && run.getRunType() == type){
+                    return tx;
+                }
+            }
+        }
+        return null;
+    }
 }
index e10986966bf85532c169a7aa8a87da1350175ec2..375249b519c79b15f82068a5eba0901fc1193d8d 100644 (file)
@@ -28,6 +28,7 @@ import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
 import java.awt.*;
 import java.awt.geom.Rectangle2D;
+import java.awt.geom.AffineTransform;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
@@ -244,6 +245,9 @@ public class Picture extends SimpleShape {
     }
 
     public void draw(Graphics2D graphics){
+        AffineTransform at = graphics.getTransform();
+        ShapePainter.paint(this, graphics);
+
         PictureData data = getPictureData();
         if (data  instanceof Bitmap){
             BufferedImage img = null;
@@ -260,5 +264,6 @@ public class Picture extends SimpleShape {
         } else {
             logger.log(POILogger.WARN, "Rendering of metafiles is not yet supported. image.type: " + (data == null ? "NA" : data.getClass().getName()));
         }
+        graphics.setTransform(at);
     }
 }
index e96e349002434786e473a7e9b3f79cfdc5e6d24d..fbea17e88f424d4c319bbf4a3102945e8031f4fd 100644 (file)
@@ -341,58 +341,7 @@ public abstract class Shape {
      * @param sh - owning shape
      */
     protected void afterInsert(Sheet sh){
-        PPDrawing ppdrawing = sh.getPPDrawing();
 
-        EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
-
-        EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
-
-        int id = allocateShapeId(dg);
-        setShapeId(id);
-    }
-
-    /**
-     * Allocates new shape id for the new drawing group id.
-     *
-     * @param dg  EscherDgRecord of the sheet that owns the shape being created
-     *
-     * @return a new shape id.
-     */
-    protected int allocateShapeId(EscherDgRecord dg)
-    {
-        EscherDggRecord dgg = _sheet.getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
-        if(dgg == null){
-            logger.log(POILogger.ERROR, "EscherDggRecord not found");
-            return 0;
-        }
-
-        dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 );
-
-        // Add to existing cluster if space available
-        for (int i = 0; i < dgg.getFileIdClusters().length; i++)
-        {
-            EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
-            if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024)
-            {
-                int result = c.getNumShapeIdsUsed() + (1024 * (i+1));
-                c.incrementShapeId();
-                dg.setNumShapes( dg.getNumShapes() + 1 );
-                dg.setLastMSOSPID( result );
-                if (result >= dgg.getShapeIdMax())
-                    dgg.setShapeIdMax( result + 1 );
-                return result;
-            }
-        }
-
-        // Create new cluster
-        dgg.addCluster( dg.getDrawingGroupId(), 0 );
-        dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId();
-        dg.setNumShapes( dg.getNumShapes() + 1 );
-        int result = (1024 * dgg.getFileIdClusters().length);
-        dg.setLastMSOSPID( result );
-        if (result >= dgg.getShapeIdMax())
-            dgg.setShapeIdMax( result + 1 );
-        return result;
     }
 
     /**
index b57a6e2336d6ba75527d622386877040aa238007..cfa8296713d6c44a1057ebffd904b19e98d8f3fc 100644 (file)
@@ -196,13 +196,8 @@ public class ShapeGroup extends Shape{
 
         Sheet sheet = getSheet();
         shape.setSheet(sheet);
+        shape.setShapeId(sheet.allocateShapeId());
         shape.afterInsert(sheet);
-
-        if (shape instanceof TextShape) {
-            TextShape tbox = (TextShape) shape;
-            EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper();
-            if(txWrapper != null) getSheet().getPPDrawing().addTextboxWrapper(txWrapper);
-        }
     }
 
     /**
@@ -277,20 +272,9 @@ public class ShapeGroup extends Shape{
     }
 
     public void draw(Graphics2D graphics){
-        Rectangle2D anchor = getAnchor2D();
-        Rectangle2D coords = getCoordinates();
 
-        //transform coordinates
         AffineTransform at = graphics.getTransform();
-        /*
-        if(!anchor.equals(coords)){
-            graphics.scale(anchor.getWidth()/coords.getWidth(), anchor.getHeight()/coords.getHeight());
 
-            graphics.translate(
-                    anchor.getX()*coords.getWidth()/anchor.getWidth() - coords.getX(),
-                    anchor.getY()*coords.getHeight()/anchor.getHeight() - coords.getY());
-        }
-        */
         Shape[] sh = getShapes();
         for (int i = 0; i < sh.length; i++) {
             sh[i].draw(graphics);
index d9c8903d5bb3038ea927defe49aa78bb5218f78d..6eb84ca2e75f93a0984ee739550e2c4011230c6a 100644 (file)
 
 package org.apache.poi.hslf.model;
 
-import org.apache.poi.ddf.EscherContainerRecord;
-import org.apache.poi.ddf.EscherDgRecord;
-import org.apache.poi.ddf.EscherRecord;
-import org.apache.poi.ddf.EscherSpRecord;
+import org.apache.poi.ddf.*;
 import org.apache.poi.hslf.record.*;
 import org.apache.poi.hslf.usermodel.SlideShow;
+import org.apache.poi.util.POILogger;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -248,15 +246,47 @@ public abstract class Sheet {
         spgr.addChildRecord(shape.getSpContainer());
 
         shape.setSheet(this);
+        shape.setShapeId(allocateShapeId());
         shape.afterInsert(this);
+    }
 
-        // If it's a TextShape, we need to tell the PPDrawing, as it has to
-        //  track TextboxWrappers specially
-        if (shape instanceof TextShape) {
-            TextShape tbox = (TextShape) shape;
-            EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper();
-            if(txWrapper != null) ppdrawing.addTextboxWrapper(txWrapper);
+    /**
+     * Allocates new shape id for the new drawing group id.
+     *
+     * @return a new shape id.
+     */
+    public int allocateShapeId()
+    {
+        EscherDggRecord dgg = _slideShow.getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
+        EscherDgRecord dg = _container.getPPDrawing().getEscherDgRecord();
+
+        dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 );
+
+        // Add to existing cluster if space available
+        for (int i = 0; i < dgg.getFileIdClusters().length; i++)
+        {
+            EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
+            if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024)
+            {
+                int result = c.getNumShapeIdsUsed() + (1024 * (i+1));
+                c.incrementShapeId();
+                dg.setNumShapes( dg.getNumShapes() + 1 );
+                dg.setLastMSOSPID( result );
+                if (result >= dgg.getShapeIdMax())
+                    dgg.setShapeIdMax( result + 1 );
+                return result;
+            }
         }
+
+        // Create new cluster
+        dgg.addCluster( dg.getDrawingGroupId(), 0, false );
+        dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId();
+        dg.setNumShapes( dg.getNumShapes() + 1 );
+        int result = (1024 * dgg.getFileIdClusters().length);
+        dg.setLastMSOSPID( result );
+        if (result >= dgg.getShapeIdMax())
+            dgg.setShapeIdMax( result + 1 );
+        return result;
     }
 
     /**
@@ -284,6 +314,13 @@ public abstract class Sheet {
         return lst.remove(shape.getSpContainer());
     }
 
+    /**
+     * Called by SlideShow ater a new sheet is created
+     */
+    public void onCreate(){
+
+    }
+
     /**
      * Return the master sheet .
      */
index ea0719a7f15a7e5635c0064584a058b16c4fad39..e15454d651c90148bc077f88136efde5da8f66c8 100644 (file)
@@ -126,8 +126,8 @@ public class SimpleShape extends Shape {
         EscherSimpleProperty p2 = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH);
         int p2val = p2 == null ? 0 : p2.getPropertyValue();
         Color clr = null;
-        if (p1 != null && (p2val  & 0x8) != 0){
-            int rgb = p1.getPropertyValue();
+        if ((p2val  & 0x8) != 0 || (p2val  & 0x10) != 0){
+            int rgb = p1 == null ? 0 : p1.getPropertyValue();
             if (rgb >= 0x8000000) {
                 int idx = rgb % 0x8000000;
                 if(getSheet() != null) {
index e618ae23033372b2869a996a0a9a84906a984396..bb99c1bcadecabfdbbe612949742275507a5a7c8 100644 (file)
 package org.apache.poi.hslf.model;
 
 import java.util.Vector;
+import java.util.Iterator;
 import java.awt.*;
 
 import org.apache.poi.hslf.record.SlideAtom;
 import org.apache.poi.hslf.record.TextHeaderAtom;
 import org.apache.poi.hslf.record.ColorSchemeAtom;
 import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
+import org.apache.poi.ddf.EscherDggRecord;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherDgRecord;
+import org.apache.poi.ddf.EscherSpRecord;
 
 /**
  * This class represents a slide in a PowerPoint Document. It allows 
@@ -126,6 +131,42 @@ public class Slide extends Sheet
                _slideNo = newSlideNumber;
        }
   
+    /**
+     * Called by SlideShow ater a new slide is created.
+     * <p>
+     * For Slide we need to do the following:
+     *  <li> set id of the drawing group.
+     *  <li> set shapeId for the container descriptor and background
+     * </p>
+     */
+    public void onCreate(){
+        //initialize drawing group id
+        EscherDggRecord dgg = getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
+        EscherContainerRecord dgContainer = (EscherContainerRecord)getSheetContainer().getPPDrawing().getEscherRecords()[0];
+        EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
+        int dgId = dgg.getMaxDrawingGroupId() + 1;
+        dg.setOptions((short)(dgId << 4));
+        dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1);
+
+        for (Iterator it = dgContainer.getChildContainers().iterator(); it.hasNext(); ) {
+            EscherContainerRecord c = (EscherContainerRecord)it.next();
+            EscherSpRecord spr = null;
+            switch(c.getRecordId()){
+                case EscherContainerRecord.SPGR_CONTAINER:
+                    EscherContainerRecord dc = (EscherContainerRecord)c.getChildRecords().get(0);
+                    spr = dc.getChildById(EscherSpRecord.RECORD_ID);
+                    break;
+                case EscherContainerRecord.SP_CONTAINER:
+                    spr = c.getChildById(EscherSpRecord.RECORD_ID);
+                    break;
+            }
+            if(spr != null) spr.setShapeId(allocateShapeId());
+        }
+
+        //PPT doen't increment the number of saved shapes for group descriptor and background 
+        dg.setNumShapes(1);
+    }
+
        /**
         * Create a <code>TextBox</code> object that represents the slide's title.
         *
index 26870dbdbbbdeaf9a81cf1ed7bb7152a640f9f83..b48edfc1a1b40bc08a4e575e00fca5bea4004d4d 100644 (file)
@@ -92,6 +92,7 @@ public class SlideMaster extends MasterSheet {
             } else {
                 switch (txtype) {
                     case TextHeaderAtom.CENTRE_BODY_TYPE:
+                    case TextHeaderAtom.HALF_BODY_TYPE:
                     case TextHeaderAtom.QUARTER_BODY_TYPE:
                         txtype = TextHeaderAtom.BODY_TYPE;
                         break;
index c1eadc336c6494af6998d28978484ac9037c4154..6eff54329078d622c775cca914a1131eafe1c873 100755 (executable)
@@ -17,6 +17,7 @@
 package org.apache.poi.hslf.model;\r
 \r
 import org.apache.poi.hslf.usermodel.RichTextRun;\r
+import org.apache.poi.hslf.record.TextRulerAtom;\r
 import org.apache.poi.util.POILogger;\r
 import org.apache.poi.util.POILogFactory;\r
 \r
@@ -38,6 +39,13 @@ import java.util.ArrayList;
 public class TextPainter {\r
     protected POILogger logger = POILogFactory.getLogger(this.getClass());\r
 \r
+    /**\r
+     * Display unicode square if a bullet char can't be displayed,\r
+     * for example, if Wingdings font is used.\r
+     * TODO: map Wingdngs and Symbol to unicode Arial\r
+     */\r
+    protected static final char DEFAULT_BULLET_CHAR = '\u25a0';\r
+\r
     protected TextShape _shape;\r
 \r
     public TextPainter(TextShape shape){\r
@@ -49,6 +57,10 @@ public class TextPainter {
      */\r
     public AttributedString getAttributedString(TextRun txrun){\r
         String text = txrun.getText();\r
+        //TODO: properly process tabs\r
+        text = text.replace('\t', ' ');\r
+        text = text.replace((char)160, ' ');\r
+\r
         AttributedString at = new AttributedString(text);\r
         RichTextRun[] rt = txrun.getRichTextRuns();\r
         for (int i = 0; i < rt.length; i++) {\r
@@ -109,7 +121,24 @@ public class TextPainter {
             }\r
 \r
             float wrappingWidth = (float)anchor.getWidth() - _shape.getMarginLeft() - _shape.getMarginRight();\r
-            wrappingWidth -= rt.getTextOffset();\r
+            int bulletOffset = rt.getBulletOffset();\r
+            int textOffset = rt.getTextOffset();\r
+            int indent = rt.getIndentLevel();\r
+\r
+            TextRulerAtom ruler = run.getTextRuler();\r
+            if(ruler != null) {\r
+                int bullet_val = ruler.getBulletOffsets()[indent]*Shape.POINT_DPI/Shape.MASTER_DPI;\r
+                int text_val = ruler.getTextOffsets()[indent]*Shape.POINT_DPI/Shape.MASTER_DPI;\r
+                if(bullet_val > text_val){\r
+                    int a = bullet_val;\r
+                    bullet_val = text_val;\r
+                    text_val = a;\r
+                }\r
+                if(bullet_val != 0 ) bulletOffset = bullet_val;\r
+                if(text_val != 0) textOffset = text_val;\r
+            }\r
+\r
+            wrappingWidth -= textOffset;\r
 \r
             if (_shape.getWordWrap() == TextShape.WrapNone) {\r
                 wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;\r
@@ -141,8 +170,9 @@ public class TextPainter {
             }\r
 \r
             el._align = rt.getAlignment();\r
-            el._text = textLayout;\r
-            el._textOffset = rt.getTextOffset();\r
+            el.advance = textLayout.getAdvance();\r
+            el._textOffset = textOffset;\r
+            el._text = new AttributedString(it, startIndex, endIndex);\r
 \r
             if (prStart){\r
                 int sp = rt.getSpaceBefore();\r
@@ -182,13 +212,25 @@ public class TextPainter {
                 Color clr = rt.getBulletColor();\r
                 if (clr != null) bat.addAttribute(TextAttribute.FOREGROUND, clr);\r
                 else bat.addAttribute(TextAttribute.FOREGROUND, it.getAttribute(TextAttribute.FOREGROUND));\r
-                bat.addAttribute(TextAttribute.FAMILY, it.getAttribute(TextAttribute.FAMILY));\r
-                bat.addAttribute(TextAttribute.SIZE, it.getAttribute(TextAttribute.SIZE));\r
 \r
-                TextLayout bulletLayout = new TextLayout(bat.getIterator(), graphics.getFontRenderContext());\r
+                int fontIdx = rt.getBulletFont();\r
+                if(fontIdx == -1) fontIdx = rt.getFontIndex();\r
+                PPFont bulletFont = _shape.getSheet().getSlideShow().getFont(fontIdx);\r
+                bat.addAttribute(TextAttribute.FAMILY, bulletFont.getFontName());\r
+\r
+                int bulletSize = rt.getBulletSize();\r
+                int fontSize = rt.getFontSize();\r
+                if(bulletSize != -1) fontSize = Math.round(fontSize*bulletSize*0.01f);\r
+                bat.addAttribute(TextAttribute.SIZE, new Float(fontSize));\r
+\r
+                if(!new Font(bulletFont.getFontName(), Font.PLAIN, 1).canDisplay(rt.getBulletChar())){\r
+                    bat.addAttribute(TextAttribute.FAMILY, "Arial");\r
+                    bat = new AttributedString("" + DEFAULT_BULLET_CHAR, bat.getIterator().getAttributes());\r
+                }\r
+\r
                 if(text.substring(startIndex, endIndex).length() > 1){\r
-                    el._bullet = bulletLayout;\r
-                    el._bulletOffset = rt.getBulletOffset();\r
+                    el._bullet = bat;\r
+                    el._bulletOffset = bulletOffset;\r
                 }\r
             }\r
             lines.add(el);\r
@@ -225,29 +267,32 @@ public class TextPainter {
                     break;\r
                 case TextShape.AlignCenter:\r
                     pen.x = anchor.getX() + _shape.getMarginLeft() +\r
-                            (anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;\r
+                            (anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;\r
                     break;\r
                 case TextShape.AlignRight:\r
                     pen.x = anchor.getX() + _shape.getMarginLeft() +\r
-                            (anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight());\r
+                            (anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight());\r
                     break;\r
             }\r
             if(elem._bullet != null){\r
-                elem._bullet.draw(graphics, (float)(pen.x + elem._bulletOffset), (float)pen.y);\r
+                graphics.drawString(elem._bullet.getIterator(), (float)(pen.x + elem._bulletOffset), (float)pen.y);\r
+            }\r
+            AttributedCharacterIterator chIt = elem._text.getIterator();\r
+            if(chIt.getEndIndex() > chIt.getBeginIndex()) {\r
+                graphics.drawString(chIt, (float)(pen.x + elem._textOffset), (float)pen.y);\r
             }\r
-            elem._text.draw(graphics, (float)(pen.x + elem._textOffset), (float)pen.y);\r
-\r
             y0 += elem.descent;\r
         }\r
     }\r
 \r
 \r
-    static class TextElement {\r
-        public TextLayout _text;\r
+    public static class TextElement {\r
+        public AttributedString _text;\r
         public int _textOffset;\r
-        public TextLayout _bullet;\r
+        public AttributedString _bullet;\r
         public int _bulletOffset;\r
         public int _align;\r
         public float ascent, descent;\r
+        public float advance;\r
     }\r
 }\r
index 2f77ac5ffa2c044d8796be07c330aedf10563127..5dac650258bad171f3b50df9978940af4c6506e7 100644 (file)
@@ -535,9 +535,13 @@ public class TextRun
                //  them to \n
                String text = rawText.replace('\r','\n');
 
-        //0xB acts like cariage return in page titles
-        text = text.replace((char) 0x0B, '\n');
-
+        int type = _headerAtom == null ? 0 : _headerAtom.getTextType();
+        if(type == TextHeaderAtom.TITLE_TYPE || type == TextHeaderAtom.CENTER_TITLE_TYPE){
+            //0xB acts like cariage return in page titles and like blank in the others
+            text = text.replace((char) 0x0B, '\n');
+        } else {
+            text = text.replace((char) 0x0B, ' ');
+        }
                return text;
        }
 
@@ -655,4 +659,11 @@ public class TextRun
         return null;
     }
 
+    public TextRulerAtom getTextRuler(){
+        for (int i = 0; i < _records.length; i++) {
+            if(_records[i] instanceof TextRulerAtom) return (TextRulerAtom)_records[i];
+        }
+        return null;
+
+    }
 }
index 7249817bed3b342d5bca22f6e58649c9323189d4..53f8ef97d57cf91c6f359946d6ea1f6ca3c76b7e 100755 (executable)
@@ -261,17 +261,28 @@ public abstract class TextShape extends SimpleShape {
     public int getVerticalAlignment(){\r
         EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
         EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);\r
-        int valign;\r
+        int valign = TextShape.AnchorTop;\r
         if (prop == null){\r
+            /**\r
+             * If vertical alignment was not found in the shape properties then try to\r
+             * fetch the master shape and search for the align property there.\r
+             */\r
             int type = getTextRun().getRunType();\r
-            switch (type){\r
-                case TextHeaderAtom.TITLE_TYPE:\r
-                case TextHeaderAtom.CENTER_TITLE_TYPE:\r
-                    valign = TextShape.AnchorMiddle;\r
-                    break;\r
-                default:\r
-                    valign = TextShape.AnchorTop;\r
-                    break;\r
+            MasterSheet master = getSheet().getMasterSheet();\r
+            if(master != null){\r
+                TextShape masterShape = master.getPlaceholder(type);\r
+                if(masterShape != null) valign = masterShape.getVerticalAlignment();\r
+            } else {\r
+                //not found in the master sheet. Use the hardcoded defaults.\r
+                switch (type){\r
+                     case TextHeaderAtom.TITLE_TYPE:\r
+                     case TextHeaderAtom.CENTER_TITLE_TYPE:\r
+                         valign = TextShape.AnchorMiddle;\r
+                         break;\r
+                     default:\r
+                         valign = TextShape.AnchorTop;\r
+                         break;\r
+                 }\r
             }\r
         } else {\r
             valign = prop.getPropertyValue();\r
index e42b358b89df78cf2230de8ac01e160473faa166..3a1ed8dbe5c865424407dccfd356f03864b82339 100644 (file)
@@ -24,11 +24,13 @@ import org.apache.poi.util.POILogger;
 
 import org.apache.poi.ddf.*;
 import org.apache.poi.hslf.model.ShapeTypes;
+import org.apache.poi.hslf.model.Shape;
 
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.List;
 import java.util.Vector;
+import java.util.Iterator;
 
 /**
  * These are actually wrappers onto Escher drawings. Make use of
@@ -52,6 +54,8 @@ public class PPDrawing extends RecordAtom
        private EscherRecord[] childRecords;
        private EscherTextboxWrapper[] textboxWrappers;
 
+    //cached EscherDgRecord
+    private EscherDgRecord dg;
 
        /**
         * Get access to the underlying Escher Records
@@ -296,4 +300,24 @@ public class PPDrawing extends RecordAtom
                tw[textboxWrappers.length] = txtbox;
                textboxWrappers = tw;
        }
+
+    /**
+     * Return EscherDgRecord which keeps track of the number of shapes and shapeId in this drawing group
+     *
+     * @return EscherDgRecord
+     */
+    public EscherDgRecord getEscherDgRecord(){
+        if(dg == null){
+            EscherContainerRecord dgContainer = (EscherContainerRecord)childRecords[0];
+            for(Iterator it = dgContainer.getChildRecords().iterator(); it.hasNext();){
+                EscherRecord r = (EscherRecord) it.next();
+                if(r instanceof EscherDgRecord){
+                    dg = (EscherDgRecord)r;
+                    break;
+                }
+            }
+        }
+        return dg;
+    }
+
 }
index 45038f7a287f1a0c557af79ca420ad47fc0f6803..cedc99ce0a7da6e896bec0f5ce43ed7516c37d7f 100644 (file)
@@ -89,7 +89,7 @@ public class RecordTypes {
     public static final Type TxMasterStyleAtom = new Type(4003,TxMasterStyleAtom.class);
     public static final Type TxCFStyleAtom = new Type(4004,null);
     public static final Type TxPFStyleAtom = new Type(4005,null);
-    public static final Type TextRulerAtom = new Type(4006,null);
+    public static final Type TextRulerAtom = new Type(4006,TextRulerAtom.class);
     public static final Type TextBookmarkAtom = new Type(4007,null);
     public static final Type TextBytesAtom = new Type(4008,TextBytesAtom.class);
     public static final Type TxSIStyleAtom = new Type(4009,null);
index 187dec12a12f8b578d7e4fb27240cd67f37e8cfe..2f3b898a7d1ac7c65ad96526cb412950c2dda11a 100644 (file)
@@ -127,8 +127,8 @@ public class StyleTextPropAtom extends RecordAtom
                                new ParagraphFlagsTextProp(),
                 new TextProp(2, 0x80, "bullet.char"),
                                new TextProp(2, 0x10, "bullet.font"),
+                new TextProp(2, 0x40, "bullet.size"),
                                new TextProp(4, 0x20, "bullet.color"),
-                               new TextProp(2, 0x40, "bullet.size"),
                 new AlignmentTextProp(),
                 new TextProp(2, 0x100, "text.offset"),
                                new TextProp(2, 0x200, "para_unknown_2"),
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java
new file mode 100755 (executable)
index 0000000..71ded85
--- /dev/null
@@ -0,0 +1,194 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.util.zip.InflaterInputStream;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+import org.apache.poi.util.POILogger;\r
+\r
+/**\r
+ * Ruler of a text as it differs from the style's ruler settings.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TextRulerAtom extends RecordAtom {\r
+\r
+    /**\r
+     * Record header.\r
+     */\r
+    private byte[] _header;\r
+\r
+    /**\r
+     * Record data.\r
+     */\r
+    private byte[] _data;\r
+\r
+    //ruler internals\r
+    private int defaultTabSize;\r
+    private int numLevels;\r
+    private int[] tabStops;\r
+    private int[] bulletOffsets = new int[5];\r
+    private int[] textOffsets = new int[5];\r
+\r
+    /**\r
+     * Constructs a new empty ruler atom.\r
+     */\r
+    protected TextRulerAtom() {\r
+        _header = new byte[8];\r
+        _data = new byte[0];\r
+\r
+        LittleEndian.putShort(_header, 2, (short)getRecordType());\r
+        LittleEndian.putInt(_header, 4, _data.length);\r
+    }\r
+\r
+    /**\r
+     * Constructs the ruler atom record from its\r
+     *  source data.\r
+     *\r
+     * @param source the source data as a byte array.\r
+     * @param start the start offset into the byte array.\r
+     * @param len the length of the slice in the byte array.\r
+     */\r
+    protected TextRulerAtom(byte[] source, int start, int len) {\r
+        // Get the header.\r
+        _header = new byte[8];\r
+        System.arraycopy(source,start,_header,0,8);\r
+\r
+        // Get the record data.\r
+        _data = new byte[len-8];\r
+        System.arraycopy(source,start+8,_data,0,len-8);\r
+\r
+        try {\r
+            read();\r
+        } catch (Exception e){\r
+            logger.log(POILogger.ERROR, "Failed to parse TextRulerAtom: " + e.getMessage()); \r
+            e.printStackTrace();\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Gets the record type.\r
+     *\r
+     * @return the record type.\r
+     */\r
+    public long getRecordType() {\r
+        return RecordTypes.TextRulerAtom.typeID;\r
+    }\r
+\r
+    /**\r
+     * Write the contents of the record back, so it can be written\r
+     * to disk.\r
+     *\r
+     * @param out the output stream to write to.\r
+     * @throws java.io.IOException if an error occurs.\r
+     */\r
+    public void writeOut(OutputStream out) throws IOException {\r
+        out.write(_header);\r
+        out.write(_data);\r
+    }\r
+\r
+    /**\r
+     * Read the record bytes and initialize the internal variables\r
+     */\r
+    private void read(){\r
+        int pos = 0;\r
+        short mask = LittleEndian.getShort(_data);  pos += 4;\r
+        short val;\r
+        int[] bits = {1, 0, 2, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12};\r
+        for (int i = 0; i < bits.length; i++) {\r
+            if((mask & 1 << bits[i]) != 0){\r
+                switch (bits[i]){\r
+                    case 0:\r
+                        //defaultTabSize\r
+                        defaultTabSize = LittleEndian.getShort(_data, pos); pos += 2;\r
+                        break;\r
+                    case 1:\r
+                        //numLevels\r
+                        numLevels = LittleEndian.getShort(_data, pos); pos += 2;\r
+                        break;\r
+                    case 2:\r
+                        //tabStops\r
+                        val = LittleEndian.getShort(_data, pos); pos += 2;\r
+                        tabStops = new int[val*2];\r
+                        for (int j = 0; j < tabStops.length; j++) {\r
+                            tabStops[j] = LittleEndian.getUShort(_data, pos); pos += 2;\r
+                        }\r
+                        break;\r
+                    case 3:\r
+                    case 4:\r
+                    case 5:\r
+                    case 6:\r
+                    case 7:\r
+                        //bullet.offset\r
+                        val = LittleEndian.getShort(_data, pos); pos += 2;\r
+                        bulletOffsets[bits[i]-3] = val;\r
+                        break;\r
+                    case 8:\r
+                    case 9:\r
+                    case 10:\r
+                    case 11:\r
+                    case 12:\r
+                        //text.offset\r
+                        val = LittleEndian.getShort(_data, pos); pos += 2;\r
+                        textOffsets[bits[i]-8] = val;\r
+                        break;\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Default distance between tab stops, in master coordinates (576 dpi).\r
+     */\r
+    public int getDefaultTabSize(){\r
+        return defaultTabSize;\r
+    }\r
+\r
+    /**\r
+     * Number of indent levels (maximum 5).\r
+     */\r
+    public int getNumberOfLevels(){\r
+        return numLevels;\r
+    }\r
+\r
+    /**\r
+     * Default distance between tab stops, in master coordinates (576 dpi).\r
+     */\r
+    public int[] getTabStops(){\r
+        return tabStops;\r
+    }\r
+\r
+    /**\r
+     * Paragraph's distance from shape's left margin, in master coordinates (576 dpi).\r
+     */\r
+    public int[] getTextOffsets(){\r
+        return textOffsets;\r
+    }\r
+\r
+    /**\r
+     * First line of paragraph's distance from shape's left margin, in master coordinates (576 dpi).\r
+     */\r
+    public int[] getBulletOffsets(){\r
+        return bulletOffsets;\r
+    }\r
+}\r
index 2a09f2224c3dfa9a4103981838b76ab431215c77..7458df7e637fd64f1195e0d3fb8657cb79f09537 100644 (file)
@@ -32,6 +32,8 @@ import org.apache.poi.hslf.model.textproperties.ParagraphFlagsTextProp;
 import org.apache.poi.hslf.model.textproperties.TextProp;
 import org.apache.poi.hslf.model.textproperties.TextPropCollection;
 import org.apache.poi.hslf.record.ColorSchemeAtom;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.POILogFactory;
 
 
 /**
@@ -39,6 +41,8 @@ import org.apache.poi.hslf.record.ColorSchemeAtom;
  * 
  */
 public class RichTextRun {
+    protected POILogger logger = POILogFactory.getLogger(this.getClass());
+
        /** The TextRun we belong to */
        private TextRun parentRun;
        /** The SlideShow we belong to */
@@ -199,10 +203,15 @@ public class RichTextRun {
         }
         if (prop == null){
             Sheet sheet = parentRun.getSheet();
-            int txtype = parentRun.getRunType();
-            MasterSheet master = sheet.getMasterSheet();
-            if (master != null)
-                prop = (BitMaskTextProp)master.getStyleAttribute(txtype, getIndentLevel(), propname, isCharacter);
+            if(sheet != null){
+                int txtype = parentRun.getRunType();
+                MasterSheet master = sheet.getMasterSheet();
+                if (master != null){
+                    prop = (BitMaskTextProp)master.getStyleAttribute(txtype, getIndentLevel(), propname, isCharacter);
+                }
+            } else {
+                logger.log(POILogger.WARN, "MasterSheet is not available");
+            }
         }
 
         return prop == null ? false : prop.getSubValue(index);
@@ -213,7 +222,7 @@ public class RichTextRun {
         *  it if required. 
         */
        private void setCharFlagsTextPropVal(int index, boolean value) {
-        setFlag(true, index, value);
+        if(getFlag(true, index) != value) setFlag(true, index, value);
        }
 
     public void setFlag(boolean isCharacter, int index, boolean value) {
@@ -281,10 +290,14 @@ public class RichTextRun {
         */
        private int getParaTextPropVal(String propName) {
         TextProp prop = null;
+        boolean hardAttribute = false;
         if (paragraphStyle != null){
             prop = paragraphStyle.findByName(propName);
+
+            BitMaskTextProp maskProp = (BitMaskTextProp)paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
+            hardAttribute = maskProp != null && maskProp.getValue() == 0;
         }
-        if (prop == null){
+        if (prop == null && !hardAttribute){
             Sheet sheet = parentRun.getSheet();
             int txtype = parentRun.getRunType();
             MasterSheet master = sheet.getMasterSheet();
@@ -574,6 +587,13 @@ public class RichTextRun {
         return getFlag(false, ParagraphFlagsTextProp.BULLET_IDX);
     }
 
+    /**
+     * Returns whether this rich text run has bullets
+     */
+    public boolean isBulletHard() {
+        return getFlag(false, ParagraphFlagsTextProp.BULLET_IDX);
+    }
+
     /**
      * Sets the bullet character
      */
index 828255087bf6606764b96cdf20b4d65502348221..d969c5b8810a41104f58ee86fd039b1319b7c247 100644 (file)
@@ -24,10 +24,7 @@ import java.util.*;
 import java.awt.Dimension;
 import java.io.*;
 
-import org.apache.poi.ddf.EscherBSERecord;
-import org.apache.poi.ddf.EscherContainerRecord;
-import org.apache.poi.ddf.EscherOptRecord;
-import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.*;
 import org.apache.poi.hslf.*;
 import org.apache.poi.hslf.model.*;
 import org.apache.poi.hslf.model.Notes;
@@ -66,9 +63,7 @@ public class SlideShow
   // Lookup between the PersitPtr "sheet" IDs, and the position
   //  in the mostRecentCoreRecords array
   private Hashtable _sheetIdToCoreRecordsLookup;
-  // Used when adding new core records
-  private int _highestSheetId;
-  
+
   // Records that are interesting
   private Document _documentRecord;
 
@@ -203,8 +198,6 @@ public class SlideShow
        for(int i=0; i<allIDs.length; i++) {
                _sheetIdToCoreRecordsLookup.put(new Integer(allIDs[i]), new Integer(i));
        }
-       // Capture the ID of the highest sheet
-       _highestSheetId = allIDs[(allIDs.length-1)];
 
        // Now convert the byte offsets back into record offsets
        for(int i=0; i<_records.length; i++) {
@@ -612,38 +605,35 @@ public class SlideShow
                                }
                        }
                }
-               
-               // Set up a new  SlidePersistAtom for this slide 
+
+               // Set up a new  SlidePersistAtom for this slide
                SlidePersistAtom sp = new SlidePersistAtom();
 
-               // Reference is the 1-based index of the slide container in 
-               //  the PersistPtr root.
-               // It always starts with 3 (1 is Document, 2 is MainMaster, 3 is 
-               //  the first slide), but quicksaves etc can leave gaps
-               _highestSheetId++;
-               sp.setRefID(_highestSheetId);
                // First slideId is always 256
                sp.setSlideIdentifier(prev == null ? 256 : (prev.getSlideIdentifier() + 1));
-               
+
                // Add this new SlidePersistAtom to the SlideListWithText
                slist.addSlidePersistAtom(sp);
-               
-               
+
+
                // Create a new Slide
                Slide slide = new Slide(sp.getSlideIdentifier(), sp.getRefID(), _slides.length+1);
+        slide.setSlideShow(this);
+        slide.onCreate();
+
                // Add in to the list of Slides
                Slide[] s = new Slide[_slides.length+1];
                System.arraycopy(_slides, 0, s, 0, _slides.length);
                s[_slides.length] = slide;
                _slides = s;
                logger.log(POILogger.INFO, "Added slide " + _slides.length + " with ref " + sp.getRefID() + " and identifier " + sp.getSlideIdentifier());
-               
+
                // Add the core records for this new Slide to the record tree
                org.apache.poi.hslf.record.Slide slideRecord = slide.getSlideRecord();
-               slideRecord.setSheetId(sp.getRefID());
                int slideRecordPos = _hslfSlideShow.appendRootLevelRecord(slideRecord);
                _records = _hslfSlideShow.getRecords();
 
+
                // Add the new Slide into the PersistPtr stuff
                int offset = 0;
                int slideOffset = 0;
@@ -653,7 +643,7 @@ public class SlideShow
                        Record record = _records[i];
                        ByteArrayOutputStream out = new ByteArrayOutputStream();
                        record.writeOut(out);
-                       
+
                        // Grab interesting records as they come past
                        if(_records[i].getRecordType() == RecordTypes.PersistPtrIncrementalBlock.typeID){
                                ptr = (PersistPtrHolder)_records[i];
@@ -661,25 +651,29 @@ public class SlideShow
                        if(_records[i].getRecordType() == RecordTypes.UserEditAtom.typeID) {
                                usr = (UserEditAtom)_records[i];
                        }
-                       
+
                        if(i == slideRecordPos) {
                                slideOffset = offset;
                        }
                        offset += out.size();
                }
-               
+
+        // persist ID is UserEditAtom.maxPersistWritten + 1
+        int psrId = usr.getMaxPersistWritten() + 1;
+        sp.setRefID(psrId);
+        slideRecord.setSheetId(psrId);
+
+        // Last view is now of the slide
+        usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW);
+        usr.setMaxPersistWritten(psrId);    //increment the number of persit objects
+
                // Add the new slide into the last PersistPtr
                // (Also need to tell it where it is)
                slideRecord.setLastOnDiskOffset(slideOffset);
                ptr.addSlideLookup(sp.getRefID(), slideOffset);
                logger.log(POILogger.INFO, "New slide ended up at " + slideOffset);
 
-               // Last view is now of the slide
-               usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW);
-               usr.setMaxPersistWritten(_highestSheetId);
-
                // All done and added
-               slide.setSlideShow(this);
                return slide;
        }
 
index 5e7e7cc4b7e359abcd075e3ed767a45987bd951b..56d5a099cb08de70eaba7fe7e9e71f49c77d9c4c 100755 (executable)
@@ -52,7 +52,7 @@ public class TestFreeform extends TestCase {
         Freeform p = new Freeform();\r
         p.setPath(path1);\r
 \r
-        GeneralPath path2 = p.getPath();\r
+        java.awt.Shape path2 = p.getOutline();\r
         assertTrue(new Area(path1).equals(new Area(path2)));\r
     }\r
 \r
@@ -63,7 +63,7 @@ public class TestFreeform extends TestCase {
         Freeform p = new Freeform();\r
         p.setPath(path1);\r
 \r
-        GeneralPath path2 = p.getPath();\r
+        java.awt.Shape path2 = p.getOutline();\r
         assertTrue(new Area(path1).equals(new Area(path2)));\r
     }\r
 \r
@@ -74,7 +74,7 @@ public class TestFreeform extends TestCase {
         Freeform p = new Freeform();\r
         p.setPath(path1);\r
 \r
-        GeneralPath path2 = p.getPath();\r
+        java.awt.Shape path2 = p.getOutline();\r
         assertTrue(new Area(path1).equals(new Area(path2)));\r
-    }\r
+   }\r
 }\r
index 511ef7f7453fc6d27317c0da4ae3f09610b05caf..3ce6b91caf285bed18a5313b35342b1e36a9514c 100644 (file)
@@ -20,6 +20,8 @@ import junit.framework.TestCase;
 import org.apache.poi.hslf.usermodel.SlideShow;
 import org.apache.poi.hslf.usermodel.RichTextRun;
 import org.apache.poi.hslf.HSLFSlideShow;
+import org.apache.poi.ddf.EscherDggRecord;
+import org.apache.poi.ddf.EscherDgRecord;
 
 import java.awt.*;
 import java.awt.Rectangle;
@@ -311,18 +313,49 @@ public class TestShapes extends TestCase {
     public void testShapeId() throws IOException {
         SlideShow ppt = new SlideShow();
         Slide slide = ppt.createSlide();
-        Shape shape;
-
-        shape = new Line();
-        assertEquals(0, shape.getShapeId());
-        slide.addShape(shape);
-        assertTrue(shape.getShapeId() > 0);
+        Shape shape = null;
+
+        //EscherDgg is a document-level record which keeps track of the drawing groups
+        EscherDggRecord dgg = ppt.getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
+        EscherDgRecord dg = slide.getSheetContainer().getPPDrawing().getEscherDgRecord();
+
+        int dggShapesUsed = dgg.getNumShapesSaved();   //total number of shapes in the ppt
+        int dggMaxId = dgg.getShapeIdMax();            //max number of shapeId
+
+        int dgMaxId = dg.getLastMSOSPID();   //max shapeId in the slide
+        int dgShapesUsed = dg.getNumShapes();          // number of shapes in the slide
+        //insert 3 shapes and make sure the Ids are properly incremented
+        for (int i = 0; i < 3; i++) {
+            shape = new Line();
+            assertEquals(0, shape.getShapeId());
+            slide.addShape(shape);
+            assertTrue(shape.getShapeId() > 0);
+
+            //check that EscherDgRecord is updated
+            assertEquals(shape.getShapeId(), dg.getLastMSOSPID());
+            assertEquals(dgMaxId + 1, dg.getLastMSOSPID());
+            assertEquals(dgShapesUsed + 1, dg.getNumShapes());
+
+            //check that EscherDggRecord is updated
+            assertEquals(shape.getShapeId() + 1, dgg.getShapeIdMax());
+            assertEquals(dggMaxId + 1, dgg.getShapeIdMax());
+            assertEquals(dggShapesUsed + 1, dgg.getNumShapesSaved());
+
+            dggShapesUsed = dgg.getNumShapesSaved();
+            dggMaxId = dgg.getShapeIdMax();
+            dgMaxId = dg.getLastMSOSPID();
+            dgShapesUsed = dg.getNumShapes();
+        }
 
-        int shapeId = shape.getShapeId();
 
-        shape = new Line();
-        assertEquals(0, shape.getShapeId());
-        slide.addShape(shape);
-        assertEquals(shapeId + 1, shape.getShapeId());
+        //For each drawing group PPT allocates clusters with size=1024
+        //if the number of shapes is greater that 1024 a new cluster is allocated
+        //make sure it is so
+        int numClusters = dgg.getNumIdClusters();
+        for (int i = 0; i < 1025; i++) {
+            shape = new Line();
+            slide.addShape(shape);
+        }
+        assertEquals(numClusters + 1, dgg.getNumIdClusters());
     }
 }
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTextRulerAtom.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTextRulerAtom.java
new file mode 100755 (executable)
index 0000000..0b610cb
--- /dev/null
@@ -0,0 +1,76 @@
+\r
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+        \r
+\r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+import org.apache.poi.hslf.HSLFSlideShow;\r
+import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;\r
+import org.apache.poi.hslf.model.textproperties.TextProp;\r
+import org.apache.poi.hslf.model.textproperties.TextPropCollection;\r
+import org.apache.poi.hslf.record.StyleTextPropAtom.*;\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.util.HexDump;\r
+\r
+import junit.framework.TestCase;\r
+import java.io.ByteArrayOutputStream;\r
+import java.util.LinkedList;\r
+import java.util.Arrays;\r
+\r
+/**\r
+ * Tests TextRulerAtom\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestTextRulerAtom extends TestCase {\r
+\r
+    //from a real file\r
+       private byte[] data_1 = new byte[] {\r
+               0x00, 0x00, (byte)0xA6, 0x0F, 0x18, 0x00, 0x00, 0x00,\r
+        (byte)0xF8, 0x1F, 0x00, 0x00, 0x75, 0x00, (byte)0xE2, 0x00, 0x59,\r
+        0x01, (byte)0xC3, 0x01, 0x1A, 0x03, (byte)0x87, 0x03, (byte)0xF8,\r
+        0x03, 0x69, 0x04, (byte)0xF6, 0x05, (byte)0xF6, 0x05\r
+       };\r
+\r
+\r
+    public void testReadRuler() throws Exception {\r
+               TextRulerAtom ruler = new TextRulerAtom(data_1, 0, data_1.length);\r
+        assertEquals(ruler.getNumberOfLevels(), 0);\r
+        assertEquals(ruler.getDefaultTabSize(), 0);\r
+\r
+        int[] tabStops = ruler.getTabStops();\r
+        assertNull(tabStops);\r
+\r
+        int[] textOffsets = ruler.getTextOffsets();\r
+        assertTrue(Arrays.equals(new int[]{226, 451, 903, 1129, 1526}, textOffsets));\r
+\r
+        int[] bulletOffsets = ruler.getBulletOffsets();\r
+        assertTrue(Arrays.equals(new int[]{117, 345, 794, 1016, 1526}, bulletOffsets));\r
+\r
+       }\r
+\r
+    public void testWriteRuler() throws Exception {\r
+               TextRulerAtom ruler = new TextRulerAtom(data_1, 0, data_1.length);\r
+        ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+        ruler.writeOut(out);\r
+\r
+        byte[] result = out.toByteArray();\r
+        assertTrue(Arrays.equals(result, data_1));\r
+       }\r
+}\r
index 0fecdab97b4a9e8ea474f7c3cc66624d9dcd4f61..eda6589c4299fa450e48d18453a55635f616d498 100644 (file)
@@ -90,9 +90,11 @@ public class TestRichTextRun extends TestCase {
                
                // Now set it to not bold
                rtr.setBold(false);
-               assertNotNull(rtr._getRawCharacterStyle());
-               assertNotNull(rtr._getRawParagraphStyle());
-               assertFalse(rtr.isBold());
+               //setting bold=false doesn't change the internal state
+        assertNull(rtr._getRawCharacterStyle());
+               assertNull(rtr._getRawParagraphStyle());
+
+        assertFalse(rtr.isBold());
                
                // And now make it bold
                rtr.setBold(true);