FileDocCategorySizeDatePackage
EscherAggregate.javaAPI DocApache Poi 3.0.133580Mon Jan 01 18:59:10 GMT 2007org.apache.poi.hssf.record

EscherAggregate

public class EscherAggregate extends AbstractEscherHolderRecord
This class is used to aggregate the MSODRAWING and OBJ record combinations. This is necessary due to the bizare way in which these records are serialized. What happens is that you get a combination of MSODRAWING -> OBJ -> MSODRAWING -> OBJ records but the escher records are serialized _across_ the MSODRAWING records.

It gets even worse when you start looking at TXO records.

So what we do with this class is aggregate lazily. That is we don't aggregate the MSODRAWING -> OBJ records unless we need to modify them.

author
Glen Stampoultzis (glens at apache.org)

Fields Summary
public static final short
sid
public static final short
ST_MIN
public static final short
ST_NOT_PRIMATIVE
public static final short
ST_RECTANGLE
public static final short
ST_ROUNDRECTANGLE
public static final short
ST_ELLIPSE
public static final short
ST_DIAMOND
public static final short
ST_ISOCELESTRIANGLE
public static final short
ST_RIGHTTRIANGLE
public static final short
ST_PARALLELOGRAM
public static final short
ST_TRAPEZOID
public static final short
ST_HEXAGON
public static final short
ST_OCTAGON
public static final short
ST_PLUS
public static final short
ST_STAR
public static final short
ST_ARROW
public static final short
ST_THICKARROW
public static final short
ST_HOMEPLATE
public static final short
ST_CUBE
public static final short
ST_BALLOON
public static final short
ST_SEAL
public static final short
ST_ARC
public static final short
ST_LINE
public static final short
ST_PLAQUE
public static final short
ST_CAN
public static final short
ST_DONUT
public static final short
ST_TEXTSIMPLE
public static final short
ST_TEXTOCTAGON
public static final short
ST_TEXTHEXAGON
public static final short
ST_TEXTCURVE
public static final short
ST_TEXTWAVE
public static final short
ST_TEXTRING
public static final short
ST_TEXTONCURVE
public static final short
ST_TEXTONRING
public static final short
ST_STRAIGHTCONNECTOR1
public static final short
ST_BENTCONNECTOR2
public static final short
ST_BENTCONNECTOR3
public static final short
ST_BENTCONNECTOR4
public static final short
ST_BENTCONNECTOR5
public static final short
ST_CURVEDCONNECTOR2
public static final short
ST_CURVEDCONNECTOR3
public static final short
ST_CURVEDCONNECTOR4
public static final short
ST_CURVEDCONNECTOR5
public static final short
ST_CALLOUT1
public static final short
ST_CALLOUT2
public static final short
ST_CALLOUT3
public static final short
ST_ACCENTCALLOUT1
public static final short
ST_ACCENTCALLOUT2
public static final short
ST_ACCENTCALLOUT3
public static final short
ST_BORDERCALLOUT1
public static final short
ST_BORDERCALLOUT2
public static final short
ST_BORDERCALLOUT3
public static final short
ST_ACCENTBORDERCALLOUT1
public static final short
ST_ACCENTBORDERCALLOUT2
public static final short
ST_ACCENTBORDERCALLOUT3
public static final short
ST_RIBBON
public static final short
ST_RIBBON2
public static final short
ST_CHEVRON
public static final short
ST_PENTAGON
public static final short
ST_NOSMOKING
public static final short
ST_SEAL8
public static final short
ST_SEAL16
public static final short
ST_SEAL32
public static final short
ST_WEDGERECTCALLOUT
public static final short
ST_WEDGERRECTCALLOUT
public static final short
ST_WEDGEELLIPSECALLOUT
public static final short
ST_WAVE
public static final short
ST_FOLDEDCORNER
public static final short
ST_LEFTARROW
public static final short
ST_DOWNARROW
public static final short
ST_UPARROW
public static final short
ST_LEFTRIGHTARROW
public static final short
ST_UPDOWNARROW
public static final short
ST_IRREGULARSEAL1
public static final short
ST_IRREGULARSEAL2
public static final short
ST_LIGHTNINGBOLT
public static final short
ST_HEART
public static final short
ST_PICTUREFRAME
public static final short
ST_QUADARROW
public static final short
ST_LEFTARROWCALLOUT
public static final short
ST_RIGHTARROWCALLOUT
public static final short
ST_UPARROWCALLOUT
public static final short
ST_DOWNARROWCALLOUT
public static final short
ST_LEFTRIGHTARROWCALLOUT
public static final short
ST_UPDOWNARROWCALLOUT
public static final short
ST_QUADARROWCALLOUT
public static final short
ST_BEVEL
public static final short
ST_LEFTBRACKET
public static final short
ST_RIGHTBRACKET
public static final short
ST_LEFTBRACE
public static final short
ST_RIGHTBRACE
public static final short
ST_LEFTUPARROW
public static final short
ST_BENTUPARROW
public static final short
ST_BENTARROW
public static final short
ST_SEAL24
public static final short
ST_STRIPEDRIGHTARROW
public static final short
ST_NOTCHEDRIGHTARROW
public static final short
ST_BLOCKARC
public static final short
ST_SMILEYFACE
public static final short
ST_VERTICALSCROLL
public static final short
ST_HORIZONTALSCROLL
public static final short
ST_CIRCULARARROW
public static final short
ST_NOTCHEDCIRCULARARROW
public static final short
ST_UTURNARROW
public static final short
ST_CURVEDRIGHTARROW
public static final short
ST_CURVEDLEFTARROW
public static final short
ST_CURVEDUPARROW
public static final short
ST_CURVEDDOWNARROW
public static final short
ST_CLOUDCALLOUT
public static final short
ST_ELLIPSERIBBON
public static final short
ST_ELLIPSERIBBON2
public static final short
ST_FLOWCHARTPROCESS
public static final short
ST_FLOWCHARTDECISION
public static final short
ST_FLOWCHARTINPUTOUTPUT
public static final short
ST_FLOWCHARTPREDEFINEDPROCESS
public static final short
ST_FLOWCHARTINTERNALSTORAGE
public static final short
ST_FLOWCHARTDOCUMENT
public static final short
ST_FLOWCHARTMULTIDOCUMENT
public static final short
ST_FLOWCHARTTERMINATOR
public static final short
ST_FLOWCHARTPREPARATION
public static final short
ST_FLOWCHARTMANUALINPUT
public static final short
ST_FLOWCHARTMANUALOPERATION
public static final short
ST_FLOWCHARTCONNECTOR
public static final short
ST_FLOWCHARTPUNCHEDCARD
public static final short
ST_FLOWCHARTPUNCHEDTAPE
public static final short
ST_FLOWCHARTSUMMINGJUNCTION
public static final short
ST_FLOWCHARTOR
public static final short
ST_FLOWCHARTCOLLATE
public static final short
ST_FLOWCHARTSORT
public static final short
ST_FLOWCHARTEXTRACT
public static final short
ST_FLOWCHARTMERGE
public static final short
ST_FLOWCHARTOFFLINESTORAGE
public static final short
ST_FLOWCHARTONLINESTORAGE
public static final short
ST_FLOWCHARTMAGNETICTAPE
public static final short
ST_FLOWCHARTMAGNETICDISK
public static final short
ST_FLOWCHARTMAGNETICDRUM
public static final short
ST_FLOWCHARTDISPLAY
public static final short
ST_FLOWCHARTDELAY
public static final short
ST_TEXTPLAINTEXT
public static final short
ST_TEXTSTOP
public static final short
ST_TEXTTRIANGLE
public static final short
ST_TEXTTRIANGLEINVERTED
public static final short
ST_TEXTCHEVRON
public static final short
ST_TEXTCHEVRONINVERTED
public static final short
ST_TEXTRINGINSIDE
public static final short
ST_TEXTRINGOUTSIDE
public static final short
ST_TEXTARCHUPCURVE
public static final short
ST_TEXTARCHDOWNCURVE
public static final short
ST_TEXTCIRCLECURVE
public static final short
ST_TEXTBUTTONCURVE
public static final short
ST_TEXTARCHUPPOUR
public static final short
ST_TEXTARCHDOWNPOUR
public static final short
ST_TEXTCIRCLEPOUR
public static final short
ST_TEXTBUTTONPOUR
public static final short
ST_TEXTCURVEUP
public static final short
ST_TEXTCURVEDOWN
public static final short
ST_TEXTCASCADEUP
public static final short
ST_TEXTCASCADEDOWN
public static final short
ST_TEXTWAVE1
public static final short
ST_TEXTWAVE2
public static final short
ST_TEXTWAVE3
public static final short
ST_TEXTWAVE4
public static final short
ST_TEXTINFLATE
public static final short
ST_TEXTDEFLATE
public static final short
ST_TEXTINFLATEBOTTOM
public static final short
ST_TEXTDEFLATEBOTTOM
public static final short
ST_TEXTINFLATETOP
public static final short
ST_TEXTDEFLATETOP
public static final short
ST_TEXTDEFLATEINFLATE
public static final short
ST_TEXTDEFLATEINFLATEDEFLATE
public static final short
ST_TEXTFADERIGHT
public static final short
ST_TEXTFADELEFT
public static final short
ST_TEXTFADEUP
public static final short
ST_TEXTFADEDOWN
public static final short
ST_TEXTSLANTUP
public static final short
ST_TEXTSLANTDOWN
public static final short
ST_TEXTCANUP
public static final short
ST_TEXTCANDOWN
public static final short
ST_FLOWCHARTALTERNATEPROCESS
public static final short
ST_FLOWCHARTOFFPAGECONNECTOR
public static final short
ST_CALLOUT90
public static final short
ST_ACCENTCALLOUT90
public static final short
ST_BORDERCALLOUT90
public static final short
ST_ACCENTBORDERCALLOUT90
public static final short
ST_LEFTRIGHTUPARROW
public static final short
ST_SUN
public static final short
ST_MOON
public static final short
ST_BRACKETPAIR
public static final short
ST_BRACEPAIR
public static final short
ST_SEAL4
public static final short
ST_DOUBLEWAVE
public static final short
ST_ACTIONBUTTONBLANK
public static final short
ST_ACTIONBUTTONHOME
public static final short
ST_ACTIONBUTTONHELP
public static final short
ST_ACTIONBUTTONINFORMATION
public static final short
ST_ACTIONBUTTONFORWARDNEXT
public static final short
ST_ACTIONBUTTONBACKPREVIOUS
public static final short
ST_ACTIONBUTTONEND
public static final short
ST_ACTIONBUTTONBEGINNING
public static final short
ST_ACTIONBUTTONRETURN
public static final short
ST_ACTIONBUTTONDOCUMENT
public static final short
ST_ACTIONBUTTONSOUND
public static final short
ST_ACTIONBUTTONMOVIE
public static final short
ST_HOSTCONTROL
public static final short
ST_TEXTBOX
public static final short
ST_NIL
protected HSSFPatriarch
patriarch
private Map
shapeToObj
Maps shape container objects to their OBJ records
private DrawingManager2
drawingManager
private short
drawingGroupId
private List
tailRec
list of "tail" records that need to be serialized after all drawing group records
Constructors Summary
public EscherAggregate(DrawingManager2 drawingManager)


        
    
        this.drawingManager = drawingManager;
    
