poi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ye...@apache.org
Subject svn commit: r690262 [1/2] - in /poi/trunk/src: documentation/content/xdocs/hslf/ scratchpad/src/org/apache/poi/hslf/blip/ scratchpad/src/org/apache/poi/hslf/dev/ scratchpad/src/org/apache/poi/hslf/model/ scratchpad/src/org/apache/poi/hslf/record/ scrat...
Date Fri, 29 Aug 2008 14:01:08 GMT
Author: yegor
Date: Fri Aug 29 07:01:04 2008
New Revision: 690262

URL: http://svn.apache.org/viewvc?rev=690262&view=rev
Log:
initial support for embedded movies and controls.

Added:
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfo.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfoAtom.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExAviMovie.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMCIMovie.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMediaAtom.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExVideoContainer.java   (with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/OEShapeAtom.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/model/TestMovieShape.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/record/TestAnimationInfoAtom.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExControl.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExMediaAtom.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExOleObjAtom.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExOleObjStg.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExVideoContainer.java   (with props)
Modified:
    poi/trunk/src/documentation/content/xdocs/hslf/how-to-shapes.xml
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/dev/PPTXMLDump.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/Table.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExControl.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExControlAtom.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjAtom.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExOleObjStg.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/InteractiveInfoAtom.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/record/TestTextRulerAtom.java

Modified: poi/trunk/src/documentation/content/xdocs/hslf/how-to-shapes.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/hslf/how-to-shapes.xml?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/hslf/how-to-shapes.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/hslf/how-to-shapes.xml Fri Aug 29 07:01:04 2008
@@ -47,6 +47,7 @@
                     <li><link href="#Graphics2D">Shapes and Graphics2D</link></li>
                     <li><link href="#Render">How to convert slides into images</link></li>
                     <li><link href="#HeadersFooters">Headers / Footers</link></li>
+                    <li><link href="#Movies">How to embed movies</link></li>
                 </ul>
             </section>
             <section><title>Features</title>
@@ -662,6 +663,28 @@
           hdd.setFootersText("Created by POI-HSLF");
                 </source>
               </section>
+            <anchor id="Movies"/>
+            <section><title>How to embed movies</title>
+              <source>
+
+        SlideShow ppt = new SlideShow();
+        Slide slide = ppt.createSlide();
+
+        //UNC or local Returns UNC or local path to a video file
+        String moviePath = "card.mpg";
+        int movieIdx = ppt.addMovie(moviePath, MovieShape.MOVIE_MPEG);
+
+        String thumbnailPath = "card.png";
+        int thumbnailIdx = ppt.addPicture(new File(thumbnailPath), Picture.PNG);
+        MovieShape shape = new MovieShape(movieIdx, thumbnailIdx);
+        shape.setAnchor(new Rectangle2D.Float(300,225,120,90));
+        slide.addShape(shape);
+
+        FileOutputStream out = new FileOutputStream("hslf-movie.ppt");
+        ppt.write(out);
+        out.close();
+                </source>
+              </section>
                 </section>
         </section>
     </body>

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java Fri Aug 29 07:01:04 2008
@@ -17,6 +17,7 @@
 package org.apache.poi.hslf.blip;
 
 import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogger;
 import org.apache.poi.hslf.model.Picture;
 import org.apache.poi.hslf.model.Shape;
 import org.apache.poi.hslf.exceptions.HSLFException;
@@ -76,7 +77,7 @@
         Header header = new Header();
         header.wmfsize = data.length - aldus.getSize();
         header.bounds = new java.awt.Rectangle((short)aldus.left, (short)aldus.top, (short)aldus.right-(short)aldus.left, (short)aldus.bottom-(short)aldus.top);
-        //coefficiaent to translate from WMF dpi to 96pdi
+        //coefficient to translate from WMF dpi to 96pdi
         int coeff = 96*Shape.EMU_PER_POINT/aldus.inch;
         header.size = new java.awt.Dimension(header.bounds.width*coeff, header.bounds.height*coeff);
         header.zipsize = compressed.length;
@@ -119,7 +120,7 @@
      *  <li>short  Checksum;       Checksum value for previous 10 shorts
      * </ul>
      */
-    public static class AldusHeader{
+    public class AldusHeader{
         public static final int APMHEADER_KEY = 0x9AC6CDD7;
 
         public int handle;
@@ -143,8 +144,9 @@
             reserved = LittleEndian.getInt(data, pos); pos += LittleEndian.INT_SIZE;
 
             checksum = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
-            if (checksum != getChecksum())
-                throw new HSLFException("WMF checksum does not match the header data");
+            if (checksum != getChecksum()){
+                logger.log(POILogger.WARN, "WMF checksum does not match the header data");
+            }
         }
 
         /**

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/dev/PPTXMLDump.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/dev/PPTXMLDump.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/dev/PPTXMLDump.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/dev/PPTXMLDump.java Fri Aug 29 07:01:04 2008
@@ -125,7 +125,7 @@
                 dump(data, pos, size, padding);
             } else {
                 //dump first 100 bytes of the atom data
-                dump(out, data, pos, Math.min(size, 100), padding, true);
+                dump(out, data, pos, size, padding, true);
             }
 			padding--;
             write(out, "</"+recname + ">" + CR, padding);

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java?rev=690262&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java Fri Aug 29 07:01:04 2008
@@ -0,0 +1,152 @@
+package org.apache.poi.hslf.model;
+
+import org.apache.poi.ddf.*;
+import org.apache.poi.hslf.record.*;
+import org.apache.poi.hslf.exceptions.HSLFException;
+import org.apache.poi.util.LittleEndian;
+
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Iterator;
+
+/**
+ * Represents an ActiveX control in a PowerPoint document.
+ *
+ * TODO: finish
+ * @author Yegor Kozlov
+ */
+public class ActiveXShape extends Picture {
+    public static final int DEFAULT_ACTIVEX_THUMBNAIL = -1;
+
+    /**
+     * Create a new <code>Picture</code>
+     *
+    * @param pictureIdx the index of the picture
+     */
+    public ActiveXShape(int movieIdx, int pictureIdx){
+        super(pictureIdx, null);
+        setActiveXIndex(movieIdx);
+    }
+
+    /**
+      * Create a <code>Picture</code> object
+      *
+      * @param escherRecord the <code>EscherSpContainer</code> record which holds information about
+      *        this picture in the <code>Slide</code>
+      * @param parent the parent shape of this picture
+      */
+     protected ActiveXShape(EscherContainerRecord escherRecord, Shape parent){
+        super(escherRecord, parent);
+    }
+
+    /**
+     * Create a new Placeholder and initialize internal structures
+     *
+     * @return the created <code>EscherContainerRecord</code> which holds shape data
+     */
+    protected EscherContainerRecord createSpContainer(int idx, boolean isChild) {
+        _escherContainer = super.createSpContainer(idx, isChild);
+
+        EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+        spRecord.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE | EscherSpRecord.FLAG_OLESHAPE);
+
+        setShapeType(ShapeTypes.HostControl);
+        setEscherProperty(EscherProperties.BLIP__PICTUREID, idx);
+        setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001);
+        setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80008);
+        setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
+        setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, -1);
+
+        EscherClientDataRecord cldata = new EscherClientDataRecord();
+        cldata.setOptions((short)0xF);
+        _escherContainer.getChildRecords().add(cldata);
+
+        OEShapeAtom oe = new OEShapeAtom();
+
+        //convert hslf into ddf
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try {
+            oe.writeOut(out);
+        } catch(Exception e){
+            throw new HSLFException(e);
+        }
+        cldata.setRemainingData(out.toByteArray());
+
+        return _escherContainer;
+    }
+
+    /**
+     * Assign a control to this shape
+     *
+     * @see {@link org.apache.poi.hslf.usermodel.SlideShow#addMovie(String, int)}
+     * @param idx  the index of the movie
+     */
+    public void setActiveXIndex(int idx){
+        EscherContainerRecord spContainer = getSpContainer();
+        for (Iterator it = spContainer.getChildRecords().iterator(); it.hasNext();) {
+            EscherRecord obj = (EscherRecord) it.next();
+            if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
+                EscherClientDataRecord clientRecord = (EscherClientDataRecord)obj;
+                byte[] recdata = clientRecord.getRemainingData();
+                LittleEndian.putInt(recdata, 8, idx);
+            }
+        }
+    }
+
+    public int getControlIndex(){
+        int idx = -1;
+        OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
+        if(oe != null) idx = oe.getOptions();
+        return idx;
+    }
+
+    /**
+     * Set a property of this ActiveX control
+     * @param key
+     * @param value
+     */
+    public void setProperty(String key, String value){
+
+    }
+
+    /**
+     * Document-level container that specifies information about an ActiveX control
+     *
+     * @return container that specifies information about an ActiveX control
+     */
+    public ExControl getExControl(){
+        int idx = getControlIndex();
+        ExControl ctrl = null;
+        Document doc = getSheet().getSlideShow().getDocumentRecord();
+        ExObjList lst = (ExObjList)doc.findFirstOfType(RecordTypes.ExObjList.typeID);
+        if(lst != null){
+            Record[] ch = lst.getChildRecords();
+            for (int i = 0; i < ch.length; i++) {
+                if(ch[i] instanceof ExControl){
+                    ExControl c = (ExControl)ch[i];
+                    if(c.getExOleObjAtom().getObjID() == idx){
+                        ctrl = c;
+                        break;
+                    }
+                }
+            }
+        }
+        return ctrl;
+    }
+
+    protected void afterInsert(Sheet sheet){
+        ExControl ctrl = getExControl();
+        ctrl.getExControlAtom().setSlideId(sheet._getSheetNumber());
+
+        try {
+            String name = ctrl.getProgId() + "-" + getControlIndex();
+            byte[] data = (name + '\u0000').getBytes("UTF-16LE");
+            EscherComplexProperty prop = new EscherComplexProperty(EscherProperties.GROUPSHAPE__SHAPENAME, false, data);
+            EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+            opt.addEscherProperty(prop);
+        } catch (UnsupportedEncodingException e){
+            throw new HSLFException(e);
+        }
+
+    }
+}

Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java?rev=690262&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java Fri Aug 29 07:01:04 2008
@@ -0,0 +1,159 @@
+package org.apache.poi.hslf.model;
+
+import org.apache.poi.ddf.*;
+import org.apache.poi.hslf.record.*;
+import org.apache.poi.hslf.exceptions.HSLFException;
+import org.apache.poi.hslf.usermodel.SlideShow;
+import org.apache.poi.util.LittleEndian;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Iterator;
+
+/**
+ * Represents a movie in a PowerPoint document.
+ *
+ * @author Yegor Kozlov
+ */
+public class MovieShape extends Picture {
+    public static final int DEFAULT_MOVIE_THUMBNAIL = -1;
+
+    public static final int MOVIE_MPEG = 1;
+    public static final int MOVIE_AVI  = 2;
+
+    /**
+     * Create a new <code>Picture</code>
+     *
+    * @param pictureIdx the index of the picture
+     */
+    public MovieShape(int movieIdx, int pictureIdx){
+        super(pictureIdx, null);
+        setMovieIndex(movieIdx);
+        setAutoPlay(true);
+    }
+
+    /**
+     * Create a new <code>Picture</code>
+     *
+     * @param idx the index of the picture
+     * @param parent the parent shape
+     */
+    public MovieShape(int movieIdx, int idx, Shape parent) {
+        super(idx, parent);
+        setMovieIndex(movieIdx);
+    }
+
+    /**
+      * Create a <code>Picture</code> object
+      *
+      * @param escherRecord the <code>EscherSpContainer</code> record which holds information about
+      *        this picture in the <code>Slide</code>
+      * @param parent the parent shape of this picture
+      */
+     protected MovieShape(EscherContainerRecord escherRecord, Shape parent){
+        super(escherRecord, parent);
+    }
+
+    /**
+     * Create a new Placeholder and initialize internal structures
+     *
+     * @return the created <code>EscherContainerRecord</code> which holds shape data
+     */
+    protected EscherContainerRecord createSpContainer(int idx, boolean isChild) {
+        _escherContainer = super.createSpContainer(idx, isChild);
+
+        setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x1000100);
+        setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x10001);
+
+        EscherClientDataRecord cldata = new EscherClientDataRecord();
+        cldata.setOptions((short)0xF);
+        _escherContainer.getChildRecords().add(cldata);
+
+        OEShapeAtom oe = new OEShapeAtom();
+        InteractiveInfo info = new InteractiveInfo();
+        InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom();
+        infoAtom.setAction(InteractiveInfoAtom.ACTION_MEDIA);
+        infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_NULL);
+
+        AnimationInfo an = new AnimationInfo();
+        AnimationInfoAtom anAtom = an.getAnimationInfoAtom();
+        anAtom.setFlag(AnimationInfoAtom.Automatic, true);
+
+        //convert hslf into ddf
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try {
+            oe.writeOut(out);
+            an.writeOut(out);
+            info.writeOut(out);
+        } catch(Exception e){
+            throw new HSLFException(e);
+        }
+        cldata.setRemainingData(out.toByteArray());
+
+        return _escherContainer;
+    }
+
+    /**
+     * Assign a movie to this shape
+     *
+     * @see {@link org.apache.poi.hslf.usermodel.SlideShow#addMovie(String, int)}
+     * @param idx  the index of the movie
+     */
+    public void setMovieIndex(int idx){
+        OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
+        oe.setOptions(idx);
+
+        AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
+        if(an != null) {
+            AnimationInfoAtom ai = an.getAnimationInfoAtom();
+            ai.setDimColor(0x07000000);
+            ai.setFlag(AnimationInfoAtom.Automatic, true);
+            ai.setFlag(AnimationInfoAtom.Play, true);
+            ai.setFlag(AnimationInfoAtom.Synchronous, true);
+            ai.setOrderID(idx + 1);
+        }
+    }
+
+    public void setAutoPlay(boolean flag){
+        AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
+        if(an != null){
+            an.getAnimationInfoAtom().setFlag(AnimationInfoAtom.Automatic, flag);
+            updateClientData();
+        }
+    }
+
+    public boolean  isAutoPlay(){
+        AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
+        if(an != null){
+            return an.getAnimationInfoAtom().getFlag(AnimationInfoAtom.Automatic);
+        }
+        return false;
+    }
+
+    /**
+     *  Returns UNC or local path to a video file
+     *
+     * @return UNC or local path to a video file
+     */
+    public String getPath(){
+        OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
+        int idx = oe.getOptions();
+
+        SlideShow ppt = getSheet().getSlideShow();
+        ExObjList lst = (ExObjList)ppt.getDocumentRecord().findFirstOfType(RecordTypes.ExObjList.typeID);
+        if(lst == null) return null;
+
+        Record[]  r = lst.getChildRecords();
+        for (int i = 0; i < r.length; i++) {
+            if(r[i] instanceof ExMCIMovie){
+                ExMCIMovie mci = (ExMCIMovie)r[i];
+                ExVideoContainer exVideo = mci.getExVideo();
+                int objectId = exVideo.getExMediaAtom().getObjectId();
+                if(objectId == idx){
+                    return exVideo.getPathAtom().getText();
+                }
+            }
+
+        }
+        return null;
+    }
+}

Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java Fri Aug 29 07:01:04 2008
@@ -19,8 +19,10 @@
 import org.apache.poi.ddf.*;
 import org.apache.poi.util.POILogger;
 import org.apache.poi.util.POILogFactory;
