Model for drawing format support

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/branches/REL_2_BRANCH@353496 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Glen Stampoultzis 2004-02-10 21:59:21 +00:00
parent 104093d45e
commit 3df231642a
9 changed files with 954 additions and 17 deletions

View File

@ -0,0 +1,126 @@
package org.apache.poi.hssf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.hssf.usermodel.*;
/**
* An abstract shape is the lowlevel model for a shape.
*
* @author Glen Stampoultzis (glens at apache.org)
*/
public abstract class AbstractShape
{
/**
* Create a new shape object used to create the escher records.
*
* @param hssfShape The simple shape this is based on.
*/
public static AbstractShape createShape( HSSFShape hssfShape, int shapeId )
{
AbstractShape shape = null;
if (hssfShape instanceof HSSFTextbox)
{
shape = new TextboxShape( (HSSFTextbox)hssfShape, shapeId );
}
else if (hssfShape instanceof HSSFPolygon)
{
shape = new PolygonShape( (HSSFPolygon) hssfShape, shapeId );
}
else if (hssfShape instanceof HSSFSimpleShape)
{
HSSFSimpleShape simpleShape = (HSSFSimpleShape) hssfShape;
switch ( simpleShape.getShapeType() )
{
case HSSFSimpleShape.OBJECT_TYPE_LINE:
shape = new LineShape( simpleShape, shapeId );
break;
case HSSFSimpleShape.OBJECT_TYPE_OVAL:
case HSSFSimpleShape.OBJECT_TYPE_RECTANGLE:
shape = new SimpleFilledShape( simpleShape, shapeId );
break;
default:
throw new IllegalArgumentException("Do not know how to handle this type of shape");
}
}
else
{
throw new IllegalArgumentException("Unknown shape type");
}
EscherSpRecord sp = shape.getSpContainer().getChildById(EscherSpRecord.RECORD_ID);
if (hssfShape.getParent() != null)
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_CHILD);
return shape;
}
protected AbstractShape()
{
}
/**
* @return The shape container and it's children that can represent this
* shape.
*/
public abstract EscherContainerRecord getSpContainer();
/**
* @return The object record that is associated with this shape.
*/
public abstract ObjRecord getObjRecord();
/**
* Creates an escher anchor record from a HSSFAnchor.
*
* @param userAnchor The high level anchor to convert.
* @return An escher anchor record.
*/
protected EscherRecord createAnchor( HSSFAnchor userAnchor )
{
return ConvertAnchor.createAnchor(userAnchor);
}
/**
* Add standard properties to the opt record. These properties effect
* all records.
*
* @param shape The user model shape.
* @param opt The opt record to add the properties to.
* @return The number of options added.
*/
protected int addStandardOptions( HSSFShape shape, EscherOptRecord opt )
{
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x080000 ) );
// opt.addEscherProperty( new EscherBoolProperty( EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x080008 ) );
if ( shape.isNoFill() )
{
// Wonderful... none of the spec's give any clue as to what these constants mean.
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.FILL__NOFILLHITTEST, 0x00110000 ) );
}
else
{
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.FILL__NOFILLHITTEST, 0x00010000 ) );
}
opt.addEscherProperty( new EscherRGBProperty( EscherProperties.FILL__FILLCOLOR, shape.getFillColor() ) );
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.GROUPSHAPE__PRINT, 0x080000 ) );
opt.addEscherProperty( new EscherRGBProperty( EscherProperties.LINESTYLE__COLOR, shape.getLineStyleColor() ) );
int options = 5;
if (shape.getLineWidth() != HSSFShape.LINEWIDTH_DEFAULT)
{
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.LINESTYLE__LINEWIDTH, shape.getLineWidth()));
options++;
}
if (shape.getLineStyle() != HSSFShape.LINESTYLE_SOLID)
{
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.LINESTYLE__LINEDASHING, shape.getLineStyle()));
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.LINESTYLE__LINEENDCAPSTYLE, 0));
if (shape.getLineStyle() == HSSFShape.LINESTYLE_NONE)
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x00080000));
else
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x00080008));
options += 3;
}
opt.sortProperties();
return options; // # options added
}
}

View File