Methods Summary
public java.lang.ObjectassoicateShapeToObjRecord(org.apache.poi.ddf.EscherRecord r, org.apache.poi.hssf.record.Record objRecord)
Associates an escher record to an OBJ record or a TXO record.

        return shapeToObj.put( r, objRecord );
    
public voidclear()

        clearEscherRecords();
        shapeToObj.clear();
//        lastShapeId = 1024;
    
private voidconvertGroup(org.apache.poi.hssf.usermodel.HSSFShapeGroup shape, org.apache.poi.ddf.EscherContainerRecord escherParent, java.util.Map shapeToObj)

        EscherContainerRecord spgrContainer = new EscherContainerRecord();
        EscherContainerRecord spContainer = new EscherContainerRecord();
        EscherSpgrRecord spgr = new EscherSpgrRecord();
        EscherSpRecord sp = new EscherSpRecord();
        EscherOptRecord opt = new EscherOptRecord();
        EscherRecord anchor;
        EscherClientDataRecord clientData = new EscherClientDataRecord();

        spgrContainer.setRecordId( EscherContainerRecord.SPGR_CONTAINER );
        spgrContainer.setOptions( (short) 0x000F );
        spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
        spContainer.setOptions( (short) 0x000F );
        spgr.setRecordId( EscherSpgrRecord.RECORD_ID );
        spgr.setOptions( (short) 0x0001 );
        spgr.setRectX1( shape.getX1() );
        spgr.setRectY1( shape.getY1() );
        spgr.setRectX2( shape.getX2() );
        spgr.setRectY2( shape.getY2() );
        sp.setRecordId( EscherSpRecord.RECORD_ID );
        sp.setOptions( (short) 0x0002 );
        int shapeId = drawingManager.allocateShapeId(drawingGroupId);
        sp.setShapeId( shapeId );
        if (shape.getAnchor() instanceof HSSFClientAnchor)
            sp.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_HAVEANCHOR );
        else
            sp.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_CHILD );
        opt.setRecordId( EscherOptRecord.RECORD_ID );
        opt.setOptions( (short) 0x0023 );
        opt.addEscherProperty( new EscherBoolProperty( EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x00040004 ) );
        opt.addEscherProperty( new EscherBoolProperty( EscherProperties.GROUPSHAPE__PRINT, 0x00080000 ) );

        anchor = ConvertAnchor.createAnchor( shape.getAnchor() );
