<li><link href="#GetShapes">How to get shapes contained in a particular slide</link></li>\r
<li><link href="#Shapes">Drawing a shape on a slide</link></li>\r
<li><link href="#Pictures">How to add/retrieve pictures</link></li>\r
+ <li><link href="#SlideTitle">How to set slide title</link></li>\r
</ul>\r
</section>\r
<section><title>Features</title>\r
The following pictute shows the class tree of HSLF shapes:\r
</p>\r
<p>\r
- <img src="hslf_shapes.gif" alt="Class Tree of HSLF Shapes" width="611" height="285"/>\r
+ <img src="hslf_shapes.gif" alt="Class Tree of HSLF Shapes" width="611" height="412"/>\r
</p>\r
<p>\r
The following fragment demonstrates how to iterate over shapes for each slide.\r
\r
</source>\r
</section>\r
+ <anchor id="SlideTitle"/>\r
+ <section><title>How to set slide title</title>\r
+ <source>\r
+ SlideShow ppt = new SlideShow();\r
+ Slide slide = ppt.createSlide();\r
+ TextBox title = slide.addTitle();\r
+ title.setText("Hello, World!");\r
+ \r
+ //save changes \r
+ FileOutputStream out = new FileOutputStream("slideshow.ppt");\r
+ wb.write(out);\r
+ out.close();\r
+ </source>\r
+ <p>\r
+ Below is the equivalent code in PowerPoint VBA:\r
+ </p> \r
+ <source>\r
+ Set myDocument = ActivePresentation.Slides(1)\r
+ myDocument.Shapes.AddTitle.TextFrame.TextRange.Text = "Hello, World!"\r
+ </source>\r
+ </section>\r
+ \r
</section>\r
</section>\r
</body>\r
+++ /dev/null
-/* ====================================================================\r
- Copyright 2002-2004 Apache Software Foundation\r
-\r
- Licensed under the Apache License, Version 2.0 (the "License");\r
- you may not use this file except in compliance with the License.\r
- You may obtain a copy of the License at\r
-\r
- http://www.apache.org/licenses/LICENSE-2.0\r
-\r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
-==================================================================== */\r
-\r
-package org.apache.poi.hslf.model;\r
-\r
-import org.apache.poi.ddf.*;\r
-\r
-import java.awt.*;\r
-\r
-/**\r
- * Represents a ellipse in a PowerPoint drawing\r
- *\r
- * @author Yegor Kozlov\r
- */\r
-public class Ellipse extends SimpleShape {\r
-\r
- protected Ellipse(EscherContainerRecord escherRecord, Shape parent){\r
- super(escherRecord, parent);\r
- }\r
-\r
- public Ellipse(Shape parent){\r
- super(null, parent);\r
- _escherContainer = createSpContainer(parent instanceof ShapeGroup);\r
- }\r
-\r
- public Ellipse(){\r
- this(null);\r
- }\r
-\r
- protected EscherContainerRecord createSpContainer(boolean isChild){\r
- EscherContainerRecord spcont = super.createSpContainer(isChild);\r
-\r
- EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);\r
- short type = (ShapeTypes.Ellipse << 4) + 2;\r
- spRecord.setOptions(type);\r
-\r
- //set default properties for a line\r
- EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);\r
-\r
- opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 4));\r
- opt.sortProperties();\r
-\r
- return spcont;\r
- }\r
-\r
-}\r
if (font != null){\r
txt.setFontSize(font.getSize());\r
txt.setFontName(font.getName());\r
- //if(getColor() != null) txt.setFontColor(getColor());\r
+ if(getColor() != null) txt.setFontColor(getColor());\r
if (font.isBold()) txt.setBold(true);\r
if (font.isItalic()) txt.setItalic(true);\r
}\r
--- /dev/null
+/* ====================================================================\r
+ Copyright 2002-2004 Apache Software Foundation\r
+\r
+ Licensed under the Apache License, Version 2.0 (the "License");\r
+ you may not use this file except in compliance with the License.\r
+ You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.model;\r
+\r
+import org.apache.poi.ddf.*;\r
+import org.apache.poi.hslf.record.OEPlaceholderAtom;\r
+\r
+import java.util.List;\r
+import java.io.ByteArrayOutputStream;\r
+\r
+/**\r
+ * Represents a Placeholder in PowerPoint.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class Placeholder extends TextBox {\r
+\r
+ protected Placeholder(EscherContainerRecord escherRecord, Shape parent){\r
+ super(escherRecord, parent);\r
+ }\r
+\r
+ public Placeholder(Shape parent){\r
+ super(parent);\r
+ }\r
+\r
+ public Placeholder(){\r
+ super();\r
+ }\r
+\r
+ /**\r
+ * Create a new Placeholder and initialize internal structures\r
+ *\r
+ * @return the created <code>EscherContainerRecord</code> which holds shape data\r
+ */\r
+ protected EscherContainerRecord createSpContainer(boolean isChild){\r
+ EscherContainerRecord spcont = super.createSpContainer(isChild);\r
+\r
+ EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);\r
+ spRecord.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER);\r
+\r
+ EscherClientDataRecord cldata = new EscherClientDataRecord();\r
+ cldata.setOptions((short)15);\r
+\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);\r
+\r
+ //Placeholders can't be grouped\r
+ setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144);\r
+\r
+ //OEPlaceholderAtom tells powerpoint that this shape is a placeholder\r
+ //\r
+ OEPlaceholderAtom oep = new OEPlaceholderAtom();\r
+ /**\r
+ * Extarct from MSDN:\r
+ *\r
+ * There is a special case when the placeholder does not have a position in the layout.\r
+ * This occurs when the user has moved the placeholder from its original position.\r
+ * In this case the placeholder ID is -1.\r
+ */\r
+ oep.setPlacementId(-1);\r
+\r
+ oep.setPlaceholderId(OEPlaceholderAtom.Body);\r
+\r
+ //convert hslf into ddf record\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ try {\r
+ oep.writeOut(out);\r
+ } catch(Exception e){\r
+ throw new RuntimeException(e);\r
+ }\r
+ cldata.setRemainingData(out.toByteArray());\r
+\r
+ //append placeholder container before EscherTextboxRecord\r
+ List lst = spcont.getChildRecords();\r
+ for (int i = 0; i < lst.size(); i++) {\r
+ EscherRecord rec = (EscherRecord)lst.get(i);\r
+ if(rec.getRecordId() == EscherTextboxRecord.RECORD_ID){\r
+ lst.add(i++, cldata);\r
+ }\r
+ }\r
+\r
+ return spcont;\r
+ }\r
+}\r
+++ /dev/null
-/* ====================================================================\r
- Copyright 2002-2004 Apache Software Foundation\r
-\r
- Licensed under the Apache License, Version 2.0 (the "License");\r
- you may not use this file except in compliance with the License.\r
- You may obtain a copy of the License at\r
-\r
- http://www.apache.org/licenses/LICENSE-2.0\r
-\r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
-==================================================================== */\r
-\r
-package org.apache.poi.hslf.model;\r
-\r
-import org.apache.poi.ddf.*;\r
-\r
-import java.awt.*;\r
-\r
-/**\r
- * Represents a rectangle shae in a PowerPoint drawing\r
- *\r
- * @author Yegor Kozlov\r
- */\r
-public class Rectangle extends TextBox {\r
-\r
- protected Rectangle(EscherContainerRecord escherRecord, Shape parent){\r
- super(escherRecord, parent);\r
- }\r
-\r
- public Rectangle(Shape parent){\r
- super(parent);\r
- }\r
-\r
- public Rectangle(){\r
- super();\r
- }\r
-\r
- protected EscherContainerRecord createSpContainer(boolean isChild){\r
- EscherContainerRecord spcont = super.createSpContainer(isChild);\r
-\r
- EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);\r
- short type = (ShapeTypes.Rectangle << 4) + 2;\r
- spRecord.setOptions(type);\r
-\r
- return spcont;\r
- }\r
-\r
-}\r
return ShapeTypes.typeName(spRecord.getOptions() >> 4);\r
}\r
\r
+ /**\r
+ * @return type of the shape.\r
+ * @see org.apache.poi.hslf.record.RecordTypes\r
+ */\r
+ public int getShapeType(){\r
+ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);\r
+ return spRecord.getOptions() >> 4;\r
+ }\r
+\r
+ /**\r
+ * @param type type of the shape.\r
+ * @see org.apache.poi.hslf.record.RecordTypes\r
+ */\r
+ public void setShapeType(int type){\r
+ EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);\r
+ spRecord.setOptions((short)(type << 4 | 0x2));\r
+ }\r
+\r
/**\r
* Returns the anchor (the bounding box rectangle) of this shape.\r
- * All coordinates are expressed in Master units (576 dpi).\r
+ * All coordinates are expressed in points (72 dpi).\r
*\r
* @return the anchor of this shape\r
*/\r
\r
/**\r
* Sets the anchor (the bounding box rectangle) of this shape.\r
- * All coordinates should be expressed in poitns (72 dpi).\r
+ * All coordinates should be expressed in points (72 dpi).\r
*\r
* @param anchor new anchor\r
*/\r
==================================================================== */\r
package org.apache.poi.hslf.model;\r
\r
-import org.apache.poi.ddf.EscherSpRecord;\r
-import org.apache.poi.ddf.EscherContainerRecord;\r
+import org.apache.poi.ddf.*;\r
\r
/**\r
* Create a <code>Shape</code> object depending on its type\r
\r
int type = spRecord.getOptions() >> 4;\r
switch (type){\r
+ case ShapeTypes.Rectangle:\r
+ EscherTextboxRecord txtbox = (EscherTextboxRecord)Shape.getEscherChild(spContainer, EscherTextboxRecord.RECORD_ID);\r
+ if (txtbox == null) shape = new AutoShape(spContainer, parent);\r
+ else{\r
+ if(Shape.getEscherChild(spContainer, EscherClientDataRecord.RECORD_ID) != null )\r
+ shape = new Placeholder(spContainer, parent);\r
+ else\r
+ shape = new TextBox(spContainer, parent);\r
+ }\r
+ break;\r
case ShapeTypes.TextBox:\r
shape = new TextBox(spContainer, parent);\r
break;\r
- case ShapeTypes.Rectangle:\r
- shape = new Rectangle(spContainer, parent);\r
- break;\r
case ShapeTypes.PictureFrame:\r
shape = new Picture(spContainer, parent);\r
break;\r
import org.apache.poi.hslf.record.PPDrawing;
import org.apache.poi.hslf.record.SlideAtom;
+import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
/**
sa.setNotesID(notes._getSheetNumber());
}
}
+
+ /**
+ * Create a <code>TextBox</code> object that represents the slide's title.
+ *
+ * @return <code>TextBox</code> object that represents the slide's title.
+ */
+ public TextBox addTitle() {
+ Placeholder pl = new Placeholder();
+ pl.setShapeType(ShapeTypes.Rectangle);
+ pl.setTextType(TextHeaderAtom.TITLE_TYPE);
+ pl.setText("Click to edit title");
+ pl.setAnchor(new java.awt.Rectangle(54, 48, 612, 90));
+ addShape(pl);
+ return pl;
+ }
// Accesser methods follow
public int _getSheetRefId() { return _refSheetNo; }
/**
* Returns the (internal, SlideIdentifier based) sheet number
- * @see getSlideNumber()
+ * @see #getSlideNumber()
*/
public int _getSheetNumber() { return _sheetNo; }
*/
public Notes getNotesSheet() { return _notes; }
+ /**
+ * Returns the PPDrawing associated with this slide, or null if there isn't one
+ */
protected PPDrawing getPPDrawing() { return _slide.getPPDrawing(); }
+
+ /**
+ * @return set of records inside <code>SlideListWithtext</code> container
+ * which hold text data for this slide (typically for placeholders).
+ */
+ protected SlideAtomsSet getSlideAtomsSet() { return _atomSet; }
}
*/\r
protected EscherTextboxWrapper _txtbox;\r
\r
+ private String _fontname;\r
+\r
/**\r
* Create a TextBox object and initialize it from the supplied Record container.\r
* \r
\r
EscherTextboxRecord textbox = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);\r
_txtbox = new EscherTextboxWrapper(textbox);\r
- \r
- // Find our TextRun\r
- Vector v = new Vector();\r
- Sheet.findTextRuns(_txtbox.getChildRecords(), v);\r
- \r
- // We should just have one\r
- if(v.size() == 1) {\r
- _txtrun = (TextRun)v.get(0);\r
- } else {\r
- throw new IllegalStateException("A TextBox should have one TextRun's worth of records in it, found " + v.size());\r
- }\r
}\r
\r
/**\r
} catch (IOException e){\r
throw new RuntimeException(e);\r
}\r
+ if(getAnchor().equals(new java.awt.Rectangle())) resizeToFitText();\r
}\r
\r
/**\r
*\r
* @return the bounds of this <code>TextFrame</code>.\r
*/\r
- protected Dimension getTextSize(){\r
+ protected Dimension getTextDimensions(){\r
FontRenderContext frc = new FontRenderContext(null, true, true);\r
RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
int size = rt.getFontSize();\r
\r
TextLayout layout = new TextLayout(getText(), font, frc);\r
int width = Math.round(layout.getAdvance());\r
- width += getMarginLeft() + getMarginRight();\r
+ width += getMarginLeft() + getMarginRight() + 2;\r
int height = Math.round(layout.getAscent());\r
- height += getMarginTop() + getMarginBottom();\r
+ height += getMarginTop() + getMarginBottom() + 12;\r
return new Dimension(width, height);\r
}\r
\r
* Adjust the size of the TextBox so it encompasses the text inside it.\r
*/\r
public void resizeToFitText(){\r
- Dimension size = getTextSize();\r
+ Dimension size = getTextDimensions();\r
java.awt.Rectangle anchor = getAnchor();\r
anchor.setSize(size);\r
setAnchor(anchor);\r
return rt.getFontSize();\r
}\r
\r
+ /**\r
+ *\r
+ * @return the size of the font applied to this text shape\r
+ */\r
+ public Color getFontColor(){\r
+ RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
+ Color color = new Color(rt.getFontColor());\r
+ //in PowerPont RGB bytes are swapped,\r
+ return new Color(color.getBlue(), color.getGreen(), color.getRed(), 255);\r
+ }\r
+\r
/**\r
* Set whether to use bold or not\r
*\r
* @param name the name of the font to be applied to this text shape\r
*/\r
public void setFontName(String name){\r
+ if (_sheet == null) {\r
+ //we can't set font since slideshow is not assigned yet\r
+ _fontname = name;\r
+ } else{\r
RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
rt.setFontName(name);\r
}\r
+ }\r
+\r
+ /**\r
+ * Sets the font color\r
+ * @param color the font color\r
+ */\r
+ public void setFontColor(Color color){\r
+ //in PowerPont RGB bytes are swapped,\r
+ int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB();\r
+ RichTextRun rt = _txtrun.getRichTextRuns()[0];\r
+ rt.setFontColor(rgb);\r
+ }\r
+\r
+ /**\r
+ * Set type of the text.\r
+ * Must be one of the static constants defined in <code>TextHeaderAtom</code>\r
+ *\r
+ * @param type type of the text\r
+ */\r
+ public void setTextType(int type){\r
+ _txtrun._headerAtom.setTextType(type);\r
+ }\r
\r
+ public void setSheet(Sheet sheet){\r
+ _sheet = sheet;\r
+\r
+ //initialize _txtrun object.\r
+ //we can't do it in the constructor because the sheet is not assigned yet\r
+ if(_txtrun == null) initTextRun();\r
+\r
+ RichTextRun[] rt = _txtrun.getRichTextRuns();\r
+ for (int i = 0; i < rt.length; i++) {\r
+ rt[i].supplySlideShow(_sheet.getSlideShow());\r
+ }\r
+ if (_fontname != null) {\r
+ setFontName(_fontname);\r
+ _fontname = null;\r
+ }\r
+\r
+ }\r
+\r
+ private void initTextRun(){\r
+\r
+ TextHeaderAtom tha = null;\r
+ TextCharsAtom tca = null;\r
+ TextBytesAtom tba = null;\r
+ StyleTextPropAtom sta = null;\r
+ OutlineTextRefAtom ota = null;\r
+ Record[] child = _txtbox.getChildRecords();\r
+ for (int i = 0; i < child.length; i++) {\r
+ if (child[i] instanceof TextHeaderAtom) tha = (TextHeaderAtom)child[i];\r
+ else if (child[i] instanceof TextBytesAtom) tba = (TextBytesAtom)child[i];\r
+ else if (child[i] instanceof StyleTextPropAtom) sta = (StyleTextPropAtom)child[i];\r
+ else if (child[i] instanceof OutlineTextRefAtom) ota = (OutlineTextRefAtom)child[i];\r
+ else if (child[i] instanceof TextCharsAtom) tca = (TextCharsAtom)child[i];\r
+ }\r
+\r
+ if (ota != null){\r
+ //TextHeaderAtom, TextBytesAtom and StyleTextPropAtom are stored outside of EscherContainerRecord\r
+ int idx = ota.getTextIndex();\r
+ Slide sl = (Slide)getSheet();\r
+ Record[] rec = sl.getSlideAtomsSet().getSlideRecords();\r
+ for (int i = 0, j = 0; i < rec.length; i++) {\r
+ if(rec[i].getRecordType() == RecordTypes.TextHeaderAtom.typeID){\r
+ if(j++ == idx) { //we found j-th TextHeaderAtom, read the text data\r
+ for (int k = i; k < rec.length; k++) {\r
+ if (rec[k] instanceof TextHeaderAtom) {\r
+ if (tha != null) break;\r
+ else tha = (TextHeaderAtom)rec[k];\r
+ }\r
+ else if (rec[k] instanceof TextBytesAtom) tba = (TextBytesAtom)rec[k];\r
+ else if (rec[k] instanceof TextCharsAtom) tca = (TextCharsAtom)rec[k];\r
+ else if (rec[k] instanceof StyleTextPropAtom) sta = (StyleTextPropAtom)rec[k];\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if(tba != null) _txtrun = new TextRun(tha,tba,sta);\r
+ else if (tca != null) _txtrun = new TextRun(tha,tca,sta);\r
+ }\r
}\r
--- /dev/null
+\r
+/* ====================================================================\r
+ Copyright 2002-2004 Apache Software Foundation\r
+\r
+ Licensed under the Apache License, Version 2.0 (the "License");\r
+ you may not use this file except in compliance with the License.\r
+ You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+ \r
+\r
+package org.apache.poi.hslf.record;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+\r
+/**\r
+ * OEPlaceholderAtom (3011).\r
+ * <p>\r
+ * Atom that describes the placeholder.\r
+ * </p>\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+\r
+public class OEPlaceholderAtom extends RecordAtom{\r
+\r
+ public static final int PLACEHOLDER_FULLSIZE = 0;\r
+ public static final int PLACEHOLDER_HALFSIZE = 1;\r
+ public static final int PLACEHOLDER_QUARTSIZE = 2;\r
+\r
+ public static final byte None = 0;\r
+\r
+ public static final byte MasterTitle = 1;\r
+\r
+ public static final byte MasterBody = 2;\r
+\r
+ public static final byte MasterCenteredTitle = 3;\r
+\r
+ public static final byte MasterNotesSlideImage = 4;\r
+\r
+ public static final byte MasterNotesBodyImage = 5;\r
+\r
+ public static final byte MasterDate = 6;\r
+\r
+ public static final byte MasterSlideNumber = 7;\r
+\r
+ public static final byte MasterFooter = 8;\r
+\r
+ public static final byte MasterHeader = 9;\r
+\r
+ public static final byte MasterSubtitle = 10;\r
+\r
+ public static final byte GenericTextObject = 11;\r
+\r
+ public static final byte Title = 12;\r
+\r
+ public static final byte Body = 13;\r
+\r
+ public static final byte NotesBody = 14;\r
+\r
+ public static final byte CenteredTitle = 15;\r
+\r
+ public static final byte Subtitle = 16;\r
+\r
+ public static final byte VerticalTextTitle = 17;\r
+\r
+ public static final byte VerticalTextBody = 18;\r
+\r
+ public static final byte NotesSlideImage = 19;\r
+\r
+ public static final byte Object = 20;\r
+\r
+ public static final byte Graph = 21;\r
+\r
+ public static final byte Table = 22;\r
+\r
+ public static final byte ClipArt = 23;\r
+\r
+ public static final byte OrganizationChart = 24;\r
+\r
+ public static final byte MediaClip = 25;\r
+\r
+ private byte[] _header;\r
+\r
+ private int placementId;\r
+ private int placeholderId;\r
+ private int placeholderSize;\r
+\r
+\r
+ /**\r
+ * Create a new instance of <code>OEPlaceholderAtom</code>\r
+ */\r
+ public OEPlaceholderAtom(){\r
+ _header = new byte[8];\r
+ LittleEndian.putUShort(_header, 0, 0);\r
+ LittleEndian.putUShort(_header, 2, (int)getRecordType());\r
+ LittleEndian.putInt(_header, 4, 8);\r
+\r
+ placementId = 0;\r
+ placeholderId = 0;\r
+ placeholderSize = 0;\r
+ }\r
+\r
+ /**\r
+ * Build an instance of <code>OEPlaceholderAtom</code> from on-disk data\r
+ */\r
+ protected OEPlaceholderAtom(byte[] source, int start, int len) {\r
+ _header = new byte[8];\r
+ System.arraycopy(source,start,_header,0,8);\r
+\r
+ placementId = LittleEndian.getInt(source, start);\r
+ placeholderId = LittleEndian.getUnsignedByte(source, start+4);\r
+ placeholderSize = LittleEndian.getUnsignedByte(source, start+5);\r
+ }\r
+\r
+ /**\r
+ * @return type of this record {@link RecordTypes#OEPlaceholderAtom}.\r
+ */\r
+ public long getRecordType() { return RecordTypes.OEPlaceholderAtom.typeID; }\r
+\r
+ /**\r
+ * Returns the placement Id.\r
+ *\r
+ * @return the placement Id.\r
+ */\r
+ public int getPlacementId(){\r
+ return placementId;\r
+ }\r
+\r
+ /**\r
+ * Sets the placement Id.\r
+ *\r
+ * @param id the placement Id.\r
+ */\r
+ public void setPlacementId(int id){\r
+ placementId = id;\r
+ }\r
+\r
+ /**\r
+ * Returns the placeholder Id.\r
+ *\r
+ * @return the placeholder Id.\r
+ */\r
+ public int getPlaceholderId(){\r
+ return placeholderId;\r
+ }\r
+\r
+ /**\r
+ * Sets the placeholder Id.\r
+ *\r
+ * @param id the placeholder Id.\r
+ */\r
+ public void setPlaceholderId(byte id){\r
+ placeholderId = id;\r
+ }\r
+\r
+ /**\r
+ * Returns the placeholder size.\r
+ * Must be one of the PLACEHOLDER_* static constants defined in this class.\r
+ *\r
+ * @return the placeholder size.\r
+ */\r
+ public int getPlaceholderSize(){\r
+ return placeholderSize;\r
+ }\r
+\r
+ /**\r
+ * Sets the placeholder size.\r
+ * Must be one of the PLACEHOLDER_* static constants defined in this class.\r
+ *\r
+ * @param size the placeholder size.\r
+ */\r
+ public void setPlaceholderSize(byte size){\r
+ placeholderSize = size;\r
+ }\r
+\r
+ /**\r
+ * Write the contents of the record back, so it can be written\r
+ * to disk\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ out.write(_header);\r
+\r
+ byte[] recdata = new byte[8];\r
+ LittleEndian.putInt(recdata, 0, placementId);\r
+ recdata[4] = (byte)placeholderId;\r
+ recdata[5] = (byte)placeholderSize;\r
+\r
+ out.write(recdata);\r
+ }\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Copyright 2002-2004 Apache Software Foundation\r
+\r
+ Licensed under the Apache License, Version 2.0 (the "License");\r
+ you may not use this file except in compliance with the License.\r
+ You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.hslf.record;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+import java.io.OutputStream;\r
+import java.io.IOException;\r
+\r
+/**\r
+ * OEPlaceholderAtom (3998).\r
+ * <br>\r
+ * What MSDN says about <code>OutlineTextRefAtom</code>:\r
+ * <p>\r
+ * Appears in a slide to indicate a text that is already contained in the document,\r
+ * in a SlideListWithText containter. Sometimes slide texts are not contained\r
+ * within the slide container to be able to delay loading a slide and still display\r
+ * the title and body text in outline view.\r
+ * </p>\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+\r
+public class OutlineTextRefAtom extends RecordAtom {\r
+ /**\r
+ * record header\r
+ */\r
+ private byte[] _header;\r
+\r
+ /**\r
+ * the text's index within the SlideListWithText (0 for title, 1..n for the nth body)\r
+ */\r
+ private int _index;\r
+\r
+ /**\r
+ * Build an instance of <code>OutlineTextRefAtom</code> from on-disk data\r
+ */\r
+ protected OutlineTextRefAtom(byte[] source, int start, int len) {\r
+ // Get the header\r
+ _header = new byte[8];\r
+ System.arraycopy(source,start,_header,0,8);\r
+\r
+ // Grab the record data\r
+ _index = LittleEndian.getInt(source, start+8);\r
+ }\r
+\r
+ /**\r
+ * Create a new instance of <code>FontEntityAtom</code>\r
+ */\r
+ protected OutlineTextRefAtom() {\r
+ _index = 0;\r
+\r
+ _header = new byte[8];\r
+ LittleEndian.putUShort(_header, 0, 0);\r
+ LittleEndian.putUShort(_header, 2, (int)getRecordType());\r
+ LittleEndian.putInt(_header, 4, 4);\r
+ }\r
+\r
+ public long getRecordType() {\r
+ return RecordTypes.OutlineTextRefAtom.typeID;\r
+ }\r
+\r
+ /**\r
+ * Write the contents of the record back, so it can be written to disk\r
+ */\r
+ public void writeOut(OutputStream out) throws IOException {\r
+ out.write(_header);\r
+\r
+ byte[] recdata = new byte[4];\r
+ LittleEndian.putInt(recdata, 0, _index);\r
+ out.write(recdata);\r
+ }\r
+\r
+ /**\r
+ * Sets text's index within the SlideListWithText container\r
+ * (0 for title, 1..n for the nth body).\r
+ *\r
+ * @param idx 0-based text's index\r
+ */\r
+ public void setTextIndex(int idx){\r
+ _index = idx;\r
+ }\r
+\r
+ /**\r
+ * Return text's index within the SlideListWithText container\r
+ * (0 for title, 1..n for the nth body).\r
+ *\r
+ * @return idx text's index\r
+ */\r
+ public int getTextIndex(){\r
+ return _index;\r
+ }\r
+\r
+}\r
public static final Type ColorSchemeAtom = new Type(2032,ColorSchemeAtom.class);
public static final Type ExObjRefAtom = new Type(3009,null);
public static final Type OEShapeAtom = new Type(3009,null);
- public static final Type OEPlaceholderAtom = new Type(3011,null);
+ public static final Type OEPlaceholderAtom = new Type(3011,OEPlaceholderAtom.class);
public static final Type GPopublicintAtom = new Type(3024,null);
public static final Type GRatioAtom = new Type(3031,null);
- public static final Type OutlineTextRefAtom = new Type(3998,null);
+ public static final Type OutlineTextRefAtom = new Type(3998,OutlineTextRefAtom.class);
public static final Type TextHeaderAtom = new Type(3999,TextHeaderAtom.class);
public static final Type TextCharsAtom = new Type(4000,TextCharsAtom.class);
public static final Type StyleTextPropAtom = new Type(4001,StyleTextPropAtom.class);
/**
* Supply the SlideShow we belong to
*/
- protected void supplySlideShow(SlideShow ss) {
+ public void supplySlideShow(SlideShow ss) {
slideShow = ss;
}
return slideShow.getFontCollection().getFontWithId(fontIdx);
}
+ /**
+ * @return font color as RGB value
+ * @see java.awt.Color
+ */
+ public int getFontColor() {
+ return getCharTextPropVal("font.color");
+ }
+ /**
+ * Sets color of the text, as a RGB value
+ * @see java.awt.Color
+ */
+ public void setFontColor(int rgb) {
+ setCharTextPropVal("font.color", rgb);
+ }
+
// --------------- Internal HSLF methods, not intended for end-user use! -------
import java.io.ByteArrayOutputStream;\r
import java.io.ByteArrayInputStream;\r
import java.io.FileOutputStream;\r
+import java.util.ArrayList;\r
\r
/**\r
* Test drawing shapes via Graphics2D\r
// Create a new textbox, and give it lots of properties\r
TextBox txtbox = new TextBox();\r
txtbox.setText(val);\r
+ txtbox.setFontName("Arial");\r
txtbox.setFontSize(42);\r
txtbox.setBold(true);\r
txtbox.setItalic(true);\r
txtbox.setUnderline(false);\r
+ txtbox.setFontColor(Color.red);\r
sl.addShape(txtbox);\r
\r
// Check it before save\r
assertTrue(rt.isBold());\r
assertTrue(rt.isItalic());\r
assertFalse(rt.isUnderlined());\r
+ assertEquals("Arial", rt.getFontName());\r
+ assertEquals(Color.red, txtbox.getFontColor());\r
\r
// Serialize and read again\r
ByteArrayOutputStream out = new ByteArrayOutputStream();\r
assertTrue(rt.isBold());\r
assertTrue(rt.isItalic());\r
assertFalse(rt.isUnderlined());\r
+ assertEquals("Arial", rt.getFontName());\r
+ assertEquals(Color.red, txtbox.getFontColor());\r
}\r
\r
/**\r
- * Verify that we can add TextBox shapes to a slide\r
- * and set some of the style attributes, with a unicode string\r
+ * If you iterate over text shapes in a slide and collect them in a set\r
+ * it must be the same as returned by Slide.getTextRuns().\r
*/\r
- public void testTextBoxWriteChars() throws Exception {\r
- ppt = new SlideShow();\r
- Slide sl = ppt.createSlide();\r
- RichTextRun rt;\r
-\r
- String val = "Hello, World! (With some \u1234 and \uffee unicode in it)";\r
-\r
- // Create a new textbox, and give it lots of properties\r
- TextBox txtbox = new TextBox();\r
- txtbox.setText(val);\r
- txtbox.setFontSize(42);\r
- txtbox.setBold(true);\r
- txtbox.setUnderline(false);\r
- sl.addShape(txtbox);\r
-\r
- // Check it before save\r
- rt = txtbox.getRichTextRuns()[0];\r
- assertEquals(val, rt.getText());\r
- assertEquals(42, rt.getFontSize());\r
- assertTrue(rt.isBold());\r
- assertFalse(rt.isItalic());\r
- assertFalse(rt.isUnderlined());\r
-\r
- // Serialize and read again\r
- ByteArrayOutputStream out = new ByteArrayOutputStream();\r
- ppt.write(out);\r
- out.close();\r
-\r
- ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())));\r
+ public void testTextBoxSet() throws Exception {\r
+ textBoxSet("/with_textbox.ppt");\r
+ textBoxSet("/basic_test_ppt_file.ppt");\r
+ textBoxSet("/next_test_ppt_file.ppt");\r
+ textBoxSet("/Single_Coloured_Page.ppt");\r
+ textBoxSet("/Single_Coloured_Page_With_Fonts_and_Alignments.ppt");\r
+ textBoxSet("/incorrect_slide_order.ppt");\r
+ }\r
\r
- txtbox = (TextBox)sl.getShapes()[0];\r
- rt = txtbox.getRichTextRuns()[0];\r
+ private void textBoxSet(String filename) throws Exception {\r
+ String dirname = System.getProperty("HSLF.testdata.path");\r
+ SlideShow ppt = new SlideShow(new HSLFSlideShow(dirname + filename));\r
+ Slide[] sl = ppt.getSlides();\r
+ for (int k = 0; k < sl.length; k++) {\r
+ ArrayList lst1 = new ArrayList();\r
+ TextRun[] txt = sl[k].getTextRuns();\r
+ for (int i = 0; i < txt.length; i++) {\r
+ lst1.add(txt[i].getText());\r
+ }\r
\r
- // Check after save\r
- assertEquals(val, rt.getText());\r
- assertEquals(42, rt.getFontSize());\r
- assertTrue(rt.isBold());\r
- assertFalse(rt.isItalic());\r
- assertFalse(rt.isUnderlined());\r
+ ArrayList lst2 = new ArrayList();\r
+ Shape[] sh = sl[k].getShapes();\r
+ for (int i = 0; i < sh.length; i++) {\r
+ if (sh[i] instanceof TextBox){\r
+ TextBox tbox = (TextBox)sh[i];\r
+ lst2.add(tbox.getText());\r
+ }\r
+ }\r
+ assertTrue(lst1.containsAll(lst2));\r
+ assertTrue(lst2.containsAll(lst1));\r
+ }\r
}\r
}\r