initial support for reading shapes, see patch from June 8 in Bugzilla 53372
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/gsoc2012@1348168 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d3f4e26985
commit
5de1aec65e
@ -43,16 +43,7 @@ import org.apache.poi.hssf.model.CommentShape;
|
|||||||
import org.apache.poi.hssf.model.ConvertAnchor;
|
import org.apache.poi.hssf.model.ConvertAnchor;
|
||||||
import org.apache.poi.hssf.model.DrawingManager2;
|
import org.apache.poi.hssf.model.DrawingManager2;
|
||||||
import org.apache.poi.hssf.model.TextboxShape;
|
import org.apache.poi.hssf.model.TextboxShape;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFAnchor;
|
import org.apache.poi.hssf.usermodel.*;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFChildAnchor;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFPicture;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFShape;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFShapeContainer;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFShapeGroup;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFTextbox;
|
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
|
|
||||||
@ -322,7 +313,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
|||||||
/**
|
/**
|
||||||
* list of "tail" records that need to be serialized after all drawing group records
|
* list of "tail" records that need to be serialized after all drawing group records
|
||||||
*/
|
*/
|
||||||
private List tailRec = new ArrayList();
|
private List<Record> tailRec = new ArrayList<Record>();
|
||||||
|
|
||||||
public EscherAggregate(DrawingManager2 drawingManager) {
|
public EscherAggregate(DrawingManager2 drawingManager) {
|
||||||
this.drawingManager = drawingManager;
|
this.drawingManager = drawingManager;
|
||||||
@ -486,7 +477,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
|||||||
|
|
||||||
public void afterRecordSerialize(int offset, short recordId, int size, EscherRecord record) {
|
public void afterRecordSerialize(int offset, short recordId, int size, EscherRecord record) {
|
||||||
if (recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID) {
|
if (recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID) {
|
||||||
spEndingOffsets.add(Integer.valueOf(offset));
|
spEndingOffsets.add(offset);
|
||||||
shapes.add(record);
|
shapes.add(record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -501,12 +492,17 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
|||||||
pos = offset;
|
pos = offset;
|
||||||
int writtenEscherBytes = 0;
|
int writtenEscherBytes = 0;
|
||||||
for (int i = 1; i < shapes.size(); i++) {
|
for (int i = 1; i < shapes.size(); i++) {
|
||||||
int endOffset = ((Integer) spEndingOffsets.get(i)).intValue() - 1;
|
int endOffset;
|
||||||
|
if (i == shapes.size()-1){
|
||||||
|
endOffset = buffer.length - 1;
|
||||||
|
} else {
|
||||||
|
endOffset = (Integer) spEndingOffsets.get(i) - 1;
|
||||||
|
}
|
||||||
int startOffset;
|
int startOffset;
|
||||||
if (i == 1)
|
if (i == 1)
|
||||||
startOffset = 0;
|
startOffset = 0;
|
||||||
else
|
else
|
||||||
startOffset = ((Integer) spEndingOffsets.get(i - 1)).intValue();
|
startOffset = (Integer) spEndingOffsets.get(i - 1);
|
||||||
|
|
||||||
|
|
||||||
byte[] drawingData = new byte[endOffset - startOffset + 1];
|
byte[] drawingData = new byte[endOffset - startOffset + 1];
|
||||||
@ -790,7 +786,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
|||||||
container.getChildren().add(shape);
|
container.getChildren().add(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HSSFClientAnchor toClientAnchor(EscherClientAnchorRecord anchorRecord) {
|
public static HSSFClientAnchor toClientAnchor(EscherClientAnchorRecord anchorRecord) {
|
||||||
HSSFClientAnchor anchor = new HSSFClientAnchor();
|
HSSFClientAnchor anchor = new HSSFClientAnchor();
|
||||||
anchor.setAnchorType(anchorRecord.getFlag());
|
anchor.setAnchorType(anchorRecord.getFlag());
|
||||||
anchor.setCol1(anchorRecord.getCol1());
|
anchor.setCol1(anchorRecord.getCol1());
|
||||||
@ -804,7 +800,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
|||||||
return anchor;
|
return anchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HSSFChildAnchor toChildAnchor(EscherChildAnchorRecord anchorRecord) {
|
public static HSSFChildAnchor toChildAnchor(EscherChildAnchorRecord anchorRecord) {
|
||||||
HSSFChildAnchor anchor = new HSSFChildAnchor();
|
HSSFChildAnchor anchor = new HSSFChildAnchor();
|
||||||
// anchor.setAnchorType(anchorRecord.getFlag());
|
// anchor.setAnchorType(anchorRecord.getFlag());
|
||||||
// anchor.setCol1( anchorRecord.getCol1() );
|
// anchor.setCol1( anchorRecord.getCol1() );
|
||||||
@ -1081,4 +1077,24 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mapping of {@link EscherClientDataRecord} and {@link EscherTextboxRecord}
|
||||||
|
* to their {@link TextObjectRecord} or {@link ObjRecord} .
|
||||||
|
*
|
||||||
|
* We need to access it outside of EscherAggregate when building shapes
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Map<EscherRecord, Record> getShapeToObjMapping(){
|
||||||
|
return Collections.unmodifiableMap(shapeToObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return tails records. We need to access them when building shapes.
|
||||||
|
* Every HSSFComment shape has a link to a NoteRecord from the tailRec collection.
|
||||||
|
*/
|
||||||
|
public List<Record> getTailRecords(){
|
||||||
|
return Collections.unmodifiableList(tailRec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,16 @@
|
|||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherChildAnchorRecord;
|
||||||
|
|
||||||
public final class HSSFChildAnchor extends HSSFAnchor {
|
public final class HSSFChildAnchor extends HSSFAnchor {
|
||||||
|
|
||||||
|
private EscherChildAnchorRecord escherChildAnchorRecord;
|
||||||
|
|
||||||
|
public HSSFChildAnchor(EscherChildAnchorRecord escherChildAnchorRecord) {
|
||||||
|
this.escherChildAnchorRecord = escherChildAnchorRecord;
|
||||||
|
}
|
||||||
|
|
||||||
public HSSFChildAnchor()
|
public HSSFChildAnchor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherClientAnchorRecord;
|
||||||
import org.apache.poi.ss.usermodel.ClientAnchor;
|
import org.apache.poi.ss.usermodel.ClientAnchor;
|
||||||
|
|
||||||
|
|
||||||
@ -33,6 +34,13 @@ public final class HSSFClientAnchor extends HSSFAnchor implements ClientAnchor {
|
|||||||
int row2;
|
int row2;
|
||||||
int anchorType;
|
int anchorType;
|
||||||
|
|
||||||
|
private EscherClientAnchorRecord escherClientAnchorRecord;
|
||||||
|
|
||||||
|
public HSSFClientAnchor(EscherClientAnchorRecord escherClientAnchorRecord) {
|
||||||
|
this.escherClientAnchorRecord = escherClientAnchorRecord;
|
||||||
|
//TODO set properties or read properties from EscherRecord ?
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new client anchor and defaults all the anchor positions to 0.
|
* Creates a new client anchor and defaults all the anchor positions to 0.
|
||||||
*/
|
*/
|
||||||
|
@ -22,9 +22,11 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.ddf.EscherComplexProperty;
|
import org.apache.poi.ddf.EscherComplexProperty;
|
||||||
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
import org.apache.poi.ddf.EscherOptRecord;
|
import org.apache.poi.ddf.EscherOptRecord;
|
||||||
import org.apache.poi.ddf.EscherProperty;
|
import org.apache.poi.ddf.EscherProperty;
|
||||||
import org.apache.poi.ddf.EscherBSERecord;
|
import org.apache.poi.ddf.EscherBSERecord;
|
||||||
|
import org.apache.poi.ddf.EscherSpgrRecord;
|
||||||
import org.apache.poi.hssf.record.EscherAggregate;
|
import org.apache.poi.hssf.record.EscherAggregate;
|
||||||
import org.apache.poi.ss.usermodel.Chart;
|
import org.apache.poi.ss.usermodel.Chart;
|
||||||
import org.apache.poi.util.StringUtil;
|
import org.apache.poi.util.StringUtil;
|
||||||
@ -314,4 +316,23 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
|
|||||||
throw new RuntimeException("NotImplemented");
|
throw new RuntimeException("NotImplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void buildShapeTree(){
|
||||||
|
EscherContainerRecord dgContainer = _boundAggregate.getEscherContainer();
|
||||||
|
EscherContainerRecord spgrConrainer = dgContainer.getChildContainers().get(0);
|
||||||
|
List<EscherContainerRecord> spgrChildren = spgrConrainer.getChildContainers();
|
||||||
|
|
||||||
|
for(int i = 0; i < spgrChildren.size(); i++){
|
||||||
|
EscherContainerRecord spContainer = spgrChildren.get(i);
|
||||||
|
if (i == 0){
|
||||||
|
EscherSpgrRecord spgr = (EscherSpgrRecord)spContainer.getChildById(EscherSpgrRecord.RECORD_ID);
|
||||||
|
setCoordinates(
|
||||||
|
spgr.getRectX1(), spgr.getRectY1(),
|
||||||
|
spgr.getRectX2(), spgr.getRectY2()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
HSSFShapeFactory.createShapeTree(spContainer, _boundAggregate, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
15
src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java
Normal file
15
src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
|
import org.apache.poi.hssf.record.ObjRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Evgeniy Berlog
|
||||||
|
* @date 08.06.12
|
||||||
|
*/
|
||||||
|
public class HSSFRectangle extends HSSFShape{
|
||||||
|
|
||||||
|
public HSSFRectangle(EscherContainerRecord spContainer, ObjRecord objRecord) {
|
||||||
|
super(spContainer, objRecord);
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,9 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
|
import org.apache.poi.hssf.record.ObjRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract shape.
|
* An abstract shape.
|
||||||
*
|
*
|
||||||
@ -40,7 +43,7 @@ public abstract class HSSFShape {
|
|||||||
public static final int LINESTYLE_NONE = -1;
|
public static final int LINESTYLE_NONE = -1;
|
||||||
|
|
||||||
// TODO - make all these fields private
|
// TODO - make all these fields private
|
||||||
final HSSFShape parent;
|
HSSFShape parent;
|
||||||
HSSFAnchor anchor;
|
HSSFAnchor anchor;
|
||||||
HSSFPatriarch _patriarch;
|
HSSFPatriarch _patriarch;
|
||||||
private int _lineStyleColor = 0x08000040;
|
private int _lineStyleColor = 0x08000040;
|
||||||
@ -49,15 +52,30 @@ public abstract class HSSFShape {
|
|||||||
private int _lineStyle = LINESTYLE_SOLID;
|
private int _lineStyle = LINESTYLE_SOLID;
|
||||||
private boolean _noFill = false;
|
private boolean _noFill = false;
|
||||||
|
|
||||||
|
private EscherContainerRecord spContainer;
|
||||||
|
private ObjRecord objRecord;
|
||||||
|
|
||||||
|
public HSSFShape(EscherContainerRecord spContainer, ObjRecord objRecord){
|
||||||
|
this.spContainer = spContainer;
|
||||||
|
this.objRecord = objRecord;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Create a new shape with the specified parent and anchor.
|
* Create a new shape with the specified parent and anchor.
|
||||||
*/
|
*/
|
||||||
HSSFShape( HSSFShape parent, HSSFAnchor anchor )
|
public HSSFShape( HSSFShape parent, HSSFAnchor anchor )
|
||||||
{
|
{
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.anchor = anchor;
|
this.anchor = anchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EscherContainerRecord getSpContainer() {
|
||||||
|
return spContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjRecord getObjRecord() {
|
||||||
|
return objRecord;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the parent shape.
|
* Gets the parent shape.
|
||||||
*/
|
*/
|
||||||
|
@ -31,4 +31,15 @@ public interface HSSFShapeContainer
|
|||||||
*/
|
*/
|
||||||
List getChildren();
|
List getChildren();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add shape to the list of child records
|
||||||
|
* @param shape
|
||||||
|
*/
|
||||||
|
public void addShape(HSSFShape shape);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set coordinates of this group relative to the parent
|
||||||
|
*/
|
||||||
|
void setCoordinates( int x1, int y1, int x2, int y2 );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
157
src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java
Normal file
157
src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherClientDataRecord;
|
||||||
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
|
import org.apache.poi.ddf.EscherRecord;
|
||||||
|
import org.apache.poi.ddf.EscherSpRecord;
|
||||||
|
import org.apache.poi.ddf.EscherSpgrRecord;
|
||||||
|
import org.apache.poi.ddf.EscherTextboxRecord;
|
||||||
|
import org.apache.poi.hssf.model.TextboxShape;
|
||||||
|
import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
|
||||||
|
import org.apache.poi.hssf.record.EscherAggregate;
|
||||||
|
import org.apache.poi.hssf.record.NoteRecord;
|
||||||
|
import org.apache.poi.hssf.record.ObjRecord;
|
||||||
|
import org.apache.poi.hssf.record.Record;
|
||||||
|
import org.apache.poi.hssf.record.TextObjectRecord;
|
||||||
|
import org.apache.poi.hssf.usermodel.drawing.HSSFShapeType;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author evgeniy
|
||||||
|
* date: 05.06.12
|
||||||
|
*/
|
||||||
|
public class HSSFShapeFactory {
|
||||||
|
|
||||||
|
private static final Map<Short, Class> shapeTypeToClass = new HashMap<Short, Class>(HSSFShapeType.values().length);
|
||||||
|
private static final ReflectionConstructorShapeCreator shapeCreator = new ReflectionConstructorShapeCreator(shapeTypeToClass);
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (HSSFShapeType type: HSSFShapeType.values()){
|
||||||
|
shapeTypeToClass.put(type.getType(), type.getShape());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ReflectionConstructorShapeCreator {
|
||||||
|
|
||||||
|
private final Map<Short, Class> shapeTypeToClass;
|
||||||
|
|
||||||
|
private ReflectionConstructorShapeCreator(Map<Short, Class> shapeTypeToClass) {
|
||||||
|
this.shapeTypeToClass = shapeTypeToClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HSSFShape createNewShape(Short type, EscherContainerRecord spContainer, ObjRecord objRecord){
|
||||||
|
if (!shapeTypeToClass.containsKey(type)){
|
||||||
|
return new HSSFUnknownShape(spContainer, objRecord);
|
||||||
|
}
|
||||||
|
Class clazz = shapeTypeToClass.get(type);
|
||||||
|
if (null == clazz){
|
||||||
|
System.out.println("No class attached to shape type: "+type);
|
||||||
|
return new HSSFUnknownShape(spContainer, objRecord);
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
Constructor constructor = clazz.getConstructor(new Class[]{EscherContainerRecord.class, ObjRecord.class});
|
||||||
|
return (HSSFShape) constructor.newInstance(spContainer, objRecord);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new IllegalStateException(clazz.getName() +" doesn't have required for shapes constructor");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("Couldn't create new instance of " + clazz.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HSSFShape createShape(EscherRecord container, ObjRecord objRecord){
|
||||||
|
if (0 == container.getChildRecords().size()){
|
||||||
|
throw new IllegalArgumentException("Couldn't create shape from empty escher container");
|
||||||
|
}
|
||||||
|
if (container.getChild(0) instanceof EscherSpgrRecord){
|
||||||
|
return new HSSFShapeGroup((EscherContainerRecord) container, objRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO implement cases for all shapes
|
||||||
|
return new HSSFUnknownShape(container, objRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HSSFShapeGroup createShapeGroup(){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HSSFShapeGroup createSimpleShape(EscherRecord container, ObjRecord objRecord){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void createShapeTree(EscherContainerRecord container, EscherAggregate agg, HSSFShapeContainer out){
|
||||||
|
if(container.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){
|
||||||
|
HSSFShapeGroup group = new HSSFShapeGroup(container,
|
||||||
|
null /* shape containers don't have a associated Obj record*/);
|
||||||
|
List<EscherContainerRecord> children = container.getChildContainers();
|
||||||
|
// skip the first child record, it is group descriptor
|
||||||
|
for(int i = 0; i < children.size(); i++) {
|
||||||
|
EscherContainerRecord spContainer = children.get(i);
|
||||||
|
if(i == 0){
|
||||||
|
EscherSpgrRecord spgr = (EscherSpgrRecord)spContainer.getChildById(EscherSpgrRecord.RECORD_ID);
|
||||||
|
group.setCoordinates(
|
||||||
|
spgr.getRectX1(), spgr.getRectY1(),
|
||||||
|
spgr.getRectX2(), spgr.getRectY2()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
createShapeTree(spContainer, agg, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.addShape(group);
|
||||||
|
} else if (container.getRecordId() == EscherContainerRecord.SP_CONTAINER){
|
||||||
|
Map<EscherRecord, Record> shapeToObj = agg.getShapeToObjMapping();
|
||||||
|
EscherSpRecord spRecord = null;
|
||||||
|
ObjRecord objRecord = null;
|
||||||
|
TextObjectRecord txtRecord = null;
|
||||||
|
|
||||||
|
for(EscherRecord record : container.getChildRecords()) {
|
||||||
|
switch(record.getRecordId()) {
|
||||||
|
case EscherSpRecord.RECORD_ID:
|
||||||
|
spRecord = (EscherSpRecord)record;
|
||||||
|
break;
|
||||||
|
case EscherClientDataRecord.RECORD_ID:
|
||||||
|
objRecord = (ObjRecord)shapeToObj.get(record);
|
||||||
|
break;
|
||||||
|
case EscherTextboxRecord.RECORD_ID:
|
||||||
|
txtRecord = (TextObjectRecord)shapeToObj.get(record);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (null != objRecord){
|
||||||
|
HSSFShape shape = shapeCreator.createNewShape(spRecord.getShapeType(), container, objRecord);
|
||||||
|
out.addShape(shape);
|
||||||
|
}
|
||||||
|
if (null != txtRecord){
|
||||||
|
//TODO resolve textbox
|
||||||
|
// TextboxShape shape = new TextboxShape(container, txtRecord);
|
||||||
|
// out.a
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// //TODO decide what shape to create based on ObjRecord / EscherSpRecord
|
||||||
|
// HSSFShape shape = new HSSFUnknownShape(container, objRecord);
|
||||||
|
// out.addShape(shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,15 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherChildAnchorRecord;
|
||||||
|
import org.apache.poi.ddf.EscherClientAnchorRecord;
|
||||||
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
|
import org.apache.poi.ddf.EscherRecord;
|
||||||
|
import org.apache.poi.ddf.EscherSpgrRecord;
|
||||||
|
import org.apache.poi.hssf.model.TextboxShape;
|
||||||
|
import org.apache.poi.hssf.record.EscherAggregate;
|
||||||
|
import org.apache.poi.hssf.record.ObjRecord;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -37,6 +46,32 @@ public class HSSFShapeGroup
|
|||||||
int x2 = 1023;
|
int x2 = 1023;
|
||||||
int y2 = 255;
|
int y2 = 255;
|
||||||
|
|
||||||
|
public HSSFShapeGroup(EscherContainerRecord spgrContainer, ObjRecord objRecord) {
|
||||||
|
super(spgrContainer, objRecord);
|
||||||
|
|
||||||
|
// read internal and external coordinates from spgrContainer
|
||||||
|
EscherContainerRecord spContainer = spgrContainer.getChildContainers().get(0);
|
||||||
|
for(EscherRecord ch : spContainer.getChildRecords()){
|
||||||
|
switch(ch.getRecordId()) {
|
||||||
|
case EscherSpgrRecord.RECORD_ID:
|
||||||
|
EscherSpgrRecord spgr = (EscherSpgrRecord)ch;
|
||||||
|
setCoordinates(
|
||||||
|
spgr.getRectX1(), spgr.getRectY1(),
|
||||||
|
spgr.getRectX2(), spgr.getRectY2()
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case EscherClientAnchorRecord.RECORD_ID:
|
||||||
|
this.anchor = EscherAggregate.toClientAnchor((EscherClientAnchorRecord)ch);
|
||||||
|
// TODO anchor = new HSSFClientAnchor((EscherChildAnchorRecord)ch);
|
||||||
|
break;
|
||||||
|
case EscherChildAnchorRecord.RECORD_ID:
|
||||||
|
this.anchor = EscherAggregate.toChildAnchor((EscherChildAnchorRecord)ch);
|
||||||
|
// TODO anchor = new HSSFChildAnchor((EscherClientAnchorRecord)ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public HSSFShapeGroup( HSSFShape parent, HSSFAnchor anchor )
|
public HSSFShapeGroup( HSSFShape parent, HSSFAnchor anchor )
|
||||||
{
|
{
|
||||||
@ -61,6 +96,11 @@ public class HSSFShapeGroup
|
|||||||
shapes.add(shape);
|
shapes.add(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addTextBox(TextboxShape textboxShape){
|
||||||
|
// HSSFTextbox shape = new HSSFTextbox(this, textboxShape.geanchor);
|
||||||
|
// shapes.add(textboxShape);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new simple shape under this group.
|
* Create a new simple shape under this group.
|
||||||
* @param anchor the position of the shape.
|
* @param anchor the position of the shape.
|
||||||
|
@ -1738,12 +1738,16 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
if(agg == null) return null;
|
if(agg == null) return null;
|
||||||
|
|
||||||
_patriarch = new HSSFPatriarch(this, agg);
|
_patriarch = new HSSFPatriarch(this, agg);
|
||||||
agg.setPatriarch(_patriarch);
|
_patriarch.buildShapeTree();
|
||||||
|
|
||||||
|
//HSSFShapeFactory.createShapeTree();
|
||||||
|
//agg.setPatriarch(_patriarch);
|
||||||
|
//EscherAggregate.createShapeTree(EscherAggregate.getMainSpgrContainer(agg), agg.getPatriarch(), agg);
|
||||||
|
|
||||||
// Have it process the records into high level objects
|
// Have it process the records into high level objects
|
||||||
// as best it can do (this step may eat anything
|
// as best it can do (this step may eat anything
|
||||||
// that isn't supported, you were warned...)
|
// that isn't supported, you were warned...)
|
||||||
agg.convertRecordsToUserModel();
|
// agg.convertRecordsToUserModel();
|
||||||
|
|
||||||
// Return what we could cope with
|
// Return what we could cope with
|
||||||
return _patriarch;
|
return _patriarch;
|
||||||
|
33
src/java/org/apache/poi/hssf/usermodel/HSSFUnknownShape.java
Normal file
33
src/java/org/apache/poi/hssf/usermodel/HSSFUnknownShape.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
|
import org.apache.poi.ddf.EscherRecord;
|
||||||
|
import org.apache.poi.hssf.record.ObjRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Evgeniy Berlog
|
||||||
|
* date: 05.06.12
|
||||||
|
*/
|
||||||
|
public class HSSFUnknownShape extends HSSFShape {
|
||||||
|
|
||||||
|
public HSSFUnknownShape(EscherRecord spContainer, ObjRecord objRecord) {
|
||||||
|
super((EscherContainerRecord) spContainer, objRecord);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel.drawing;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFRectangle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Evgeniy Berlog
|
||||||
|
* date: 08.06.12
|
||||||
|
*/
|
||||||
|
public enum HSSFShapeType {
|
||||||
|
NOT_PRIMITIVE(0x0, null),
|
||||||
|
RECTANGLE(0x1, HSSFRectangle.class),
|
||||||
|
ROUND_RECTANGLE(0x2, null);
|
||||||
|
|
||||||
|
private Short type;
|
||||||
|
private Class shape;
|
||||||
|
|
||||||
|
HSSFShapeType(Integer type, Class shape) {
|
||||||
|
this.type = type.shortValue();
|
||||||
|
this.shape = shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Short getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getShape() {
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
}
|
@ -17,13 +17,13 @@
|
|||||||
package org.apache.poi.hssf.model;
|
package org.apache.poi.hssf.model;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
import org.apache.poi.ddf.EscherDggRecord;
|
import org.apache.poi.ddf.EscherDggRecord;
|
||||||
|
import org.apache.poi.ddf.EscherRecord;
|
||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
import org.apache.poi.hssf.record.*;
|
import org.apache.poi.hssf.record.*;
|
||||||
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
import org.apache.poi.hssf.usermodel.*;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFTestHelper;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
||||||
import org.apache.poi.util.HexRead;
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -35,19 +35,85 @@ import java.util.List;
|
|||||||
* @author Evgeniy Berlog
|
* @author Evgeniy Berlog
|
||||||
*/
|
*/
|
||||||
public class TestDrawingAggregate extends TestCase {
|
public class TestDrawingAggregate extends TestCase {
|
||||||
private static byte[] toByteArray(List<RecordBase> records){
|
|
||||||
|
private int spgrCount = 0;
|
||||||
|
private int spCount = 0;
|
||||||
|
private int shapeCount = 0;
|
||||||
|
private int shGroupCount = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EscherAggregate must have for each SpgrContainer HSSFShapeGroup and for each SpContainer HSSFShape
|
||||||
|
*/
|
||||||
|
private void checkEscherAndShapesCount(EscherAggregate agg, HSSFSheet sheet) {
|
||||||
|
/*
|
||||||
|
HSSFPatriarch patriarch = HSSFTestHelper.createTestPatriarch(sheet, agg);
|
||||||
|
agg.setPatriarch(patriarch);
|
||||||
|
EscherAggregate.createShapeTree(EscherAggregate.getMainSpgrContainer(agg), agg.getPatriarch(), agg);
|
||||||
|
EscherContainerRecord mainContainer = EscherAggregate.getMainSpgrContainer(agg);
|
||||||
|
calculateShapesCount(agg.getPatriarch());
|
||||||
|
calculateEscherContainersCount(mainContainer);
|
||||||
|
|
||||||
|
assertEquals(spgrCount, shGroupCount);
|
||||||
|
assertEquals(spCount - spgrCount - 1, shapeCount);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateEscherContainersCount(EscherContainerRecord spgr) {
|
||||||
|
for (EscherRecord record : spgr.getChildRecords()) {
|
||||||
|
if (EscherContainerRecord.SP_CONTAINER == record.getRecordId()) {
|
||||||
|
spCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (EscherContainerRecord.SPGR_CONTAINER == record.getRecordId()) {
|
||||||
|
spgrCount++;
|
||||||
|
calculateEscherContainersCount((EscherContainerRecord) record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateShapesCount(HSSFShapeContainer group) {
|
||||||
|
for (HSSFShape shape : (List<HSSFShape>) group.getChildren()) {
|
||||||
|
if (shape instanceof HSSFShapeGroup) {
|
||||||
|
shGroupCount++;
|
||||||
|
calculateShapesCount((HSSFShapeGroup) shape);
|
||||||
|
} else {
|
||||||
|
shapeCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static byte[] toByteArray(List<RecordBase> records) {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
for(RecordBase rb : records) {
|
for (RecordBase rb : records) {
|
||||||
Record r = (Record)rb;
|
Record r = (Record) rb;
|
||||||
try {
|
try {
|
||||||
out.write(r.serialize());
|
out.write(r.serialize());
|
||||||
} catch (IOException e){
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testSolverContainerMustBeSavedDuringSerialization(){
|
||||||
|
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SolverContainerAfterSPGR.xls");
|
||||||
|
HSSFSheet sh = wb.getSheetAt(0);
|
||||||
|
InternalSheet ish = HSSFTestHelper.getSheetForTest(sh);
|
||||||
|
sh.getDrawingPatriarch();
|
||||||
|
EscherAggregate agg = (EscherAggregate) ish.findFirstRecordBySid(EscherAggregate.sid);
|
||||||
|
assertEquals(agg.getEscherRecords().get(0).getChildRecords().size(), 3);
|
||||||
|
assertEquals(agg.getEscherRecords().get(0).getChild(2).getRecordId(), EscherContainerRecord.SOLVER_CONTAINER);
|
||||||
|
wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||||
|
sh = wb.getSheetAt(0);
|
||||||
|
sh.getDrawingPatriarch();
|
||||||
|
ish = HSSFTestHelper.getSheetForTest(sh);
|
||||||
|
agg = (EscherAggregate) ish.findFirstRecordBySid(EscherAggregate.sid);
|
||||||
|
assertEquals(agg.getEscherRecords().get(0).getChildRecords().size(), 3);
|
||||||
|
assertEquals(agg.getEscherRecords().get(0).getChild(2).getRecordId(), EscherContainerRecord.SOLVER_CONTAINER);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test reading drawing aggregate from a test file from Bugzilla 45129
|
* test reading drawing aggregate from a test file from Bugzilla 45129
|
||||||
*/
|
*/
|
||||||
@ -107,6 +173,7 @@ public class TestDrawingAggregate extends TestCase {
|
|||||||
byte[] dgBytesAfterSave = agg.serialize();
|
byte[] dgBytesAfterSave = agg.serialize();
|
||||||
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
||||||
assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
||||||
|
checkEscherAndShapesCount(agg, sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,7 +241,7 @@ public class TestDrawingAggregate extends TestCase {
|
|||||||
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
||||||
assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
||||||
|
|
||||||
|
checkEscherAndShapesCount(agg, sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -185,21 +252,20 @@ public class TestDrawingAggregate extends TestCase {
|
|||||||
List<RecordBase> records = isheet.getRecords();
|
List<RecordBase> records = isheet.getRecords();
|
||||||
|
|
||||||
HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||||
InternalSheet isheet2 = HSSFTestHelper.getSheetForTest( wb2.getSheetAt(0));
|
InternalSheet isheet2 = HSSFTestHelper.getSheetForTest(wb2.getSheetAt(0));
|
||||||
List<RecordBase> records2 = isheet2.getRecords();
|
List<RecordBase> records2 = isheet2.getRecords();
|
||||||
|
|
||||||
assertEquals(records.size(), records2.size());
|
assertEquals(records.size(), records2.size());
|
||||||
for(int i = 0; i < records.size(); i++) {
|
for (int i = 0; i < records.size(); i++) {
|
||||||
RecordBase r1 = records.get(i);
|
RecordBase r1 = records.get(i);
|
||||||
RecordBase r2 = records2.get(i);
|
RecordBase r2 = records2.get(i);
|
||||||
assertTrue(r1.getClass() == r2.getClass());
|
assertTrue(r1.getClass() == r2.getClass());
|
||||||
assertEquals(r1.getRecordSize(), r2.getRecordSize());
|
assertEquals(r1.getRecordSize(), r2.getRecordSize());
|
||||||
if(r1 instanceof Record ){
|
if (r1 instanceof Record) {
|
||||||
assertEquals(((Record)r1).getSid(), ((Record)r2).getSid());
|
assertEquals(((Record) r1).getSid(), ((Record) r2).getSid());
|
||||||
assertTrue(Arrays.equals(((Record) r1).serialize(), ((Record) r2).serialize()));
|
assertTrue(Arrays.equals(((Record) r1).serialize(), ((Record) r2).serialize()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSerializeDrawingWithComments() throws IOException {
|
public void testSerializeDrawingWithComments() throws IOException {
|
||||||
@ -257,6 +323,7 @@ public class TestDrawingAggregate extends TestCase {
|
|||||||
byte[] dgBytesAfterSave = agg.serialize();
|
byte[] dgBytesAfterSave = agg.serialize();
|
||||||
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
||||||
assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
||||||
|
checkEscherAndShapesCount(agg, sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -314,7 +381,8 @@ public class TestDrawingAggregate extends TestCase {
|
|||||||
|
|
||||||
byte[] dgBytesAfterSave = agg.serialize();
|
byte[] dgBytesAfterSave = agg.serialize();
|
||||||
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
||||||
assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
||||||
|
checkEscherAndShapesCount(agg, sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUnhandledContinue() {
|
public void testUnhandledContinue() {
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package org.apache.poi.hssf.usermodel;
|
package org.apache.poi.hssf.usermodel;
|
||||||
import org.apache.poi.hssf.model.InternalSheet;
|
import org.apache.poi.hssf.model.InternalSheet;
|
||||||
import org.apache.poi.hssf.model.InternalWorkbook;
|
import org.apache.poi.hssf.model.InternalWorkbook;
|
||||||
|
import org.apache.poi.hssf.record.EscherAggregate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for HSSF tests that aren't within the
|
* Helper class for HSSF tests that aren't within the
|
||||||
@ -34,4 +35,8 @@ public class HSSFTestHelper {
|
|||||||
public static InternalSheet getSheetForTest(HSSFSheet sheet) {
|
public static InternalSheet getSheetForTest(HSSFSheet sheet) {
|
||||||
return sheet.getSheet();
|
return sheet.getSheet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HSSFPatriarch createTestPatriarch(HSSFSheet sheet, EscherAggregate agg){
|
||||||
|
return new HSSFPatriarch(sheet, agg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
BIN
test-data/spreadsheet/SolverContainerAfterSPGR.xls
Executable file
BIN
test-data/spreadsheet/SolverContainerAfterSPGR.xls
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user