//        clientAnchor.setCol1( ( (HSSFClientAnchor) shape.getAnchor() ).getCol1() );
//        clientAnchor.setRow1( (short) ( (HSSFClientAnchor) shape.getAnchor() ).getRow1() );
//        clientAnchor.setDx1( (short) shape.getAnchor().getDx1() );
//        clientAnchor.setDy1( (short) shape.getAnchor().getDy1() );
//        clientAnchor.setCol2( ( (HSSFClientAnchor) shape.getAnchor() ).getCol2() );
//        clientAnchor.setRow2( (short) ( (HSSFClientAnchor) shape.getAnchor() ).getRow2() );
//        clientAnchor.setDx2( (short) shape.getAnchor().getDx2() );
//        clientAnchor.setDy2( (short) shape.getAnchor().getDy2() );
        clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
        clientData.setOptions( (short) 0x0000 );

        spgrContainer.addChildRecord( spContainer );
        spContainer.addChildRecord( spgr );
        spContainer.addChildRecord( sp );
        spContainer.addChildRecord( opt );
        spContainer.addChildRecord( anchor );
        spContainer.addChildRecord( clientData );

        ObjRecord obj = new ObjRecord();
        CommonObjectDataSubRecord cmo = new CommonObjectDataSubRecord();
        cmo.setObjectType( CommonObjectDataSubRecord.OBJECT_TYPE_GROUP );
        cmo.setObjectId( (short) ( shapeId ) );
        cmo.setLocked( true );
        cmo.setPrintable( true );
        cmo.setAutofill( true );
        cmo.setAutoline( true );
        GroupMarkerSubRecord gmo = new GroupMarkerSubRecord();
        EndSubRecord end = new EndSubRecord();
        obj.addSubRecord( cmo );
        obj.addSubRecord( gmo );
        obj.addSubRecord( end );
        shapeToObj.put( clientData, obj );

        escherParent.addChildRecord( spgrContainer );

        convertShapes( shape, spgrContainer, shapeToObj );

    
