diff --git a/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java b/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java
index f12896a14..ed2de1af2 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/HSLFSlideShow.java
@@ -262,6 +262,7 @@ public class HSLFSlideShow
int oldPos = pdr.getLastOnDiskOffset();
int newPos = baos.size();
pdr.setLastOnDiskOffset(newPos);
+ //System.out.println(i + " " + oldPos + " " + newPos);
oldToNewPositions.put(new Integer(oldPos),new Integer(newPos));
pdr.updateOtherRecordReferences(oldToNewPositions);
}
@@ -317,6 +318,31 @@ public class HSLFSlideShow
* Returns an array of all the records found in the slideshow
*/
public Record[] getRecords() { return _records; }
+
+ /**
+ * Adds a new root level record, at the end, but before the last
+ * PersistPtrIncrementalBlock.
+ */
+ public synchronized int appendRootLevelRecord(Record newRecord) {
+ int addedAt = -1;
+ Record[] r = new Record[_records.length+1];
+ boolean added = false;
+ for(int i=(_records.length-1); i>=0; i--) {
+ if(added) {
+ // Just copy over
+ r[i] = _records[i];
+ } else {
+ r[(i+1)] = _records[i];
+ if(_records[i] instanceof PersistPtrHolder) {
+ r[i] = newRecord;
+ added = true;
+ addedAt = i;
+ }
+ }
+ }
+ _records = r;
+ return addedAt;
+ }
/**
* Returns an array of the bytes of the file. Only correct after a
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Ellipse.java b/src/scratchpad/src/org/apache/poi/hslf/model/Ellipse.java
new file mode 100644
index 000000000..9db95012c
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Ellipse.java
@@ -0,0 +1,60 @@
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hslf.model;
+
+import org.apache.poi.ddf.*;
+
+import java.awt.*;
+
+/**
+ * Represents a ellipse in a PowerPoint drawing
+ *
+ * @author Yegor Kozlov
+ */
+public class Ellipse extends SimpleShape {
+
+ protected Ellipse(EscherContainerRecord escherRecord, Shape parent){
+ super(escherRecord, parent);
+ }
+
+ public Ellipse(Shape parent){
+ super(null, parent);
+ _escherContainer = create(parent instanceof ShapeGroup);
+ }
+
+ public Ellipse(){
+ this(null);
+ }
+
+ protected EscherContainerRecord create(boolean isChild){
+ EscherContainerRecord spcont = super.create(isChild);
+ spcont.setOptions((short)15);
+
+ EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
+ short type = (ShapeTypes.Ellipse << 4) + 2;
+ spRecord.setOptions(type);
+
+ //set default properties for a line
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
+
+ opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 4));
+ opt.sortProperties();
+
+ return spcont;
+ }
+
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Line.java b/src/scratchpad/src/org/apache/poi/hslf/model/Line.java
new file mode 100644
index 000000000..ea8e32fa6
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Line.java
@@ -0,0 +1,123 @@
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hslf.model;
+
+import org.apache.poi.ddf.*;
+
+import java.awt.*;
+
+/**
+ * Represents a line in a PowerPoint drawing
+ *
+ * @author Yegor Kozlov
+ */
+public class Line extends SimpleShape {
+ /**
+ * Solid (continuous) pen
+ */
+ public static final int LineSolid = 1;
+ /**
+ * PS_DASH system dash style
+ */
+ public static final int LineDashSys = 2;
+ /**
+ * PS_DOT system dash style
+ */
+ public static final int LineDotSys = 3;
+ /**
+ * PS_DASHDOT system dash style
+ */
+ public static final int LineDashDotSys = 4;
+
+ /**
+ * PS_DASHDOTDOT system dash style
+ */
+ public static final int LineDashDotDotSys = 5;
+ /**
+ * square dot style
+ */
+ public static final int LineDotGEL = 6;
+ /**
+ * dash style
+ */
+ public static final int LineDashGEL = 7;
+ /**
+ * long dash style
+ */
+ public static final int LineLongDashGEL = 8;
+ /**
+ * dash short dash
+ */
+ public static final int LineDashDotGEL = 9;
+ /**
+ * long dash short dash
+ */
+ public static final int LineLongDashDotGEL = 10;
+ /**
+ * long dash short dash short dash
+ */
+ public static final int LineLongDashDotDotGEL = 11;
+
+ /**
+ * Decoration of the end of line,
+ * reserved in API but not supported.
+ */
+
+ /**
+ * Line ends at end point
+ */
+ public static final int EndCapFlat = 0;
+ /**
+ * Rounded ends - the default
+ */
+ public static final int EndCapRound = 1;
+ /**
+ * Square protrudes by half line width
+ */
+ public static final int EndCapSquare = 2;
+
+ protected Line(EscherContainerRecord escherRecord, Shape parent){
+ super(escherRecord, parent);
+ }
+
+ public Line(Shape parent){
+ super(null, parent);
+ _escherContainer = create(parent instanceof ShapeGroup);
+ }
+
+ public Line(){
+ this(null);
+ }
+
+ protected EscherContainerRecord create(boolean isChild){
+ EscherContainerRecord spcont = super.create(isChild);
+ spcont.setOptions((short)15);
+
+ EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
+ short type = (ShapeTypes.Line << 4) + 2;
+ spRecord.setOptions(type);
+
+ //set default properties for a line
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
+
+ //opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 4));
+ opt.sortProperties();
+
+ return spcont;
+ }
+
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Notes.java b/src/scratchpad/src/org/apache/poi/hslf/model/Notes.java
index ca1b467a5..f7fd00385 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/Notes.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Notes.java
@@ -70,4 +70,5 @@ public class Notes extends Sheet
* Returns the sheet number
*/
public int getSheetNumber() { return _sheetNo; }
-}
+
+ protected PPDrawing getPPDrawing() { return _notes.getPPDrawing(); }}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java
new file mode 100644
index 000000000..f84d968d2
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java
@@ -0,0 +1,434 @@
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hslf.model;
+
+
+import java.awt.*;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.image.*;
+import java.awt.image.renderable.RenderableImage;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+import org.apache.poi.ddf.EscherProperties;
+
+/**
+ * Translates Graphics2D calls into PowerPoint.
+ *
+ * @author Yegor Kozlov
+ */
+public class PPGraphics2D extends Graphics2D {
+ //The group to write the graphics calls into.
+ private ShapeGroup group;
+
+ private AffineTransform transform;
+ private Stroke stroke;
+ private Paint paint;
+ private Font font;
+ private Color foreground;
+ private Color background = Color.white;
+ private Shape clip;
+
+ /**
+ * Construct an powerpoint Graphics object.
+ *
+ * @param group The shape group to write the graphics calls into.
+ */
+ public PPGraphics2D(ShapeGroup group){
+ this.group = group;
+ transform = new AffineTransform();
+ }
+
+ /**
+ * @return the shape group being used for drawing
+ */
+ public ShapeGroup getShapeGroup(){
+ return group;
+ }
+
+ public Font getFont(){
+ return font;
+ }
+
+ public void setFont(Font font){
+ this.font = font;
+ }
+
+ public Color getColor(){
+ return foreground;
+ }
+
+ public void setColor(Color color) {
+ this.foreground = color;
+ }
+
+ public Stroke getStroke(){
+ return stroke;
+ }
+
+ public void setStroke(Stroke s){
+ this.stroke = s;
+ }
+
+ public Paint getPaint(){
+ return paint;
+ }
+
+ public void setPaint(Paint paint){
+ this.paint = paint;
+ if (paint instanceof Color) setColor((Color)paint);
+ }
+
+ public AffineTransform getTransform(){
+ return (AffineTransform)transform.clone();
+ }
+
+ public void setTransform(AffineTransform trans) {
+ transform = (AffineTransform)trans.clone();
+ }
+
+ public void draw(Shape shape){
+ if(clip != null) {
+ if (!clip.getBounds().contains(transform.createTransformedShape(shape).getBounds())) {
+ //return;
+ }
+ }
+
+ PathIterator it = shape.getPathIterator(transform);
+ double[] prev = null;
+ double[] coords = new double[6];
+ double[] first = new double[6];
+ if(!it.isDone()) it.currentSegment(first); //first point
+ while(!it.isDone()){
+ int type = it.currentSegment(coords);
+ if (prev != null ){
+ Line line = new Line(group);
+ if (stroke instanceof BasicStroke){
+ BasicStroke bs = (BasicStroke)stroke;
+ line.setLineWidth(bs.getLineWidth());
+ }
+ if(getColor() != null) line.setLineColor(getColor());
+ if (type == PathIterator.SEG_LINETO) {
+ line.setAnchor(new java.awt.Rectangle((int)prev[0], (int)prev[1], (int)(coords[0] - prev[0]), (int)(coords[1] - prev[1])));
+ } else if (type == PathIterator.SEG_CLOSE){
+ line.setAnchor(new java.awt.Rectangle((int)coords[0], (int)coords[1], (int)(first[0] - coords[0]), (int)(first[1] - coords[1])));
+ }
+ group.addShape(line);
+ }
+ prev = new double[]{coords[0], coords[1]};
+ it.next();
+ }
+
+ }
+
+ public void drawString(String string, float x, float y){
+ }
+
+ public void fill(Shape shape){
+ if (paint instanceof Color){
+ Color color = (Color)paint;
+ }
+
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void translate(int x, int y) {
+ AffineTransform at = new AffineTransform();
+ at.translate(x, y);
+ transform.concatenate(at);
+ }
+
+ public void clip(Shape shape) {
+ this.clip = transform.createTransformedShape(shape);
+ //update size of the escher group which holds the drawing
+ group.setAnchor(clip.getBounds());
+ }
+
+ public Shape getClip() {
+ return clip;
+ }
+
+ public void scale(double sx, double sy) {
+ AffineTransform at = new AffineTransform();
+ at.scale(sx, sy);
+ transform.concatenate(at);
+ }
+ //===============================================
+ public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void drawString(String str, int x, int y) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void fillOval(int x, int y, int width, int height) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void fillArc(int x, int y, int width, int height,
+ int startAngle, int arcAngle) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void setPaintMode() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void drawArc(int x, int y, int width, int height,
+ int startAngle, int arcAngle) {
+ throw new RuntimeException("Not implemented");
+ }
+
+
+ public void drawPolyline(int xPoints[], int yPoints[],
+ int nPoints) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public Graphics create() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void drawOval(int x, int y, int width, int height) {
+ Ellipse ellipse = new Ellipse();
+ ellipse.setAnchor(new java.awt.Rectangle(x-width/2, y-height/2, width, height));
+ if (stroke instanceof BasicStroke){
+ BasicStroke bs = (BasicStroke)stroke;
+ ellipse.setLineWidth(bs.getLineWidth());
+ }
+ if(getColor() != null) ellipse.setLineColor(getColor());
+ if (paint instanceof Color){
+ Color color = (Color)paint;
+ ellipse.setFillColor(color);
+ }
+
+ group.addShape(ellipse);
+ }
+
+ public void setXORMode(Color color1) {
+ throw new RuntimeException("Not implemented");
+ }
+
+
+ public boolean drawImage(Image img, int x, int y,
+ Color bgcolor,
+ ImageObserver observer) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public boolean drawImage(Image img, int x, int y,
+ int width, int height,
+ Color bgcolor,
+ ImageObserver observer) {
+ throw new RuntimeException("Not implemented");
+ }
+
+
+ public boolean drawImage(Image img,
+ int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2,
+ ImageObserver observer) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public boolean drawImage(Image img,
+ int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2,
+ Color bgcolor,
+ ImageObserver observer) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public boolean drawImage(Image img, int x, int y,
+ ImageObserver observer) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public boolean drawImage(Image img, int x, int y,
+ int width, int height,
+ ImageObserver observer) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void dispose() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ Line line = new Line();
+ line.setAnchor(new java.awt.Rectangle(x1, y1, x2-x1, y2-y1));
+ if (stroke instanceof BasicStroke){
+ BasicStroke bs = (BasicStroke)stroke;
+ line.setLineWidth(bs.getLineWidth());
+ }
+ if(getColor() != null) line.setLineColor(getColor());
+ group.addShape(line);
+ }
+
+ public void fillPolygon(int xPoints[], int yPoints[],
+ int nPoints) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public FontMetrics getFontMetrics(Font f) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void fillRect(int x, int y, int width, int height) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void drawPolygon(int xPoints[], int yPoints[],
+ int nPoints) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void clipRect(int x, int y, int width, int height) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void setClip(Shape clip) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public java.awt.Rectangle getClipBounds() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void clearRect(int x, int y, int width, int height) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void copyArea(int x, int y, int width, int height, int dx, int dy) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void setClip(int x, int y, int width, int height) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void rotate(double d) {
+ throw new RuntimeException("Not implemented");
+
+ }
+
+ public void rotate(double d, double d1, double d2) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void shear(double d, double d1) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public FontRenderContext getFontRenderContext() {
+ return new FontRenderContext(transform, true, true);
+ }
+
+ public void transform(AffineTransform affinetransform) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void drawImage(BufferedImage bufferedimage, BufferedImageOp op, int x, int y) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void setBackground(Color c) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void drawRenderedImage(RenderedImage renderedimage, AffineTransform affinetransform) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public Color getBackground() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void setComposite(Composite composite) {
+ throw new RuntimeException("Not implemented");
+
+ }
+
+ public Composite getComposite() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public Object getRenderingHint(java.awt.RenderingHints.Key key) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public boolean drawImage(Image image, AffineTransform affinetransform, ImageObserver imageobserver) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void setRenderingHint(java.awt.RenderingHints.Key key, Object obj) {
+ throw new RuntimeException("Not implemented");
+ }
+
+
+ public void drawGlyphVector(GlyphVector g, float x, float y) {
+ throw new RuntimeException("Not implemented");
+
+ }
+
+ public GraphicsConfiguration getDeviceConfiguration() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void addRenderingHints(Map map) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void translate(double d, double d1) {
+
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void drawString(AttributedCharacterIterator attributedcharacteriterator, float x, float y) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public boolean hit(java.awt.Rectangle rectangle, Shape shape, boolean flag) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public RenderingHints getRenderingHints() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public void setRenderingHints(Map map) {
+ throw new RuntimeException("Not implemented");
+
+ }
+
+ public void drawRenderableImage(RenderableImage renderableimage, AffineTransform affinetransform) {
+ throw new RuntimeException("Not implemented");
+ }
+
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Rectangle.java b/src/scratchpad/src/org/apache/poi/hslf/model/Rectangle.java
new file mode 100644
index 000000000..a4be8e271
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Rectangle.java
@@ -0,0 +1,60 @@
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hslf.model;
+
+import org.apache.poi.ddf.*;
+
+import java.awt.*;
+
+/**
+ * Represents a line in a PowerPoint drawing
+ *
+ * @author Yegor Kozlov
+ */
+public class Rectangle extends SimpleShape {
+
+ protected Rectangle(EscherContainerRecord escherRecord, Shape parent){
+ super(escherRecord, parent);
+ }
+
+ public Rectangle(Shape parent){
+ super(null, parent);
+ _escherContainer = create(parent instanceof ShapeGroup);
+ }
+
+ public Rectangle(){
+ this(null);
+ }
+
+ protected EscherContainerRecord create(boolean isChild){
+ EscherContainerRecord spcont = super.create(isChild);
+ spcont.setOptions((short)15);
+
+ EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
+ short type = (ShapeTypes.Rectangle << 4) + 2;
+ spRecord.setOptions(type);
+
+ //set default properties for a rectangle
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
+
+ opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 4));
+ opt.sortProperties();
+
+ return spcont;
+ }
+
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java b/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java
new file mode 100644
index 000000000..a01b11691
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java
@@ -0,0 +1,172 @@
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hslf.model;
+
+import org.apache.poi.ddf.*;
+import org.apache.poi.hslf.model.ShapeTypes;
+
+import java.awt.*;
+import java.util.Iterator;
+
+/**
+ * Represents a Shape which is the elemental object that composes a drawing.
+ *
+ * @author Yegor Kozlov
+ */
+public class Shape {
+
+ public static final int EMU_PER_POINT = 12700;
+
+ /**
+ * The parent of the shape
+ */
+ protected Shape _parent;
+
+ /**
+ * Either EscherSpContainer or EscheSpgrContainer record
+ * which holds information about this shape.
+ */
+ protected EscherContainerRecord _escherContainer;
+
+ protected Shape(EscherContainerRecord escherRecord, Shape parent){
+ _escherContainer = escherRecord;
+ _parent = parent;
+ }
+
+ /**
+ * @return the parent of this shape
+ */
+ public Shape getParent(){
+ return _parent;
+ }
+
+ /**
+ * @return name of the shape.
+ */
+ public String getShapeName(){
+ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+ return ShapeTypes.typeName(spRecord.getOptions() >> 4);
+ }
+
+ /**
+ * Returns the anchor (the bounding box rectangle) of this shape.
+ * All coordinates are expressed in Master units (576 dpi).
+ *
+ * @return the anchor of this shape
+ */
+ public java.awt.Rectangle getAnchor(){
+ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+ int flags = spRecord.getFlags();
+ java.awt.Rectangle anchor=null;
+ if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
+ EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
+ anchor = new java.awt.Rectangle();
+ anchor.x = rec.getDx1();
+ anchor.y = rec.getDy1();
+ anchor.width = rec.getDx2() - anchor.x;
+ anchor.height = rec.getDy2() - anchor.y;
+ }
+ else {
+ EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
+ anchor = new java.awt.Rectangle();
+ anchor.y = rec.getFlag();
+ anchor.x = rec.getCol1();
+ anchor.width = rec.getDx1() - anchor.x;
+ anchor.height = rec.getRow1() - anchor.y;
+ }
+ return anchor;
+ }
+
+ /**
+ * Sets the anchor (the bounding box rectangle) of this shape.
+ * All coordinates should be expressed in Master units (576 dpi).
+ *
+ * @param anchor new anchor
+ */
+ public void setAnchor(java.awt.Rectangle anchor){
+ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+ int flags = spRecord.getFlags();
+ if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
+ EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
+ rec.setDx1(anchor.x);
+ rec.setDy1(anchor.y);
+ rec.setDx2(anchor.width + anchor.x);
+ rec.setDy2(anchor.height + anchor.y);
+ }
+ else {
+ EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
+ rec.setFlag((short)anchor.y);
+ rec.setCol1((short)anchor.x);
+ rec.setDx1((short)(anchor.width + anchor.x));
+ rec.setRow1((short)(anchor.height + anchor.y));
+ }
+
+ }
+
+ /**
+ * Moves the top left corner of the shape to the specified point.
+ *
+ * @param x the x coordinate of the top left corner of the shape
+ * @param y the y coordinate of the top left corner of the shape
+ */
+ public void moveTo(int x, int y){
+ java.awt.Rectangle anchor = getAnchor();
+ anchor.setLocation(x, y);
+ setAnchor(anchor);
+ }
+
+ protected static EscherRecord getEscherChild(EscherContainerRecord owner, int recordId){
+ for ( Iterator iterator = owner.getChildRecords().iterator(); iterator.hasNext(); )
+ {
+ EscherRecord escherRecord = (EscherRecord) iterator.next();
+ if (escherRecord.getRecordId() == recordId)
+ return (EscherRecord) escherRecord;
+ }
+ return null;
+ }
+
+ protected static EscherProperty getEscherProperty(EscherOptRecord opt, int propId){
+ for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
+ {
+ EscherProperty prop = (EscherProperty) iterator.next();
+ if (prop.getId() == propId)
+ return prop;
+ }
+ return null;
+ }
+
+ protected static void setEscherProperty(EscherOptRecord opt, short propId, int value){
+ java.util.List props = opt.getEscherProperties();
+ for ( Iterator iterator = props.iterator(); iterator.hasNext(); ) {
+ EscherProperty prop = (EscherProperty) iterator.next();
+ if (prop.getId() == propId){
+ iterator.remove();
+ }
+ }
+ if (value != -1) {
+ opt.addEscherProperty(new EscherSimpleProperty(propId, value));
+ opt.sortProperties();
+ }
+ }
+
+ /**
+ *
+ * @return escher container which holds information about this shape
+ */
+ public EscherContainerRecord getShapeRecord(){
+ return _escherContainer;
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java
new file mode 100644
index 000000000..67f2d708b
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java
@@ -0,0 +1,61 @@
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hslf.model;
+
+import org.apache.poi.ddf.EscherSpRecord;
+import org.apache.poi.ddf.EscherContainerRecord;
+
+/**
+ * Create a Shape
object depending on its type
+ *
+ * @author Yegor Kozlov
+ */
+public class ShapeFactory {
+
+ public static Shape createShape(EscherContainerRecord spContainer, Shape parent){
+ if (spContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){
+ return new ShapeGroup(spContainer, parent);
+ }
+
+ Shape shape;
+ EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID);
+
+ int type = spRecord.getOptions() >> 4;
+ switch (type){
+ case ShapeTypes.TextBox:
+ case ShapeTypes.Rectangle:
+ shape = new Shape(spContainer, parent);
+ break;
+ case ShapeTypes.PictureFrame:
+ shape = new Shape(spContainer, parent);
+ break;
+ case ShapeTypes.Line:
+ shape = new Line(spContainer, parent);
+ break;
+ case ShapeTypes.Ellipse:
+ shape = new Ellipse(spContainer, parent);
+ break;
+ case ShapeTypes.NotPrimitive:
+ shape = new ShapeGroup(spContainer, parent);
+ break;
+ default:
+ shape = new Shape(spContainer, parent);
+ break;
+ }
+ return shape;
+ }
+
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java
new file mode 100644
index 000000000..c11e29471
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java
@@ -0,0 +1,151 @@
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hslf.model;
+
+import org.apache.poi.ddf.*;
+import org.apache.poi.util.LittleEndian;
+
+import java.util.List;
+
+/**
+ * Represents a group of shapes.
+ *
+ * @author Yegor Kozlov
+ */
+public class ShapeGroup extends Shape{
+
+ public ShapeGroup(Shape parent){
+ super(null, parent);
+ _escherContainer = create();
+ }
+
+ public ShapeGroup(){
+ this(null);
+ }
+
+ protected ShapeGroup(EscherContainerRecord escherRecord, Shape parent){
+ super(escherRecord, parent);
+ }
+
+ /**
+ * @return the shapes contained in this group container
+ */
+ public Shape[] getShapes() {
+ //several SpContainers, the first of which is the group shape itself
+ List lst = _escherContainer.getChildRecords();
+
+ //don't include the first SpContainer, it is always NotPrimitive
+ Shape[] shapes = new Shape[lst.size() - 1];
+ for (int i = 1; i < lst.size(); i++){
+ EscherContainerRecord container = (EscherContainerRecord)lst.get(i);
+ shapes[i-1] = ShapeFactory.createShape(container, this);
+ }
+ return shapes;
+ }
+
+ /**
+ * Sets the anchor (the bounding box rectangle) of this shape.
+ * All coordinates should be expressed in Master units (576 dpi).
+ *
+ * @param anchor new anchor
+ */
+ public void setAnchor(java.awt.Rectangle anchor){
+
+ EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChildRecords().get(0);
+
+ EscherClientAnchorRecord clientAnchor = (EscherClientAnchorRecord)getEscherChild(spContainer, EscherClientAnchorRecord.RECORD_ID);
+ //hack. internal variable EscherClientAnchorRecord.shortRecord can be
+ //initialized only in fillFields(). We need to set shortRecord=false;
+ byte[] header = new byte[16];
+ LittleEndian.putUShort(header, 0, 0);
+ LittleEndian.putUShort(header, 2, 0);
+ LittleEndian.putInt(header, 4, 8);
+ clientAnchor.fillFields(header, 0, null);
+
+ clientAnchor.setFlag((short)anchor.y);
+ clientAnchor.setCol1((short)anchor.x);
+ clientAnchor.setDx1((short)(anchor.width + anchor.x));
+ clientAnchor.setRow1((short)(anchor.height + anchor.y));
+
+ EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
+
+ spgr.setRectX1(anchor.x);
+ spgr.setRectY1(anchor.y);
+ spgr.setRectX2(anchor.x + anchor.width);
+ spgr.setRectY2(anchor.y + anchor.height);
+ }
+
+ /**
+ * Create a new ShapeGroup and create an instance of EscherSpgrContainer
which represents a group of shapes
+ */
+ protected EscherContainerRecord create() {
+ EscherContainerRecord spgr = new EscherContainerRecord();
+ spgr.setRecordId(EscherContainerRecord.SPGR_CONTAINER);
+ spgr.setOptions((short)15);
+
+ //The group itself is a shape, and always appears as the first EscherSpContainer in the group container.
+ EscherContainerRecord spcont = new EscherContainerRecord();
+ spcont.setRecordId(EscherContainerRecord.SP_CONTAINER);
+ spcont.setOptions((short)15);
+
+ EscherSpgrRecord spg = new EscherSpgrRecord();
+ spg.setOptions((short)1);
+ spcont.addChildRecord(spg);
+
+ EscherSpRecord sp = new EscherSpRecord();
+ short type = (ShapeTypes.NotPrimitive << 4) + 2;
+ sp.setOptions(type);
+ sp.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_GROUP);
+ spcont.addChildRecord(sp);
+
+ EscherClientAnchorRecord anchor = new EscherClientAnchorRecord();
+ spcont.addChildRecord(anchor);
+
+ spgr.addChildRecord(spcont);
+ return spgr;
+ }
+
+ /**
+ * Add a shape to this group.
+ *
+ * @param shape - the Shape to add
+ */
+ public void addShape(Shape shape){
+ _escherContainer.addChildRecord(shape.getShapeRecord());
+ }
+
+ /**
+ * Moves this ShapeGroup
to the specified location.
+ *
+ * @param x the x coordinate of the top left corner of the shape in new location
+ * @param y the y coordinate of the top left corner of the shape in new location
+ */
+ public void moveTo(int x, int y){
+ java.awt.Rectangle anchor = getAnchor();
+ int dx = x - anchor.x;
+ int dy = y - anchor.y;
+ anchor.translate(dx, dy);
+ setAnchor(anchor);
+
+ Shape[] shape = getShapes();
+ for (int i = 0; i < shape.length; i++) {
+ java.awt.Rectangle chanchor = shape[i].getAnchor();
+ chanchor.translate(dx, dy);
+ shape[i].setAnchor(chanchor);
+ }
+ }
+
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeTypes.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeTypes.java
new file mode 100644
index 000000000..fd571c181
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeTypes.java
@@ -0,0 +1,257 @@
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hslf.model;
+
+import java.util.HashMap;
+import java.lang.reflect.Field;
+
+/**
+ * Contains all known shape types in PowerPoint
+ *
+ * @author Yegor Kozlov
+ */
+public class ShapeTypes {
+ public static final int NotPrimitive = 0;
+ public static final int Rectangle = 1;
+ public static final int RoundRectangle = 2;
+ public static final int Ellipse = 3;
+ public static final int Diamond = 4;
+ public static final int IsocelesTriangle = 5;
+ public static final int RightTriangle = 6;
+ public static final int Parallelogram = 7;
+ public static final int Trapezoid = 8;
+ public static final int Hexagon = 9;
+ public static final int Octagon = 10;
+ public static final int Plus = 11;
+ public static final int Star = 12;
+ public static final int Arrow = 13;
+ public static final int ThickArrow = 14;
+ public static final int HomePlate = 15;
+ public static final int Cube = 16;
+ public static final int Balloon = 17;
+ public static final int Seal = 18;
+ public static final int Arc = 19;
+ public static final int Line = 20;
+ public static final int Plaque = 21;
+ public static final int Can = 22;
+ public static final int Donut = 23;
+ public static final int TextSimple = 24;
+ public static final int TextOctagon = 25;
+ public static final int TextHexagon = 26;
+ public static final int TextCurve = 27;
+ public static final int TextWave = 28;
+ public static final int TextRing = 29;
+ public static final int TextOnCurve = 30;
+ public static final int TextOnRing = 31;
+ public static final int StraightConnector1 = 32;
+ public static final int BentConnector2 = 33;
+ public static final int BentConnector3 = 34;
+ public static final int BentConnector4 = 35;
+ public static final int BentConnector5 = 36;
+ public static final int CurvedConnector2 = 37;
+ public static final int CurvedConnector3 = 38;
+ public static final int CurvedConnector4 = 39;
+ public static final int CurvedConnector5 = 40;
+ public static final int Callout1 = 41;
+ public static final int Callout2 = 42;
+ public static final int Callout3 = 43;
+ public static final int AccentCallout1 = 44;
+ public static final int AccentCallout2 = 45;
+ public static final int AccentCallout3 = 46;
+ public static final int BorderCallout1 = 47;
+ public static final int BorderCallout2 = 48;
+ public static final int BorderCallout3 = 49;
+ public static final int AccentBorderCallout1 = 50;
+ public static final int AccentBorderCallout2 = 51;
+ public static final int AccentBorderCallout3 = 52;
+ public static final int Ribbon = 53;
+ public static final int Ribbon2 = 54;
+ public static final int Chevron = 55;
+ public static final int Pentagon = 56;
+ public static final int NoSmoking = 57;
+ public static final int Seal8 = 58;
+ public static final int Seal16 = 59;
+ public static final int Seal32 = 60;
+ public static final int WedgeRectCallout = 61;
+ public static final int WedgeRRectCallout = 62;
+ public static final int WedgeEllipseCallout = 63;
+ public static final int Wave = 64;
+ public static final int FoldedCorner = 65;
+ public static final int LeftArrow = 66;
+ public static final int DownArrow = 67;
+ public static final int UpArrow = 68;
+ public static final int LeftRightArrow = 69;
+ public static final int UpDownArrow = 70;
+ public static final int IrregularSeal1 = 71;
+ public static final int IrregularSeal2 = 72;
+ public static final int LightningBolt = 73;
+ public static final int Heart = 74;
+ public static final int PictureFrame = 75;
+ public static final int QuadArrow = 76;
+ public static final int LeftArrowCallout = 77;
+ public static final int RightArrowCallout = 78;
+ public static final int UpArrowCallout = 79;
+ public static final int DownArrowCallout = 80;
+ public static final int LeftRightArrowCallout = 81;
+ public static final int UpDownArrowCallout = 82;
+ public static final int QuadArrowCallout = 83;
+ public static final int Bevel = 84;
+ public static final int LeftBracket = 85;
+ public static final int RightBracket = 86;
+ public static final int LeftBrace = 87;
+ public static final int RightBrace = 88;
+ public static final int LeftUpArrow = 89;
+ public static final int BentUpArrow = 90;
+ public static final int BentArrow = 91;
+ public static final int Seal24 = 92;
+ public static final int StripedRightArrow = 93;
+ public static final int NotchedRightArrow = 94;
+ public static final int BlockArc = 95;
+ public static final int SmileyFace = 96;
+ public static final int VerticalScroll = 97;
+ public static final int HorizontalScroll = 98;
+ public static final int CircularArrow = 99;
+ public static final int NotchedCircularArrow = 100;
+ public static final int UturnArrow = 101;
+ public static final int CurvedRightArrow = 102;
+ public static final int CurvedLeftArrow = 103;
+ public static final int CurvedUpArrow = 104;
+ public static final int CurvedDownArrow = 105;
+ public static final int CloudCallout = 106;
+ public static final int EllipseRibbon = 107;
+ public static final int EllipseRibbon2 = 108;
+ public static final int FlowChartProcess = 109;
+ public static final int FlowChartDecision = 110;
+ public static final int FlowChartInputOutput = 111;
+ public static final int FlowChartPredefinedProcess = 112;
+ public static final int FlowChartInternalStorage = 113;
+ public static final int FlowChartDocument = 114;
+ public static final int FlowChartMultidocument = 115;
+ public static final int FlowChartTerminator = 116;
+ public static final int FlowChartPreparation = 117;
+ public static final int FlowChartManualInput = 118;
+ public static final int FlowChartManualOperation = 119;
+ public static final int FlowChartConnector = 120;
+ public static final int FlowChartPunchedCard = 121;
+ public static final int FlowChartPunchedTape = 122;
+ public static final int FlowChartSummingJunction = 123;
+ public static final int FlowChartOr = 124;
+ public static final int FlowChartCollate = 125;
+ public static final int FlowChartSort = 126;
+ public static final int FlowChartExtract = 127;
+ public static final int FlowChartMerge = 128;
+ public static final int FlowChartOfflineStorage = 129;
+ public static final int FlowChartOnlineStorage = 130;
+ public static final int FlowChartMagneticTape = 131;
+ public static final int FlowChartMagneticDisk = 132;
+ public static final int FlowChartMagneticDrum = 133;
+ public static final int FlowChartDisplay = 134;
+ public static final int FlowChartDelay = 135;
+ public static final int TextPlainText = 136;
+ public static final int TextStop = 137;
+ public static final int TextTriangle = 138;
+ public static final int TextTriangleInverted = 139;
+ public static final int TextChevron = 140;
+ public static final int TextChevronInverted = 141;
+ public static final int TextRingInside = 142;
+ public static final int TextRingOutside = 143;
+ public static final int TextArchUpCurve = 144;
+ public static final int TextArchDownCurve = 145;
+ public static final int TextCircleCurve = 146;
+ public static final int TextButtonCurve = 147;
+ public static final int TextArchUpPour = 148;
+ public static final int TextArchDownPour = 149;
+ public static final int TextCirclePour = 150;
+ public static final int TextButtonPour = 151;
+ public static final int TextCurveUp = 152;
+ public static final int TextCurveDown = 153;
+ public static final int TextCascadeUp = 154;
+ public static final int TextCascadeDown = 155;
+ public static final int TextWave1 = 156;
+ public static final int TextWave2 = 157;
+ public static final int TextWave3 = 158;
+ public static final int TextWave4 = 159;
+ public static final int TextInflate = 160;
+ public static final int TextDeflate = 161;
+ public static final int TextInflateBottom = 162;
+ public static final int TextDeflateBottom = 163;
+ public static final int TextInflateTop = 164;
+ public static final int TextDeflateTop = 165;
+ public static final int TextDeflateInflate = 166;
+ public static final int TextDeflateInflateDeflate = 167;
+ public static final int TextFadeRight = 168;
+ public static final int TextFadeLeft = 169;
+ public static final int TextFadeUp = 170;
+ public static final int TextFadeDown = 171;
+ public static final int TextSlantUp = 172;
+ public static final int TextSlantDown = 173;
+ public static final int TextCanUp = 174;
+ public static final int TextCanDown = 175;
+ public static final int FlowChartAlternateProcess = 176;
+ public static final int FlowChartOffpageConnector = 177;
+ public static final int Callout90 = 178;
+ public static final int AccentCallout90 = 179;
+ public static final int BorderCallout90 = 180;
+ public static final int AccentBorderCallout90 = 181;
+ public static final int LeftRightUpArrow = 182;
+ public static final int Sun = 183;
+ public static final int Moon = 184;
+ public static final int BracketPair = 185;
+ public static final int BracePair = 186;
+ public static final int Seal4 = 187;
+ public static final int DoubleWave = 188;
+ public static final int ActionButtonBlank = 189;
+ public static final int ActionButtonHome = 190;
+ public static final int ActionButtonHelp = 191;
+ public static final int ActionButtonInformation = 192;
+ public static final int ActionButtonForwardNext = 193;
+ public static final int ActionButtonBackPrevious = 194;
+ public static final int ActionButtonEnd = 195;
+ public static final int ActionButtonBeginning = 196;
+ public static final int ActionButtonReturn = 197;
+ public static final int ActionButtonDocument = 198;
+ public static final int ActionButtonSound = 199;
+ public static final int ActionButtonMovie = 200;
+ public static final int HostControl = 201;
+ public static final int TextBox = 202;
+
+ /**
+ * Return name of the shape by id
+ * @param type - the id of the shape, one of the static constants defined in this class
+ * @return the name of the shape
+ */
+ public static String typeName(int type) {
+ String name = (String)types.get(new Integer(type));
+ return name;
+ }
+
+ public static HashMap types;
+ static {
+ types = new HashMap();
+ try {
+ Field[] f = ShapeTypes.class.getFields();
+ for (int i = 0; i < f.length; i++){
+ Object val = f[i].get(null);
+ if (val instanceof Integer) {
+ types.put(val, f[i].getName());
+ }
+ }
+ } catch (IllegalAccessException e){
+ throw new RuntimeException("Failed to initialize shape types");
+ }
+ }
+
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java b/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java
index ca5c1a565..f0834578e 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java
@@ -19,7 +19,14 @@
package org.apache.poi.hslf.model;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherDgRecord;
+import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.hslf.record.*;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
import java.util.Vector;
/**
@@ -40,6 +47,11 @@ public abstract class Sheet
* Returns the sheet number
*/
public abstract int getSheetNumber();
+
+ /**
+ * Fetch the PPDrawing from the underlying record
+ */
+ protected abstract PPDrawing getPPDrawing();
/**
* For a given PPDrawing, grab all the TextRuns
@@ -106,4 +118,49 @@ public abstract class Sheet
}
}
+ /**
+ * Returns all shapes contained in this Sheet
+ *
+ * @return all shapes contained in this Sheet (Slide or Notes)
+ */
+ public Shape[] getShapes() {
+ PPDrawing ppdrawing = getPPDrawing();
+
+ EscherContainerRecord dg = (EscherContainerRecord)ppdrawing.getEscherRecords()[0];
+ EscherContainerRecord spgr = null;
+ List ch = dg.getChildRecords();
+
+ for (Iterator it = ch.iterator(); it.hasNext();) {
+ EscherRecord rec = (EscherRecord)it.next();
+ if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){
+ spgr = (EscherContainerRecord)rec;
+ break;
+ }
+ }
+ ch = spgr.getChildRecords();
+
+ ArrayList shapes = new ArrayList();
+ for (int i=1;ifalse
otherwise
+ * @return the record container which holds this shape
+ */
+ protected EscherContainerRecord create(boolean isChild) {
+ EscherContainerRecord spContainer = new EscherContainerRecord();
+ spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
+ //spContainer.setOptions((short)15);
+
+ EscherSpRecord sp = new EscherSpRecord();
+ int flags = EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE;
+ if (isChild) flags |= EscherSpRecord.FLAG_CHILD;
+ sp.setFlags(flags);
+ spContainer.addChildRecord(sp);
+
+ EscherOptRecord opt = new EscherOptRecord();
+ opt.setRecordId(EscherOptRecord.RECORD_ID);
+ spContainer.addChildRecord(opt);
+
+ EscherRecord anchor;
+ if(isChild) anchor = new EscherChildAnchorRecord();
+ else {
+ anchor = new EscherClientAnchorRecord();
+
+ //hack. internal variable EscherClientAnchorRecord.shortRecord can be
+ //initialized only in fillFields(). We need to set shortRecord=false;
+ byte[] header = new byte[16];
+ LittleEndian.putUShort(header, 0, 0);
+ LittleEndian.putUShort(header, 2, 0);
+ LittleEndian.putInt(header, 4, 8);
+ anchor.fillFields(header, 0, null);
+ }
+ spContainer.addChildRecord(anchor);
+
+ return spContainer;
+ }
+
+ /**
+ * Returns width of the line in in points
+ */
+ public double getLineWidth(){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
+ return prop == null ? 0 : (double)prop.getPropertyValue()/EMU_PER_POINT;
+ }
+
+ /**
+ * Sets the width of line in in points
+ * @param width the width of line in in points
+ */
+ public void setLineWidth(double width){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ setEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH, (int)(width*EMU_PER_POINT));
+ }
+
+ /**
+ * Sets the color of line
+ *
+ * @param color new color of the line
+ */
+ public void setLineColor(Color color){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB();
+ setEscherProperty(opt, EscherProperties.LINESTYLE__COLOR, rgb);
+ }
+
+ /**
+ * @return color of the line
+ */
+ public Color getLineColor(){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ EscherRGBProperty prop = (EscherRGBProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__COLOR);
+ Color color = null;
+ if (prop != null){
+ Color swp = new Color(prop.getRgbColor());
+ color = new Color(swp.getBlue(), swp.getGreen(), swp.getRed());
+ }
+ return color;
+ }
+
+ /**
+ * Sets line style. One of the constants defined in this class.
+ *
+ * @param style new style of the line.
+ */
+ public void setLineStyle(int style){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ setEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING, style == Line.LineSolid ? -1 : style);
+ }
+
+ /**
+ * Returns line style. One of the constants defined in this class.
+ *
+ * @return style of the line.
+ */
+ public int getLineStyle(){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING);
+ return prop == null ? Line.LineSolid : prop.getPropertyValue();
+ }
+
+ public void setFillColor(Color color){
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+ int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB();
+ setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, rgb);
+ setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 1376273);
+ }
+
+
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java b/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java
index 5719c7e8a..6f374ec05 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java
@@ -86,7 +86,13 @@ public class Slide extends Sheet
_runs[i] = _otherRuns[k];
}
}
-
+
+ /**
+ * Create a new Slide instance
+ */
+ public Slide(){
+ _slide = new org.apache.poi.hslf.record.Slide();
+ }
/**
* Sets the Notes that are associated with this. Updates the
@@ -129,4 +135,6 @@ public class Slide extends Sheet
* Returns the Notes Sheet for this slide, or null if there isn't one
*/
public Notes getNotesSheet() { return _notes; }
+
+ protected PPDrawing getPPDrawing() { return _slide.getPPDrawing(); }
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/ColorSchemeAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/ColorSchemeAtom.java
index 61c67ae61..c0b9bf4ec 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/ColorSchemeAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/ColorSchemeAtom.java
@@ -118,6 +118,27 @@ public class ColorSchemeAtom extends RecordAtom
accentAndHyperlinkColourRGB = (int)LittleEndian.getInt(source,start+8+24);
accentAndFollowingHyperlinkColourRGB = (int)LittleEndian.getInt(source,start+8+28);
}
+
+ /**
+ * Create a new ColorSchemeAtom, to go with a new Slide
+ */
+ public ColorSchemeAtom(){
+ _header = new byte[8];
+ LittleEndian.putUShort(_header, 0, 16);
+ LittleEndian.putUShort(_header, 2, (int)_type);
+ LittleEndian.putInt(_header, 4, 32);
+
+ // Setup the default rgb values
+ backgroundColourRGB = 16777215;
+ textAndLinesColourRGB = 0;
+ shadowsColourRGB = 8421504;
+ titleTextColourRGB = 0;
+ fillsColourRGB = 10079232;
+ accentColourRGB = 13382451;
+ accentAndHyperlinkColourRGB = 16764108;
+ accentAndFollowingHyperlinkColourRGB = 11711154;
+ }
+
/**
* We are of type 3999
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java b/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java
index 44b584e75..d11ba429e 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java
@@ -81,8 +81,8 @@ public class FontCollection extends RecordContainer {
fnt.setFontName(name);
fonts.add(name);
- // append new child to the end
- _children = appendChildRecord(fnt,_children);
+ // Append new child to the end
+ appendChildRecord(fnt);
return fonts.size()-1; //the added font is the last in the list
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java b/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
index e19bc0a99..4cbcca00b 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
@@ -21,6 +21,7 @@ package org.apache.poi.hslf.record;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.ddf.*;
+import org.apache.poi.hslf.model.ShapeTypes;
import java.io.IOException;
import java.io.OutputStream;
@@ -97,6 +98,20 @@ public class PPDrawing extends RecordAtom
textboxWrappers[i] = (EscherTextboxWrapper)textboxes.get(i);
}
}
+
+ /**
+ * Creates a new, empty, PPDrawing (typically for use with a new Slide
+ * or Notes)
+ */
+ public PPDrawing(){
+ _header = new byte[8];
+ LittleEndian.putUShort(_header, 0, 15);
+ LittleEndian.putUShort(_header, 2, (int)RecordTypes.PPDrawing.typeID);
+ LittleEndian.putInt(_header, 4, 0);
+
+ textboxWrappers = new EscherTextboxWrapper[]{};
+ create();
+ }
/**
* Tree walking way of finding Escher Child Records
@@ -188,4 +203,63 @@ public class PPDrawing extends RecordAtom
// Finally, write out the children
out.write(b);
}
+
+ /**
+ * Create the Escher records associated with a new PPDrawing
+ */
+ private void create(){
+ EscherContainerRecord dgContainer = new EscherContainerRecord();
+ dgContainer.setRecordId( EscherContainerRecord.DG_CONTAINER );
+ dgContainer.setOptions((short)15);
+
+ EscherDgRecord dg = new EscherDgRecord();
+ dg.setOptions((short)16);
+ dg.setNumShapes(1);
+ dgContainer.addChildRecord(dg);
+
+ EscherContainerRecord spgrContainer = new EscherContainerRecord();
+ spgrContainer.setOptions((short)15);
+ spgrContainer.setRecordId(EscherContainerRecord.SPGR_CONTAINER);
+
+ EscherContainerRecord spContainer = new EscherContainerRecord();
+ spContainer.setOptions((short)15);
+ spContainer.setRecordId(EscherContainerRecord.SP_CONTAINER);
+
+ EscherSpgrRecord spgr = new EscherSpgrRecord();
+ spgr.setOptions((short)1);
+ spContainer.addChildRecord(spgr);
+
+ EscherSpRecord sp = new EscherSpRecord();
+ sp.setOptions((short)((ShapeTypes.NotPrimitive << 4) + 2));
+ sp.setFlags(EscherSpRecord.FLAG_PATRIARCH | EscherSpRecord.FLAG_GROUP);
+ spContainer.addChildRecord(sp);
+ spgrContainer.addChildRecord(spContainer);
+ dgContainer.addChildRecord(spgrContainer);
+
+ spContainer = new EscherContainerRecord();
+ spContainer.setOptions((short)15);
+ spContainer.setRecordId(EscherContainerRecord.SP_CONTAINER);
+ sp = new EscherSpRecord();
+ sp.setOptions((short)((ShapeTypes.Rectangle << 4) + 2));
+ sp.setFlags(EscherSpRecord.FLAG_BACKGROUND | EscherSpRecord.FLAG_HASSHAPETYPE);
+ spContainer.addChildRecord(sp);
+
+ EscherOptRecord opt = new EscherOptRecord();
+ opt.setRecordId(EscherOptRecord.RECORD_ID);
+ opt.addEscherProperty(new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, 134217728));
+ opt.addEscherProperty(new EscherRGBProperty(EscherProperties.FILL__FILLBACKCOLOR, 134217733));
+ opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__RECTRIGHT, 10064750));
+ opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__RECTBOTTOM, 7778750));
+ opt.addEscherProperty(new EscherBoolProperty(EscherProperties.FILL__NOFILLHITTEST, 1179666));
+ opt.addEscherProperty(new EscherBoolProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 524288));
+ opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.SHAPE__BLACKANDWHITESETTINGS, 9));
+ opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.SHAPE__BACKGROUNDSHAPE, 65537));
+ spContainer.addChildRecord(opt);
+
+ dgContainer.addChildRecord(spContainer);
+
+ childRecords = new EscherRecord[]{
+ dgContainer
+ };
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/PersistPtrHolder.java b/src/scratchpad/src/org/apache/poi/hslf/record/PersistPtrHolder.java
index cb5b5dee2..34671ee4a 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/PersistPtrHolder.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/PersistPtrHolder.java
@@ -77,6 +77,13 @@ public class PersistPtrHolder extends PositionDependentRecordAtom
public Hashtable getSlideLocationsLookup() {
return _slideLocations;
}
+ /**
+ * Get the lookup from slide numbers to their offsets inside
+ * _ptrData, used when adding or moving slides.
+ */
+ public Hashtable getSlideOffsetDataLocationsLookup() {
+ return _slideOffsetDataLocation;
+ }
/**
* Adds a new slide, notes or similar, to be looked up by this.
@@ -104,6 +111,10 @@ public class PersistPtrHolder extends PositionDependentRecordAtom
// Update the atom header
LittleEndian.putInt(_header,4,newPtrData.length);
+
+ // Update info (first 4 bytes in ptr data)
+ int info = (slideID << 20 | 1);
+ LittleEndian.putInt(_ptrData, 0, info);
}
/**
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/RecordContainer.java b/src/scratchpad/src/org/apache/poi/hslf/record/RecordContainer.java
index cd7aa16b3..996f92909 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/RecordContainer.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/RecordContainer.java
@@ -48,17 +48,12 @@ public abstract class RecordContainer extends Record
public boolean isAnAtom() { return false; }
/**
- * Add a new child record onto a record's list of children, and
- * return the new list.
+ * Add a new child record onto a record's list of children.
*/
- public Record[] appendChildRecord(Record newChild, Record[] children) {
- Record[] r;
+ public void appendChildRecord(Record newChild) {
synchronized(addingChildRecordLock) {
- r = new Record[children.length + 1];
- System.arraycopy(children,0,r,0,children.length);
- r[r.length-1] = newChild;
+ addChildAt(newChild, _children.length);
}
- return r;
}
/**
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/Slide.java b/src/scratchpad/src/org/apache/poi/hslf/record/Slide.java
index 9717a58c2..06262909a 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/Slide.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/Slide.java
@@ -18,10 +18,10 @@
package org.apache.poi.hslf.record;
-import org.apache.poi.util.LittleEndian;
import java.io.IOException;
import java.io.OutputStream;
-import java.io.ByteArrayOutputStream;
+
+import org.apache.poi.util.LittleEndian;
/**
* Master container for Slides. There is one of these for every slide,
@@ -73,6 +73,27 @@ public class Slide extends PositionDependentRecordContainer
}
}
+ /**
+ * Create a new, empty, Slide, along with its required
+ * child records.
+ */
+ public Slide(){
+ _header = new byte[8];
+ LittleEndian.putUShort(_header, 0, 15);
+ LittleEndian.putUShort(_header, 2, (int)_type);
+ LittleEndian.putInt(_header, 4, 0);
+
+ slideAtom = new SlideAtom();
+ ppDrawing = new PPDrawing();
+
+ ColorSchemeAtom colorAtom = new ColorSchemeAtom();
+
+ _children = new Record[] {
+ slideAtom,
+ ppDrawing,
+ colorAtom
+ };
+ }
/**
* We are of type 1006
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/SlideAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/SlideAtom.java
index 677b3d859..f1c4bcb68 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/SlideAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/SlideAtom.java
@@ -111,6 +111,27 @@ public class SlideAtom extends RecordAtom
reserved = new byte[len-30];
System.arraycopy(source,start+30,reserved,0,reserved.length);
}
+
+ /**
+ * Create a new SlideAtom, to go with a new Slide
+ */
+ public SlideAtom(){
+ _header = new byte[8];
+ LittleEndian.putUShort(_header, 0, 2);
+ LittleEndian.putUShort(_header, 2, (int)_type);
+ LittleEndian.putInt(_header, 4, 24);
+
+ byte[] ssdate = new byte[12];
+ layoutAtom = new SSlideLayoutAtom(ssdate);
+ layoutAtom.setGeometryType(SSlideLayoutAtom.BLANK_SLIDE);
+
+ followMasterObjects = true;
+ followMasterScheme = true;
+ followMasterBackground = true;
+ masterID = -2147483648;
+ notesID = 0;
+ reserved = new byte[2];
+ }
/**
* We are of type 1007
@@ -180,6 +201,8 @@ public class SlideAtom extends RecordAtom
/** Retrieve the geometry type */
public int getGeometryType() { return geometry; }
+ /** Set the geometry type */
+ public void setGeometryType(int geom) { geometry = geom; }
/**
* Create a new Embeded SSlideLayoutAtom, from 12 bytes of data
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/SlideListWithText.java b/src/scratchpad/src/org/apache/poi/hslf/record/SlideListWithText.java
index ca1f88ff2..560dd1e5b 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/SlideListWithText.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/SlideListWithText.java
@@ -97,6 +97,17 @@ public class SlideListWithText extends RecordContainer
}
}
+ /**
+ * Create a new, empty, SlideListWithText
+ */
+ public SlideListWithText(){
+ _header = new byte[8];
+ LittleEndian.putUShort(_header, 0, 15);
+ LittleEndian.putUShort(_header, 2, (int)_type);
+ LittleEndian.putInt(_header, 4, 0);
+
+ _children = new Record[0];
+ }
/**
* Get access to the SlideAtomsSets of the children of this record
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/SlidePersistAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/SlidePersistAtom.java
index f52bfbfc2..7c93494fc 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/SlidePersistAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/SlidePersistAtom.java
@@ -48,6 +48,14 @@ public class SlidePersistAtom extends RecordAtom
public int getSlideIdentifier() { return slideIdentifier; }
public int getNumPlaceholderTexts() { return numPlaceholderTexts; }
public boolean getHasShapesOtherThanPlaceholders() { return hasShapesOtherThanPlaceholders; }
+
+ // Only set these if you know what you're doing!
+ public void setRefID(int id) {
+ refID = id;
+ }
+ public void setSlideIdentifier(int id) {
+ slideIdentifier = id;
+ }
/* *************** record code follows ********************** */
@@ -84,6 +92,19 @@ public class SlidePersistAtom extends RecordAtom
reservedFields = new byte[len-24];
System.arraycopy(source,start+24,reservedFields,0,reservedFields.length);
}
+
+ /**
+ * Create a new SlidePersistAtom, for use with a new Slide
+ */
+ public SlidePersistAtom(){
+ _header = new byte[8];
+ LittleEndian.putUShort(_header, 0, 0);
+ LittleEndian.putUShort(_header, 2, (int)_type);
+ LittleEndian.putInt(_header, 4, 20);
+
+ hasShapesOtherThanPlaceholders = true;
+ reservedFields = new byte[4];
+ }
/**
* We are of type 1011
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/UserEditAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/UserEditAtom.java
index 2bc61f857..534dabfce 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/UserEditAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/UserEditAtom.java
@@ -66,6 +66,7 @@ public class UserEditAtom extends PositionDependentRecordAtom
// More scary internal setters
public void setLastUserEditAtomOffset(int offset) { lastUserEditAtomOffset = offset; }
public void setPersistPointersOffset(int offset) { persistPointersOffset = offset; }
+ public void setLastViewType(short type) { lastViewType=type; }
/* *************** record code follows ********************** */
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
index ac16539c4..c47294495 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
@@ -34,6 +34,8 @@ import org.apache.poi.hslf.record.RecordContainer;
import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.record.SlideAtom;
import org.apache.poi.hslf.record.SlideListWithText;
+import org.apache.poi.hslf.record.SlidePersistAtom;
+import org.apache.poi.hslf.record.UserEditAtom;
import org.apache.poi.hslf.record.SlideListWithText.*;
import org.apache.poi.hslf.record.PersistPtrHolder;
import org.apache.poi.hslf.record.PositionDependentRecord;
@@ -378,74 +380,94 @@ public class SlideShow
* @throws IOException
*/
public Slide createSlide() throws IOException {
-// RecordContainer slist=null;
-// Record[] rec = doc.getChildRecords();
-// int num = 0;
-// for (int i = 0; i < rec.length; i++) {
-// Record record = rec[i];
-// if (record.getRecordType() == RecordTypes.SlideListWithText.typeID){
-// if (num > 0){
-// slist = (RecordContainer)record;
-// }
-// num++;
-// }
-// }
-// if (num == 1){
-// slist = new SlideListWithText();
-// rec = doc.getChildRecords();
-// for (int i = 0; i < rec.length-1; i++) {
-// Record record = rec[i+1];
-// if (record.getRecordType() == RecordTypes.EndDocument.typeID){
-//
-// doc.addChildAfter(slist, rec[i]);
-// }
-// }
-// }
-// rec = slist.getChildRecords();
-//
-// //add SlidePersistAtom
-// SlidePersistAtom prev = rec.length == 0 ? null : (SlidePersistAtom)rec[rec.length - 1];
-// SlidePersistAtom sp = new SlidePersistAtom();
-//
-// //refernce is the 1-based index of the slide container in the document root.
-// //it always starts with 3 (1 is Document, 2 is MainMaster, 3 is the first slide)
-// sp.setRefID(prev == null ? 3 : (prev.getRefID() + 1));
-// //first slideId is always 256
-// sp.setSlideIdentifier(prev == null ? 256 : (prev.getSlideIdentifier() + 1));
-//
-// Record[] r = slist.appendChildRecord(sp,
-// slist.getChildRecords() == null ? new Record[]{} : slist.getChildRecords());
-// slist.setChildRecords(r);
-// Slide slide = new Slide();
-//
-// int offset = 0;
-// List lst = new ArrayList();
-// for (int i = 0; i < _records.length; i++) {
-// Record record = _records[i];
-// lst.add(record);
-// ByteArrayOutputStream out = new ByteArrayOutputStream();
-// record.writeOut(out);
-//
-// if (_records[i].getRecordType() == RecordTypes.PersistPtrIncrementalBlock.typeID){
-// lst.add(i, slide.getSlideRecord());
-//
-// slide.getSlideRecord().setLastOnDiskOffset(offset);
-// PersistPtrHolder ptr = (PersistPtrHolder)_records[i];
-// int id = sp.getRefID();
-// ptr.getSlideDataLocationsLookup().put(new Integer(id), new Integer((i+1)*4));
-// ptr.getSlideLocationsLookup().put(new Integer(id), new Integer(offset));
-// ptr.addSlideLookup(id, offset);
-//
-// }
-// offset += out.size() ;
-// }
-// _records = (Record[])lst.toArray(new Record[lst.size()]);
-// _hslfSlideShow.setRecords(_records);
-//
-// UserEditAtom usr = (UserEditAtom)_records[_records.length-1];
-// usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW);
-// return slide;
- return null;
+ SlideListWithText[] slwts = _documentRecord.getSlideListWithTexts();
+ SlideListWithText slist = null;
+
+ if(slwts.length > 1) {
+ // Just use the last one
+ slist = slwts[slwts.length - 1];
+ } else {
+ // Need to add a new one
+ slist = new SlideListWithText();
+
+ // Goes in just before the EndDocumentRecord
+ Record[] docChildren = _documentRecord.getChildRecords();
+ Record endDoc = docChildren[docChildren.length - 1];
+ if(endDoc.getRecordType() != RecordTypes.EndDocument.typeID) {
+ throw new IllegalStateException("The last child record of a Document should be EndDocument, but it was " + endDoc);
+ }
+ _documentRecord.addChildBefore(slist, endDoc);
+ }
+
+ Record[] rec = slist.getChildRecords();
+
+ // Add SlidePersistAtom
+ SlidePersistAtom prev = rec.length == 0 ? null : (SlidePersistAtom)rec[rec.length - 1];
+ SlidePersistAtom sp = new SlidePersistAtom();
+
+ // Refernce is the 1-based index of the slide container in
+ // the document root.
+ // It always starts with 3 (1 is Document, 2 is MainMaster, 3 is
+ // the first slide)
+ sp.setRefID(prev == null ? 3 : (prev.getRefID() + 1));
+ // First slideId is always 256
+ sp.setSlideIdentifier(prev == null ? 256 : (prev.getSlideIdentifier() + 1));
+
+ slist.appendChildRecord(sp);
+
+ // Create a new Slide
+ Slide slide = new Slide();
+ Slide[] s = new Slide[_slides.length+1];
+ System.arraycopy(_slides, 0, s, 0, _slides.length);
+ s[_slides.length] = slide;
+ _slides = s;
+ System.out.println("Added slide " + _slides.length + " with ref " + sp.getRefID() + " and identifier " + sp.getSlideIdentifier());
+
+ // Add in to the core records
+ org.apache.poi.hslf.record.Slide slideRecord = slide.getSlideRecord();
+ int slideRecordPos = _hslfSlideShow.appendRootLevelRecord(slideRecord);
+
+ // Add the new Slide into the PersistPtr stuff
+ int offset = 0;
+ int slideOffset = 0;
+ PersistPtrHolder ptr = null;
+ UserEditAtom usr = null;
+ for (int i = 0; i < _records.length; i++) {
+ Record record = _records[i];
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ record.writeOut(out);
+
+ // Grab interesting records as they come past
+ if(_records[i].getRecordType() == RecordTypes.PersistPtrIncrementalBlock.typeID){
+ ptr = (PersistPtrHolder)_records[i];
+ }
+ if(_records[i].getRecordType() == RecordTypes.UserEditAtom.typeID) {
+ usr = (UserEditAtom)_records[i];
+ }
+
+ if(i == slideRecordPos) {
+ slideOffset = offset;
+ }
+ offset += out.size();
+ }
+
+ // Add the new slide into the last PersistPtr
+ slideRecord.setLastOnDiskOffset(slideOffset);
+ int id = sp.getRefID();
+ ptr.getSlideOffsetDataLocationsLookup().put(
+ new Integer(id),
+ new Integer((slideRecordPos+1)*4)
+ );
+ ptr.getSlideLocationsLookup().put(
+ new Integer(id), new Integer(slideOffset));
+ ptr.addSlideLookup(id, slideOffset);
+ System.out.println("New slide ended up at " + slideOffset);
+
+ // Last view is now of the slide
+ usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW);
+
+ // All done and added
+ return slide;
}