@ -0,0 +1,50 @@
package org.apache.poi.hssf.model;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherClientAnchorRecord;
import org.apache.poi.ddf.EscherChildAnchorRecord;
import org.apache.poi.hssf.usermodel.HSSFAnchor;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFChildAnchor;
/**
* $Id$
*/
public class ConvertAnchor
{
public static EscherRecord createAnchor( HSSFAnchor userAnchor )
{
if (userAnchor instanceof HSSFClientAnchor)
{
HSSFClientAnchor a = (HSSFClientAnchor) userAnchor;
EscherClientAnchorRecord anchor = new EscherClientAnchorRecord();
anchor.setRecordId( EscherClientAnchorRecord.RECORD_ID );
anchor.setOptions( (short) 0x0000 );
anchor.setFlag( (short) 0 );
anchor.setCol1( (short) Math.min(a.getCol1(), a.getCol2()) );
anchor.setDx1( (short) Math.min(a.getDx1(), a.getDx2()) );
anchor.setRow1( (short) Math.min(a.getRow1(), a.getRow2()) );
anchor.setDy1( (short) Math.min(a.getDy1(), a.getDy2()) );
anchor.setCol2( (short) Math.max(a.getCol1(), a.getCol2()) );
anchor.setDx2( (short) Math.max(a.getDx1(), a.getDx2()) );
anchor.setRow2( (short) Math.max(a.getRow1(), a.getRow2()) );
anchor.setDy2( (short) Math.max(a.getDy1(), a.getDy2() ) );
return anchor;
}
else
{
HSSFChildAnchor a = (HSSFChildAnchor) userAnchor;
EscherChildAnchorRecord anchor = new EscherChildAnchorRecord();
anchor.setRecordId( EscherChildAnchorRecord.RECORD_ID );
anchor.setOptions( (short) 0x0000 );
anchor.setDx1( (short) Math.min(a.getDx1(), a.getDx2()) );
anchor.setDy1( (short) Math.min(a.getDy1(), a.getDy2()) );
anchor.setDx2( (short) Math.max(a.getDx2(), a.getDx1()) );
anchor.setDy2( (short) Math.max(a.getDy2(), a.getDy1()) );
return anchor;
}
}
}

View File

@ -0,0 +1,136 @@
package org.apache.poi.hssf.model;
import org.apache.poi.ddf.EscherDggRecord;
import org.apache.poi.ddf.EscherDgRecord;
import java.util.Map;
import java.util.HashMap;
/**
* Provides utilities to manage drawing groups.
*
* @author Glen Stampoultzis (glens at apache.org)
*/
public class DrawingManager
{
EscherDggRecord dgg;
Map dgMap = new HashMap(); // key = Short(drawingId), value=EscherDgRecord
public DrawingManager( EscherDggRecord dgg )
{
this.dgg = dgg;
}
public EscherDgRecord createDgRecord()
{
EscherDgRecord dg = new EscherDgRecord();
dg.setRecordId( EscherDgRecord.RECORD_ID );
short dgId = findNewDrawingGroupId();
dg.setOptions( (short) ( dgId << 4 ) );
dg.setNumShapes( 0 );
dg.setLastMSOSPID( -1 );
dgg.addCluster( dgId, 0 );
dgg.setDrawingsSaved( dgg.getDrawingsSaved() + 1 );
dgMap.put( new Short( dgId ), dg );
return dg;
}
/**
* Allocates new shape id for the new drawing group id.
*
* @return a new shape id.
*/
public int allocateShapeId(short drawingGroupId)
{
// Get the last shape id for this drawing group.
EscherDgRecord dg = (EscherDgRecord) dgMap.get(new Short(drawingGroupId));
int lastShapeId = dg.getLastMSOSPID();
// Have we run out of shapes for this cluster?
int newShapeId = 0;
if (lastShapeId % 1024 == 1023)
{
// Yes:
// Find the starting shape id of the next free cluster
newShapeId = findFreeSPIDBlock();
// Create a new cluster in the dgg record.
dgg.addCluster(drawingGroupId, 1);
}
else
{
// No:
// Find the cluster for this drawing group with free space.
for (int i = 0; i < dgg.getFileIdClusters().length; i++)
{
EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
if (c.getDrawingGroupId() == drawingGroupId)
{
if (c.getNumShapeIdsUsed() != 1024)
{
// Increment the number of shapes used for this cluster.
c.incrementShapeId();
}
}
// If the last shape id = -1 then we know to find a free block;
if (dg.getLastMSOSPID() == -1)
{
newShapeId = findFreeSPIDBlock();
}
else
{
// The new shape id to be the last shapeid of this cluster + 1
newShapeId = dg.getLastMSOSPID() + 1;
}
}
}
// Increment the total number of shapes used in the dgg.
dgg.setNumShapesSaved(dgg.getNumShapesSaved() + 1);
// Is the new shape id >= max shape id for dgg?
if (newShapeId >= dgg.getShapeIdMax())
{
// Yes:
// Set the max shape id = new shape id + 1
dgg.setShapeIdMax(newShapeId + 1);
}
// Set last shape id for this drawing group.
dg.setLastMSOSPID(newShapeId);
// Increased the number of shapes used for this drawing group.
dg.incrementShapeCount();
return newShapeId;
}
//////////// Non-public methods /////////////
short findNewDrawingGroupId()
{
short dgId = 1;
while ( drawingGroupExists( dgId ) )
dgId++;
return dgId;
}
boolean drawingGroupExists( short dgId )
{
for ( int i = 0; i < dgg.getFileIdClusters().length; i++ )
{
if ( dgg.getFileIdClusters()[i].getDrawingGroupId() == dgId )
return true;
}
return false;
}
int findFreeSPIDBlock()
{
int max = dgg.getShapeIdMax();
int next = ( ( max / 1024 ) + 1 ) * 1024;
return next;
}
public EscherDggRecord getDgg()
{
return dgg;
}
}