private voidconvertPatriarch(org.apache.poi.hssf.usermodel.HSSFPatriarch patriarch)

        EscherContainerRecord dgContainer = new EscherContainerRecord();
        EscherDgRecord dg;
        EscherContainerRecord spgrContainer = new EscherContainerRecord();
        EscherContainerRecord spContainer1 = new EscherContainerRecord();
        EscherSpgrRecord spgr = new EscherSpgrRecord();
        EscherSpRecord sp1 = new EscherSpRecord();

        dgContainer.setRecordId( EscherContainerRecord.DG_CONTAINER );
        dgContainer.setOptions( (short) 0x000F );
        dg = drawingManager.createDgRecord();
        drawingGroupId = dg.getDrawingGroupId();
//        dg.setOptions( (short) ( drawingId << 4 ) );
//        dg.setNumShapes( getNumberOfShapes( patriarch ) );
//        dg.setLastMSOSPID( 0 );  // populated after all shape id's are assigned.
        spgrContainer.setRecordId( EscherContainerRecord.SPGR_CONTAINER );
        spgrContainer.setOptions( (short) 0x000F );
        spContainer1.setRecordId( EscherContainerRecord.SP_CONTAINER );
        spContainer1.setOptions( (short) 0x000F );
        spgr.setRecordId( EscherSpgrRecord.RECORD_ID );
        spgr.setOptions( (short) 0x0001 );    // version
        spgr.setRectX1( patriarch.getX1() );
        spgr.setRectY1( patriarch.getY1() );
        spgr.setRectX2( patriarch.getX2() );
        spgr.setRectY2( patriarch.getY2() );
        sp1.setRecordId( EscherSpRecord.RECORD_ID );
        sp1.setOptions( (short) 0x0002 );
        sp1.setShapeId( drawingManager.allocateShapeId(dg.getDrawingGroupId()) );
        sp1.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_PATRIARCH );

        dgContainer.addChildRecord( dg );
        dgContainer.addChildRecord( spgrContainer );
        spgrContainer.addChildRecord( spContainer1 );
        spContainer1.addChildRecord( spgr );
        spContainer1.addChildRecord( sp1 );

        addEscherRecord( dgContainer );
    