+import org.apache.poi.hslf.record.*;
 
 import java.util.List;
+import java.util.Iterator;
 
 /**
  * Create a <code>Shape</code> object depending on its type
@@ -45,14 +47,14 @@
 
     public static ShapeGroup createShapeGroup(EscherContainerRecord spContainer, Shape parent){
         ShapeGroup group = null;
-        UnknownEscherRecord opt = (UnknownEscherRecord)Shape.getEscherChild((EscherContainerRecord)spContainer.getChild(0), (short)0xF122);
+        EscherRecord opt = Shape.getEscherChild((EscherContainerRecord)spContainer.getChild(0), (short)0xF122);
         if(opt != null){
             try {
                 EscherPropertyFactory f = new EscherPropertyFactory();
-                List props = f.createProperties( opt.getData(), 0, opt.getInstance() );
+                List props = f.createProperties( opt.serialize(), 8, opt.getInstance() );
                 EscherSimpleProperty p = (EscherSimpleProperty)props.get(0);
                 if(p.getPropertyNumber() == 0x39F && p.getPropertyValue() == 1){
-                    group = new ShapeGroup(spContainer, parent);
+                    group = new Table(spContainer, parent);
                 } else {
                     group = new ShapeGroup(spContainer, parent);
                 }
@@ -68,7 +70,7 @@
      }
 
     public static Shape createSimpeShape(EscherContainerRecord spContainer, Shape parent){
-        Shape shape;
+        Shape shape = null;
         EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID);
 
         int type = spRecord.getOptions() >> 4;
@@ -76,14 +78,26 @@
             case ShapeTypes.TextBox:
                 shape = new TextBox(spContainer, parent);
                 break;
-            case ShapeTypes.HostControl: 
+            case ShapeTypes.HostControl:
             case ShapeTypes.PictureFrame: {
-                EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
-                EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.BLIP__PICTUREID);
-                if(prop != null)
-                    shape = new OLEShape(spContainer, parent); //presence of BLIP__PICTUREID indicates it is an embedded object 
-                else
-                    shape = new Picture(spContainer, parent);
+                InteractiveInfo info = (InteractiveInfo)getClientDataRecord(spContainer, RecordTypes.InteractiveInfo.typeID);
+                OEShapeAtom oes = (OEShapeAtom)getClientDataRecord(spContainer, RecordTypes.OEShapeAtom.typeID);
+                if(info != null && info.getInteractiveInfoAtom() != null){
+                    switch(info.getInteractiveInfoAtom().getAction()){
+                        case InteractiveInfoAtom.ACTION_OLE:
+                            shape = new OLEShape(spContainer, parent);
+                            break;
+                        case InteractiveInfoAtom.ACTION_MEDIA:
+                            shape = new MovieShape(spContainer, parent);
+                            break;
+                        default:
+                            break;
+                    }
+                } else if (oes != null){
+                    shape = new OLEShape(spContainer, parent);
+                }
+                
+                if(shape == null) shape = new Picture(spContainer, parent);
                 break;
             }
             case ShapeTypes.Line:
@@ -108,4 +122,22 @@
         return shape;
 
     }
+
+    protected static Record getClientDataRecord(EscherContainerRecord spContainer, int recordType) {
+        Record oep = null;
+        for (Iterator it = spContainer.getChildRecords().iterator(); it.hasNext();) {
+            EscherRecord obj = (EscherRecord) it.next();
+            if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
+                byte[] data = obj.serialize();
+                Record[] records = Record.findChildRecords(data, 8, data.length - 8);
+                for (int j = 0; j < records.length; j++) {
+                    if (records[j].getRecordType() == recordType) {
+                        return records[j];
+                    }
+                }
+            }
+        }
+        return oep;
+    }
+
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java Fri Aug 29 07:01:04 2008
@@ -21,11 +21,13 @@
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.hslf.record.ColorSchemeAtom;
 import org.apache.poi.hslf.record.Record;
+import org.apache.poi.hslf.exceptions.HSLFException;
 
 import java.awt.*;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
 import java.util.Iterator;
+import java.io.ByteArrayOutputStream;
 
 /**
  *  An abstract simple (non-group) shape.
@@ -36,6 +38,12 @@
 public class SimpleShape extends Shape {
 
     /**
+     * Records stored in EscherClientDataRecord
+     */
+    protected Record[] _clientRecords;
+    protected EscherClientDataRecord _clientData;
+
+    /**
      * Create a SimpleShape object and initialize it from the supplied Record container.
      *
      * @param escherRecord    <code>EscherSpContainer</code> container which holds information about this shape
@@ -293,21 +301,46 @@
      * @param recordType type of the record to search
      */
     protected Record getClientDataRecord(int recordType) {
-        Record oep = null;
-        EscherContainerRecord spContainer = getSpContainer();
-        for (Iterator it = spContainer.getChildRecords().iterator(); it.hasNext();) {
-            EscherRecord obj = (EscherRecord) it.next();
-            if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
-                byte[] data = obj.serialize();
-                Record[] records = Record.findChildRecords(data, 8, data.length - 8);
-                for (int j = 0; j < records.length; j++) {
-                    if (records[j].getRecordType() == recordType) {
-                        return records[j];
-                    }
-                }
+
+        Record[] records = getClientRecords();
+        if(records != null) for (int i = 0; i < records.length; i++) {
+            if(records[i].getRecordType() == recordType){
+                return records[i];
+            }
+        }
+        return null;
+    }
+
+    protected Record[] getClientRecords() {
+        if(_clientData == null){
+            EscherRecord r = Shape.getEscherChild(getSpContainer(), EscherClientDataRecord.RECORD_ID);
+            //ddf can return EscherContainerRecord with recordId=EscherClientDataRecord.RECORD_ID
+            //convert in to EscherClientDataRecord on the fly
+            if(!(r instanceof EscherClientDataRecord)){
+                byte[] data = r.serialize();
+                r = new EscherClientDataRecord();
+                r.fillFields(data, 0, new DefaultEscherRecordFactory());
             }
+            _clientData = (EscherClientDataRecord)r;
         }
-        return oep;
+        if(_clientData != null && _clientRecords == null){
+            byte[] data = _clientData.getRemainingData();
+            _clientRecords = Record.findChildRecords(data, 0, data.length);
+        }
+        return _clientRecords;
     }
 
+    protected void updateClientData() {
+        if(_clientData != null && _clientRecords != null){
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            try {
+                for (int i = 0; i < _clientRecords.length; i++) {
+                    _clientRecords[i].writeOut(out);
+                }
+            } catch(Exception e){
+                throw new HSLFException(e);
+            }
+            _clientData.setRemainingData(out.toByteArray());
+        }
+    }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/Table.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/Table.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/Table.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/Table.java Fri Aug 29 07:01:04 2008
@@ -89,7 +89,7 @@
      * @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
      * @param parent       the parent of the shape
      */
-    protected Table(EscherContainerRecord escherRecord, Shape parent) {
+    public Table(EscherContainerRecord escherRecord, Shape parent) {
         super(escherRecord, parent);
     }
 

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java Fri Aug 29 07:01:04 2008
@@ -23,9 +23,11 @@
 
 import java.text.AttributedString;
 import java.text.AttributedCharacterIterator;
+import java.text.BreakIterator;
 import java.awt.font.TextAttribute;
 import java.awt.font.LineBreakMeasurer;
 import java.awt.font.TextLayout;
+import java.awt.font.FontRenderContext;
 import java.awt.*;
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.Point2D;
@@ -89,11 +91,69 @@
     }
 
     public void paint(Graphics2D graphics){
+        Rectangle2D anchor = _shape.getLogicalAnchor2D();
+        TextElement[] elem = getTextElements((float)anchor.getWidth(), graphics.getFontRenderContext());
+        if(elem == null) return;
+
+        float textHeight = 0;
+        for (int i = 0; i < elem.length; i++) {
+            textHeight += elem[i].ascent + elem[i].descent;
+        }
+
+        int valign = _shape.getVerticalAlignment();
+        double y0 = anchor.getY();
+        switch (valign){
+            case TextShape.AnchorTopBaseline:
+            case TextShape.AnchorTop:
+                y0 += _shape.getMarginTop();
+                break;
+            case TextShape.AnchorBottom:
+                y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom();
+                break;
+            default:
+            case TextShape.AnchorMiddle:
+                float delta =  (float)anchor.getHeight() - textHeight - _shape.getMarginTop() - _shape.getMarginBottom();
+                y0 += _shape.getMarginTop()  + delta/2;
+                break;
+        }
+
+        //finally draw the text fragments
+        for (int i = 0; i < elem.length; i++) {
+            y0 += elem[i].ascent;
+
+            Point2D.Double pen = new Point2D.Double();
+            pen.y = y0;
+            switch (elem[i]._align) {
+                default:
+                case TextShape.AlignLeft:
+                    pen.x = anchor.getX() + _shape.getMarginLeft();
+                    break;
+                case TextShape.AlignCenter:
+                    pen.x = anchor.getX() + _shape.getMarginLeft() +
+                            (anchor.getWidth() - elem[i].advance - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;
+                    break;
+                case TextShape.AlignRight:
+                    pen.x = anchor.getX() + _shape.getMarginLeft() +
+                            (anchor.getWidth() - elem[i].advance - _shape.getMarginLeft() - _shape.getMarginRight());
+                    break;
+            }
+            if(elem[i]._bullet != null){
+                graphics.drawString(elem[i]._bullet.getIterator(), (float)(pen.x + elem[i]._bulletOffset), (float)pen.y);
+            }
+            AttributedCharacterIterator chIt = elem[i]._text.getIterator();
+            if(chIt.getEndIndex() > chIt.getBeginIndex()) {
+                graphics.drawString(chIt, (float)(pen.x + elem[i]._textOffset), (float)pen.y);
+            }
+            y0 += elem[i].descent;
+        }
+    }
+
+    public TextElement[] getTextElements(float textWidth, FontRenderContext frc){
         TextRun run = _shape.getTextRun();
-        if (run == null) return;
+        if (run == null) return null;
 
         String text = run.getText();
-        if (text == null || text.equals("")) return;
+        if (text == null || text.equals("")) return null;
 
         AttributedString at = getAttributedString(run);
 
@@ -101,11 +161,8 @@
         int paragraphStart = it.getBeginIndex();
         int paragraphEnd = it.getEndIndex();
 
-        Rectangle2D anchor = _shape.getLogicalAnchor2D();
-
-        float textHeight = 0;
         ArrayList lines = new ArrayList();
-        LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext());
+        LineBreakMeasurer measurer = new LineBreakMeasurer(it, frc);
         measurer.setPosition(paragraphStart);
         while (measurer.getPosition() < paragraphEnd) {
             int startIndex = measurer.getPosition();
@@ -120,7 +177,7 @@
                 break;
             }
 
-            float wrappingWidth = (float)anchor.getWidth() - _shape.getMarginLeft() - _shape.getMarginRight();
+            float wrappingWidth = textWidth - _shape.getMarginLeft() - _shape.getMarginRight();
             int bulletOffset = rt.getBulletOffset();
             int textOffset = rt.getTextOffset();
             int indent = rt.getIndentLevel();
@@ -138,7 +195,7 @@
                 if(text_val != 0) textOffset = text_val;
             }
 
-            wrappingWidth -= textOffset;
+            if(bulletOffset > 0 || prStart || startIndex == 0) wrappingWidth -= textOffset;
 
             if (_shape.getWordWrap() == TextShape.WrapNone) {
                 wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;
@@ -147,7 +204,7 @@
             TextLayout textLayout = measurer.nextLayout(wrappingWidth + 1,
                     nextBreak == -1 ? paragraphEnd : nextBreak, true);
             if (textLayout == null) {
-                textLayout = measurer.nextLayout((float)anchor.getWidth(),
+                textLayout = measurer.nextLayout(textWidth,
                     nextBreak == -1 ? paragraphEnd : nextBreak, false);
             }
             if(textLayout == null){
@@ -173,6 +230,8 @@
             el.advance = textLayout.getAdvance();
             el._textOffset = textOffset;
             el._text = new AttributedString(it, startIndex, endIndex);
+            el.textStartIndex = startIndex;
+            el.textEndIndex = endIndex;
 
             if (prStart){
                 int sp = rt.getSpaceBefore();
@@ -203,8 +262,6 @@
             }
             el.descent = descent;
 
-            textHeight += el.ascent + el.descent;
-
             if(rt.isBullet() && (prStart || startIndex == 0)){
                 it.setIndex(startIndex);
 
@@ -236,56 +293,11 @@
             lines.add(el);
         }
 
-        int valign = _shape.getVerticalAlignment();
-        double y0 = anchor.getY();
-        switch (valign){
-            case TextShape.AnchorTopBaseline:
-            case TextShape.AnchorTop:
-                y0 += _shape.getMarginTop();
-                break;
-            case TextShape.AnchorBottom:
-                y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom();
-                break;
-            default:
-            case TextShape.AnchorMiddle:
-                float delta =  (float)anchor.getHeight() - textHeight - _shape.getMarginTop() - _shape.getMarginBottom();
-                y0 += _shape.getMarginTop()  + delta/2;
-                break;
-        }
-
         //finally draw the text fragments
-        for (int i = 0; i < lines.size(); i++) {
-            TextElement elem = (TextElement)lines.get(i);
-            y0 += elem.ascent;
-
-            Point2D.Double pen = new Point2D.Double();
-            pen.y = y0;
-            switch (elem._align) {
-                default:
-                case TextShape.AlignLeft:
-                    pen.x = anchor.getX() + _shape.getMarginLeft();
-                    break;
-                case TextShape.AlignCenter:
-                    pen.x = anchor.getX() + _shape.getMarginLeft() +
-                            (anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;
-                    break;
-                case TextShape.AlignRight:
-                    pen.x = anchor.getX() + _shape.getMarginLeft() +
-                            (anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight());
-                    break;
-            }
-            if(elem._bullet != null){
-                graphics.drawString(elem._bullet.getIterator(), (float)(pen.x + elem._bulletOffset), (float)pen.y);
-            }
-            AttributedCharacterIterator chIt = elem._text.getIterator();
-            if(chIt.getEndIndex() > chIt.getBeginIndex()) {
-                graphics.drawString(chIt, (float)(pen.x + elem._textOffset), (float)pen.y);
-            }
-            y0 += elem.descent;
-        }
+        TextElement[] elems = new TextElement[lines.size()];
+        return (TextElement[])lines.toArray(elems);
     }
 
-
     public static class TextElement {
         public AttributedString _text;
         public int _textOffset;
@@ -294,5 +306,6 @@
         public int _align;
         public float ascent, descent;
         public float advance;
+        public int textStartIndex, textEndIndex;
     }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java Fri Aug 29 07:01:04 2008
@@ -22,6 +22,7 @@
 
 import java.util.LinkedList;
 import java.util.Vector;
+import java.util.List;
 
 import org.apache.poi.hslf.model.textproperties.TextPropCollection;
 import org.apache.poi.hslf.record.*;
@@ -45,7 +46,8 @@
 	protected TextBytesAtom  _byteAtom;
 	protected TextCharsAtom  _charAtom;
 	protected StyleTextPropAtom _styleAtom;
-	protected boolean _isUnicode;
+    protected TextRulerAtom _ruler;
+    protected boolean _isUnicode;
 	protected RichTextRun[] _rtRuns;
 	private SlideShow slideShow;
     private Sheet sheet;
@@ -103,155 +105,159 @@
 			pStyles = _styleAtom.getParagraphStyles();
 			cStyles = _styleAtom.getCharacterStyles();
 		}
-
-		// Handle case of no current style, with a default
-		if(pStyles.size() == 0 || cStyles.size() == 0) { 
-			_rtRuns = new RichTextRun[1];
-			_rtRuns[0] = new RichTextRun(this, 0, runRawText.length());
-		} else {
-			// Build up Rich Text Runs, one for each 
-			//  character/paragraph style pair
-			Vector rtrs = new Vector();
-
-			int pos = 0;
-			
-			int curP = 0;
-			int curC = 0;
-			int pLenRemain = -1;
-			int cLenRemain = -1;
-			
-			// Build one for each run with the same style
-			while(pos <= runRawText.length() && curP < pStyles.size() && curC < cStyles.size()) {
-				// Get the Props to use
-				TextPropCollection pProps = (TextPropCollection)pStyles.get(curP);
-				TextPropCollection cProps = (TextPropCollection)cStyles.get(curC);
-				
-				int pLen = pProps.getCharactersCovered();
-				int cLen = cProps.getCharactersCovered();
-				
-				// Handle new pass
-				boolean freshSet = false;
-				if(pLenRemain == -1 && cLenRemain == -1) { freshSet = true; }
-				if(pLenRemain == -1) { pLenRemain = pLen; }
-				if(cLenRemain == -1) { cLenRemain = cLen; }
-				
-				// So we know how to build the eventual run
-				int runLen = -1;
-				boolean pShared = false;
-				boolean cShared = false;
-				
-				// Same size, new styles - neither shared
-				if(pLen == cLen && freshSet) {
-					runLen = cLen;
-					pShared = false;
-					cShared = false;
-					curP++;
-					curC++;
-					pLenRemain = -1;
-					cLenRemain = -1;
-				} else {
-					// Some sharing
-					
-					// See if we are already in a shared block
-					if(pLenRemain < pLen) {
-						// Existing shared p block
-						pShared = true;
-						
-						// Do we end with the c block, or either side of it?
-						if(pLenRemain == cLenRemain) {
-							// We end at the same time
-							cShared = false;
-							runLen = pLenRemain;
-							curP++;
-							curC++;
-							pLenRemain = -1;
-							cLenRemain = -1;
-						} else if(pLenRemain < cLenRemain) {
-							// We end before the c block
-							cShared = true;
-							runLen = pLenRemain;
-							curP++;
-							cLenRemain -= pLenRemain;
-							pLenRemain = -1;
-						} else {
-							// We end after the c block
-							cShared = false;
-							runLen = cLenRemain;
-							curC++;
-							pLenRemain -= cLenRemain;
-							cLenRemain = -1;
-						}
-					} else if(cLenRemain < cLen) {
-						// Existing shared c block
-						cShared = true;
-						
-						// Do we end with the p block, or either side of it?
-						if(pLenRemain == cLenRemain) {
-							// We end at the same time
-							pShared = false;
-							runLen = cLenRemain;
-							curP++;
-							curC++;
-							pLenRemain = -1;
-							cLenRemain = -1;
-						} else if(cLenRemain < pLenRemain) {
-							// We end before the p block
-							pShared = true;
-							runLen = cLenRemain;
-							curC++;
-							pLenRemain -= cLenRemain;
-							cLenRemain = -1;
-						} else {
-							// We end after the p block
-							pShared = false;
-							runLen = pLenRemain;
-							curP++;
-							cLenRemain -= pLenRemain;
-							pLenRemain = -1;
-						}
-					} else {
-						// Start of a shared block
-						if(pLenRemain < cLenRemain) {
-							// Shared c block
-							pShared = false;
-							cShared = true;
-							runLen = pLenRemain;
-							curP++;
-							cLenRemain -= pLenRemain;
-							pLenRemain = -1;
-						} else {
-							// Shared p block
-							pShared = true;
-							cShared = false;
-							runLen = cLenRemain;
-							curC++;
-							pLenRemain -= cLenRemain;
-							cLenRemain = -1;
-						}
-					}
-				}
-				
-				// Wind on
-				int prevPos = pos;
-				pos += runLen;
-				// Adjust for end-of-run extra 1 length
-				if(pos > runRawText.length()) {
-					runLen--; 
-				}
-				
-				// Save
-				RichTextRun rtr = new RichTextRun(this, prevPos, runLen, pProps, cProps, pShared, cShared);
-				rtrs.add(rtr);
-			}
-			
-			// Build the array
-			_rtRuns = new RichTextRun[rtrs.size()];
-			rtrs.copyInto(_rtRuns);
-		}
+        buildRichTextRuns(pStyles, cStyles, runRawText);
 	}
 	
-	
-	// Update methods follow
+	public void buildRichTextRuns(LinkedList pStyles, LinkedList cStyles, String runRawText){
+
+        // Handle case of no current style, with a default
+        if(pStyles.size() == 0 || cStyles.size() == 0) {
+            _rtRuns = new RichTextRun[1];
+            _rtRuns[0] = new RichTextRun(this, 0, runRawText.length());
+        } else {
+            // Build up Rich Text Runs, one for each
+            //  character/paragraph style pair
+            Vector rtrs = new Vector();
+
+            int pos = 0;
+
+            int curP = 0;
+            int curC = 0;
+            int pLenRemain = -1;
+            int cLenRemain = -1;
+
+            // Build one for each run with the same style
+            while(pos <= runRawText.length() && curP < pStyles.size() && curC < cStyles.size()) {
+                // Get the Props to use
+                TextPropCollection pProps = (TextPropCollection)pStyles.get(curP);
+                TextPropCollection cProps = (TextPropCollection)cStyles.get(curC);
+
+                int pLen = pProps.getCharactersCovered();
+                int cLen = cProps.getCharactersCovered();
+
+                // Handle new pass
+                boolean freshSet = false;
+                if(pLenRemain == -1 && cLenRemain == -1) { freshSet = true; }
+                if(pLenRemain == -1) { pLenRemain = pLen; }
+                if(cLenRemain == -1) { cLenRemain = cLen; }
+
+                // So we know how to build the eventual run
+                int runLen = -1;
+                boolean pShared = false;
+                boolean cShared = false;
+
+                // Same size, new styles - neither shared
+                if(pLen == cLen && freshSet) {
+                    runLen = cLen;
+                    pShared = false;
+                    cShared = false;
+                    curP++;
+                    curC++;
+                    pLenRemain = -1;
+                    cLenRemain = -1;
+                } else {
+                    // Some sharing
+
+                    // See if we are already in a shared block
+                    if(pLenRemain < pLen) {
+                        // Existing shared p block
+                        pShared = true;
+
+                        // Do we end with the c block, or either side of it?
+                        if(pLenRemain == cLenRemain) {
+                            // We end at the same time
+                            cShared = false;
+                            runLen = pLenRemain;
+                            curP++;
+                            curC++;
+                            pLenRemain = -1;
+                            cLenRemain = -1;
+                        } else if(pLenRemain < cLenRemain) {
+                            // We end before the c block
+                            cShared = true;
+                            runLen = pLenRemain;
+                            curP++;
+                            cLenRemain -= pLenRemain;
+                            pLenRemain = -1;
+                        } else {
+                            // We end after the c block
+                            cShared = false;
+                            runLen = cLenRemain;
+                            curC++;
+                            pLenRemain -= cLenRemain;
+                            cLenRemain = -1;
+                        }
+                    } else if(cLenRemain < cLen) {
+                        // Existing shared c block
+                        cShared = true;
+
+                        // Do we end with the p block, or either side of it?
+                        if(pLenRemain == cLenRemain) {
+                            // We end at the same time
+                            pShared = false;
+                            runLen = cLenRemain;
+                            curP++;
+                            curC++;
+                            pLenRemain = -1;
+                            cLenRemain = -1;
+                        } else if(cLenRemain < pLenRemain) {
+                            // We end before the p block
+                            pShared = true;
+                            runLen = cLenRemain;
+                            curC++;
+                            pLenRemain -= cLenRemain;
+                            cLenRemain = -1;
+                        } else {
+                            // We end after the p block
+                            pShared = false;
+                            runLen = pLenRemain;
+                            curP++;
+                            cLenRemain -= pLenRemain;
+                            pLenRemain = -1;
+                        }
+                    } else {
+                        // Start of a shared block
+                        if(pLenRemain < cLenRemain) {
+                            // Shared c block
+                            pShared = false;
+                            cShared = true;
+                            runLen = pLenRemain;
+                            curP++;
+                            cLenRemain -= pLenRemain;
+                            pLenRemain = -1;
+                        } else {
+                            // Shared p block
+                            pShared = true;
+                            cShared = false;
+                            runLen = cLenRemain;
+                            curC++;
+                            pLenRemain -= cLenRemain;
+                            cLenRemain = -1;
+                        }
+                    }
+                }
+
+                // Wind on
+                int prevPos = pos;
+                pos += runLen;
+                // Adjust for end-of-run extra 1 length
+                if(pos > runRawText.length()) {
+                    runLen--;
+                }
+
+                // Save
+                RichTextRun rtr = new RichTextRun(this, prevPos, runLen, pProps, cProps, pShared, cShared);
+                rtrs.add(rtr);
+            }
+
+            // Build the array
+            _rtRuns = new RichTextRun[rtrs.size()];
+            rtrs.copyInto(_rtRuns);
+        }
+
+    }
+
+    // Update methods follow
 	
 	/**
 	 * Adds the supplied text onto the end of the TextRun, 
@@ -379,7 +385,7 @@
 	 * @param run
 	 * @param s
 	 */
-	public synchronized void changeTextInRichTextRun(RichTextRun run, String s) {
+	public void changeTextInRichTextRun(RichTextRun run, String s) {
 		// Figure out which run it is
 		int runID = -1;
 		for(int i=0; i<_rtRuns.length; i++) {
@@ -457,7 +463,7 @@
 	 *  as the the first character has. 
 	 * If you care about styling, do setText on a RichTextRun instead 
 	 */
-	public synchronized void setRawText(String s) {
+	public void setRawText(String s) {
 		// Save the new text to the atoms
 		storeText(s);
 		RichTextRun fst = _rtRuns[0];
@@ -491,7 +497,7 @@
      * Changes the text.
      * Converts '\r' into '\n'
      */
-    public synchronized void setText(String s) {
+    public void setText(String s) {
         String text = normalize(s);
         setRawText(text);
     }
@@ -500,7 +506,7 @@
 	 * Ensure a StyleTextPropAtom is present for this run, 
 	 *  by adding if required. Normally for internal TextRun use.
 	 */
-	public synchronized void ensureStyleAtomPresent() {
+	public void ensureStyleAtomPresent() {
 		if(_styleAtom != null) {
 			// All there
 			return;
@@ -669,13 +675,28 @@
     }
 
     public TextRulerAtom getTextRuler(){
-        for (int i = 0; i < _records.length; i++) {
-            if(_records[i] instanceof TextRulerAtom) return (TextRulerAtom)_records[i];
+        if(_ruler == null){
+            if(_records != null) for (int i = 0; i < _records.length; i++) {
+                if(_records[i] instanceof TextRulerAtom) {
+                    _ruler = (TextRulerAtom)_records[i];
+                    break;
+                }
+            }
+
         }
-        return null;
+        return _ruler;
 
     }
 
+    public TextRulerAtom createTextRuler(){
+        _ruler = getTextRuler();
+        if(_ruler == null){
+            _ruler = TextRulerAtom.getParagraphInstance();
+            _headerAtom.getParentRecord().appendChildRecord(_ruler);
+        }
+        return _ruler;
+    }
+
     /**
      * Returns a new string with line breaks converted into internal ppt representation
      */
@@ -692,4 +713,5 @@
     public Record[] getRecords(){
         return _records;
     }
+
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java Fri Aug 29 07:01:04 2008
@@ -133,6 +133,7 @@
             _txtbox.appendChildRecord(sta);
 
             _txtrun = new TextRun(tha,tca,sta);
+            _txtrun._records = new Record[]{tha, tca, sta};
             _txtrun.setText("");
 
             _escherContainer.addChildRecord(_txtbox.getEscherRecord());

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfo.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfo.java?rev=690262&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfo.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfo.java Fri Aug 29 07:01:04 2008
@@ -0,0 +1,97 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.poi.hslf.record;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogger;
+
+/**
+ * A container record that specifies information about animation information for a shape.
+ *
+ * @author Yegor Kozlov
+ */
+public class AnimationInfo extends RecordContainer {
+	private byte[] _header;
+
+	// Links to our more interesting children
+	private AnimationInfoAtom animationAtom;
+
+	/**
+	 * Set things up, and find our more interesting children
+	 */
+	protected AnimationInfo(byte[] source, int start, int len) {
+		// Grab the header
+		_header = new byte[8];
+		System.arraycopy(source,start,_header,0,8);
+
+		// Find our children
+		_children = Record.findChildRecords(source,start+8,len-8);
+		findInterestingChildren();
+	}
+
+	/**
+	 * Go through our child records, picking out the ones that are
+	 *  interesting, and saving those for use by the easy helper
+	 *  methods.
+	 */	
+	private void findInterestingChildren() {
+
+		// First child should be the ExMediaAtom
+		if(_children[0] instanceof AnimationInfoAtom) {
+			animationAtom = (AnimationInfoAtom)_children[0];
+		} else {
+			logger.log(POILogger.ERROR, "First child record wasn't a AnimationInfoAtom, was of type " + _children[0].getRecordType());
+		}
+	}
+
+	/**
+	 * Create a new AnimationInfo, with blank fields
+	 */
+	public AnimationInfo() {
+        // Setup our header block
+		_header = new byte[8];
+		_header[0] = 0x0f; // We are a container record
+		LittleEndian.putShort(_header, 2, (short)getRecordType());
+		
+        _children = new Record[1];
+		_children[0] = animationAtom = new AnimationInfoAtom();
+	}
+
+	/**
+	 * We are of type 4103
+	 */
+	public long getRecordType() { return RecordTypes.AnimationInfo.typeID; }
+
+	/**
+	 * Write the contents of the record back, so it can be written
+	 *  to disk
+	 */
+	public void writeOut(OutputStream out) throws IOException {
+		writeOut(_header[0],_header[1],getRecordType(),_children,out);
+	}
+
+    /**
+     * Returns the AnimationInfo
+     */
+    public AnimationInfoAtom getAnimationInfoAtom() {
+        return animationAtom;
+    }
+
+}

Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfo.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfoAtom.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfoAtom.java?rev=690262&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfoAtom.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfoAtom.java Fri Aug 29 07:01:04 2008
@@ -0,0 +1,278 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+        
+
+package org.apache.poi.hslf.record;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+
+import org.apache.poi.hslf.util.SystemTimeUtils;
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * An atom record that specifies the animation information for a shape.
+ *
+ * @author Yegor Kozlov
+ */
+public class AnimationInfoAtom extends RecordAtom
+{
+
+    /**
+     * whether the animation plays in the reverse direction
+     */
+    public static final int Reverse = 1;
+    /**
+     * whether the animation starts automatically
+     */
+    public static final int Automatic = 4;
+    /**
+     * whether the animation has an associated sound
+     */
+    public static final int Sound = 16;
+    /**
+     * whether all playing sounds are stopped when this animation begins
+     */
+    public static final int StopSound = 64;
+    /**
+     * whether an associated sound, media or action verb is activated when the shape is clicked.
+     */
+    public static final int Play = 256;
+    /**
+     * specifies that the animation, while playing, stops other slide show actions.
+     */
+    public static final int Synchronous = 1024;
+    /**
+     * whether the shape is hidden while the animation is not playing
+     */
+    public static final int Hide = 4096;
+    /**
+     * whether the background of the shape is animated
+     */
+    public static final int AnimateBg = 16384;
+
+    /**
+     * Record header.
+     */
+    private byte[] _header;
+
+    /**
+     * record data
+     */
+    private byte[] _recdata;
+
+    /**
+     * Constructs a brand new link related atom record.
+     */
+    protected AnimationInfoAtom() {
+        _recdata = new byte[28];
+
+        _header = new byte[8];
+        LittleEndian.putShort(_header, 0, (short)0x01);
+        LittleEndian.putShort(_header, 2, (short)getRecordType());
+        LittleEndian.putInt(_header, 4, _recdata.length);
+    }
+
+    /**
+     * Constructs the link related atom record from its
+     *  source data.
+     *
+     * @param source the source data as a byte array.
+     * @param start the start offset into the byte array.
+     * @param len the length of the slice in the byte array.
+     */
+    protected AnimationInfoAtom(byte[] source, int start, int len) {
+        // Get the header
+        _header = new byte[8];
+        System.arraycopy(source,start,_header,0,8);
+
+        // Grab the record data
+        _recdata = new byte[len-8];
+        System.arraycopy(source,start+8,_recdata,0,len-8);
+    }
+
+    /**
+     * Gets the record type.
+     * @return the record type.
+     */
+    public long getRecordType() {
+        return RecordTypes.AnimationInfoAtom.typeID;
+    }
+
+    /**
+     * Write the contents of the record back, so it can be written
+     * to disk
+     *
+     * @param out the output stream to write to.
+     * @throws java.io.IOException if an error occurs.
+     */
+    public void writeOut(OutputStream out) throws IOException {
+        out.write(_header);
+        out.write(_recdata);
+    }
+
+    /**
+     * A rgb structure that specifies a color for the dim effect after the animation is complete.
+     *
+     * @return  color for the dim effect after the animation is complete
+     */
+    public int getDimColor(){
+        return LittleEndian.getInt(_recdata, 0);
+    }
+
+    /**
+     * A rgb structure that specifies a color for the dim effect after the animation is complete.
+     *
+     * @param rgb  color for the dim effect after the animation is complete
+     */
+    public void setDimColor(int rgb){
+         LittleEndian.putInt(_recdata, 0, rgb);
+    }
+
+    /**
+     *  A bit mask specifying options for displaying headers and footers
+     *
+     * @return A bit mask specifying options for displaying headers and footers
+     */
+    public int getMask(){
+        return LittleEndian.getInt(_recdata, 4);
+    }
+
+    /**
+     *  A bit mask specifying options for displaying video
+     *
+     * @param mask A bit mask specifying options for displaying video
+     */
+    public void setMask(int mask){
+        LittleEndian.putInt(_recdata, 4, mask);
+    }
+
+    /**
+     * @param bit the bit to check
+     * @return whether the specified flag is set
+     */
+    public boolean getFlag(int bit){
+        return (getMask() & bit) != 0;
+    }
+
+    /**
+     * @param  bit the bit to set
+     * @param  value whether the specified bit is set
+     */
+    public void setFlag(int bit, boolean value){
+        int mask = getMask();
+        if(value) mask |= bit;
+        else mask &= ~bit;
+        setMask(mask);
+    }
+
+    /**
+     * A 4-byte unsigned integer that specifies a reference to a sound
+     * in the SoundCollectionContainer record to locate the embedded audio
+     *
+     * @return  reference to a sound
+     */
+    public int getSoundIdRef(){
+        return LittleEndian.getInt(_recdata, 8);
+    }
+
+    /**
+     * A 4-byte unsigned integer that specifies a reference to a sound
+     * in the SoundCollectionContainer record to locate the embedded audio
+     *
+     * @param id reference to a sound
+     */
+    public void setSoundIdRef(int id){
+         LittleEndian.putInt(_recdata, 8, id);
+    }
+
+    /**
+     * A signed integer that specifies the delay time, in milliseconds, before the animation starts to play.
+     * If {@link Automatic} is 0x1, this value MUST be greater than or equal to 0; otherwise, this field MUST be ignored.
+     */
+    public int getDelayTime(){
+        return LittleEndian.getInt(_recdata, 12);
+    }
+    /**
+     * A signed integer that specifies the delay time, in milliseconds, before the animation starts to play.
+     * If {@link Automatic} is 0x1, this value MUST be greater than or equal to 0; otherwise, this field MUST be ignored.
+     */
+    public void setDelayTime(int id){
+         LittleEndian.putInt(_recdata, 12, id);
+    }
+
+    /**
+     * A signed integer that specifies the order of the animation in the slide.
+     * It MUST be greater than or equal to -2. The value -2 specifies that this animation follows the order of
+     * the corresponding placeholder shape on the main master slide or title master slide.
+     * The value -1 SHOULD NOT <105> be used.
+     */
+    public int getOrderID(){
+        return LittleEndian.getInt(_recdata, 16);
+    }
+
+    /**
+     * A signed integer that specifies the order of the animation in the slide.
+     * It MUST be greater than or equal to -2. The value -2 specifies that this animation follows the order of
+     * the corresponding placeholder shape on the main master slide or title master slide.
+     * The value -1 SHOULD NOT <105> be used.
+     */
+    public void setOrderID(int id){
+         LittleEndian.putInt(_recdata, 16, id);
+    }
+
+    /**
+     * An unsigned integer that specifies the number of slides that this animation continues playing.
+     * This field is utilized only in conjunction with media.
+     * The value 0xFFFFFFFF specifies that the animation plays for one slide.
+     */
+    public int getSlideCount(){
+        return LittleEndian.getInt(_recdata, 18);
+    }
+
+    /**
+     * An unsigned integer that specifies the number of slides that this animation continues playing.
+     * This field is utilized only in conjunction with media.
+     * The value 0xFFFFFFFF specifies that the animation plays for one slide.
+     */
+    public void setSlideCount(int id){
+         LittleEndian.putInt(_recdata, 18, id);
+    }
+
+    public String toString(){
+        StringBuffer buf = new StringBuffer();
+        buf.append("AnimationInfoAtom\n");
+        buf.append("\tDimColor: " + getDimColor() + "\n");
+        int mask = getMask();
+        buf.append("\tMask: " + mask + ", 0x"+Integer.toHexString(mask)+"\n");
+        buf.append("\t  Reverse: " + getFlag(Reverse)+"\n");
+        buf.append("\t  Automatic: " + getFlag(Automatic)+"\n");
+        buf.append("\t  Sound: " + getFlag(Sound)+"\n");
+        buf.append("\t  StopSound: " + getFlag(StopSound)+"\n");
+        buf.append("\t  Play: " + getFlag(Play)+"\n");
+        buf.append("\t  Synchronous: " + getFlag(Synchronous)+"\n");
+        buf.append("\t  Hide: " + getFlag(Hide)+"\n");
+        buf.append("\t  AnimateBg: " + getFlag(AnimateBg)+"\n");
+        buf.append("\tSoundIdRef: " + getSoundIdRef() + "\n");
+        buf.append("\tDelayTime: " + getDelayTime() + "\n");
+        buf.append("\tOrderID: " + getOrderID() + "\n");
+        buf.append("\tSlideCount: " + getSlideCount() + "\n");
+        return buf.toString();
+    }
+
+}

Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/AnimationInfoAtom.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExAviMovie.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExAviMovie.java?rev=690262&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExAviMovie.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExAviMovie.java Fri Aug 29 07:01:04 2008
@@ -0,0 +1,53 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.poi.hslf.record;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogger;
+
+/**
+ * A container record that specifies information about a movie stored externally.
+ *
+ * @author Yegor Kozlov
+ */
+public class ExAviMovie extends ExMCIMovie {
+
+    /**
+     * Set things up, and find our more interesting children
+     */
+    protected ExAviMovie(byte[] source, int start, int len) {
+        super(source, start, len);
+    }
+
+    /**
+     * Create a new ExAviMovie, with blank fields
+     */
+    public ExAviMovie() {
+        super();
+
+    }
+    /**
+     * We are of type 4102
+     */
+    public long getRecordType() {
+        return RecordTypes.ExAviMovie.typeID;
+    }
+
+}

Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExAviMovie.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExControl.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExControl.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExControl.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExControl.java Fri Aug 29 07:01:04 2008
@@ -24,7 +24,7 @@
 import org.apache.poi.util.POILogger;
 
 /**
- * Container for OLE Control object. It contains:
+ * A container record that specifies information about an ActiveX control. It contains:
  * <p>
  * 1. ExControlAtom (4091)
  * 2. ExOleObjAtom (4035)
@@ -40,9 +40,6 @@
  */
 public class ExControl extends ExEmbed {
 
-    // Links to our more interesting children
-    private ExControlAtom ctrlAtom;
-
     /**
      * Set things up, and find our more interesting children
      *
@@ -60,7 +57,7 @@
     public ExControl() {
         super();
 
-        _children[0] = ctrlAtom = new ExControlAtom();
+        _children[0] = embedAtom = new ExControlAtom();
     }
 
     /**
@@ -70,7 +67,7 @@
      */
     public ExControlAtom getExControlAtom()
     {
-        return ctrlAtom;
+        return (ExControlAtom)_children[0];
     }
 
     /**
@@ -82,14 +79,4 @@
     public long getRecordType() {
         return RecordTypes.ExControl.typeID;
     }
-
-    protected RecordAtom getEmbedAtom(Record[] children){
-        RecordAtom atom = null;
-        if(_children[0] instanceof ExControlAtom) {
-            atom = (ExControlAtom)_children[0];
-        } else {
-            logger.log(POILogger.ERROR, "First child record wasn't a ExControlAtom, was of type " + _children[0].getRecordType());
-        }
-        return atom;
-    }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExControlAtom.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExControlAtom.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExControlAtom.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExControlAtom.java Fri Aug 29 07:01:04 2008
@@ -23,8 +23,7 @@
 import org.apache.poi.util.LittleEndian;
 
 /**
- * Contains a long integer, slideID, which stores the unique slide identifier of the slide
- * where this control resides.
+ * An atom record that specifies an ActiveX control.
  *
  * @author Yegor Kozlov
  */
@@ -67,11 +66,33 @@
         _id = LittleEndian.getInt(source, start + 8);
     }
 
+    /**
+     * An integer that specifies which presentation slide is associated with the ActiveX control.
+     * <p>
+     * It MUST be 0x00000000 or equal to the value of the slideId field of a SlidePersistAtom record.
+     * The value 0x00000000 specifies a null reference.
+     * </p>
+     *
+     * @return an integer that specifies which presentation slide is associated with the ActiveX control
+     */
     public int getSlideId() {
         return _id;
     }
 
     /**
+     * Sets which presentation slide is associated with the ActiveX control.
+     *
+     * @param id an integer that specifies which presentation slide is associated with the ActiveX control
+     * <p>
+     * It MUST be 0x00000000 or equal to the value of the slideId field of a SlidePersistAtom record.
+     * The value 0x00000000 specifies a null reference.
+     * </p>
+     */
+    public void setSlideId(int id) {
+        _id = id;
+    }
+
+    /**
      * Gets the record type.
      * @return the record type.
      */

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java?rev=690262&r1=690261&r2=690262&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExEmbed.java Fri Aug 29 07:01:04 2008
@@ -36,7 +36,7 @@
     private byte[] _header;
 
     // Links to our more interesting children
-    private RecordAtom embedAtom;
+    protected RecordAtom embedAtom;
     private ExOleObjAtom oleObjAtom;
     private CString menuName;
     private CString progId;
@@ -72,10 +72,11 @@
 
         // Setup our child records
         CString cs1 = new CString();
+        cs1.setOptions(0x1 << 4);
         CString cs2 = new CString();
+        cs2.setOptions(0x2 << 4);
         CString cs3 = new CString();
-//        cs1.setOptions(0x00);
-//        cs2.setOptions(0x10);
+        cs3.setOptions(0x3 << 4);
         _children[0] = new ExEmbedAtom();
         _children[1] = new ExOleObjAtom();
         _children[2] = cs1;
@@ -91,7 +92,11 @@
     private void findInterestingChildren() {
 
         // First child should be the ExHyperlinkAtom
-        embedAtom = getEmbedAtom(_children);
+        if(_children[0] instanceof ExEmbedAtom) {
+            embedAtom = (ExEmbedAtom)_children[0];
+        } else {
+            logger.log(POILogger.ERROR, "First child record wasn't a ExEmbedAtom, was of type " + _children[0].getRecordType());
+        }
 
         // Second child should be the ExOleObjAtom
         if (_children[1] instanceof ExOleObjAtom) {
@@ -102,25 +107,17 @@
 
         for (int i = 2; i < _children.length; i++) {
             if (_children[i] instanceof CString){
-                if (menuName == null) menuName = (CString)_children[i];
-                else if (progId == null) progId = (CString)_children[i];
-                else if (clipboardName == null) clipboardName = (CString)_children[i];
-            } else {
-                logger.log(POILogger.ERROR, "Record after atoms wasn't a CString, was of type " + _children[i].getRecordType());
+                CString cs = (CString)_children[i];
+                int opts = cs.getOptions() >> 4;
+                switch(opts){
+                    case 0x1: menuName = cs; break;
+                    case 0x2: progId = cs; break;
+                    case 0x3: clipboardName = cs; break;
+                }
             }
         }
     }
 
-    protected RecordAtom getEmbedAtom(Record[] children){
-        RecordAtom atom = null;
-        if(_children[0] instanceof ExEmbedAtom) {
-            atom = (ExEmbedAtom)_children[0];
-        } else {
-            logger.log(POILogger.ERROR, "First child record wasn't a ExEmbedAtom, was of type " + _children[0].getRecordType());
-        }
-        return atom;
-    }
-
     /**
      * Gets the {@link ExEmbedAtom}.
      *
@@ -151,6 +148,11 @@
         return menuName == null ? null : menuName.getText();
     }
 
+    public void setMenuName(String s)
+    {
+        if(menuName != null) menuName.setText(s);
+    }
+
     /**
      * Gets the OLE Programmatic Identifier.
      * 
@@ -161,6 +163,10 @@
         return progId == null ? null : progId.getText();
     }
 
+    public void setProgId(String s)
+    {
+        if(progId != null) progId.setText(s);
+    }
     /**
      * Gets the name that appears in the paste special dialog.
      *
@@ -171,6 +177,10 @@
         return clipboardName == null ? null : clipboardName.getText();
     }
 
+    public void setClipboardName(String s)
+    {
+        if(clipboardName != null) clipboardName.setText(s);
+    }
     /**
      * Returns the type (held as a little endian in bytes 3 and 4)
      * that this class handles.

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMCIMovie.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMCIMovie.java?rev=690262&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMCIMovie.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMCIMovie.java Fri Aug 29 07:01:04 2008
@@ -0,0 +1,100 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.poi.hslf.record;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogger;
+
+/**
+ * A container record that specifies information about a movie stored externally.
+ *
+ * @author Yegor Kozlov
+ */
+public class ExMCIMovie extends RecordContainer {
+    private byte[] _header;
+
+    //An ExVideoContainer record that specifies information about the MCI movie
+    private ExVideoContainer exVideo;
+
+    /**
+     * Set things up, and find our more interesting children
+     */
+    protected ExMCIMovie(byte[] source, int start, int len) {
+        // Grab the header
+        _header = new byte[8];
+        System.arraycopy(source, start, _header, 0, 8);
+
+        // Find our children
+        _children = Record.findChildRecords(source, start + 8, len - 8);
+        findInterestingChildren();
+    }
+
+    /**
+     * Create a new ExMCIMovie, with blank fields
+     */
+    public ExMCIMovie() {
+        _header = new byte[8];
+        // Setup our header block
+        _header[0] = 0x0f; // We are a container record
+        LittleEndian.putShort(_header, 2, (short) getRecordType());
+
+        exVideo = new ExVideoContainer();
+        _children = new Record[]{exVideo};
+
+    }
+
+    /**
+     * Go through our child records, picking out the ones that are
+     * interesting, and saving those for use by the easy helper
+     * methods.
+     */
+    private void findInterestingChildren() {
+
+        // First child should be the ExVideoContainer
+        if (_children[0] instanceof ExVideoContainer) {
+            exVideo = (ExVideoContainer) _children[0];
+        } else {
+            logger.log(POILogger.ERROR, "First child record wasn't a ExVideoContainer, was of type " + _children[0].getRecordType());
+        }
+    }
+
+    /**
+     * We are of type 4103
+     */
+    public long getRecordType() {
+        return RecordTypes.ExMCIMovie.typeID;
+    }
+
+    /**
+     * Write the contents of the record back, so it can be written
+     * to disk
+     */
+    public void writeOut(OutputStream out) throws IOException {
+        writeOut(_header[0], _header[1], getRecordType(), _children, out);
+    }
+
+    /**
+     * Returns the ExVideoContainer that specifies information about the MCI movie
+     */
+    public ExVideoContainer getExVideo() {
+        return exVideo; }
+
+
+}

Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMCIMovie.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMediaAtom.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMediaAtom.java?rev=690262&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMediaAtom.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMediaAtom.java Fri Aug 29 07:01:04 2008
@@ -0,0 +1,172 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+        
+
+package org.apache.poi.hslf.record;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+
+import org.apache.poi.hslf.util.SystemTimeUtils;
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * An atom record that specifies information about external audio or video data.
+ *
+ * @author Yegor Kozlov
+ */
+public class ExMediaAtom extends RecordAtom
+{
+
+    /**
+     * A bit that specifies whether the audio or video data is repeated continuously during playback.
+     */
+    public static final int fLoop = 1;
+    /**
+     * A bit that specifies whether the audio or video data is rewound after playing.
+     */
+    public static final int fRewind = 2;
+    /**
+     * A bit that specifies whether the audio data is recorded narration for the slide show. It MUST be FALSE if this ExMediaAtom record is contained by an ExVideoContainer record.
+     */
+    public static final int fNarration = 4;
+
+    /**
+     * Record header.
+     */
+    private byte[] _header;
+
+    /**
+     * record data
+     */
+    private byte[] _recdata;
+
+    /**
+     * Constructs a brand new link related atom record.
+     */
+    protected ExMediaAtom() {
+        _recdata = new byte[8];
+
+        _header = new byte[8];
+        LittleEndian.putShort(_header, 2, (short)getRecordType());
+        LittleEndian.putInt(_header, 4, _recdata.length);
+    }
+
+    /**
+     * Constructs the link related atom record from its
+     *  source data.
+     *
+     * @param source the source data as a byte array.
+     * @param start the start offset into the byte array.
+     * @param len the length of the slice in the byte array.
+     */
+    protected ExMediaAtom(byte[] source, int start, int len) {
+        // Get the header
+        _header = new byte[8];
+        System.arraycopy(source,start,_header,0,8);
+
+        // Grab the record data
+        _recdata = new byte[len-8];
+        System.arraycopy(source,start+8,_recdata,0,len-8);
+    }
+
+    /**
+     * Gets the record type.
+     * @return the record type.
+     */
+    public long getRecordType() { return RecordTypes.ExMediaAtom.typeID; }
+
+    /**
+     * Write the contents of the record back, so it can be written
+     * to disk
+     *
+     * @param out the output stream to write to.
+     * @throws java.io.IOException if an error occurs.
+     */
+    public void writeOut(OutputStream out) throws IOException {
+        out.write(_header);
+        out.write(_recdata);
+    }
+
+    /**
+     * A 4-byte unsigned integer that specifies an ID for an external object.
+     *
+     * @return  A 4-byte unsigned integer that specifies an ID for an external object.
+     */
+    public int getObjectId(){
+        return LittleEndian.getInt(_recdata, 0);
+    }
+
+    /**
+     * A 4-byte unsigned integer that specifies an ID for an external object.
+     *
+     * @param id  A 4-byte unsigned integer that specifies an ID for an external object.
+     */
+    public void setObjectId(int id){
+         LittleEndian.putInt(_recdata, 0, id);
+    }
+
+    /**
+     *  A bit mask specifying options for displaying headers and footers
+     *
+     * @return A bit mask specifying options for displaying headers and footers
+     */
+    public int getMask(){
+        return LittleEndian.getInt(_recdata, 4);
+    }
+
+    /**
+     *  A bit mask specifying options for displaying video
+     *
+     * @param mask A bit mask specifying options for displaying video
+     */
+    public void setMask(int mask){
+        LittleEndian.putInt(_recdata, 4, mask);
+    }
+
+    /**
+     * @param bit the bit to check
+     * @return whether the specified flag is set
+     */
+    public boolean getFlag(int bit){
+        return (getMask() & bit) != 0;
+    }
+
+    /**
+     * @param  bit the bit to set
+     * @param  value whether the specified bit is set
+     */
+    public void setFlag(int bit, boolean value){
+        int mask = getMask();
+        if(value) mask |= bit;
+        else mask &= ~bit;
+        setMask(mask);
+    }
+
+    public String toString(){
+        StringBuffer buf = new StringBuffer();
+        buf.append("ExMediaAtom\n");
+        buf.append("\tObjectId: " + getObjectId() + "\n");
+        buf.append("\tMask    : " + getMask() + "\n");
+        buf.append("\t  fLoop        : " + getFlag(fLoop) + "\n");
+        buf.append("\t  fRewind   : " + getFlag(fRewind) + "\n");
+        buf.append("\t  fNarration    : " + getFlag(fNarration) + "\n");
+        return buf.toString();
+    }
+
+}

Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/ExMediaAtom.java
------------------------------------------------------------------------------
    svn:executable = *



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org


Mime
View raw message