View File

@ -0,0 +1,105 @@
package org.apache.poi.hssf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.usermodel.*;
/**
* Represents a line shape and creates all the line specific low level records.
*
* @author Glen Stampoultzis (glens at apache.org)
*/
public class LineShape
extends AbstractShape
{
private EscherContainerRecord spContainer;
private ObjRecord objRecord;
/**
* Creates the line shape from the highlevel user shape. All low level
* records are created at this point.
*
* @param hssfShape The user model shape.
* @param shapeId The identifier to use for this shape.
*/
LineShape( HSSFSimpleShape hssfShape, int shapeId )
{
spContainer = createSpContainer(hssfShape, shapeId);
objRecord = createObjRecord(hssfShape, shapeId);
}
/**
* Creates the lowerlevel escher records for this shape.
*/
private EscherContainerRecord createSpContainer(HSSFSimpleShape hssfShape, int shapeId)
{
HSSFShape shape = hssfShape;
EscherContainerRecord spContainer = new EscherContainerRecord();
EscherSpRecord sp = new EscherSpRecord();
EscherOptRecord opt = new EscherOptRecord();
EscherRecord anchor = new EscherClientAnchorRecord();
EscherClientDataRecord clientData = new EscherClientDataRecord();
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
spContainer.setOptions( (short) 0x000F );
sp.setRecordId( EscherSpRecord.RECORD_ID );
sp.setOptions( (short) ( (EscherAggregate.ST_LINE << 4) | 0x2 ) );
sp.setShapeId( shapeId );
sp.setFlags( EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE );
opt.setRecordId( EscherOptRecord.RECORD_ID );
opt.addEscherProperty( new EscherShapePathProperty( EscherProperties.GEOMETRY__SHAPEPATH, EscherShapePathProperty.COMPLEX ) );
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.LINESTYLE__NOLINEDRAWDASH, 1048592 ) );
addStandardOptions(shape, opt);
HSSFAnchor userAnchor = shape.getAnchor();
if (userAnchor.isHorizontallyFlipped())
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPHORIZ);
if (userAnchor.isVerticallyFlipped())
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPVERT);
anchor = createAnchor(userAnchor);
clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
clientData.setOptions( (short) 0x0000 );
spContainer.addChildRecord(sp);
spContainer.addChildRecord(opt);
spContainer.addChildRecord(anchor);
spContainer.addChildRecord(clientData);
return spContainer;
}
/**
* Creates the low level OBJ record for this shape.
*/
private ObjRecord createObjRecord(HSSFShape hssfShape, int shapeId)
{
HSSFShape shape = hssfShape;
ObjRecord obj = new ObjRecord();
CommonObjectDataSubRecord c = new CommonObjectDataSubRecord();
c.setObjectType((short) ((HSSFSimpleShape)shape).getShapeType());
c.setObjectId((short) ( shapeId ));
c.setLocked(true);
c.setPrintable(true);
c.setAutofill(true);
c.setAutoline(true);
EndSubRecord e = new EndSubRecord();
obj.addSubRecord(c);
obj.addSubRecord(e);
return obj;
}
public EscherContainerRecord getSpContainer()
{
return spContainer;
}
public ObjRecord getObjRecord()
{
return objRecord;
}
}