private voidconvertShapes(org.apache.poi.hssf.usermodel.HSSFShapeContainer parent, org.apache.poi.ddf.EscherContainerRecord escherParent, java.util.Map shapeToObj)

        if ( escherParent == null ) throw new IllegalArgumentException( "Parent record required" );

        List shapes = parent.getChildren();
        for ( Iterator iterator = shapes.iterator(); iterator.hasNext(); )
        {
            HSSFShape shape = (HSSFShape) iterator.next();
            if ( shape instanceof HSSFShapeGroup )
            {
                convertGroup( (HSSFShapeGroup) shape, escherParent, shapeToObj );
            }
            else
            {
                AbstractShape shapeModel = AbstractShape.createShape(
                        shape,
                        drawingManager.allocateShapeId(drawingGroupId) );
                shapeToObj.put( findClientData( shapeModel.getSpContainer() ), shapeModel.getObjRecord() );
                if ( shapeModel instanceof TextboxShape )
                {
                    EscherRecord escherTextbox = ( (TextboxShape) shapeModel ).getEscherTextbox();
                    shapeToObj.put( escherTextbox, ( (TextboxShape) shapeModel ).getTextObjectRecord() );
                    //                    escherParent.addChildRecord(escherTextbox);
                    
                    if ( shapeModel instanceof CommentShape ){
                        CommentShape comment = (CommentShape)shapeModel;
                        tailRec.add(comment.getNoteRecord());
                    }

                }
                escherParent.addChildRecord( shapeModel.getSpContainer() );
            }
        }
//        drawingManager.newCluster( (short)1 );
//        drawingManager.newCluster( (short)2 );

    
private voidconvertUserModelToRecords()

        if ( patriarch != null )
        {
            shapeToObj.clear();
            tailRec.clear();
            clearEscherRecords();
            if ( patriarch.getChildren().size() != 0 )
            {
                convertPatriarch( patriarch );
                EscherContainerRecord dgContainer = (EscherContainerRecord) getEscherRecord( 0 );
                EscherContainerRecord spgrContainer = null;
                for ( int i = 0; i < dgContainer.getChildRecords().size(); i++ )
                    if ( dgContainer.getChild( i ).getRecordId() == EscherContainerRecord.SPGR_CONTAINER )
                        spgrContainer = (EscherContainerRecord) dgContainer.getChild( i );
                convertShapes( patriarch, spgrContainer, shapeToObj );

                patriarch = null;
            }
        }
    
