git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@405092 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_0_ALPHA3
@@ -18,6 +18,7 @@ | |||
<li><link href="#GetShapes">How to get shapes contained in a particular slide</link></li> | |||
<li><link href="#Shapes">Drawing a shape on a slide</link></li> | |||
<li><link href="#Pictures">How to add/retrieve pictures</link></li> | |||
<li><link href="#SlideTitle">How to set slide title</link></li> | |||
</ul> | |||
</section> | |||
<section><title>Features</title> | |||
@@ -62,7 +63,7 @@ | |||
The following pictute shows the class tree of HSLF shapes: | |||
</p> | |||
<p> | |||
<img src="hslf_shapes.gif" alt="Class Tree of HSLF Shapes" width="611" height="285"/> | |||
<img src="hslf_shapes.gif" alt="Class Tree of HSLF Shapes" width="611" height="412"/> | |||
</p> | |||
<p> | |||
The following fragment demonstrates how to iterate over shapes for each slide. | |||
@@ -209,6 +210,28 @@ | |||
</source> | |||
</section> | |||
<anchor id="SlideTitle"/> | |||
<section><title>How to set slide title</title> | |||
<source> | |||
SlideShow ppt = new SlideShow(); | |||
Slide slide = ppt.createSlide(); | |||
TextBox title = slide.addTitle(); | |||
title.setText("Hello, World!"); | |||
//save changes | |||
FileOutputStream out = new FileOutputStream("slideshow.ppt"); | |||
wb.write(out); | |||
out.close(); | |||
</source> | |||
<p> | |||
Below is the equivalent code in PowerPoint VBA: | |||
</p> | |||
<source> | |||
Set myDocument = ActivePresentation.Slides(1) | |||
myDocument.Shapes.AddTitle.TextFrame.TextRange.Text = "Hello, World!" | |||
</source> | |||
</section> | |||
</section> | |||
</section> | |||
</body> |
@@ -1,59 +0,0 @@ | |||
/* ==================================================================== | |||
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 = createSpContainer(parent instanceof ShapeGroup); | |||
} | |||
public Ellipse(){ | |||
this(null); | |||
} | |||
protected EscherContainerRecord createSpContainer(boolean isChild){ | |||
EscherContainerRecord spcont = super.createSpContainer(isChild); | |||
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; | |||
} | |||
} |
@@ -151,7 +151,7 @@ public class PPGraphics2D extends Graphics2D { | |||
if (font != null){ | |||
txt.setFontSize(font.getSize()); | |||
txt.setFontName(font.getName()); | |||
//if(getColor() != null) txt.setFontColor(getColor()); | |||
if(getColor() != null) txt.setFontColor(getColor()); | |||
if (font.isBold()) txt.setBold(true); | |||
if (font.isItalic()) txt.setItalic(true); | |||
} |
@@ -0,0 +1,97 @@ | |||
/* ==================================================================== | |||
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.record.OEPlaceholderAtom; | |||
import java.util.List; | |||
import java.io.ByteArrayOutputStream; | |||
/** | |||
* Represents a Placeholder in PowerPoint. | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class Placeholder extends TextBox { | |||
protected Placeholder(EscherContainerRecord escherRecord, Shape parent){ | |||
super(escherRecord, parent); | |||
} | |||
public Placeholder(Shape parent){ | |||
super(parent); | |||
} | |||
public Placeholder(){ | |||
super(); | |||
} | |||
/** | |||
* Create a new Placeholder and initialize internal structures | |||
* | |||
* @return the created <code>EscherContainerRecord</code> which holds shape data | |||
*/ | |||
protected EscherContainerRecord createSpContainer(boolean isChild){ | |||
EscherContainerRecord spcont = super.createSpContainer(isChild); | |||
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID); | |||
spRecord.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER); | |||
EscherClientDataRecord cldata = new EscherClientDataRecord(); | |||
cldata.setOptions((short)15); | |||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID); | |||
//Placeholders can't be grouped | |||
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144); | |||
//OEPlaceholderAtom tells powerpoint that this shape is a placeholder | |||
// | |||
OEPlaceholderAtom oep = new OEPlaceholderAtom(); | |||
/** | |||
* Extarct from MSDN: | |||
* | |||
* There is a special case when the placeholder does not have a position in the layout. | |||
* This occurs when the user has moved the placeholder from its original position. | |||
* In this case the placeholder ID is -1. | |||
*/ | |||
oep.setPlacementId(-1); | |||
oep.setPlaceholderId(OEPlaceholderAtom.Body); | |||
//convert hslf into ddf record | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
try { | |||
oep.writeOut(out); | |||
} catch(Exception e){ | |||
throw new RuntimeException(e); | |||
} | |||
cldata.setRemainingData(out.toByteArray()); | |||
//append placeholder container before EscherTextboxRecord | |||
List lst = spcont.getChildRecords(); | |||
for (int i = 0; i < lst.size(); i++) { | |||
EscherRecord rec = (EscherRecord)lst.get(i); | |||
if(rec.getRecordId() == EscherTextboxRecord.RECORD_ID){ | |||
lst.add(i++, cldata); | |||
} | |||
} | |||
return spcont; | |||
} | |||
} |
@@ -1,52 +0,0 @@ | |||
/* ==================================================================== | |||
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 rectangle shae in a PowerPoint drawing | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class Rectangle extends TextBox { | |||
protected Rectangle(EscherContainerRecord escherRecord, Shape parent){ | |||
super(escherRecord, parent); | |||
} | |||
public Rectangle(Shape parent){ | |||
super(parent); | |||
} | |||
public Rectangle(){ | |||
super(); | |||
} | |||
protected EscherContainerRecord createSpContainer(boolean isChild){ | |||
EscherContainerRecord spcont = super.createSpContainer(isChild); | |||
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID); | |||
short type = (ShapeTypes.Rectangle << 4) + 2; | |||
spRecord.setOptions(type); | |||
return spcont; | |||
} | |||
} |
@@ -112,9 +112,27 @@ public abstract class Shape { | |||
return ShapeTypes.typeName(spRecord.getOptions() >> 4); | |||
} | |||
/** | |||
* @return type of the shape. | |||
* @see org.apache.poi.hslf.record.RecordTypes | |||
*/ | |||
public int getShapeType(){ | |||
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID); | |||
return spRecord.getOptions() >> 4; | |||
} | |||
/** | |||
* @param type type of the shape. | |||
* @see org.apache.poi.hslf.record.RecordTypes | |||
*/ | |||
public void setShapeType(int type){ | |||
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID); | |||
spRecord.setOptions((short)(type << 4 | 0x2)); | |||
} | |||
/** | |||
* Returns the anchor (the bounding box rectangle) of this shape. | |||
* All coordinates are expressed in Master units (576 dpi). | |||
* All coordinates are expressed in points (72 dpi). | |||
* | |||
* @return the anchor of this shape | |||
*/ | |||
@@ -143,7 +161,7 @@ public abstract class Shape { | |||
/** | |||
* Sets the anchor (the bounding box rectangle) of this shape. | |||
* All coordinates should be expressed in poitns (72 dpi). | |||
* All coordinates should be expressed in points (72 dpi). | |||
* | |||
* @param anchor new anchor | |||
*/ |
@@ -15,8 +15,7 @@ | |||
==================================================================== */ | |||
package org.apache.poi.hslf.model; | |||
import org.apache.poi.ddf.EscherSpRecord; | |||
import org.apache.poi.ddf.EscherContainerRecord; | |||
import org.apache.poi.ddf.*; | |||
/** | |||
* Create a <code>Shape</code> object depending on its type | |||
@@ -38,12 +37,19 @@ public class ShapeFactory { | |||
int type = spRecord.getOptions() >> 4; | |||
switch (type){ | |||
case ShapeTypes.Rectangle: | |||
EscherTextboxRecord txtbox = (EscherTextboxRecord)Shape.getEscherChild(spContainer, EscherTextboxRecord.RECORD_ID); | |||
if (txtbox == null) shape = new AutoShape(spContainer, parent); | |||
else{ | |||
if(Shape.getEscherChild(spContainer, EscherClientDataRecord.RECORD_ID) != null ) | |||
shape = new Placeholder(spContainer, parent); | |||
else | |||
shape = new TextBox(spContainer, parent); | |||
} | |||
break; | |||
case ShapeTypes.TextBox: | |||
shape = new TextBox(spContainer, parent); | |||
break; | |||
case ShapeTypes.Rectangle: | |||
shape = new Rectangle(spContainer, parent); | |||
break; | |||
case ShapeTypes.PictureFrame: | |||
shape = new Picture(spContainer, parent); | |||
break; |
@@ -23,6 +23,7 @@ import java.util.Vector; | |||
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; | |||
/** | |||
@@ -117,6 +118,21 @@ public class Slide extends Sheet | |||
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 | |||
@@ -133,7 +149,7 @@ public class Slide extends Sheet | |||
public int _getSheetRefId() { return _refSheetNo; } | |||
/** | |||
* Returns the (internal, SlideIdentifier based) sheet number | |||
* @see getSlideNumber() | |||
* @see #getSlideNumber() | |||
*/ | |||
public int _getSheetNumber() { return _sheetNo; } | |||
@@ -152,5 +168,14 @@ public class Slide extends Sheet | |||
*/ | |||
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; } | |||
} |
@@ -85,6 +85,8 @@ public class TextBox extends SimpleShape { | |||
*/ | |||
protected EscherTextboxWrapper _txtbox; | |||
private String _fontname; | |||
/** | |||
* Create a TextBox object and initialize it from the supplied Record container. | |||
* | |||
@@ -96,17 +98,6 @@ public class TextBox extends SimpleShape { | |||
EscherTextboxRecord textbox = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID); | |||
_txtbox = new EscherTextboxWrapper(textbox); | |||
// Find our TextRun | |||
Vector v = new Vector(); | |||
Sheet.findTextRuns(_txtbox.getChildRecords(), v); | |||
// We should just have one | |||
if(v.size() == 1) { | |||
_txtrun = (TextRun)v.get(0); | |||
} else { | |||
throw new IllegalStateException("A TextBox should have one TextRun's worth of records in it, found " + v.size()); | |||
} | |||
} | |||
/** | |||
@@ -206,6 +197,7 @@ public class TextBox extends SimpleShape { | |||
} catch (IOException e){ | |||
throw new RuntimeException(e); | |||
} | |||
if(getAnchor().equals(new java.awt.Rectangle())) resizeToFitText(); | |||
} | |||
/** | |||
@@ -214,7 +206,7 @@ public class TextBox extends SimpleShape { | |||
* | |||
* @return the bounds of this <code>TextFrame</code>. | |||
*/ | |||
protected Dimension getTextSize(){ | |||
protected Dimension getTextDimensions(){ | |||
FontRenderContext frc = new FontRenderContext(null, true, true); | |||
RichTextRun rt = _txtrun.getRichTextRuns()[0]; | |||
int size = rt.getFontSize(); | |||
@@ -229,9 +221,9 @@ public class TextBox extends SimpleShape { | |||
TextLayout layout = new TextLayout(getText(), font, frc); | |||
int width = Math.round(layout.getAdvance()); | |||
width += getMarginLeft() + getMarginRight(); | |||
width += getMarginLeft() + getMarginRight() + 2; | |||
int height = Math.round(layout.getAscent()); | |||
height += getMarginTop() + getMarginBottom(); | |||
height += getMarginTop() + getMarginBottom() + 12; | |||
return new Dimension(width, height); | |||
} | |||
@@ -239,7 +231,7 @@ public class TextBox extends SimpleShape { | |||
* Adjust the size of the TextBox so it encompasses the text inside it. | |||
*/ | |||
public void resizeToFitText(){ | |||
Dimension size = getTextSize(); | |||
Dimension size = getTextDimensions(); | |||
java.awt.Rectangle anchor = getAnchor(); | |||
anchor.setSize(size); | |||
setAnchor(anchor); | |||
@@ -448,6 +440,17 @@ public class TextBox extends SimpleShape { | |||
return rt.getFontSize(); | |||
} | |||
/** | |||
* | |||
* @return the size of the font applied to this text shape | |||
*/ | |||
public Color getFontColor(){ | |||
RichTextRun rt = _txtrun.getRichTextRuns()[0]; | |||
Color color = new Color(rt.getFontColor()); | |||
//in PowerPont RGB bytes are swapped, | |||
return new Color(color.getBlue(), color.getGreen(), color.getRed(), 255); | |||
} | |||
/** | |||
* Set whether to use bold or not | |||
* | |||
@@ -484,8 +487,92 @@ public class TextBox extends SimpleShape { | |||
* @param name the name of the font to be applied to this text shape | |||
*/ | |||
public void setFontName(String name){ | |||
if (_sheet == null) { | |||
//we can't set font since slideshow is not assigned yet | |||
_fontname = name; | |||
} else{ | |||
RichTextRun rt = _txtrun.getRichTextRuns()[0]; | |||
rt.setFontName(name); | |||
} | |||
} | |||
/** | |||
* Sets the font color | |||
* @param color the font color | |||
*/ | |||
public void setFontColor(Color color){ | |||
//in PowerPont RGB bytes are swapped, | |||
int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB(); | |||
RichTextRun rt = _txtrun.getRichTextRuns()[0]; | |||
rt.setFontColor(rgb); | |||
} | |||
/** | |||
* Set type of the text. | |||
* Must be one of the static constants defined in <code>TextHeaderAtom</code> | |||
* | |||
* @param type type of the text | |||
*/ | |||
public void setTextType(int type){ | |||
_txtrun._headerAtom.setTextType(type); | |||
} | |||
public void setSheet(Sheet sheet){ | |||
_sheet = sheet; | |||
//initialize _txtrun object. | |||
//we can't do it in the constructor because the sheet is not assigned yet | |||
if(_txtrun == null) initTextRun(); | |||
RichTextRun[] rt = _txtrun.getRichTextRuns(); | |||
for (int i = 0; i < rt.length; i++) { | |||
rt[i].supplySlideShow(_sheet.getSlideShow()); | |||
} | |||
if (_fontname != null) { | |||
setFontName(_fontname); | |||
_fontname = null; | |||
} | |||
} | |||
private void initTextRun(){ | |||
TextHeaderAtom tha = null; | |||
TextCharsAtom tca = null; | |||
TextBytesAtom tba = null; | |||
StyleTextPropAtom sta = null; | |||
OutlineTextRefAtom ota = null; | |||
Record[] child = _txtbox.getChildRecords(); | |||
for (int i = 0; i < child.length; i++) { | |||
if (child[i] instanceof TextHeaderAtom) tha = (TextHeaderAtom)child[i]; | |||
else if (child[i] instanceof TextBytesAtom) tba = (TextBytesAtom)child[i]; | |||
else if (child[i] instanceof StyleTextPropAtom) sta = (StyleTextPropAtom)child[i]; | |||
else if (child[i] instanceof OutlineTextRefAtom) ota = (OutlineTextRefAtom)child[i]; | |||
else if (child[i] instanceof TextCharsAtom) tca = (TextCharsAtom)child[i]; | |||
} | |||
if (ota != null){ | |||
//TextHeaderAtom, TextBytesAtom and StyleTextPropAtom are stored outside of EscherContainerRecord | |||
int idx = ota.getTextIndex(); | |||
Slide sl = (Slide)getSheet(); | |||
Record[] rec = sl.getSlideAtomsSet().getSlideRecords(); | |||
for (int i = 0, j = 0; i < rec.length; i++) { | |||
if(rec[i].getRecordType() == RecordTypes.TextHeaderAtom.typeID){ | |||
if(j++ == idx) { //we found j-th TextHeaderAtom, read the text data | |||
for (int k = i; k < rec.length; k++) { | |||
if (rec[k] instanceof TextHeaderAtom) { | |||
if (tha != null) break; | |||
else tha = (TextHeaderAtom)rec[k]; | |||
} | |||
else if (rec[k] instanceof TextBytesAtom) tba = (TextBytesAtom)rec[k]; | |||
else if (rec[k] instanceof TextCharsAtom) tca = (TextCharsAtom)rec[k]; | |||
else if (rec[k] instanceof StyleTextPropAtom) sta = (StyleTextPropAtom)rec[k]; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
if(tba != null) _txtrun = new TextRun(tha,tba,sta); | |||
else if (tca != null) _txtrun = new TextRun(tha,tca,sta); | |||
} | |||
} |
@@ -0,0 +1,200 @@ | |||
/* ==================================================================== | |||
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.record; | |||
import org.apache.poi.util.LittleEndian; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
/** | |||
* OEPlaceholderAtom (3011). | |||
* <p> | |||
* Atom that describes the placeholder. | |||
* </p> | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class OEPlaceholderAtom extends RecordAtom{ | |||
public static final int PLACEHOLDER_FULLSIZE = 0; | |||
public static final int PLACEHOLDER_HALFSIZE = 1; | |||
public static final int PLACEHOLDER_QUARTSIZE = 2; | |||
public static final byte None = 0; | |||
public static final byte MasterTitle = 1; | |||
public static final byte MasterBody = 2; | |||
public static final byte MasterCenteredTitle = 3; | |||
public static final byte MasterNotesSlideImage = 4; | |||
public static final byte MasterNotesBodyImage = 5; | |||
public static final byte MasterDate = 6; | |||
public static final byte MasterSlideNumber = 7; | |||
public static final byte MasterFooter = 8; | |||
public static final byte MasterHeader = 9; | |||
public static final byte MasterSubtitle = 10; | |||
public static final byte GenericTextObject = 11; | |||
public static final byte Title = 12; | |||
public static final byte Body = 13; | |||
public static final byte NotesBody = 14; | |||
public static final byte CenteredTitle = 15; | |||
public static final byte Subtitle = 16; | |||
public static final byte VerticalTextTitle = 17; | |||
public static final byte VerticalTextBody = 18; | |||
public static final byte NotesSlideImage = 19; | |||
public static final byte Object = 20; | |||
public static final byte Graph = 21; | |||
public static final byte Table = 22; | |||
public static final byte ClipArt = 23; | |||
public static final byte OrganizationChart = 24; | |||
public static final byte MediaClip = 25; | |||
private byte[] _header; | |||
private int placementId; | |||
private int placeholderId; | |||
private int placeholderSize; | |||
/** | |||
* Create a new instance of <code>OEPlaceholderAtom</code> | |||
*/ | |||
public OEPlaceholderAtom(){ | |||
_header = new byte[8]; | |||
LittleEndian.putUShort(_header, 0, 0); | |||
LittleEndian.putUShort(_header, 2, (int)getRecordType()); | |||
LittleEndian.putInt(_header, 4, 8); | |||
placementId = 0; | |||
placeholderId = 0; | |||
placeholderSize = 0; | |||
} | |||
/** | |||
* Build an instance of <code>OEPlaceholderAtom</code> from on-disk data | |||
*/ | |||
protected OEPlaceholderAtom(byte[] source, int start, int len) { | |||
_header = new byte[8]; | |||
System.arraycopy(source,start,_header,0,8); | |||
placementId = LittleEndian.getInt(source, start); | |||
placeholderId = LittleEndian.getUnsignedByte(source, start+4); | |||
placeholderSize = LittleEndian.getUnsignedByte(source, start+5); | |||
} | |||
/** | |||
* @return type of this record {@link RecordTypes#OEPlaceholderAtom}. | |||
*/ | |||
public long getRecordType() { return RecordTypes.OEPlaceholderAtom.typeID; } | |||
/** | |||
* Returns the placement Id. | |||
* | |||
* @return the placement Id. | |||
*/ | |||
public int getPlacementId(){ | |||
return placementId; | |||
} | |||
/** | |||
* Sets the placement Id. | |||
* | |||
* @param id the placement Id. | |||
*/ | |||
public void setPlacementId(int id){ | |||
placementId = id; | |||
} | |||
/** | |||
* Returns the placeholder Id. | |||
* | |||
* @return the placeholder Id. | |||
*/ | |||
public int getPlaceholderId(){ | |||
return placeholderId; | |||
} | |||
/** | |||
* Sets the placeholder Id. | |||
* | |||
* @param id the placeholder Id. | |||
*/ | |||
public void setPlaceholderId(byte id){ | |||
placeholderId = id; | |||
} | |||
/** | |||
* Returns the placeholder size. | |||
* Must be one of the PLACEHOLDER_* static constants defined in this class. | |||
* | |||
* @return the placeholder size. | |||
*/ | |||
public int getPlaceholderSize(){ | |||
return placeholderSize; | |||
} | |||
/** | |||
* Sets the placeholder size. | |||
* Must be one of the PLACEHOLDER_* static constants defined in this class. | |||
* | |||
* @param size the placeholder size. | |||
*/ | |||
public void setPlaceholderSize(byte size){ | |||
placeholderSize = size; | |||
} | |||
/** | |||
* Write the contents of the record back, so it can be written | |||
* to disk | |||
*/ | |||
public void writeOut(OutputStream out) throws IOException { | |||
out.write(_header); | |||
byte[] recdata = new byte[8]; | |||
LittleEndian.putInt(recdata, 0, placementId); | |||
recdata[4] = (byte)placeholderId; | |||
recdata[5] = (byte)placeholderSize; | |||
out.write(recdata); | |||
} | |||
} |
@@ -0,0 +1,107 @@ | |||
/* ==================================================================== | |||
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.record; | |||
import org.apache.poi.util.LittleEndian; | |||
import java.io.OutputStream; | |||
import java.io.IOException; | |||
/** | |||
* OEPlaceholderAtom (3998). | |||
* <br> | |||
* What MSDN says about <code>OutlineTextRefAtom</code>: | |||
* <p> | |||
* Appears in a slide to indicate a text that is already contained in the document, | |||
* in a SlideListWithText containter. Sometimes slide texts are not contained | |||
* within the slide container to be able to delay loading a slide and still display | |||
* the title and body text in outline view. | |||
* </p> | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class OutlineTextRefAtom extends RecordAtom { | |||
/** | |||
* record header | |||
*/ | |||
private byte[] _header; | |||
/** | |||
* the text's index within the SlideListWithText (0 for title, 1..n for the nth body) | |||
*/ | |||
private int _index; | |||
/** | |||
* Build an instance of <code>OutlineTextRefAtom</code> from on-disk data | |||
*/ | |||
protected OutlineTextRefAtom(byte[] source, int start, int len) { | |||
// Get the header | |||
_header = new byte[8]; | |||
System.arraycopy(source,start,_header,0,8); | |||
// Grab the record data | |||
_index = LittleEndian.getInt(source, start+8); | |||
} | |||
/** | |||
* Create a new instance of <code>FontEntityAtom</code> | |||
*/ | |||
protected OutlineTextRefAtom() { | |||
_index = 0; | |||
_header = new byte[8]; | |||
LittleEndian.putUShort(_header, 0, 0); | |||
LittleEndian.putUShort(_header, 2, (int)getRecordType()); | |||
LittleEndian.putInt(_header, 4, 4); | |||
} | |||
public long getRecordType() { | |||
return RecordTypes.OutlineTextRefAtom.typeID; | |||
} | |||
/** | |||
* Write the contents of the record back, so it can be written to disk | |||
*/ | |||
public void writeOut(OutputStream out) throws IOException { | |||
out.write(_header); | |||
byte[] recdata = new byte[4]; | |||
LittleEndian.putInt(recdata, 0, _index); | |||
out.write(recdata); | |||
} | |||
/** | |||
* Sets text's index within the SlideListWithText container | |||
* (0 for title, 1..n for the nth body). | |||
* | |||
* @param idx 0-based text's index | |||
*/ | |||
public void setTextIndex(int idx){ | |||
_index = idx; | |||
} | |||
/** | |||
* Return text's index within the SlideListWithText container | |||
* (0 for title, 1..n for the nth body). | |||
* | |||
* @return idx text's index | |||
*/ | |||
public int getTextIndex(){ | |||
return _index; | |||
} | |||
} |
@@ -76,10 +76,10 @@ public class RecordTypes { | |||
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); |
@@ -93,7 +93,7 @@ public class RichTextRun | |||
/** | |||
* Supply the SlideShow we belong to | |||
*/ | |||
protected void supplySlideShow(SlideShow ss) { | |||
public void supplySlideShow(SlideShow ss) { | |||
slideShow = ss; | |||
} | |||
@@ -281,6 +281,21 @@ public class RichTextRun | |||
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! ------- | |||
@@ -25,6 +25,7 @@ import java.awt.Rectangle; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.FileOutputStream; | |||
import java.util.ArrayList; | |||
/** | |||
* Test drawing shapes via Graphics2D | |||
@@ -132,10 +133,12 @@ public class TestShapes extends TestCase { | |||
// Create a new textbox, and give it lots of properties | |||
TextBox txtbox = new TextBox(); | |||
txtbox.setText(val); | |||
txtbox.setFontName("Arial"); | |||
txtbox.setFontSize(42); | |||
txtbox.setBold(true); | |||
txtbox.setItalic(true); | |||
txtbox.setUnderline(false); | |||
txtbox.setFontColor(Color.red); | |||
sl.addShape(txtbox); | |||
// Check it before save | |||
@@ -145,6 +148,8 @@ public class TestShapes extends TestCase { | |||
assertTrue(rt.isBold()); | |||
assertTrue(rt.isItalic()); | |||
assertFalse(rt.isUnderlined()); | |||
assertEquals("Arial", rt.getFontName()); | |||
assertEquals(Color.red, txtbox.getFontColor()); | |||
// Serialize and read again | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
@@ -162,50 +167,44 @@ public class TestShapes extends TestCase { | |||
assertTrue(rt.isBold()); | |||
assertTrue(rt.isItalic()); | |||
assertFalse(rt.isUnderlined()); | |||
assertEquals("Arial", rt.getFontName()); | |||
assertEquals(Color.red, txtbox.getFontColor()); | |||
} | |||
/** | |||
* Verify that we can add TextBox shapes to a slide | |||
* and set some of the style attributes, with a unicode string | |||
* If you iterate over text shapes in a slide and collect them in a set | |||
* it must be the same as returned by Slide.getTextRuns(). | |||
*/ | |||
public void testTextBoxWriteChars() throws Exception { | |||
ppt = new SlideShow(); | |||
Slide sl = ppt.createSlide(); | |||
RichTextRun rt; | |||
String val = "Hello, World! (With some \u1234 and \uffee unicode in it)"; | |||
// Create a new textbox, and give it lots of properties | |||
TextBox txtbox = new TextBox(); | |||
txtbox.setText(val); | |||
txtbox.setFontSize(42); | |||
txtbox.setBold(true); | |||
txtbox.setUnderline(false); | |||
sl.addShape(txtbox); | |||
// Check it before save | |||
rt = txtbox.getRichTextRuns()[0]; | |||
assertEquals(val, rt.getText()); | |||
assertEquals(42, rt.getFontSize()); | |||
assertTrue(rt.isBold()); | |||
assertFalse(rt.isItalic()); | |||
assertFalse(rt.isUnderlined()); | |||
// Serialize and read again | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
ppt.write(out); | |||
out.close(); | |||
ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray()))); | |||
public void testTextBoxSet() throws Exception { | |||
textBoxSet("/with_textbox.ppt"); | |||
textBoxSet("/basic_test_ppt_file.ppt"); | |||
textBoxSet("/next_test_ppt_file.ppt"); | |||
textBoxSet("/Single_Coloured_Page.ppt"); | |||
textBoxSet("/Single_Coloured_Page_With_Fonts_and_Alignments.ppt"); | |||
textBoxSet("/incorrect_slide_order.ppt"); | |||
} | |||
txtbox = (TextBox)sl.getShapes()[0]; | |||
rt = txtbox.getRichTextRuns()[0]; | |||
private void textBoxSet(String filename) throws Exception { | |||
String dirname = System.getProperty("HSLF.testdata.path"); | |||
SlideShow ppt = new SlideShow(new HSLFSlideShow(dirname + filename)); | |||
Slide[] sl = ppt.getSlides(); | |||
for (int k = 0; k < sl.length; k++) { | |||
ArrayList lst1 = new ArrayList(); | |||
TextRun[] txt = sl[k].getTextRuns(); | |||
for (int i = 0; i < txt.length; i++) { | |||
lst1.add(txt[i].getText()); | |||
} | |||
// Check after save | |||
assertEquals(val, rt.getText()); | |||
assertEquals(42, rt.getFontSize()); | |||
assertTrue(rt.isBold()); | |||
assertFalse(rt.isItalic()); | |||
assertFalse(rt.isUnderlined()); | |||
ArrayList lst2 = new ArrayList(); | |||
Shape[] sh = sl[k].getShapes(); | |||
for (int i = 0; i < sh.length; i++) { | |||
if (sh[i] instanceof TextBox){ | |||
TextBox tbox = (TextBox)sh[i]; | |||
lst2.add(tbox.getText()); | |||
} | |||
} | |||
assertTrue(lst1.containsAll(lst2)); | |||
assertTrue(lst2.containsAll(lst1)); | |||
} | |||
} | |||
} |