View File

@ -0,0 +1,143 @@
package org.apache.poi.hssf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.hssf.record.EscherAggregate;
import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
import org.apache.poi.hssf.record.EndSubRecord;
import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
import org.apache.poi.hssf.usermodel.HSSFShape;
import org.apache.poi.hssf.usermodel.HSSFPolygon;
import org.apache.poi.util.LittleEndian;
public class PolygonShape
extends AbstractShape
{
public final static short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 30;
private EscherContainerRecord spContainer;
private ObjRecord objRecord;
/**
* Creates the low evel records for an polygon.
*
* @param hssfShape The highlevel shape.
* @param shapeId The shape id to use for this shape.
*/
PolygonShape( HSSFPolygon hssfShape, int shapeId )
{
spContainer = createSpContainer( hssfShape, shapeId );
objRecord = createObjRecord( hssfShape, shapeId );
}
/**
* Generates the shape records for this shape.
*
*/
private EscherContainerRecord createSpContainer( HSSFPolygon hssfShape, int shapeId )
{
HSSFShape shape = hssfShape;
EscherContainerRecord spContainer = new EscherContainerRecord();
EscherSpRecord sp = new EscherSpRecord();
EscherOptRecord opt = new EscherOptRecord();
EscherClientDataRecord clientData = new EscherClientDataRecord();
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
spContainer.setOptions( (short) 0x000F );
sp.setRecordId( EscherSpRecord.RECORD_ID );
sp.setOptions( (short) ( ( EscherAggregate.ST_DONUT << 4 ) | 0x2 ) );
sp.setShapeId( shapeId );
if (hssfShape.getParent() == null)
sp.setFlags( EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE );
else
sp.setFlags( EscherSpRecord.FLAG_CHILD | EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE );
opt.setRecordId( EscherOptRecord.RECORD_ID );
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.TRANSFORM__ROTATION, false, false, 0));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__RIGHT, false, false, hssfShape.getDrawAreaWidth()));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__BOTTOM, false, false, hssfShape.getDrawAreaHeight()));
opt.addEscherProperty(new EscherShapePathProperty(EscherProperties.GEOMETRY__SHAPEPATH, EscherShapePathProperty.COMPLEX));
EscherArrayProperty verticesProp = new EscherArrayProperty(EscherProperties.GEOMETRY__VERTICES, false, new byte[0] );
verticesProp.setNumberOfElementsInArray(hssfShape.getXPoints().length+1);
verticesProp.setNumberOfElementsInMemory(hssfShape.getXPoints().length+1);
verticesProp.setSizeOfElements(0xFFF0);
for (int i = 0; i < hssfShape.getXPoints().length; i++)
{
byte[] data = new byte[4];
LittleEndian.putShort(data, 0, (short)hssfShape.getXPoints()[i]);
LittleEndian.putShort(data, 2, (short)hssfShape.getYPoints()[i]);
verticesProp.setElement(i, data);
}
int point = hssfShape.getXPoints().length;
byte[] data = new byte[4];
LittleEndian.putShort(data, 0, (short)hssfShape.getXPoints()[0]);
LittleEndian.putShort(data, 2, (short)hssfShape.getYPoints()[0]);
verticesProp.setElement(point, data);
opt.addEscherProperty(verticesProp);
EscherArrayProperty segmentsProp = new EscherArrayProperty(EscherProperties.GEOMETRY__SEGMENTINFO, false, null );
segmentsProp.setSizeOfElements(0x0002);
segmentsProp.setNumberOfElementsInArray(hssfShape.getXPoints().length * 2 + 4);
segmentsProp.setNumberOfElementsInMemory(hssfShape.getXPoints().length * 2 + 4);
segmentsProp.setElement(0, new byte[] { (byte)0x00, (byte)0x40 } );
segmentsProp.setElement(1, new byte[] { (byte)0x00, (byte)0xAC } );
for (int i = 0; i < hssfShape.getXPoints().length; i++)
{
segmentsProp.setElement(2 + i * 2, new byte[] { (byte)0x01, (byte)0x00 } );
segmentsProp.setElement(3 + i * 2, new byte[] { (byte)0x00, (byte)0xAC } );
}
segmentsProp.setElement(segmentsProp.getNumberOfElementsInArray() - 2, new byte[] { (byte)0x01, (byte)0x60 } );
segmentsProp.setElement(segmentsProp.getNumberOfElementsInArray() - 1, new byte[] { (byte)0x00, (byte)0x80 } );
opt.addEscherProperty(segmentsProp);
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__FILLOK, false, false, 0x00010001));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__LINESTARTARROWHEAD, false, false, 0x0));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__LINEENDARROWHEAD, false, false, 0x0));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__LINEENDCAPSTYLE, false, false, 0x0));
addStandardOptions(shape, opt);
EscherRecord anchor = createAnchor( shape.getAnchor() );
clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
clientData.setOptions( (short) 0x0000 );
spContainer.addChildRecord( sp );
spContainer.addChildRecord( opt );
spContainer.addChildRecord( anchor );
spContainer.addChildRecord( clientData );
return spContainer;
}
/**
* Creates the low level OBJ record for this shape.
*/
private ObjRecord createObjRecord( HSSFShape hssfShape, int shapeId )
{
HSSFShape shape = hssfShape;
ObjRecord obj = new ObjRecord();
CommonObjectDataSubRecord c = new CommonObjectDataSubRecord();
c.setObjectType( OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING );
c.setObjectId( (short) ( shapeId ) );
c.setLocked( true );
c.setPrintable( true );
c.setAutofill( true );
c.setAutoline( true );
EndSubRecord e = new EndSubRecord();
obj.addSubRecord( c );
obj.addSubRecord( e );
return obj;
}
public EscherContainerRecord getSpContainer()
{
return spContainer;
}
public ObjRecord getObjRecord()
{
return objRecord;
}
}

