implemented cloning of shapes

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/gsoc2012@1363479 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Evgeniy Berlog 2012-07-19 19:02:43 +00:00
parent 57f0fe06b9
commit 426ef18c61
23 changed files with 376 additions and 676 deletions

View File

@ -354,9 +354,9 @@ public final class InternalSheet {
// EscherAggregate is used only as a container for SODRAWING and OBJ record combinations
// So, if the container is empty, there is no reason to clone this record
// See https://issues.apache.org/bugzilla/show_bug.cgi?id=49529
if (0 == rb.getRecordSize()){
// if (0 == rb.getRecordSize()){
continue;
}
// }
}
Record rec = (Record) ((Record) rb).clone();
clonedRecords.add(rec);

View File

@ -22,27 +22,16 @@ import java.io.IOException;
import java.util.*;
import org.apache.poi.ddf.DefaultEscherRecordFactory;
import org.apache.poi.ddf.EscherBoolProperty;
import org.apache.poi.ddf.EscherChildAnchorRecord;
import org.apache.poi.ddf.EscherClientAnchorRecord;
import org.apache.poi.ddf.EscherClientDataRecord;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherDgRecord;
import org.apache.poi.ddf.EscherDggRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherRecordFactory;
import org.apache.poi.ddf.EscherSerializationListener;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.ddf.EscherSpgrRecord;
import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.hssf.model.AbstractShape;
import org.apache.poi.hssf.model.CommentShape;
import org.apache.poi.hssf.model.ConvertAnchor;
import org.apache.poi.hssf.model.DrawingManager2;
import org.apache.poi.hssf.model.TextboxShape;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -313,8 +302,6 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
* Maps shape container objects to their {@link TextObjectRecord} or {@link ObjRecord}
*/
private final Map<EscherRecord, Record> shapeToObj = new HashMap<EscherRecord, Record>();
private DrawingManager2 drawingManager;
private short drawingGroupId;
/**
* list of "tail" records that need to be serialized after all drawing group records
@ -326,11 +313,6 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
}
public EscherAggregate(DrawingManager2 drawingManager) {
this.drawingManager = drawingManager;
}
public DrawingManager2 getDrawingManager() {
return drawingManager;
}
/**
@ -458,8 +440,6 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
// replace drawing block with the created EscherAggregate
records.subList(locFirstDrawingRecord, locLastDrawingRecord).clear();
records.add(locFirstDrawingRecord, agg);
return agg;
}
@ -472,14 +452,11 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
* @return The number of bytes serialized.
*/
public int serialize(int offset, byte[] data) {
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();
@ -594,8 +571,6 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
}
public int getRecordSize() {
// TODO - convert this to RecordAggregate
convertUserModelToRecords();
// To determine size of aggregate record we have to know size of each DrawingRecord because if DrawingRecord
// is split into several continue records we have to add header size to total EscherAggregate size
int continueRecordsHeadersSize = 0;
@ -657,249 +632,6 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
shapeToObj.remove(rec);
}
public HSSFPatriarch getPatriarch() {
return patriarch;
}
public void setPatriarch(HSSFPatriarch patriarch) {
this.patriarch = patriarch;
}
/**
* Converts the Records into UserModel
* objects on the bound HSSFPatriarch
*/
public void convertRecordsToUserModel() {
if (patriarch == null) {
throw new IllegalStateException("Must call setPatriarch() first");
}
// The top level container ought to have
// the DgRecord and the container of one container
// per shape group (patriach overall first)
EscherContainerRecord topContainer = getEscherContainer();
if (topContainer == null) {
return;
}
topContainer = topContainer.getChildContainers().get(0);
List tcc = topContainer.getChildContainers();
if (tcc.size() == 0) {
throw new IllegalStateException("No child escher containers at the point that should hold the patriach data, and one container per top level shape!");
}
// First up, get the patriach position
// This is in the first EscherSpgrRecord, in
// the first container, with a EscherSRecord too
EscherContainerRecord patriachContainer =
(EscherContainerRecord) tcc.get(0);
EscherSpgrRecord spgr = null;
for (Iterator<EscherRecord> it = patriachContainer.getChildIterator(); it.hasNext(); ) {
EscherRecord r = it.next();
if (r instanceof EscherSpgrRecord) {
spgr = (EscherSpgrRecord) r;
break;
}
}
if (spgr != null) {
patriarch.setCoordinates(
spgr.getRectX1(), spgr.getRectY1(),
spgr.getRectX2(), spgr.getRectY2()
);
}
convertRecordsToUserModelRecursive(tcc, patriarch, null);
// Now, clear any trace of what records make up
// the patriarch
// Otherwise, everything will go horribly wrong
// when we try to write out again....
// clearEscherRecords();
drawingManager.getDgg().setFileIdClusters(new EscherDggRecord.FileIdCluster[0]);
// TODO: Support converting our records
// back into shapes
// log.log(POILogger.WARN, "Not processing objects into Patriarch!");
}
private static void convertRecordsToUserModelRecursive(List tcc, HSSFShapeContainer container, HSSFShape parent) {
// Now process the containers for each group
// and objects
for (int i = 1; i < tcc.size(); i++) {
EscherContainerRecord shapeContainer = (EscherContainerRecord) tcc.get(i);
// Could be a group, or a base object
if (shapeContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
// Group
final int shapeChildren = shapeContainer.getChildRecords().size();
if (shapeChildren > 0) {
HSSFShapeGroup group = new HSSFShapeGroup(parent, new HSSFClientAnchor());
addToParentOrContainer(group, container, parent);
EscherContainerRecord groupContainer = (EscherContainerRecord) shapeContainer.getChild(0);
convertRecordsToUserModel(groupContainer, group);
if (shapeChildren > 1) {
convertRecordsToUserModelRecursive(shapeContainer.getChildRecords(), container, group);
}
} else {
log.log(POILogger.WARN,
"Found drawing group without children.");
}
} else if (shapeContainer.getRecordId() == EscherContainerRecord.SP_CONTAINER) {
EscherSpRecord spRecord = shapeContainer
.getChildById(EscherSpRecord.RECORD_ID);
int type = spRecord.getShapeType();
switch (type) {
case ST_TEXTBOX:
HSSFTextbox box = new HSSFTextbox(parent,
new HSSFClientAnchor());
addToParentOrContainer(box, container, parent);
convertRecordsToUserModel(shapeContainer, box);
break;
case ST_PICTUREFRAME:
// Duplicated from
// org.apache.poi.hslf.model.Picture.getPictureIndex()
EscherOptRecord opt = (EscherOptRecord) getEscherChild(
shapeContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty) opt.lookup(
EscherProperties.BLIP__BLIPTODISPLAY);
if (prop == null) {
log.log(POILogger.WARN,
"Picture index for picture shape not found.");
} else {
int pictureIndex = prop.getPropertyValue();
EscherClientAnchorRecord anchorRecord = (EscherClientAnchorRecord) getEscherChild(
shapeContainer,
EscherClientAnchorRecord.RECORD_ID);
EscherChildAnchorRecord childRecord = (EscherChildAnchorRecord) getEscherChild(
shapeContainer,
EscherChildAnchorRecord.RECORD_ID);
if (anchorRecord != null && childRecord != null) {
log.log(POILogger.WARN, "Picture with both CLIENT and CHILD anchor: " + type);
}
HSSFAnchor anchor;
if (anchorRecord != null) {
anchor = toClientAnchor(anchorRecord);
} else {
anchor = toChildAnchor(childRecord);
}
HSSFPicture picture = new HSSFPicture(parent, anchor);
picture.setPictureIndex(pictureIndex);
addToParentOrContainer(picture, container, parent);
}
break;
default:
final HSSFSimpleShape shape = new HSSFSimpleShape(parent,
new HSSFClientAnchor());
addToParentOrContainer(shape, container, parent);
convertRecordsToUserModel(shapeContainer, shape);
log.log(POILogger.WARN, "Unhandled shape type: "
+ type);
break;
}
} else {
log.log(POILogger.WARN, "Unexpected record id of shape group.");
}
}
}
private static void addToParentOrContainer(HSSFShape shape, HSSFShapeContainer container, HSSFShape parent) {
if (parent instanceof HSSFShapeGroup)
((HSSFShapeGroup) parent).addShape(shape);
else if (container instanceof HSSFPatriarch)
((HSSFPatriarch) container).addShape(shape);
else
container.getChildren().add(shape);
}
public static HSSFClientAnchor toClientAnchor(EscherClientAnchorRecord anchorRecord) {
HSSFClientAnchor anchor = new HSSFClientAnchor();
anchor.setAnchorType(anchorRecord.getFlag());
anchor.setCol1(anchorRecord.getCol1());
anchor.setCol2(anchorRecord.getCol2());
anchor.setDx1(anchorRecord.getDx1());
anchor.setDx2(anchorRecord.getDx2());
anchor.setDy1(anchorRecord.getDy1());
anchor.setDy2(anchorRecord.getDy2());
anchor.setRow1(anchorRecord.getRow1());
anchor.setRow2(anchorRecord.getRow2());
return anchor;
}
public static HSSFChildAnchor toChildAnchor(EscherChildAnchorRecord anchorRecord) {
HSSFChildAnchor anchor = new HSSFChildAnchor();
// anchor.setAnchorType(anchorRecord.getFlag());
// anchor.setCol1( anchorRecord.getCol1() );
// anchor.setCol2( anchorRecord.getCol2() );
anchor.setDx1(anchorRecord.getDx1());
anchor.setDx2(anchorRecord.getDx2());
anchor.setDy1(anchorRecord.getDy1());
anchor.setDy2(anchorRecord.getDy2());
// anchor.setRow1( anchorRecord.getRow1() );
// anchor.setRow2( anchorRecord.getRow2() );
return anchor;
}
private static void convertRecordsToUserModel(EscherContainerRecord shapeContainer, Object model) {
for (Iterator<EscherRecord> it = shapeContainer.getChildIterator(); it.hasNext(); ) {
EscherRecord r = it.next();
if (r instanceof EscherSpgrRecord) {
// This may be overriden by a later EscherClientAnchorRecord
EscherSpgrRecord spgr = (EscherSpgrRecord) r;
if (model instanceof HSSFShapeGroup) {
HSSFShapeGroup g = (HSSFShapeGroup) model;
g.setCoordinates(
spgr.getRectX1(), spgr.getRectY1(),
spgr.getRectX2(), spgr.getRectY2()
);
} else {
throw new IllegalStateException("Got top level anchor but not processing a group");
}
} else if (r instanceof EscherClientAnchorRecord) {
EscherClientAnchorRecord car = (EscherClientAnchorRecord) r;
if (model instanceof HSSFShape) {
HSSFShape g = (HSSFShape) model;
g.getAnchor().setDx1(car.getDx1());
g.getAnchor().setDx2(car.getDx2());
g.getAnchor().setDy1(car.getDy1());
g.getAnchor().setDy2(car.getDy2());
} else {
throw new IllegalStateException("Got top level anchor but not processing a group or shape");
}
} else if (r instanceof EscherTextboxRecord) {
EscherTextboxRecord tbr = (EscherTextboxRecord) r;
// Also need to find the TextObjectRecord too
// TODO
} else if (r instanceof EscherSpRecord) {
// Use flags if needed
final EscherSpRecord spr = (EscherSpRecord) r;
if (model instanceof HSSFShape) {
final HSSFShape s = (HSSFShape) model;
}
} else if (r instanceof EscherOptRecord) {
// Use properties if needed
} else {
//System.err.println(r);
}
}
}
public void clear() {
clearEscherRecords();
shapeToObj.clear();
@ -916,133 +648,6 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
return sid(records, loc) == ObjRecord.sid || sid(records, loc) == TextObjectRecord.sid;
}
private void convertUserModelToRecords() {
if (patriarch != null) {
shapeToObj.clear();
tailRec.clear();
clearEscherRecords();
if (patriarch.getChildren().size() != 0) {
convertPatriarch(patriarch);
EscherContainerRecord dgContainer = (EscherContainerRecord) getEscherRecord(0);
EscherContainerRecord spgrContainer = null;
Iterator<EscherRecord> iter = dgContainer.getChildIterator();
while (iter.hasNext()) {
EscherRecord child = iter.next();
if (child.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
spgrContainer = (EscherContainerRecord) child;
}
}
convertShapes(patriarch, spgrContainer, shapeToObj);
patriarch = null;
}
}
}
private void convertShapes(HSSFShapeContainer parent, EscherContainerRecord escherParent, 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.put(comment.getNoteRecord().getShapeId(), comment.getNoteRecord());
}
}
escherParent.addChildRecord(shapeModel.getSpContainer());
}
}
// drawingManager.newCluster( (short)1 );
// drawingManager.newCluster( (short)2 );
}
private void convertGroup(HSSFShapeGroup shape, EscherContainerRecord escherParent, 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(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 EscherRecord findClientData(EscherContainerRecord spContainer) {
for (Iterator<EscherRecord> iterator = spContainer.getChildIterator(); iterator.hasNext(); ) {
EscherRecord r = iterator.next();
@ -1067,7 +672,6 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
dg.setOptions((short) (dgId << 4));
dg.setNumShapes(0);
dg.setLastMSOSPID(1024);
drawingGroupId = dg.getDrawingGroupId();
spgrContainer.setRecordId(EscherContainerRecord.SPGR_CONTAINER);
spgrContainer.setOptions((short) 0x000F);
spContainer1.setRecordId(EscherContainerRecord.SP_CONTAINER);
@ -1105,46 +709,6 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
sp.setShapeId(shapeId);
}
private void convertPatriarch(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 static short sid(List records, int loc) {
return ((Record) records.get(loc)).getSid();
}

View File

@ -18,6 +18,11 @@ public class HSSFCombobox extends HSSFSimpleShape {
super.setShapeType(OBJECT_TYPE_COMBO_BOX);
}
@Override
protected TextObjectRecord createTextObjRecord() {
return null;
}
@Override
protected EscherContainerRecord createSpContainer() {
EscherContainerRecord spContainer = new EscherContainerRecord();

View File

@ -70,7 +70,7 @@ public class HSSFComment extends HSSFTextbox implements Comment {
@Override
void afterInsert(HSSFPatriarch patriarch) {
super.afterInsert(patriarch);
_patriarch._getBoundAggregate().addTailRecord(getNoteRecord());
patriarch._getBoundAggregate().addTailRecord(getNoteRecord());
}
@Override
@ -113,8 +113,8 @@ public class HSSFComment extends HSSFTextbox implements Comment {
void setShapeId(int shapeId) {
super.setShapeId(shapeId);
CommonObjectDataSubRecord cod = (CommonObjectDataSubRecord) getObjRecord().getSubRecords().get(0);
cod.setObjectId((short) (shapeId));
_note.setShapeId(shapeId);
cod.setObjectId((short) (shapeId % 1024));
_note.setShapeId(shapeId % 1024);
}
/**
@ -214,4 +214,15 @@ public class HSSFComment extends HSSFTextbox implements Comment {
patriarch._getBoundAggregate().removeShapeToObjRecord(getEscherContainer().getChildById(EscherTextboxRecord.RECORD_ID));
patriarch._getBoundAggregate().removeTailRecord(getNoteRecord());
}
@Override
public HSSFShape cloneShape() {
TextObjectRecord txo = (TextObjectRecord) getTextObjectRecord().cloneViaReserialise();
EscherContainerRecord spContainer = new EscherContainerRecord();
byte [] inSp = getEscherContainer().serialize();
spContainer.fillFields(inSp, 0, new DefaultEscherRecordFactory());
ObjRecord obj = (ObjRecord) getObjRecord().cloneViaReserialise();
NoteRecord note = (NoteRecord) getNoteRecord().cloneViaReserialise();
return new HSSFComment(spContainer, obj, txo, note);
}
}

View File

@ -21,22 +21,20 @@ package org.apache.poi.hssf.usermodel;
import java.io.IOException;
import java.util.Iterator;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord;
import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.hssf.record.SubRecord;
import org.apache.poi.ddf.*;
import org.apache.poi.hssf.record.*;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.util.HexDump;
/**
* Represents binary object (i.e. OLE) data stored in the file. Eg. A GIF, JPEG etc...
*
* <p/>
* Right now, 13, july, 2012 can not be created from scratch
*
* @author Daniel Noll
*/
public final class HSSFObjectData extends HSSFShape{
public final class HSSFObjectData extends HSSFShape {
/**
* Reference to the filesystem root, required for retrieving the object data.
*/
@ -56,7 +54,7 @@ public final class HSSFObjectData extends HSSFShape{
/**
* Gets the object data. Only call for ones that have
* data though. See {@link #hasDirectoryEntry()}
* data though. See {@link #hasDirectoryEntry()}
*
* @return the object data as an OLE2 directory.
* @throws IOException if there was an error reading the data.
@ -76,8 +74,8 @@ public final class HSSFObjectData extends HSSFShape{
/**
* Returns the data portion, for an ObjectData
* that doesn't have an associated POIFS Directory
* Entry
* that doesn't have an associated POIFS Directory
* Entry
*/
public byte[] getObjectData() {
return findObjectRecord().getObjectData();
@ -85,7 +83,7 @@ public final class HSSFObjectData extends HSSFShape{
/**
* Does this ObjectData have an associated POIFS
* Directory Entry?
* Directory Entry?
* (Not all do, those that don't have a data portion)
*/
public boolean hasDirectoryEntry() {
@ -98,7 +96,7 @@ public final class HSSFObjectData extends HSSFShape{
/**
* Finds the EmbeddedObjectRefSubRecord, or throws an
* Exception if there wasn't one
* Exception if there wasn't one
*/
protected EmbeddedObjectRefSubRecord findObjectRecord() {
Iterator<SubRecord> subRecordIter = getObjRecord().getSubRecords().iterator();
@ -106,7 +104,7 @@ public final class HSSFObjectData extends HSSFShape{
while (subRecordIter.hasNext()) {
Object subRecord = subRecordIter.next();
if (subRecord instanceof EmbeddedObjectRefSubRecord) {
return (EmbeddedObjectRefSubRecord)subRecord;
return (EmbeddedObjectRefSubRecord) subRecord;
}
}
@ -130,6 +128,39 @@ public final class HSSFObjectData extends HSSFShape{
@Override
void afterInsert(HSSFPatriarch patriarch) {
throw new IllegalStateException("HSSFObjectData cannot be created from scratch");
EscherAggregate agg = patriarch._getBoundAggregate();
agg.associateShapeToObjRecord(getEscherContainer().getChildById(EscherClientDataRecord.RECORD_ID), getObjRecord());
EscherBSERecord bse =
patriarch._sheet.getWorkbook().getWorkbook().getBSERecord(getPictureIndex());
bse.setRef(bse.getRef() + 1);
}
@Override
public HSSFShape cloneShape() {
EscherContainerRecord spContainer = new EscherContainerRecord();
byte[] inSp = getEscherContainer().serialize();
spContainer.fillFields(inSp, 0, new DefaultEscherRecordFactory());
ObjRecord obj = (ObjRecord) getObjRecord().cloneViaReserialise();
return new HSSFObjectData(spContainer, obj, _root);
}
public int getPictureIndex() {
EscherSimpleProperty property = getOptRecord().lookup(EscherProperties.BLIP__BLIPTODISPLAY);
if (null == property) {
return -1;
}
return property.getPropertyValue();
}
public void setPictureIndex(int pictureIndex) {
setPropertyValue(new EscherSimpleProperty(EscherProperties.BLIP__BLIPTODISPLAY, false, true, pictureIndex));
}
@Override
void setShapeId(int shapeId) {
EscherSpRecord spRecord = getEscherContainer().getChildById(EscherSpRecord.RECORD_ID);
spRecord.setShapeId(shapeId);
CommonObjectDataSubRecord cod = (CommonObjectDataSubRecord) getObjRecord().getSubRecords().get(0);
cod.setObjectId((short) (shapeId % 1024));
}
}

View File

@ -38,10 +38,6 @@ import org.apache.poi.ss.usermodel.ClientAnchor;
*/
public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
private final List<HSSFShape> _shapes = new ArrayList<HSSFShape>();
// private int _x1 = 0;
// private int _y1 = 0 ;
// private int _x2 = 1023;
// private int _y2 = 255;
private final EscherSpgrRecord _spgrRecord;
private final EscherContainerRecord _mainSpgrContainer;
@ -49,19 +45,19 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
/**
* The EscherAggregate we have been bound to.
* (This will handle writing us out into records,
* and building up our shapes from the records)
* and building up our shapes from the records)
*/
private EscherAggregate _boundAggregate;
final HSSFSheet _sheet; // TODO make private
final HSSFSheet _sheet; // TODO make private
/**
* Creates the patriarch.
*
* @param sheet the sheet this patriarch is stored in.
*/
HSSFPatriarch(HSSFSheet sheet, EscherAggregate boundAggregate){
HSSFPatriarch(HSSFSheet sheet, EscherAggregate boundAggregate) {
_sheet = sheet;
_boundAggregate = boundAggregate;
_boundAggregate = boundAggregate;
_mainSpgrContainer = _boundAggregate.getEscherContainer().getChildContainers().get(0);
EscherContainerRecord spContainer = (EscherContainerRecord) _boundAggregate.getEscherContainer()
.getChildContainers().get(0).getChild(0);
@ -69,17 +65,36 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
buildShapeTree();
}
static HSSFPatriarch createPatriarch(HSSFPatriarch patriarch, HSSFSheet sheet){
HSSFPatriarch newPatriarch = new HSSFPatriarch(sheet, new EscherAggregate());
newPatriarch.afterCreate();
for (HSSFShape shape: patriarch.getChildren()){
HSSFShape newShape;
if (shape instanceof HSSFShapeGroup){
newShape = ((HSSFShapeGroup)shape).cloneShape(newPatriarch);
} else {
newShape = shape.cloneShape();
}
newPatriarch.onCreate(newShape);
newPatriarch.addShape(newShape);
}
return newPatriarch;
}
/**
* remove first level shapes
*
* @param shape to be removed
*/
public void removeShape(HSSFShape shape){
public void removeShape(HSSFShape shape) {
_mainSpgrContainer.removeChildRecord(shape.getEscherContainer());
shape.afterRemove(this);
_shapes.remove(shape);
}
public void afterCreate(){
void afterCreate() {
DrawingManager2 drawingManager = _sheet.getWorkbook().getWorkbook().getDrawingManager();
short dgId = drawingManager.findNewDrawingGroupId();
_boundAggregate.setDgId(dgId);
@ -90,12 +105,11 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
/**
* Creates a new group record stored under this patriarch.
*
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created group.
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created group.
*/
public HSSFShapeGroup createGroup(HSSFClientAnchor anchor)
{
public HSSFShapeGroup createGroup(HSSFClientAnchor anchor) {
HSSFShapeGroup group = new HSSFShapeGroup(null, anchor);
addShape(group);
onCreate(group);
@ -106,21 +120,20 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
* Creates a simple shape. This includes such shapes as lines, rectangles,
* and ovals.
*
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created shape.
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created shape.
*/
public HSSFSimpleShape createSimpleShape(HSSFClientAnchor anchor)
{
public HSSFSimpleShape createSimpleShape(HSSFClientAnchor anchor) {
HSSFSimpleShape shape = new HSSFSimpleShape(null, anchor);
addShape(shape);
//open existing file
onCreate(shape);
EscherSpRecord sp = shape.getEscherContainer().getChildById(EscherSpRecord.RECORD_ID);
if (shape.anchor.isHorizontallyFlipped()){
if (shape.anchor.isHorizontallyFlipped()) {
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPHORIZ);
}
if (shape.anchor.isVerticallyFlipped()){
if (shape.anchor.isVerticallyFlipped()) {
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPVERT);
}
return shape;
@ -129,42 +142,39 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
/**
* Creates a picture.
*
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created shape.
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created shape.
*/
public HSSFPicture createPicture(HSSFClientAnchor anchor, int pictureIndex)
{
public HSSFPicture createPicture(HSSFClientAnchor anchor, int pictureIndex) {
HSSFPicture shape = new HSSFPicture(null, anchor);
shape.setPictureIndex( pictureIndex );
shape.setPictureIndex(pictureIndex);
addShape(shape);
//open existing file
onCreate(shape);
EscherSpRecord sp = shape.getEscherContainer().getChildById(EscherSpRecord.RECORD_ID);
if (shape.anchor.isHorizontallyFlipped()){
if (shape.anchor.isHorizontallyFlipped()) {
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPHORIZ);
}
if (shape.anchor.isVerticallyFlipped()){
if (shape.anchor.isVerticallyFlipped()) {
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPVERT);
}
return shape;
}
public HSSFPicture createPicture(ClientAnchor anchor, int pictureIndex)
{
return createPicture((HSSFClientAnchor)anchor, pictureIndex);
public HSSFPicture createPicture(ClientAnchor anchor, int pictureIndex) {
return createPicture((HSSFClientAnchor) anchor, pictureIndex);
}
/**
* Creates a polygon
*
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created shape.
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created shape.
*/
public HSSFPolygon createPolygon(HSSFClientAnchor anchor)
{
public HSSFPolygon createPolygon(HSSFClientAnchor anchor) {
HSSFPolygon shape = new HSSFPolygon(null, anchor);
addShape(shape);
onCreate(shape);
@ -174,12 +184,11 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
/**
* Constructs a textbox under the patriarch.
*
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created textbox.
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created textbox.
*/
public HSSFTextbox createTextbox(HSSFClientAnchor anchor)
{
public HSSFTextbox createTextbox(HSSFClientAnchor anchor) {
HSSFTextbox shape = new HSSFTextbox(null, anchor);
addShape(shape);
onCreate(shape);
@ -189,12 +198,11 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
/**
* Constructs a cell comment.
*
* @param anchor the client anchor describes how this comment is attached
* to the sheet.
* @return the newly created comment.
* @param anchor the client anchor describes how this comment is attached
* to the sheet.
* @return the newly created comment.
*/
public HSSFComment createComment(HSSFAnchor anchor)
{
public HSSFComment createComment(HSSFAnchor anchor) {
HSSFComment shape = new HSSFComment(null, anchor);
addShape(shape);
onCreate(shape);
@ -206,23 +214,21 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
*
* @see org.apache.poi.hssf.usermodel.HSSFSheet#setAutoFilter(org.apache.poi.ss.util.CellRangeAddress)
*/
HSSFSimpleShape createComboBox(HSSFAnchor anchor)
{
HSSFCombobox shape = new HSSFCombobox(null, anchor);
addShape(shape);
onCreate(shape);
return shape;
}
HSSFSimpleShape createComboBox(HSSFAnchor anchor) {
HSSFCombobox shape = new HSSFCombobox(null, anchor);
addShape(shape);
onCreate(shape);
return shape;
}
public HSSFComment createCellComment(ClientAnchor anchor) {
return createComment((HSSFAnchor)anchor);
return createComment((HSSFAnchor) anchor);
}
/**
* Returns a list of all shapes contained by the patriarch.
*/
public List<HSSFShape> getChildren()
{
public List<HSSFShape> getChildren() {
return _shapes;
}
@ -230,23 +236,21 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
* add a shape to this drawing
*/
@Internal
public void addShape(HSSFShape shape){
public void addShape(HSSFShape shape) {
shape._patriarch = this;
_shapes.add(shape);
}
private void onCreate(HSSFShape shape){
if(_boundAggregate.getPatriarch() == null){
EscherContainerRecord spgrContainer =
_boundAggregate.getEscherContainer().getChildContainers().get(0);
private void onCreate(HSSFShape shape) {
EscherContainerRecord spgrContainer =
_boundAggregate.getEscherContainer().getChildContainers().get(0);
EscherContainerRecord spContainer = shape.getEscherContainer();
int shapeId = newShapeId();
shape.setShapeId(shapeId);
EscherContainerRecord spContainer = shape.getEscherContainer();
int shapeId = newShapeId();
shape.setShapeId(shapeId);
spgrContainer.addChildRecord(spContainer);
shape.afterInsert(this);
}
spgrContainer.addChildRecord(spContainer);
shape.afterInsert(this);
}
/**
@ -254,17 +258,18 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
*/
public int countOfAllChildren() {
int count = _shapes.size();
for (Iterator<HSSFShape> iterator = _shapes.iterator(); iterator.hasNext();) {
for (Iterator<HSSFShape> iterator = _shapes.iterator(); iterator.hasNext(); ) {
HSSFShape shape = iterator.next();
count += shape.countOfAllChildren();
}
return count;
}
/**
* Sets the coordinate space of this group. All children are constrained
* to these coordinates.
*/
public void setCoordinates(int x1, int y1, int x2, int y2){
public void setCoordinates(int x1, int y1, int x2, int y2) {
_spgrRecord.setRectY1(y1);
_spgrRecord.setRectY2(y2);
_spgrRecord.setRectX1(x1);
@ -282,28 +287,28 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
/**
* Does this HSSFPatriarch contain a chart?
* (Technically a reference to a chart, since they
* get stored in a different block of records)
* get stored in a different block of records)
* FIXME - detect chart in all cases (only seems
* to work on some charts so far)
* to work on some charts so far)
*/
public boolean containsChart() {
// TODO - support charts properly in usermodel
// We're looking for a EscherOptRecord
EscherOptRecord optRecord = (EscherOptRecord)
_boundAggregate.findFirstWithId(EscherOptRecord.RECORD_ID);
if(optRecord == null) {
_boundAggregate.findFirstWithId(EscherOptRecord.RECORD_ID);
if (optRecord == null) {
// No opt record, can't have chart
return false;
}
for(Iterator<EscherProperty> it = optRecord.getEscherProperties().iterator(); it.hasNext();) {
for (Iterator<EscherProperty> it = optRecord.getEscherProperties().iterator(); it.hasNext(); ) {
EscherProperty prop = it.next();
if(prop.getPropertyNumber() == 896 && prop.isComplex()) {
EscherComplexProperty cp = (EscherComplexProperty)prop;
if (prop.getPropertyNumber() == 896 && prop.isComplex()) {
EscherComplexProperty cp = (EscherComplexProperty) prop;
String str = StringUtil.getFromUnicodeLE(cp.getComplexData());
if(str.equals("Chart 1\0")) {
if (str.equals("Chart 1\0")) {
return true;
}
}
@ -315,32 +320,28 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
/**
* The top left x coordinate of this group.
*/
public int getX1()
{
public int getX1() {
return _spgrRecord.getRectX1();
}
/**
* The top left y coordinate of this group.
*/
public int getY1()
{
public int getY1() {
return _spgrRecord.getRectY1();
}
/**
* The bottom right x coordinate of this group.
*/
public int getX2()
{
public int getX2() {
return _spgrRecord.getRectX2();
}
/**
* The bottom right y coordinate of this group.
*/
public int getY2()
{
public int getY2() {
return _spgrRecord.getRectY2();
}
@ -365,26 +366,26 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
* @param row2 the row (0 based) of the second cell.
* @return the newly created client anchor
*/
public HSSFClientAnchor createAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2){
return new HSSFClientAnchor(dx1, dy1, dx2, dy2, (short)col1, row1, (short)col2, row2);
public HSSFClientAnchor createAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2) {
return new HSSFClientAnchor(dx1, dy1, dx2, dy2, (short) col1, row1, (short) col2, row2);
}
public Chart createChart(ClientAnchor anchor) {
throw new RuntimeException("NotImplemented");
}
public Chart createChart(ClientAnchor anchor) {
throw new RuntimeException("NotImplemented");
}
void buildShapeTree(){
void buildShapeTree() {
EscherContainerRecord dgContainer = _boundAggregate.getEscherContainer();
if (dgContainer == null){
if (dgContainer == null) {
return;
}
EscherContainerRecord spgrConrainer = dgContainer.getChildContainers().get(0);
List<EscherContainerRecord> spgrChildren = spgrConrainer.getChildContainers();
for(int i = 0; i < spgrChildren.size(); i++){
for (int i = 0; i < spgrChildren.size(); i++) {
EscherContainerRecord spContainer = spgrChildren.get(i);
if (i == 0){
if (i == 0) {
continue;
} else {
HSSFShapeFactory.createShapeTree(spContainer, _boundAggregate, this, _sheet.getWorkbook().getRootDirectory());

View File

@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import org.apache.poi.ddf.*;
import org.apache.poi.hssf.record.EscherAggregate;
import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.ss.usermodel.Picture;
import org.apache.poi.ss.util.ImageUtils;
@ -88,6 +89,7 @@ public final class HSSFPicture extends HSSFSimpleShape implements Picture {
EscherOptRecord opt = spContainer.getChildById(EscherOptRecord.RECORD_ID);
removeEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING);
removeEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH);
spContainer.removeChildRecord(spContainer.getChildById(EscherTextboxRecord.RECORD_ID));
return spContainer;
}
@ -250,7 +252,8 @@ public final class HSSFPicture extends HSSFSimpleShape implements Picture {
@Override
void afterInsert(HSSFPatriarch patriarch) {
super.afterInsert(patriarch);
EscherAggregate agg = patriarch._getBoundAggregate();
agg.associateShapeToObjRecord(getEscherContainer().getChildById(EscherClientDataRecord.RECORD_ID), getObjRecord());
EscherBSERecord bse =
patriarch._sheet.getWorkbook().getWorkbook().getBSERecord(getPictureIndex());
bse.setRef(bse.getRef() + 1);
@ -285,4 +288,13 @@ public final class HSSFPicture extends HSSFSimpleShape implements Picture {
public void setShapeType(int shapeType) {
throw new IllegalStateException("Shape type can not be changed in "+this.getClass().getSimpleName());
}
@Override
public HSSFShape cloneShape() {
EscherContainerRecord spContainer = new EscherContainerRecord();
byte [] inSp = getEscherContainer().serialize();
spContainer.fillFields(inSp, 0, new DefaultEscherRecordFactory());
ObjRecord obj = (ObjRecord) getObjRecord().cloneViaReserialise();
return new HSSFPicture(spContainer, obj);
}
}

View File

@ -18,19 +18,20 @@
package org.apache.poi.hssf.usermodel;
import org.apache.poi.ddf.*;
import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
import org.apache.poi.hssf.record.EndSubRecord;
import org.apache.poi.hssf.record.EscherAggregate;
import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.hssf.record.*;
import org.apache.poi.util.LittleEndian;
/**
* @author Glen Stampoultzis (glens at superlinksoftware.com)
*/
public class HSSFPolygon extends HSSFShape {
public class HSSFPolygon extends HSSFSimpleShape {
public final static short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 0x1E;
public HSSFPolygon(EscherContainerRecord spContainer, ObjRecord objRecord, TextObjectRecord _textObjectRecord) {
super(spContainer, objRecord, _textObjectRecord);
}
public HSSFPolygon(EscherContainerRecord spContainer, ObjRecord objRecord) {
super(spContainer, objRecord);
}
@ -39,6 +40,11 @@ public class HSSFPolygon extends HSSFShape {
super(parent, anchor);
}
@Override
protected TextObjectRecord createTextObjRecord() {
return null;
}
/**
* Generates the shape records for this shape.
*/
@ -200,10 +206,4 @@ public class HSSFPolygon extends HSSFShape {
EscherSimpleProperty property = getOptRecord().lookup(EscherProperties.GEOMETRY__BOTTOM);
return property == null ? 100: property.getPropertyValue();
}
@Override
void afterInsert(HSSFPatriarch patriarch) {
EscherAggregate agg = patriarch._getBoundAggregate();
agg.associateShapeToObjRecord(getEscherContainer().getChildById(EscherClientDataRecord.RECORD_ID), getObjRecord());
}
}

View File

@ -302,4 +302,6 @@ public abstract class HSSFShape {
public int countOfAllChildren() {
return 1;
}
public abstract HSSFShape cloneShape();
}

View File

@ -74,8 +74,12 @@ public class HSSFShapeFactory {
public static void createShapeTree(EscherContainerRecord container, EscherAggregate agg, HSSFShapeContainer out, DirectoryNode root) {
if (container.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
HSSFShapeGroup group = new HSSFShapeGroup(container,
null /* shape containers don't have a associated Obj record*/);
ObjRecord obj = null;
EscherClientDataRecord clientData = ((EscherContainerRecord)container.getChild(0)).getChildById(EscherClientDataRecord.RECORD_ID);
if (null != clientData){
obj = (ObjRecord) agg.getShapeToObjMapping().get(clientData);
}
HSSFShapeGroup group = new HSSFShapeGroup(container, obj);
List<EscherContainerRecord> children = container.getChildContainers();
// skip the first child record, it is group descriptor
for (int i = 0; i < children.size(); i++) {
@ -130,7 +134,7 @@ public class HSSFShapeFactory {
EscherOptRecord optRecord = container.getChildById(EscherOptRecord.RECORD_ID);
EscherProperty property = optRecord.lookup(EscherProperties.GEOMETRY__VERTICES);
if (null != property) {
shape = new HSSFPolygon(container, objRecord);
shape = new HSSFPolygon(container, objRecord, txtRecord);
} else {
shape = new HSSFSimpleShape(container, objRecord);
}

View File

@ -127,13 +127,18 @@ public class HSSFShapeGroup extends HSSFShape implements HSSFShapeContainer {
}
private void onCreate(HSSFShape shape){
if(_patriarch != null && _patriarch._getBoundAggregate().getPatriarch() == null){
if(_patriarch != null){
EscherContainerRecord spContainer = shape.getEscherContainer();
int shapeId = _patriarch.newShapeId();
shape.setShapeId(shapeId);
getEscherContainer().addChildRecord(spContainer);
shape.afterInsert(_patriarch);
EscherSpRecord sp = shape.getEscherContainer().getChildById(EscherSpRecord.RECORD_ID);
EscherSpRecord sp;
if (shape instanceof HSSFShapeGroup){
sp = shape.getEscherContainer().getChildContainers().get(0).getChildById(EscherSpRecord.RECORD_ID);
} else {
sp = shape.getEscherContainer().getChildById(EscherSpRecord.RECORD_ID);
}
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_CHILD);
}
}
@ -312,7 +317,7 @@ public class HSSFShapeGroup extends HSSFShape implements HSSFShapeContainer {
EscherSpRecord spRecord = containerRecord.getChildById(EscherSpRecord.RECORD_ID);
spRecord.setShapeId(shapeId);
CommonObjectDataSubRecord cod = (CommonObjectDataSubRecord) getObjRecord().getSubRecords().get(0);
cod.setObjectId((short) (shapeId));
cod.setObjectId((short) (shapeId % 1024));
}
@Override
@ -320,4 +325,39 @@ public class HSSFShapeGroup extends HSSFShape implements HSSFShapeContainer {
EscherContainerRecord containerRecord = getEscherContainer().getChildById(EscherContainerRecord.SP_CONTAINER);
return ((EscherSpRecord)containerRecord.getChildById(EscherSpRecord.RECORD_ID)).getShapeId();
}
@Override
public HSSFShape cloneShape() {
throw new IllegalStateException("Use method cloneShape(HSSFPatriarch patriarch)");
}
public HSSFShape cloneShape(HSSFPatriarch patriarch) {
EscherContainerRecord spgrContainer = new EscherContainerRecord();
spgrContainer.setRecordId(EscherContainerRecord.SPGR_CONTAINER);
spgrContainer.setOptions((short) 0x000F);
EscherContainerRecord spContainer = new EscherContainerRecord();
byte [] inSp = getEscherContainer().getChildById(EscherContainerRecord.SP_CONTAINER).serialize();
spContainer.fillFields(inSp, 0, new DefaultEscherRecordFactory());
spgrContainer.addChildRecord(spContainer);
ObjRecord obj = null;
if (null != getObjRecord()){
obj = (ObjRecord) getObjRecord().cloneViaReserialise();
}
HSSFShapeGroup group = new HSSFShapeGroup(spgrContainer, obj);
group._patriarch = patriarch;
for (HSSFShape shape: getChildren()){
HSSFShape newShape;
if (shape instanceof HSSFShapeGroup){
newShape = ((HSSFShapeGroup)shape).cloneShape(patriarch);
} else {
newShape = shape.cloneShape();
}
group.addShape(newShape);
group.onCreate(newShape);
}
return group;
}
}

View File

@ -115,7 +115,15 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
}
HSSFSheet cloneSheet(HSSFWorkbook workbook) {
return new HSSFSheet(workbook, _sheet.cloneSheet());
this.getDrawingPatriarch();/**Aggregate drawing records**/
HSSFSheet sheet = new HSSFSheet(workbook, _sheet.cloneSheet());
if (getDrawingPatriarch() != null){
int insertPos = sheet._sheet.findFirstRecordLocBySid(WindowTwoRecord.sid);
HSSFPatriarch patr = HSSFPatriarch.createPatriarch(this.getDrawingPatriarch(), sheet);
sheet._sheet.getRecords().add(insertPos, patr._getBoundAggregate());
sheet._patriarch = patr;
}
return sheet;
}
/**

View File

@ -68,14 +68,13 @@ public class HSSFSimpleShape extends HSSFShape
objTypeToShapeType.put(OBJECT_TYPE_OVAL, HSSFShapeType.OVAL.getType());
}
public HSSFSimpleShape(EscherContainerRecord spContainer, ObjRecord objRecord, TextObjectRecord _textObjectRecord) {
public HSSFSimpleShape(EscherContainerRecord spContainer, ObjRecord objRecord, TextObjectRecord textObjectRecord) {
super(spContainer, objRecord);
this._textObjectRecord = _textObjectRecord == null ? createTextObjRecord() : _textObjectRecord;
this._textObjectRecord = textObjectRecord;
}
public HSSFSimpleShape(EscherContainerRecord spContainer, ObjRecord objRecord) {
super(spContainer, objRecord);
this._textObjectRecord = createTextObjRecord();
}
public HSSFSimpleShape( HSSFShape parent, HSSFAnchor anchor)
@ -92,6 +91,7 @@ public class HSSFSimpleShape extends HSSFShape
TextObjectRecord obj = new TextObjectRecord();
obj.setTextLocked(true);
obj.setTextOrientation(TextObjectRecord.TEXT_ORIENTATION_NONE);
obj.setStr(new HSSFRichTextString(""));
return obj;
}
@ -123,10 +123,15 @@ public class HSSFSimpleShape extends HSSFShape
optRecord.setEscherProperty(new EscherBoolProperty( EscherProperties.GROUPSHAPE__PRINT, 0x080000));
optRecord.setRecordId( EscherOptRecord.RECORD_ID );
EscherTextboxRecord escherTextbox = new EscherTextboxRecord();
escherTextbox.setRecordId(EscherTextboxRecord.RECORD_ID);
escherTextbox.setOptions((short) 0x0000);
spContainer.addChildRecord(sp);
spContainer.addChildRecord(optRecord);
spContainer.addChildRecord(anchor.getEscherAnchor());
spContainer.addChildRecord(clientData);
spContainer.addChildRecord(escherTextbox);
return spContainer;
}
@ -167,21 +172,6 @@ public class HSSFSimpleShape extends HSSFShape
HSSFRichTextString rtr = (HSSFRichTextString) string;
// If font is not set we must set the default one
if (rtr.numFormattingRuns() == 0) rtr.applyFont((short) 0);
EscherTextboxRecord textbox = getEscherContainer().getChildById(EscherTextboxRecord.RECORD_ID);
if (string.getString()!= null && !string.getString().equals("")){
if (null == textbox){
EscherTextboxRecord escherTextbox = new EscherTextboxRecord();
escherTextbox.setRecordId(EscherTextboxRecord.RECORD_ID);
escherTextbox.setOptions((short) 0x0000);
getEscherContainer().addChildRecord(escherTextbox);
_patriarch._getBoundAggregate().associateShapeToObjRecord(getEscherContainer().getChildById(EscherTextboxRecord.RECORD_ID), getTextObjectRecord());
}
} else {
if (null != textbox){
getEscherContainer().removeChildRecord(textbox);
_patriarch._getBoundAggregate().removeShapeToObjRecord(textbox);
}
}
_textObjectRecord.setStr(rtr);
}
@ -189,6 +179,24 @@ public class HSSFSimpleShape extends HSSFShape
void afterInsert(HSSFPatriarch patriarch){
EscherAggregate agg = patriarch._getBoundAggregate();
agg.associateShapeToObjRecord(getEscherContainer().getChildById(EscherClientDataRecord.RECORD_ID), getObjRecord());
//used only when clone shapes
if (null != getTextObjectRecord()){
agg.associateShapeToObjRecord(getEscherContainer().getChildById(EscherTextboxRecord.RECORD_ID), getTextObjectRecord());
}
}
@Override
public HSSFShape cloneShape() {
TextObjectRecord txo = null;
EscherContainerRecord spContainer = new EscherContainerRecord();
byte [] inSp = getEscherContainer().serialize();
spContainer.fillFields(inSp, 0, new DefaultEscherRecordFactory());
ObjRecord obj = (ObjRecord) getObjRecord().cloneViaReserialise();
if (getTextObjectRecord() != null && getString() != null && !"".equals(getString().getString())){
txo = (TextObjectRecord) getTextObjectRecord().cloneViaReserialise();
}
return new HSSFSimpleShape(spContainer, obj, txo);
}

View File

@ -235,4 +235,14 @@ public class HSSFTextbox extends HSSFSimpleShape {
public void setShapeType(int shapeType) {
throw new IllegalStateException("Shape type can not be changed in "+this.getClass().getSimpleName());
}
@Override
public HSSFShape cloneShape() {
TextObjectRecord txo = (TextObjectRecord) getTextObjectRecord().cloneViaReserialise();
EscherContainerRecord spContainer = new EscherContainerRecord();
byte [] inSp = getEscherContainer().serialize();
spContainer.fillFields(inSp, 0, new DefaultEscherRecordFactory());
ObjRecord obj = (ObjRecord) getObjRecord().cloneViaReserialise();
return new HSSFTextbox(spContainer, obj, txo);
}
}

View File

@ -48,4 +48,9 @@ public class HSSFUnknownShape extends HSSFShape {
@Override
void afterInsert(HSSFPatriarch patriarch) {
}
@Override
public HSSFShape cloneShape() {
return null;
}
}

View File

@ -701,7 +701,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
names.add(newName);
}
// TODO - maybe same logic required for other/all built-in name records
workbook.cloneDrawings(clonedSheet.getSheet());
// workbook.cloneDrawings(clonedSheet.getSheet());
return clonedSheet;
}

View File

@ -194,46 +194,6 @@ public class TestDrawingAggregate extends TestCase {
}
}
public void testBuildBaseTree(){
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
EscherAggregate agg = HSSFTestHelper.getEscherAggregate(patriarch);
EscherAggregate agg1 = new EscherAggregate(new HSSFTestHelper.MockDrawingManager());
EscherSpgrRecord spgr = new EscherSpgrRecord();
spgr.setRectY1(0);
spgr.setRectY2(255);
spgr.setRectX1(0);
spgr.setRectX2(1023);
EscherContainerRecord spContainer = new EscherContainerRecord();
spContainer.addChildRecord(spgr);
EscherContainerRecord spgrContainer = new EscherContainerRecord();
spgrContainer.addChildRecord(spContainer);
EscherContainerRecord dgContainer = new EscherContainerRecord();
dgContainer.addChildRecord(spgrContainer);
agg1.addEscherRecord(dgContainer);
agg1.setPatriarch(HSSFTestHelper.createTestPatriarch(sheet, agg1));
agg1.clear();
HSSFTestHelper.callConvertPatriarch(agg1);
agg1.setPatriarch(null);
agg.setPatriarch(null);
//
EscherSpRecord sp = (EscherSpRecord) agg.getEscherContainer().getChildContainers().get(0).getChild(0).getChild(1);
sp.setShapeId(1025);
EscherDgRecord dg = (EscherDgRecord) agg.getEscherContainer().getChild(0);
dg.setNumShapes(1);
dg.setOptions((short) (1 << 4));
byte[] aggS = agg.serialize();
byte []agg1S = agg1.serialize();
assertEquals(aggS.length, agg1S.length);
assertTrue(Arrays.equals(aggS, agg1S));
}
/**
* when reading incomplete data ensure that the serialized bytes
match the source

View File

@ -352,8 +352,7 @@ public class TestDrawingShapes extends TestCase {
shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE);
EscherAggregate agg = HSSFTestHelper.getEscherAggregate(patriarch);
assertNull(shape.getEscherContainer().getChildById(EscherTextboxRecord.RECORD_ID));
assertEquals(agg.getShapeToObjMapping().size(), 1);
assertEquals(agg.getShapeToObjMapping().size(), 2);
wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
@ -362,8 +361,7 @@ public class TestDrawingShapes extends TestCase {
shape = (HSSFSimpleShape) patriarch.getChildren().get(0);
agg = HSSFTestHelper.getEscherAggregate(patriarch);
assertNull(shape.getEscherContainer().getChildById(EscherTextboxRecord.RECORD_ID));
assertEquals(agg.getShapeToObjMapping().size(), 1);
assertEquals(agg.getShapeToObjMapping().size(), 2);
shape.setString(new HSSFRichTextString("string1"));
assertEquals(shape.getString().getString(), "string1");

View File

@ -101,21 +101,6 @@ public class HSSFTestHelper {
}
}
public static void callConvertPatriarch(EscherAggregate agg) {
Method method = null;
try {
method = agg.getClass().getDeclaredMethod("convertPatriarch", HSSFPatriarch.class);
method.setAccessible(true);
method.invoke(agg, agg.getPatriarch());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public static void setShapeId(HSSFShape shape, int id){
shape.setShapeId(id);
}

View File

@ -19,8 +19,14 @@ package org.apache.poi.hssf.usermodel;
import junit.framework.TestCase;
import org.apache.poi.ddf.EscherDgRecord;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.hssf.record.EscherAggregate;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.IOException;
import java.util.Arrays;
/**
* Test the ability to clone a sheet.
* If adding new records that belong to a sheet (as opposed to a book)
@ -55,4 +61,74 @@ public final class TestCloneSheet extends TestCase {
assertTrue("Row 3 still should be broken", clone.isRowBroken(3));
}
public void testCloneSheetWithoutDrawings(){
HSSFWorkbook b = new HSSFWorkbook();
HSSFSheet s = b.createSheet("Test");
HSSFSheet s2 = s.cloneSheet(b);
assertNull(s.getDrawingPatriarch());
assertNull(s2.getDrawingPatriarch());
assertEquals(HSSFTestHelper.getSheetForTest(s).getRecords().size(), HSSFTestHelper.getSheetForTest(s2).getRecords().size());
}
public void testCloneSheetWithEmptyDrawingAggregate(){
HSSFWorkbook b = new HSSFWorkbook();
HSSFSheet s = b.createSheet("Test");
HSSFPatriarch patriarch = s.createDrawingPatriarch();
EscherAggregate agg1 = patriarch._getBoundAggregate();
HSSFSheet s2 = s.cloneSheet(b);
patriarch = s2.getDrawingPatriarch();
EscherAggregate agg2 = patriarch._getBoundAggregate();
EscherSpRecord sp1 = (EscherSpRecord) agg1.getEscherContainer().getChild(1).getChild(0).getChild(1);
EscherSpRecord sp2 = (EscherSpRecord) agg2.getEscherContainer().getChild(1).getChild(0).getChild(1);
assertEquals(sp1.getShapeId(), 1024);
assertEquals(sp2.getShapeId(), 2048);
EscherDgRecord dg = (EscherDgRecord) agg2.getEscherContainer().getChild(0);
assertEquals(dg.getLastMSOSPID(), 2048);
assertEquals(dg.getInstance(), 0x2);
//everything except id and DgRecord.lastMSOSPID and DgRecord.Instance must be the same
sp2.setShapeId(1024);
dg.setLastMSOSPID(1024);
dg.setInstance((short) 0x1);
assertEquals(agg1.serialize().length, agg2.serialize().length);
assertEquals(agg1.toXml(""), agg2.toXml(""));
assertTrue(Arrays.equals(agg1.serialize(), agg2.serialize()));
}
public void testCloneComment() throws IOException {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sh = wb.createSheet();
HSSFPatriarch p = sh.createDrawingPatriarch();
HSSFComment c = p.createComment(new HSSFClientAnchor(0,0,100,100, (short) 0,0,(short)5,5));
c.setColumn(1);
c.setRow(2);
c.setString(new HSSFRichTextString("qwertyuio"));
HSSFSheet sh2 = wb.cloneSheet(0);
HSSFPatriarch p2 = sh2.getDrawingPatriarch();
HSSFComment c2 = (HSSFComment) p2.getChildren().get(0);
assertTrue(Arrays.equals(c2.getTextObjectRecord().serialize(), c.getTextObjectRecord().serialize()));
assertTrue(Arrays.equals(c2.getObjRecord().serialize(), c.getObjRecord().serialize()));
assertTrue(Arrays.equals(c2.getNoteRecord().serialize(), c.getNoteRecord().serialize()));
//everything except spRecord.shapeId must be the same
assertFalse(Arrays.equals(c2.getEscherContainer().serialize(), c.getEscherContainer().serialize()));
EscherSpRecord sp = (EscherSpRecord) c2.getEscherContainer().getChild(0);
sp.setShapeId(1025);
assertTrue(Arrays.equals(c2.getEscherContainer().serialize(), c.getEscherContainer().serialize()));
}
}

View File

@ -58,6 +58,8 @@ public class TestComment extends TestCase {
ObjRecord obj = comment.getObjRecord();
ObjRecord objShape = commentShape.getObjRecord();
/**shapeId = 1025 % 1024**/
((CommonObjectDataSubRecord)objShape.getSubRecords().get(0)).setObjectId(1);
expected = obj.serialize();
actual = objShape.serialize();
@ -76,6 +78,7 @@ public class TestComment extends TestCase {
NoteRecord note = comment.getNoteRecord();
NoteRecord noteShape = commentShape.getNoteRecord();
noteShape.setShapeId(1);
expected = note.serialize();
actual = noteShape.serialize();
@ -225,17 +228,17 @@ public class TestComment extends TestCase {
comment.setShapeId(2024);
/**
* SpRecord.id == shapeId
* ObjRecord.id == shapeId - 1024
* NoteRecord.id == ObjectRecord.id == shapeId - 1024
* ObjRecord.id == shapeId % 1024
* NoteRecord.id == ObjectRecord.id == shapeId % 1024
*/
assertEquals(comment.getShapeId(), 2024);
CommonObjectDataSubRecord cod = (CommonObjectDataSubRecord) comment.getObjRecord().getSubRecords().get(0);
assertEquals(cod.getObjectId(), 2024);
assertEquals(cod.getObjectId(), 1000);
EscherSpRecord spRecord = (EscherSpRecord) comment.getEscherContainer().getChild(0);
assertEquals(spRecord.getShapeId(), 2024);
assertEquals(comment.getShapeId(), 2024);
assertEquals(comment.getNoteRecord().getShapeId(), 2024);
assertEquals(comment.getNoteRecord().getShapeId(), 1000);
}
}

View File

@ -808,8 +808,8 @@ public final class TestHSSFSheet extends BaseTestSheet {
HSSFSheet sheet2 = wb2.getSheetAt(1);
//check that id of the drawing group was updated
EscherDgRecord dg1 = (EscherDgRecord)sheet1.getDrawingEscherAggregate().findFirstWithId(EscherDgRecord.RECORD_ID);
EscherDgRecord dg2 = (EscherDgRecord)sheet2.getDrawingEscherAggregate().findFirstWithId(EscherDgRecord.RECORD_ID);
EscherDgRecord dg1 = (EscherDgRecord)sheet1.getDrawingPatriarch()._getBoundAggregate().findFirstWithId(EscherDgRecord.RECORD_ID);
EscherDgRecord dg2 = (EscherDgRecord)sheet2.getDrawingPatriarch()._getBoundAggregate().findFirstWithId(EscherDgRecord.RECORD_ID);
int dg_id_1 = dg1.getOptions() >> 4;
int dg_id_2 = dg2.getOptions() >> 4;
assertEquals(dg_id_1 + 1, dg_id_2);

View File

@ -17,29 +17,6 @@ import java.util.Map;
*/
public class TestShapeGroup extends TestCase{
public void testResultEqualsToAbstractShape() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
HSSFShapeGroup group = patriarch.createGroup(new HSSFClientAnchor());
EscherContainerRecord container = new EscherContainerRecord();
Map shapeToObj = new HashMap();
HSSFTestHelper.convertHSSFGroup(group, container, shapeToObj);
byte [] actual = group.getEscherContainer().serialize();
byte [] expected = container.getChild(0).serialize();
assertEquals(actual.length, expected.length);
assertTrue(Arrays.equals(actual, expected));
actual = group.getObjRecord().serialize();
expected = ((ObjRecord)shapeToObj.values().toArray()[0]).serialize();
assertEquals(actual.length, expected.length);
assertTrue(Arrays.equals(actual, expected));
}
public void testSetGetCoordinates(){
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sh = wb.createSheet();