public static org.apache.poi.hssf.record.EscherAggregatecreateAggregate(java.util.List records, int locFirstDrawingRecord, org.apache.poi.hssf.model.DrawingManager2 drawingManager)
Collapses the drawing records into an aggregate.

        // Keep track of any shape records created so we can match them back to the object id's.
        // Textbox objects are also treated as shape objects.
        final List shapeRecords = new ArrayList();
        EscherRecordFactory recordFactory = new DefaultEscherRecordFactory()
        {
            public EscherRecord createRecord( byte[] data, int offset )
            {
                EscherRecord r = super.createRecord( data, offset );
                if ( r.getRecordId() == EscherClientDataRecord.RECORD_ID || r.getRecordId() == EscherTextboxRecord.RECORD_ID )
                {
                    shapeRecords.add( r );
                }
                return r;
            }
        };

        // Calculate the size of the buffer
        EscherAggregate agg = new EscherAggregate(drawingManager);
        int loc = locFirstDrawingRecord;
        int dataSize = 0;
        while ( loc + 1 < records.size()
                && sid( records, loc ) == DrawingRecord.sid
                && isObjectRecord( records, loc + 1 ) )
        {
            dataSize += ( (DrawingRecord) records.get( loc ) ).getData().length;
            loc += 2;
        }

        // Create one big buffer
        byte buffer[] = new byte[dataSize];
        int offset = 0;
        loc = locFirstDrawingRecord;
        while ( loc + 1 < records.size()
                && sid( records, loc ) == DrawingRecord.sid
                && isObjectRecord( records, loc + 1 ) )
        {
            DrawingRecord drawingRecord = (DrawingRecord) records.get( loc );
            System.arraycopy( drawingRecord.getData(), 0, buffer, offset, drawingRecord.getData().length );
            offset += drawingRecord.getData().length;
            loc += 2;
        }

        // Decode the shapes
        //        agg.escherRecords = new ArrayList();
        int pos = 0;
        while ( pos < dataSize )
        {
            EscherRecord r = recordFactory.createRecord( buffer, pos );
            int bytesRead = r.fillFields( buffer, pos, recordFactory );
            agg.addEscherRecord( r );
            pos += bytesRead;
        }

        // Associate the object records with the shapes
        loc = locFirstDrawingRecord;
        int shapeIndex = 0;
        agg.shapeToObj = new HashMap();
        while ( loc + 1 < records.size()
                && sid( records, loc ) == DrawingRecord.sid
                && isObjectRecord( records, loc + 1 ) )
        {
            Record objRecord = (Record) records.get( loc + 1 );
            agg.shapeToObj.put( shapeRecords.get( shapeIndex++ ), objRecord );
            loc += 2;
        }

        return agg;

    
protected voidfillFields(byte[] data, short size, int offset)
Unused since this is an aggregate record. Use createAggregate().

see
#createAggregate

        throw new IllegalStateException( "Should not reach here" );
    
private org.apache.poi.ddf.EscherRecordfindClientData(org.apache.poi.ddf.EscherContainerRecord spContainer)

        for ( Iterator iterator = spContainer.getChildRecords().iterator(); iterator.hasNext(); )
        {
            EscherRecord r = (EscherRecord) iterator.next();
            if ( r.getRecordId() == EscherClientDataRecord.RECORD_ID )
                return r;
        }
        throw new IllegalArgumentException( "Can not find client data record" );
    
private intgetEscherRecordSize(java.util.List records)
How many bytes do the raw escher records contain.

param
records List of escher records
return
the number of bytes

        int size = 0;
        for ( Iterator iterator = records.iterator(); iterator.hasNext(); )
            size += ( (EscherRecord) iterator.next() ).getRecordSize();
        return size;
    
public org.apache.poi.hssf.usermodel.HSSFPatriarchgetPatriarch()

        return patriarch;
    
protected java.lang.StringgetRecordName()

        return "ESCHERAGGREGATE";
    
public intgetRecordSize()
The number of bytes required to serialize this record.

        convertUserModelToRecords();
        List records = getEscherRecords();
        int rawEscherSize = getEscherRecordSize( records );
        int drawingRecordSize = rawEscherSize + ( shapeToObj.size() ) * 4;
        int objRecordSize = 0;
        for ( Iterator iterator = shapeToObj.values().iterator(); iterator.hasNext(); )
        {
            Record r = (Record) iterator.next();
            objRecordSize += r.getRecordSize();
        }
        int tailRecordSize = 0;
        for ( Iterator iterator = tailRec.iterator(); iterator.hasNext(); )
        {
            Record r = (Record) iterator.next();
            tailRecordSize += r.getRecordSize();
        }
        return drawingRecordSize + objRecordSize + tailRecordSize;
    