View File

@ -55,16 +55,18 @@
package org.apache.poi.hssf.model; package org.apache.poi.hssf.model;
import java.util.List; import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.util.IntList;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import org.apache.poi.hssf
.record.*; // normally I don't do this, buy we literally mean ALL
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.util.*;
import org.apache.poi.hssf.record
.aggregates.*; // normally I don't do this, buy we literally mean ALL
/** /**
* Low level model implementation of a Sheet (one workbook contains many sheets) * Low level model implementation of a Sheet (one workbook contains many sheets)
@ -795,12 +797,17 @@ public class Sheet implements Model
// System.arraycopy(rec, 0, data, offset + pos, rec.length); // System.arraycopy(rec, 0, data, offset + pos, rec.length);
Record record = (( Record ) records.get(k)); Record record = (( Record ) records.get(k));
//uncomment to test record sizes //// uncomment to test record sizes ////
// System.out.println( record.getClass().getName() );
// byte[] data2 = new byte[record.getRecordSize()]; // byte[] data2 = new byte[record.getRecordSize()];
// record.serialize(0, data2 ); // rec.length; // record.serialize(0, data2 ); // rec.length;
// if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4 // if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4
// && record instanceof RowRecordsAggregate == false && record instanceof ValueRecordsAggregate == false) // && record instanceof RowRecordsAggregate == false
// throw new RuntimeException("Blah!!!"); // && record instanceof ValueRecordsAggregate == false
// && record instanceof EscherAggregate == false)
// {
// throw new RuntimeException("Blah!!! Size off by " + ( LittleEndian.getUShort(data2, 2) - record.getRecordSize() - 4) + " records.");
// }
pos += record.serialize(pos + offset, data ); // rec.length; pos += record.serialize(pos + offset, data ); // rec.length;
@ -2623,6 +2630,60 @@ public class Sheet implements Model
return margins; return margins;
} }
public int aggregateDrawingRecords(DrawingManager drawingManager)
{
int loc = findFirstRecordLocBySid(DrawingRecord.sid);
boolean noDrawingRecordsFound = loc == -1;
if (noDrawingRecordsFound)
{
EscherAggregate aggregate = new EscherAggregate( drawingManager );
loc = findFirstRecordLocBySid(EscherAggregate.sid);
if (loc == -1)
{
loc = findFirstRecordLocBySid( WindowTwoRecord.sid );
}
else
{
getRecords().remove(loc);
}
getRecords().add( loc, aggregate );
return loc;
}
else
{
List records = getRecords();
EscherAggregate r = EscherAggregate.createAggregate( records, loc, drawingManager );
int startloc = loc;
while ( loc + 1 < records.size()
&& records.get( loc ) instanceof DrawingRecord
&& records.get( loc + 1 ) instanceof ObjRecord )
{
loc += 2;
}
int endloc = loc-1;
for(int i = 0; i < (endloc - startloc + 1); i++)
records.remove(startloc);
records.add(startloc, r);
return startloc;
}
}
/**
* Perform any work necessary before the sheet is about to be serialized.
* For instance the escher aggregates size needs to be calculated before
* serialization so that the dgg record (which occurs first) can be written.
*/
public void preSerialize()
{
for ( Iterator iterator = getRecords().iterator(); iterator.hasNext(); )
{
Record r = (Record) iterator.next();
if (r instanceof EscherAggregate)
r.getRecordSize(); // Trigger flatterning of user model and corresponding update of dgg record.
}
}
/** /**
* Shifts all the page breaks in the range "count" number of rows/columns * Shifts all the page breaks in the range "count" number of rows/columns
* @param breaks The page record to be shifted * @param breaks The page record to be shifted

View File

@ -0,0 +1,111 @@
package org.apache.poi.hssf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.hssf.record.EscherAggregate;
import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
import org.apache.poi.hssf.record.EndSubRecord;
import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
import org.apache.poi.hssf.usermodel.HSSFShape;
public class SimpleFilledShape
extends AbstractShape
{
private EscherContainerRecord spContainer;
private ObjRecord objRecord;
/**
* Creates the low evel records for an oval.
*
* @param hssfShape The highlevel shape.
* @param shapeId The shape id to use for this shape.
*/
SimpleFilledShape( HSSFSimpleShape hssfShape, int shapeId )
{
spContainer = createSpContainer( hssfShape, shapeId );
objRecord = createObjRecord( hssfShape, shapeId );
}
/**
* Generates the shape records for this shape.
*
* @param hssfShape
* @param shapeId
* @return
*/
private EscherContainerRecord createSpContainer( HSSFSimpleShape hssfShape, int shapeId )
{
HSSFShape shape = hssfShape;
EscherContainerRecord spContainer = new EscherContainerRecord();
EscherSpRecord sp = new EscherSpRecord();
EscherOptRecord opt = new EscherOptRecord();
EscherClientDataRecord clientData = new EscherClientDataRecord();
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
spContainer.setOptions( (short) 0x000F );
sp.setRecordId( EscherSpRecord.RECORD_ID );
short shapeType = objTypeToShapeType( hssfShape.getShapeType() );
sp.setOptions( (short) ( ( shapeType << 4 ) | 0x2 ) );
sp.setShapeId( shapeId );
sp.setFlags( EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE );
opt.setRecordId( EscherOptRecord.RECORD_ID );
addStandardOptions(shape, opt);
EscherRecord anchor = createAnchor( shape.getAnchor() );
clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
clientData.setOptions( (short) 0x0000 );
spContainer.addChildRecord( sp );
spContainer.addChildRecord( opt );
spContainer.addChildRecord( anchor );
spContainer.addChildRecord( clientData );
return spContainer;
}
private short objTypeToShapeType( int objType )
{
short shapeType;
if (objType == HSSFSimpleShape.OBJECT_TYPE_OVAL)
shapeType = EscherAggregate.ST_ELLIPSE;
else if (objType == HSSFSimpleShape.OBJECT_TYPE_RECTANGLE)
shapeType = EscherAggregate.ST_RECTANGLE;
else
throw new IllegalArgumentException("Unable to handle an object of this type");
return shapeType;
}
/**
* Creates the low level OBJ record for this shape.
*/
private ObjRecord createObjRecord( HSSFShape hssfShape, int shapeId )
{
HSSFShape shape = hssfShape;
ObjRecord obj = new ObjRecord();
CommonObjectDataSubRecord c = new CommonObjectDataSubRecord();
c.setObjectType( (short) ( (HSSFSimpleShape) shape ).getShapeType() );
c.setObjectId( (short) ( shapeId ) );
c.setLocked( true );
c.setPrintable( true );
c.setAutofill( true );
c.setAutoline( true );
EndSubRecord e = new EndSubRecord();
obj.addSubRecord( c );
obj.addSubRecord( e );
return obj;
}
public EscherContainerRecord getSpContainer()
{
return spContainer;
}
public ObjRecord getObjRecord()
{
return objRecord;
}
}

