Index: src/testcases/org/apache/poi/hssf/model/TestDrawingAggregate.java =================================================================== --- src/testcases/org/apache/poi/hssf/model/TestDrawingAggregate.java (revision 1345858) +++ src/testcases/org/apache/poi/hssf/model/TestDrawingAggregate.java (revision ) @@ -17,13 +17,13 @@ package org.apache.poi.hssf.model; import junit.framework.TestCase; +import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherDggRecord; +import org.apache.poi.ddf.EscherRecord; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.record.*; import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFTestHelper; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.usermodel.*; import org.apache.poi.util.HexRead; import java.io.*; @@ -35,19 +35,85 @@ * @author Evgeniy Berlog */ public class TestDrawingAggregate extends TestCase { + + 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) group.getChildren()) { + if (shape instanceof HSSFShapeGroup) { + shGroupCount++; + calculateShapesCount((HSSFShapeGroup) shape); + } else { + shapeCount++; + } + } + } + + - private static byte[] toByteArray(List records){ + private static byte[] toByteArray(List 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 { - out.write(r.serialize()); + try { + out.write(r.serialize()); - } catch (IOException e){ + } catch (IOException e) { - throw new RuntimeException(e); - } - } - return out.toByteArray(); - } + throw new RuntimeException(e); + } + } + 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 */ @@ -107,6 +173,7 @@ byte[] dgBytesAfterSave = agg.serialize(); 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)); + checkEscherAndShapesCount(agg, sh); } /** @@ -174,7 +241,7 @@ 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)); - + checkEscherAndShapesCount(agg, sh); } @@ -185,21 +252,20 @@ List records = isheet.getRecords(); HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb); - InternalSheet isheet2 = HSSFTestHelper.getSheetForTest( wb2.getSheetAt(0)); + InternalSheet isheet2 = HSSFTestHelper.getSheetForTest(wb2.getSheetAt(0)); List records2 = isheet2.getRecords(); 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 r2 = records2.get(i); assertTrue(r1.getClass() == r2.getClass()); 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())); } } - } public void testSerializeDrawingWithComments() throws IOException { @@ -257,6 +323,7 @@ byte[] dgBytesAfterSave = agg.serialize(); 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)); + checkEscherAndShapesCount(agg, sh); } @@ -314,7 +381,8 @@ byte[] dgBytesAfterSave = agg.serialize(); 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() { Index: src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java (revision 805492) +++ src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java (revision ) @@ -17,6 +17,7 @@ package org.apache.poi.hssf.usermodel; +import org.apache.poi.ddf.EscherClientAnchorRecord; import org.apache.poi.ss.usermodel.ClientAnchor; @@ -33,6 +34,13 @@ int row2; 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. */ Index: src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java (revision 1148637) +++ src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java (revision ) @@ -22,9 +22,11 @@ import java.util.List; import org.apache.poi.ddf.EscherComplexProperty; +import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherOptRecord; import org.apache.poi.ddf.EscherProperty; import org.apache.poi.ddf.EscherBSERecord; +import org.apache.poi.ddf.EscherSpgrRecord; import org.apache.poi.hssf.record.EscherAggregate; import org.apache.poi.ss.usermodel.Chart; import org.apache.poi.util.StringUtil; @@ -314,4 +316,23 @@ throw new RuntimeException("NotImplemented"); } + + void buildShapeTree(){ + EscherContainerRecord dgContainer = _boundAggregate.getEscherContainer(); + EscherContainerRecord spgrConrainer = dgContainer.getChildContainers().get(0); + List 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); -} + } + } + } +} Index: src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java (revision ) +++ src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java (revision ) @@ -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); + } +} Index: src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java (revision 805262) +++ src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java (revision ) @@ -18,7 +18,16 @@ package org.apache.poi.hssf.usermodel; +import org.apache.poi.ddf.EscherChildAnchorRecord; + public final class HSSFChildAnchor extends HSSFAnchor { + + private EscherChildAnchorRecord escherChildAnchorRecord; + + public HSSFChildAnchor(EscherChildAnchorRecord escherChildAnchorRecord) { + this.escherChildAnchorRecord = escherChildAnchorRecord; + } + public HSSFChildAnchor() { } Index: src/java/org/apache/poi/hssf/usermodel/HSSFShapeContainer.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFShapeContainer.java (revision 489730) +++ src/java/org/apache/poi/hssf/usermodel/HSSFShapeContainer.java (revision ) @@ -31,4 +31,15 @@ */ 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 ); + } Index: src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java (revision 1296979) +++ src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java (revision ) @@ -1738,12 +1738,16 @@ if(agg == null) return null; _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 // as best it can do (this step may eat anything // that isn't supported, you were warned...) - agg.convertRecordsToUserModel(); +// agg.convertRecordsToUserModel(); // Return what we could cope with return _patriarch; Index: src/java/org/apache/poi/hssf/usermodel/HSSFUnknownShape.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFUnknownShape.java (revision ) +++ src/java/org/apache/poi/hssf/usermodel/HSSFUnknownShape.java (revision ) @@ -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); + } +} Index: src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java (revision 1169679) +++ src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java (revision ) @@ -17,6 +17,15 @@ 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.List; import java.util.Iterator; @@ -37,7 +46,33 @@ int x2 = 1023; 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 ) { super( parent, anchor ); @@ -61,6 +96,11 @@ 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. * @param anchor the position of the shape. Index: src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java (revision ) +++ src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java (revision ) @@ -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 shapeTypeToClass = new HashMap(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 shapeTypeToClass; + + private ReflectionConstructorShapeCreator(Map 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 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 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); + } + } +} Index: src/testcases/org/apache/poi/hssf/usermodel/HSSFTestHelper.java =================================================================== --- src/testcases/org/apache/poi/hssf/usermodel/HSSFTestHelper.java (revision 894081) +++ src/testcases/org/apache/poi/hssf/usermodel/HSSFTestHelper.java (revision ) @@ -18,6 +18,7 @@ package org.apache.poi.hssf.usermodel; import org.apache.poi.hssf.model.InternalSheet; import org.apache.poi.hssf.model.InternalWorkbook; +import org.apache.poi.hssf.record.EscherAggregate; /** * Helper class for HSSF tests that aren't within the @@ -34,4 +35,8 @@ public static InternalSheet getSheetForTest(HSSFSheet sheet) { return sheet.getSheet(); } + + public static HSSFPatriarch createTestPatriarch(HSSFSheet sheet, EscherAggregate agg){ + return new HSSFPatriarch(sheet, agg); -} + } +} Index: src/java/org/apache/poi/hssf/usermodel/HSSFShape.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFShape.java (revision 1148637) +++ src/java/org/apache/poi/hssf/usermodel/HSSFShape.java (revision ) @@ -17,6 +17,9 @@ package org.apache.poi.hssf.usermodel; +import org.apache.poi.ddf.EscherContainerRecord; +import org.apache.poi.hssf.record.ObjRecord; + /** * An abstract shape. * @@ -40,7 +43,7 @@ public static final int LINESTYLE_NONE = -1; // TODO - make all these fields private - final HSSFShape parent; + HSSFShape parent; HSSFAnchor anchor; HSSFPatriarch _patriarch; private int _lineStyleColor = 0x08000040; @@ -49,15 +52,30 @@ private int _lineStyle = LINESTYLE_SOLID; 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. */ - HSSFShape( HSSFShape parent, HSSFAnchor anchor ) + public HSSFShape( HSSFShape parent, HSSFAnchor anchor ) { this.parent = parent; this.anchor = anchor; } + public EscherContainerRecord getSpContainer() { + return spContainer; + } + + public ObjRecord getObjRecord() { + return objRecord; + } + /** * Gets the parent shape. */ Index: src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java (revision ) +++ src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java (revision ) @@ -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; + } +} Index: src/java/org/apache/poi/hssf/record/EscherAggregate.java =================================================================== --- src/java/org/apache/poi/hssf/record/EscherAggregate.java (revision 1345858) +++ src/java/org/apache/poi/hssf/record/EscherAggregate.java (revision ) @@ -43,16 +43,7 @@ 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.HSSFAnchor; -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.hssf.usermodel.*; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -322,7 +313,7 @@ /** * list of "tail" records that need to be serialized after all drawing group records */ - private List tailRec = new ArrayList(); + private List tailRec = new ArrayList(); public EscherAggregate(DrawingManager2 drawingManager) { this.drawingManager = drawingManager; @@ -413,7 +404,7 @@ } // Decode the shapes - // agg.escherRecords = new ArrayList(); + // agg.escherRecords = new ArrayList(); int pos = 0; while (pos < buffer.size()) { EscherRecord r = recordFactory.createRecord(buffer.toByteArray(), pos); @@ -486,7 +477,7 @@ public void afterRecordSerialize(int offset, short recordId, int size, EscherRecord record) { if (recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID) { - spEndingOffsets.add(Integer.valueOf(offset)); + spEndingOffsets.add(offset); shapes.add(record); } } @@ -501,12 +492,17 @@ pos = offset; int writtenEscherBytes = 0; 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; if (i == 1) startOffset = 0; else - startOffset = ((Integer) spEndingOffsets.get(i - 1)).intValue(); + startOffset = (Integer) spEndingOffsets.get(i - 1); byte[] drawingData = new byte[endOffset - startOffset + 1]; @@ -790,7 +786,7 @@ container.getChildren().add(shape); } - private static HSSFClientAnchor toClientAnchor(EscherClientAnchorRecord anchorRecord) { + public static HSSFClientAnchor toClientAnchor(EscherClientAnchorRecord anchorRecord) { HSSFClientAnchor anchor = new HSSFClientAnchor(); anchor.setAnchorType(anchorRecord.getFlag()); anchor.setCol1(anchorRecord.getCol1()); @@ -804,7 +800,7 @@ return anchor; } - private static HSSFChildAnchor toChildAnchor(EscherChildAnchorRecord anchorRecord) { + public static HSSFChildAnchor toChildAnchor(EscherChildAnchorRecord anchorRecord) { HSSFChildAnchor anchor = new HSSFChildAnchor(); // anchor.setAnchorType(anchorRecord.getFlag()); // anchor.setCol1( anchorRecord.getCol1() ); @@ -1081,4 +1077,24 @@ 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 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 getTailRecords(){ + return Collections.unmodifiableList(tailRec); + } +}