public shortgetSid()

return
Returns the current sid.

        return sid;
    
private static booleanisObjectRecord(java.util.List records, int loc)

        return sid( records, loc ) == ObjRecord.sid || sid( records, loc ) == TextObjectRecord.sid;
    
public intserialize(int offset, byte[] data)
Serializes this aggregate to a byte array. Since this is an aggregate record it will effectively serialize the aggregated records.

param
offset The offset into the start of the array.
param
data The byte array to serialize to.
return
The number of bytes serialized.

        convertUserModelToRecords();

        // Determine buffer size
        List records = getEscherRecords();
        int size = getEscherRecordSize( records );
        byte[] buffer = new byte[size];


        // Serialize escher records into one big data structure and keep note of ending offsets.
        final List spEndingOffsets = new ArrayList();
        final List shapes = new ArrayList();
        int pos = 0;
        for ( Iterator iterator = records.iterator(); iterator.hasNext(); )
        {
            EscherRecord e = (EscherRecord) iterator.next();
            pos += e.serialize( pos, buffer, new EscherSerializationListener()
            {
                public void beforeRecordSerialize( int offset, short recordId, EscherRecord record )
                {
                }

                public void afterRecordSerialize( int offset, short recordId, int size, EscherRecord record )
                {
                    if ( recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID )
                    {
                        spEndingOffsets.add( new Integer( offset ) );
                        shapes.add( record );
                    }
                }
            } );
        }
        // todo: fix this
        shapes.add( 0, null );
        spEndingOffsets.add( 0, null );

        // Split escher records into separate MSODRAWING and OBJ, TXO records.  (We don't break on
        // the first one because it's the patriach).
        pos = offset;
        for ( int i = 1; i < shapes.size(); i++ )
        {
            int endOffset = ( (Integer) spEndingOffsets.get( i ) ).intValue() - 1;
            int startOffset;
            if ( i == 1 )
                startOffset = 0;
            else
                startOffset = ( (Integer) spEndingOffsets.get( i - 1 ) ).intValue();

            // Create and write a new MSODRAWING record
            DrawingRecord drawing = new DrawingRecord();
            byte[] drawingData = new byte[endOffset - startOffset + 1];
            System.arraycopy( buffer, startOffset, drawingData, 0, drawingData.length );
            drawing.setData( drawingData );
            int temp = drawing.serialize( pos, data );
            pos += temp;

            // Write the matching OBJ record
            Record obj = (Record) shapeToObj.get( shapes.get( i ) );
            temp = obj.serialize( pos, data );
            pos += temp;

        }

        // write records that need to be serialized after all drawing group records
        for ( int i = 0; i < tailRec.size(); i++ )
        {
            Record rec = (Record)tailRec.get(i);
            pos += rec.serialize( pos, data );
        }

        int bytesWritten = pos - offset;
        if ( bytesWritten != getRecordSize() )
            throw new RecordFormatException( bytesWritten + " bytes written but getRecordSize() reports " + getRecordSize() );
        return bytesWritten;
    
public voidsetPatriarch(org.apache.poi.hssf.usermodel.HSSFPatriarch patriarch)

        this.patriarch = patriarch;
    
private static shortsid(java.util.List records, int loc)
Retrieve the number of shapes (including the patriarch).

        return ( (Record) records.get( loc ) ).getSid();
    
public java.lang.StringtoString()
Calculates the string representation of this record. This is simply a dump of all the records.

        String nl = System.getProperty( "line.separtor" );

        StringBuffer result = new StringBuffer();
        result.append( '[" ).append( getRecordName() ).append( ']" + nl );
        for ( Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); )
        {
            EscherRecord escherRecord = (EscherRecord) iterator.next();
            result.append( escherRecord.toString() );
        }
        result.append( "[/" ).append( getRecordName() ).append( ']" + nl );

        return result.toString();