View File

@ -0,0 +1,151 @@
package org.apache.poi.hssf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.usermodel.*;
/**
* Represents an textbox shape and converts between the highlevel records
* and lowlevel records for an oval.
*
* @author Glen Stampoultzis (glens at apache.org)
*/
public class TextboxShape
extends AbstractShape
{
private EscherContainerRecord spContainer;
private TextObjectRecord textObjectRecord;
private ObjRecord objRecord;
private EscherTextboxRecord escherTextbox;
/**
* Creates the low evel records for an textbox.
*
* @param hssfShape The highlevel shape.
* @param shapeId The shape id to use for this shape.
*/
TextboxShape( HSSFTextbox hssfShape, int shapeId )
{
spContainer = createSpContainer( hssfShape, shapeId );
objRecord = createObjRecord( hssfShape, shapeId );
textObjectRecord = createTextObjectRecord( hssfShape, shapeId );
}
/**
* Creates the low level OBJ record for this shape.
*/
private ObjRecord createObjRecord( HSSFTextbox hssfShape, int shapeId )
{
HSSFShape shape = hssfShape;
ObjRecord obj = new ObjRecord();
CommonObjectDataSubRecord c = new CommonObjectDataSubRecord();
c.setObjectType( (short) ( (HSSFSimpleShape) shape ).getShapeType() );
c.setObjectId( (short) ( shapeId ) );
c.setLocked( true );
c.setPrintable( true );
c.setAutofill( true );
c.setAutoline( true );
EndSubRecord e = new EndSubRecord();
obj.addSubRecord( c );
obj.addSubRecord( e );
return obj;
}
/**
* Generates the escher shape records for this shape.
*
* @param hssfShape
* @param shapeId
* @return
*/
private EscherContainerRecord createSpContainer( HSSFTextbox hssfShape, int shapeId )
{
HSSFTextbox shape = hssfShape;
EscherContainerRecord spContainer = new EscherContainerRecord();
EscherSpRecord sp = new EscherSpRecord();
EscherOptRecord opt = new EscherOptRecord();
EscherRecord anchor = new EscherClientAnchorRecord();
EscherClientDataRecord clientData = new EscherClientDataRecord();
escherTextbox = new EscherTextboxRecord();
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
spContainer.setOptions( (short) 0x000F );
sp.setRecordId( EscherSpRecord.RECORD_ID );
sp.setOptions( (short) ( ( EscherAggregate.ST_TEXTBOX << 4 ) | 0x2 ) );
sp.setShapeId( shapeId );
sp.setFlags( EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE );
opt.setRecordId( EscherOptRecord.RECORD_ID );
// opt.addEscherProperty( new EscherBoolProperty( EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144 ) );
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.TEXT__TEXTID, 0 ) );
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.TEXT__TEXTLEFT, shape.getMarginLeft() ) );
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.TEXT__TEXTRIGHT, shape.getMarginRight() ) );
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.TEXT__TEXTBOTTOM, shape.getMarginBottom() ) );
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.TEXT__TEXTTOP, shape.getMarginTop() ) );
addStandardOptions( shape, opt );
HSSFAnchor userAnchor = shape.getAnchor();
// if (userAnchor.isHorizontallyFlipped())
// sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPHORIZ);
// if (userAnchor.isVerticallyFlipped())
// sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPVERT);
anchor = createAnchor( userAnchor );
clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
clientData.setOptions( (short) 0x0000 );
escherTextbox.setRecordId( EscherTextboxRecord.RECORD_ID );
escherTextbox.setOptions( (short) 0x0000 );
spContainer.addChildRecord( sp );
spContainer.addChildRecord( opt );
spContainer.addChildRecord( anchor );
spContainer.addChildRecord( clientData );
spContainer.addChildRecord( escherTextbox );
return spContainer;
}
/**
* Textboxes also have an extra TXO record associated with them that most
* other shapes dont have.
*/
private TextObjectRecord createTextObjectRecord( HSSFTextbox hssfShape, int shapeId )
{
HSSFTextbox shape = hssfShape;
TextObjectRecord obj = new TextObjectRecord();
obj.setHorizontalTextAlignment( TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED );
obj.setVerticalTextAlignment( TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP );
obj.setTextLocked( true );
obj.setTextOrientation( TextObjectRecord.TEXT_ORIENTATION_NONE );
int frLength = ( shape.getString().numFormattingRuns() + 1 ) * 8;
obj.setFormattingRunLength( (short) frLength );
obj.setTextLength( (short) shape.getString().length() );
obj.setStr( shape.getString() );
obj.setReserved7( 0 );
return obj;
}
public EscherContainerRecord getSpContainer()
{
return spContainer;
}
public ObjRecord getObjRecord()
{
return objRecord;
}
public TextObjectRecord getTextObjectRecord()
{
return textObjectRecord;
}
public EscherRecord getEscherTextbox()
{
return escherTextbox;
}
}

View File

@ -58,8 +58,10 @@ package org.apache.poi.hssf.model;
import org.apache.poi.hssf.record.*; import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.hssf.util.SheetReferences; import org.apache.poi.hssf.util.SheetReferences;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.ddf.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
@ -91,7 +93,8 @@ import java.util.Locale;
* @version 1.0-pre * @version 1.0-pre
*/ */
public class Workbook implements Model { public class Workbook implements Model
{
private static final int DEBUG = POILogger.DEBUG; private static final int DEBUG = POILogger.DEBUG;
// public static Workbook currentBook = null; // public static Workbook currentBook = null;
@ -133,6 +136,7 @@ public class Workbook implements Model {
protected int numfonts = 0; // hold the number of font records protected int numfonts = 0; // hold the number of font records
private short maxformatid = -1; // holds the max format id private short maxformatid = -1; // holds the max format id
private boolean uses1904datewindowing = false; // whether 1904 date windowing is being used private boolean uses1904datewindowing = false; // whether 1904 date windowing is being used
private DrawingManager drawingManager;
private static POILogger log = POILogFactory.getLogger(Workbook.class); private static POILogger log = POILogFactory.getLogger(Workbook.class);
@ -2081,6 +2085,56 @@ public class Workbook implements Model {
return palette; return palette;
} }
/**
* Creates a drawing group record. If it already exists then it's left
* alone.
*/
public void createDrawingGroup()
{
int dggLoc = findFirstRecordLocBySid(EscherContainerRecord.DGG_CONTAINER);
if (dggLoc == -1)
{
EscherContainerRecord dggContainer = new EscherContainerRecord();
EscherDggRecord dgg = new EscherDggRecord();
EscherOptRecord opt = new EscherOptRecord();
EscherSplitMenuColorsRecord splitMenuColors = new EscherSplitMenuColorsRecord();
dggContainer.setRecordId((short) 0xF000);
dggContainer.setOptions((short) 0x000F);
dgg.setRecordId(EscherDggRecord.RECORD_ID);
dgg.setOptions((short)0x0000);
dgg.setShapeIdMax(1024);
dgg.setNumShapesSaved(0);
dgg.setDrawingsSaved(0);
dgg.setFileIdClusters(new EscherDggRecord.FileIdCluster[] {} );
drawingManager = new DrawingManager(dgg);
opt.setRecordId((short) 0xF00B);
opt.setOptions((short) 0x0033);
opt.addEscherProperty( new EscherBoolProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 524296) );
opt.addEscherProperty( new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, 134217737) );
opt.addEscherProperty( new EscherRGBProperty(EscherProperties.LINESTYLE__COLOR, 134217792) );
splitMenuColors.setRecordId((short) 0xF11E);
splitMenuColors.setOptions((short) 0x0040);
splitMenuColors.setColor1(0x0800000D);
splitMenuColors.setColor2(0x0800000C);
splitMenuColors.setColor3(0x08000017);
splitMenuColors.setColor4(0x100000F7);
dggContainer.addChildRecord(dgg);
dggContainer.addChildRecord(opt);
dggContainer.addChildRecord(splitMenuColors);
DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
drawingGroup.addEscherRecord(dggContainer);
int loc = findFirstRecordLocBySid(CountryRecord.sid);
getRecords().add(loc+1, drawingGroup);
}
}
public DrawingManager getDrawingManager()
{
return drawingManager;
}
} }