TextShape is a common superclass of all shapes that can hold text. The subclasses are TextBox and AutoShape.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@648156 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2008-04-15 07:54:20 +00:00
parent f98e88e706
commit 95326239ee
16 changed files with 798 additions and 471 deletions

View File

@ -459,6 +459,7 @@ public class ApacheconEU08 {
TextBox box2 = new TextBox(); TextBox box2 = new TextBox();
TextRun tr2 = box2.getTextRun(); TextRun tr2 = box2.getTextRun();
tr2.setRunType(TextHeaderAtom.BODY_TYPE); tr2.setRunType(TextHeaderAtom.BODY_TYPE);
tr2.getRichTextRuns()[0].setFontSize(32);
tr2.setText( tr2.setText(
"Support for more PowerPoint functionality\r" + "Support for more PowerPoint functionality\r" +
"Rendering slides into java.awt.Graphics2D"); "Rendering slides into java.awt.Graphics2D");
@ -477,6 +478,7 @@ public class ApacheconEU08 {
TextBox box4 = new TextBox(); TextBox box4 = new TextBox();
TextRun tr4 = box4.getTextRun(); TextRun tr4 = box4.getTextRun();
tr4.setRunType(TextHeaderAtom.BODY_TYPE); tr4.setRunType(TextHeaderAtom.BODY_TYPE);
tr4.getRichTextRuns()[0].setFontSize(32);
tr4.setText( tr4.setText(
"Integration with Apache FOP - Formatting Objects Processor"); "Integration with Apache FOP - Formatting Objects Processor");
box4.setAnchor(new Rectangle(36, 290, 648, 90)); box4.setAnchor(new Rectangle(36, 290, 648, 90));

View File

@ -20,11 +20,15 @@ package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*; import org.apache.poi.ddf.*;
/** /**
* Represents a autoshape in a PowerPoint drawing * Represents an AutoShape.
* <p>
* AutoShapes are drawing objects with a particular shape that may be customized through smart resizing and adjustments.
* See {@link ShapeTypes}
* </p>
* *
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
public class AutoShape extends SimpleShape { public class AutoShape extends TextShape {
protected AutoShape(EscherContainerRecord escherRecord, Shape parent){ protected AutoShape(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent); super(escherRecord, parent);
@ -40,23 +44,62 @@ public class AutoShape extends SimpleShape {
} }
protected EscherContainerRecord createSpContainer(int shapeType, boolean isChild){ protected EscherContainerRecord createSpContainer(int shapeType, boolean isChild){
EscherContainerRecord spcont = super.createSpContainer(isChild); _escherContainer = super.createSpContainer(isChild);
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID); setShapeType(shapeType);
short type = (short)((shapeType << 4) | 0x2);
spRecord.setOptions(type);
//set default properties for an autoshape //set default properties for an autoshape
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID); setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000);
setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004);
setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004);
setEscherProperty(EscherProperties.FILL__FILLBACKCOLOR, 0x8000000);
setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x100010);
setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001);
setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80008);
setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004)); return _escherContainer;
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__FILLBACKCOLOR, 0x8000000));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__NOFILLHITTEST, 0x100010));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80008));
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002));
return spcont;
} }
protected void setDefaultTextProperties(TextRun _txtrun){
setVerticalAlignment(TextBox.AnchorMiddle);
setHorizontalAlignment(TextBox.AlignCenter);
setWordWrap(TextBox.WrapNone);
}
/**
* Gets adjust value which controls smart resizing of the auto-shape.
*
* <p>
* The adjustment values are given in shape coordinates:
* the origin is at the top-left, positive-x is to the right, positive-y is down.
* The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
* </p>
*
* @param idx the adjust index in the [0, 9] range
* @return the adjustment value
*/
public int getAdjustmentValue(int idx){
if(idx < 0 || idx > 9) throw new IllegalArgumentException("The index of an adjustment value must be in the [0, 9] range");
return getEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx));
}
/**
* Sets adjust value which controls smart resizing of the auto-shape.
*
* <p>
* The adjustment values are given in shape coordinates:
* the origin is at the top-left, positive-x is to the right, positive-y is down.
* The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
* </p>
*
* @param idx the adjust index in the [0, 9] range
* @param val the adjustment value
*/
public void setAdjustmentValue(int idx, int val){
if(idx < 0 || idx > 9) throw new IllegalArgumentException("The index of an adjustment value must be in the [0, 9] range");
setEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx), val);
}
} }

View File

@ -106,14 +106,14 @@ public class Line extends SimpleShape {
} }
protected EscherContainerRecord createSpContainer(boolean isChild){ protected EscherContainerRecord createSpContainer(boolean isChild){
EscherContainerRecord spcont = super.createSpContainer(isChild); _escherContainer = super.createSpContainer(isChild);
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID); EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
short type = (ShapeTypes.Line << 4) | 0x2; short type = (ShapeTypes.Line << 4) | 0x2;
spRecord.setOptions(type); spRecord.setOptions(type);
//set default properties for a line //set default properties for a line
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID); EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
//default line properties //default line properties
setEscherProperty(opt, EscherProperties.GEOMETRY__SHAPEPATH, 4); setEscherProperty(opt, EscherProperties.GEOMETRY__SHAPEPATH, 4);
@ -123,7 +123,7 @@ public class Line extends SimpleShape {
setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0xA0008); setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0xA0008);
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__COLOR, 0x8000002); setEscherProperty(opt, EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
return spcont; return _escherContainer;
} }
} }

View File

@ -120,20 +120,20 @@ public class Picture extends SimpleShape {
* @return the create Picture object * @return the create Picture object
*/ */
protected EscherContainerRecord createSpContainer(int idx, boolean isChild) { protected EscherContainerRecord createSpContainer(int idx, boolean isChild) {
EscherContainerRecord spContainer = super.createSpContainer(isChild); _escherContainer = super.createSpContainer(isChild);
spContainer.setOptions((short)15); _escherContainer.setOptions((short)15);
EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID); EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
spRecord.setOptions((short)((ShapeTypes.PictureFrame << 4) | 0x2)); spRecord.setOptions((short)((ShapeTypes.PictureFrame << 4) | 0x2));
//set default properties for a picture //set default properties for a picture
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spContainer, EscherOptRecord.RECORD_ID); EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 8388736); setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 8388736);
//another weird feature of powerpoint: for picture id we must add 0x4000. //another weird feature of powerpoint: for picture id we must add 0x4000.
setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx); setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx);
return spContainer; return _escherContainer;
} }
/** /**

View File

@ -49,15 +49,15 @@ public class Placeholder extends TextBox {
* @return the created <code>EscherContainerRecord</code> which holds shape data * @return the created <code>EscherContainerRecord</code> which holds shape data
*/ */
protected EscherContainerRecord createSpContainer(boolean isChild){ protected EscherContainerRecord createSpContainer(boolean isChild){
EscherContainerRecord spcont = super.createSpContainer(isChild); _escherContainer = super.createSpContainer(isChild);
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID); EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
spRecord.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER); spRecord.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER);
EscherClientDataRecord cldata = new EscherClientDataRecord(); EscherClientDataRecord cldata = new EscherClientDataRecord();
cldata.setOptions((short)15); cldata.setOptions((short)15);
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID); EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
//Placeholders can't be grouped //Placeholders can't be grouped
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144); setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144);
@ -86,7 +86,7 @@ public class Placeholder extends TextBox {
cldata.setRemainingData(out.toByteArray()); cldata.setRemainingData(out.toByteArray());
//append placeholder container before EscherTextboxRecord //append placeholder container before EscherTextboxRecord
List lst = spcont.getChildRecords(); List lst = _escherContainer.getChildRecords();
for (int i = 0; i < lst.size(); i++) { for (int i = 0; i < lst.size(); i++) {
EscherRecord rec = (EscherRecord)lst.get(i); EscherRecord rec = (EscherRecord)lst.get(i);
if(rec.getRecordId() == EscherTextboxRecord.RECORD_ID){ if(rec.getRecordId() == EscherTextboxRecord.RECORD_ID){
@ -94,6 +94,6 @@ public class Placeholder extends TextBox {
} }
} }
return spcont; return _escherContainer;
} }
} }

View File

@ -39,12 +39,7 @@ public class ShapeFactory {
int type = spRecord.getOptions() >> 4; int type = spRecord.getOptions() >> 4;
switch (type){ switch (type){
case ShapeTypes.TextBox: case ShapeTypes.TextBox:
case ShapeTypes.Rectangle: shape = new TextBox(spContainer, parent);
EscherTextboxRecord txtbox = (EscherTextboxRecord)Shape.getEscherChild(spContainer, EscherTextboxRecord.RECORD_ID);
if (txtbox == null)
shape = new AutoShape(spContainer, parent);
else
shape = new TextBox(spContainer, parent);
break; break;
case ShapeTypes.PictureFrame: case ShapeTypes.PictureFrame:
shape = new Picture(spContainer, parent); shape = new Picture(spContainer, parent);
@ -54,9 +49,13 @@ public class ShapeFactory {
break; break;
case ShapeTypes.NotPrimitive: case ShapeTypes.NotPrimitive:
if ((spRecord.getFlags() & EscherSpRecord.FLAG_GROUP) != 0) if ((spRecord.getFlags() & EscherSpRecord.FLAG_GROUP) != 0)
shape = new ShapeGroup(spContainer, parent); //TODO: check if the shape group is a Table
else shape = new ShapeGroup(spContainer, parent);
else {
//TODO: check if the shape has GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO properties.
//if it does, then return Freeform or Polygon
shape = new AutoShape(spContainer, parent); shape = new AutoShape(spContainer, parent);
}
break; break;
default: default:
shape = new AutoShape(spContainer, parent); shape = new AutoShape(spContainer, parent);

View File

@ -19,6 +19,7 @@ package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*; import org.apache.poi.ddf.*;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.hslf.record.EscherTextboxWrapper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -154,9 +155,10 @@ public class ShapeGroup extends Shape{
shape.setSheet(sheet); shape.setSheet(sheet);
shape.afterInsert(sheet); shape.afterInsert(sheet);
if(shape instanceof TextBox) { if (shape instanceof TextShape) {
TextBox tbox = (TextBox)shape; TextShape tbox = (TextShape) shape;
getSheet().getPPDrawing().addTextboxWrapper(tbox._txtbox); EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper();
if(txWrapper != null) getSheet().getPPDrawing().addTextboxWrapper(txWrapper);
} }
} }

View File

@ -257,11 +257,12 @@ public abstract class Sheet {
shape.setSheet(this); shape.setSheet(this);
shape.afterInsert(this); shape.afterInsert(this);
// If it's a TextBox, we need to tell the PPDrawing, as it has to // If it's a TextShape, we need to tell the PPDrawing, as it has to
// track TextboxWrappers specially // track TextboxWrappers specially
if (shape instanceof TextBox) { if (shape instanceof TextShape) {
TextBox tbox = (TextBox) shape; TextShape tbox = (TextShape) shape;
ppdrawing.addTextboxWrapper(tbox._txtbox); EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper();
if(txWrapper != null) ppdrawing.addTextboxWrapper(txWrapper);
} }
} }

View File

@ -48,19 +48,19 @@ public class SimpleShape extends Shape {
* @return the record container which holds this shape * @return the record container which holds this shape
*/ */
protected EscherContainerRecord createSpContainer(boolean isChild) { protected EscherContainerRecord createSpContainer(boolean isChild) {
EscherContainerRecord spContainer = new EscherContainerRecord(); _escherContainer = new EscherContainerRecord();
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER ); _escherContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
spContainer.setOptions((short)15); _escherContainer.setOptions((short)15);
EscherSpRecord sp = new EscherSpRecord(); EscherSpRecord sp = new EscherSpRecord();
int flags = EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE; int flags = EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE;
if (isChild) flags |= EscherSpRecord.FLAG_CHILD; if (isChild) flags |= EscherSpRecord.FLAG_CHILD;
sp.setFlags(flags); sp.setFlags(flags);
spContainer.addChildRecord(sp); _escherContainer.addChildRecord(sp);
EscherOptRecord opt = new EscherOptRecord(); EscherOptRecord opt = new EscherOptRecord();
opt.setRecordId(EscherOptRecord.RECORD_ID); opt.setRecordId(EscherOptRecord.RECORD_ID);
spContainer.addChildRecord(opt); _escherContainer.addChildRecord(opt);
EscherRecord anchor; EscherRecord anchor;
if(isChild) anchor = new EscherChildAnchorRecord(); if(isChild) anchor = new EscherChildAnchorRecord();
@ -75,9 +75,9 @@ public class SimpleShape extends Shape {
LittleEndian.putInt(header, 4, 8); LittleEndian.putInt(header, 4, 8);
anchor.fillFields(header, 0, null); anchor.fillFields(header, 0, null);
} }
spContainer.addChildRecord(anchor); _escherContainer.addChildRecord(anchor);
return spContainer; return _escherContainer;
} }
/** /**

View File

@ -63,15 +63,15 @@ public class TableCell extends TextBox {
} }
protected EscherContainerRecord createSpContainer(boolean isChild){ protected EscherContainerRecord createSpContainer(boolean isChild){
EscherContainerRecord spContainer = super.createSpContainer(isChild); _escherContainer = super.createSpContainer(isChild);
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spContainer, EscherOptRecord.RECORD_ID); EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0); setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);
setEscherProperty(opt, EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20000); setEscherProperty(opt, EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20000);
setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150001); setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150001);
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000); setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000);
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000); setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000);
return spContainer; return _escherContainer;
} }
protected void anchorBorder(int type, Line line){ protected void anchorBorder(int type, Line line){

View File

@ -38,55 +38,7 @@ import java.io.IOException;
* *
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
public class TextBox extends SimpleShape { public class TextBox extends TextShape {
/**
* How to anchor the text
*/
public static final int AnchorTop = 0;
public static final int AnchorMiddle = 1;
public static final int AnchorBottom = 2;
public static final int AnchorTopCentered = 3;
public static final int AnchorMiddleCentered = 4;
public static final int AnchorBottomCentered = 5;
public static final int AnchorTopBaseline = 6;
public static final int AnchorBottomBaseline = 7;
public static final int AnchorTopCenteredBaseline = 8;
public static final int AnchorBottomCenteredBaseline = 9;
/**
* How to wrap the text
*/
public static final int WrapSquare = 0;
public static final int WrapByPoints = 1;
public static final int WrapNone = 2;
public static final int WrapTopBottom = 3;
public static final int WrapThrough = 4;
/**
* How to align the text
*/
public static final int AlignLeft = 0;
public static final int AlignCenter = 1;
public static final int AlignRight = 2;
public static final int AlignJustify = 3;
/**
* Low-level object which holds actual text and format data
*/
protected TextRun _txtrun;
/**
* Escher container which holds text attributes such as
* TextHeaderAtom, TextBytesAtom ot TextCharsAtom, StyleTextPropAtom etc.
*/
protected EscherTextboxWrapper _txtbox;
/**
* Is the TextBox missing the text records which actually
* store the text?
*/
private boolean _missingTextRecords = false;
/** /**
* Create a TextBox object and initialize it from the supplied Record container. * Create a TextBox object and initialize it from the supplied Record container.
@ -97,8 +49,6 @@ public class TextBox extends SimpleShape {
protected TextBox(EscherContainerRecord escherRecord, Shape parent){ protected TextBox(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent); super(escherRecord, parent);
EscherTextboxRecord textbox = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);
_txtbox = new EscherTextboxWrapper(textbox);
} }
/** /**
@ -108,8 +58,7 @@ public class TextBox extends SimpleShape {
* in a table then the parent is Table. * in a table then the parent is Table.
*/ */
public TextBox(Shape parent){ public TextBox(Shape parent){
super(null, parent); super(parent);
_escherContainer = createSpContainer(parent instanceof ShapeGroup);
} }
/** /**
@ -121,376 +70,31 @@ public class TextBox extends SimpleShape {
} }
/** /**
* Create a new textBox and initialize internal structures * Create a new TextBox and initialize its internal structures
* *
* @return the created <code>EscherContainerRecord</code> which holds shape data * @return the created <code>EscherContainerRecord</code> which holds shape data
*/ */
protected EscherContainerRecord createSpContainer(boolean isChild){ protected EscherContainerRecord createSpContainer(boolean isChild){
EscherContainerRecord spcont = super.createSpContainer(isChild); _escherContainer = super.createSpContainer(isChild);
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID); setShapeType(ShapeTypes.TextBox);
short type = (ShapeTypes.TextBox << 4) | 0x2;
spRecord.setOptions(type);
//set default properties for a textbox //set default properties for a TextBox
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID); setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004);
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0); setEscherProperty(EscherProperties.FILL__FILLBACKCOLOR, 0x8000000);
setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x100000);
setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001);
setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80000);
setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, 0x8000004); _txtrun = createTextRun();
setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, 0x8000000);
setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x100000);
setEscherProperty(opt, EscherProperties.LINESTYLE__COLOR, 0x8000001);
setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80000);
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
//create EscherTextboxWrapper return _escherContainer;
_txtbox = new EscherTextboxWrapper();
TextHeaderAtom tha = new TextHeaderAtom();
tha.setParentRecord(_txtbox); // TextHeaderAtom is parent aware
_txtbox.appendChildRecord(tha);
TextCharsAtom tca = new TextCharsAtom();
_txtbox.appendChildRecord(tca);
StyleTextPropAtom sta = new StyleTextPropAtom(0);
_txtbox.appendChildRecord(sta);
_txtrun = new TextRun(tha,tca,sta);
_txtrun.setText("");
spcont.addChildRecord(_txtbox.getEscherRecord());
return spcont;
} }
/** protected void setDefaultTextProperties(TextRun _txtrun){
* Returns the text contained in this text frame. setVerticalAlignment(TextBox.AnchorTop);
* setEscherProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20002);
* @return the text string for this textbox.
*/
public String getText(){
return _txtrun == null ? null : _txtrun.getText();
} }
/**
* Sets the text contained in this text frame.
*
* @param text the text string used by this object.
*/
public void setText(String text){
_txtrun.setText(text);
}
/**
* When a textbox is added to a sheet we need to tell upper-level
* <code>PPDrawing</code> about it.
*
* @param sh the sheet we are adding to
*/
protected void afterInsert(Sheet sh){
PPDrawing ppdrawing = sh.getPPDrawing();
ppdrawing.addTextboxWrapper(_txtbox);
// Ensure the escher layer knows about the added records
try {
_txtbox.writeOut(null);
} catch (IOException e){
throw new HSLFException(e);
}
if(getAnchor().equals(new java.awt.Rectangle()) && !"".equals(getText())) resizeToFitText();
}
/**
* Adjust the size of the TextBox so it encompasses the text inside it.
*/
public void resizeToFitText(){
try{
FontRenderContext frc = new FontRenderContext(null, true, true);
RichTextRun rt = _txtrun.getRichTextRuns()[0];
int size = rt.getFontSize();
int style = 0;
if (rt.isBold()) style |= Font.BOLD;
if (rt.isItalic()) style |= Font.ITALIC;
String fntname = rt.getFontName();
Font font = new Font(fntname, style, size);
TextLayout layout = new TextLayout(getText(), font, frc);
int width = Math.round(layout.getAdvance());
int height = Math.round(layout.getAscent());
Dimension txsize = new Dimension(width, height);
java.awt.Rectangle anchor = getAnchor();
anchor.setSize(txsize);
setAnchor(anchor);
} catch (Exception e){
e.printStackTrace();
}
}
/**
* Returns the type of vertical alignment for the text.
* One of the <code>Anchor*</code> constants defined in this class.
*
* @return the type of alignment
*/
public int getVerticalAlignment(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
int valign;
if (prop == null){
int type = getTextRun().getRunType();
switch (type){
case TextHeaderAtom.TITLE_TYPE:
case TextHeaderAtom.CENTER_TITLE_TYPE:
valign = TextBox.AnchorMiddle;
break;
default:
valign = TextBox.AnchorTop;
break;
}
} else {
valign = prop.getPropertyValue();
}
return valign;
}
/**
* Sets the type of vertical alignment for the text.
* One of the <code>Anchor*</code> constants defined in this class.
*
* @param align - the type of alignment
*/
public void setVerticalAlignment(int align){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT, align);
}
public void setHorizontalAlignment(int align){
_txtrun.getRichTextRuns()[0].setAlignment(align);
}
public int getHorizontalAlignment(){
return _txtrun.getRichTextRuns()[0].getAlignment();
}
/**
* Returns the distance (in points) between the bottom of the text frame
* and the bottom of the inscribed rectangle of the shape that contains the text.
* Default value is 1/20 inch.
*
* @return the botom margin
*/
public int getMarginBottom(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
return val/EMU_PER_POINT;
}
/**
* Sets the botom margin.
* @see #getMarginBottom()
*
* @param margin the bottom margin
*/
public void setMarginBottom(int margin){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM, margin*EMU_PER_POINT);
}
/**
* Returns the distance (in EMUs) between the left edge of the text frame
* and the left edge of the inscribed rectangle of the shape that contains
* the text.
* Default value is 1/10 inch.
*
* @return the left margin
*/
public int getMarginLeft(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
return val/EMU_PER_POINT;
}
/**
* Sets the left margin.
* @see #getMarginLeft()
*
* @param margin the left margin
*/
public void setMarginLeft(int margin){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT, margin*EMU_PER_POINT);
}
/**
* Returns the distance (in EMUs) between the right edge of the
* text frame and the right edge of the inscribed rectangle of the shape
* that contains the text.
* Default value is 1/10 inch.
*
* @return the right margin
*/
public int getMarginRight(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
return val/EMU_PER_POINT;
}
/**
* Sets the right margin.
* @see #getMarginRight()
*
* @param margin the right margin
*/
public void setMarginRight(int margin){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT, margin*EMU_PER_POINT);
}
/**
* Returns the distance (in EMUs) between the top of the text frame
* and the top of the inscribed rectangle of the shape that contains the text.
* Default value is 1/20 inch.
*
* @return the top margin
*/
public int getMarginTop(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
return val/EMU_PER_POINT;
}
/**
* Sets the top margin.
* @see #getMarginTop()
*
* @param margin the top margin
*/
public void setMarginTop(int margin){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTTOP, margin*EMU_PER_POINT);
}
/**
* Returns the value indicating word wrap.
* One of the <code>Wrap*</code> constants defined in this class.
*
* @return the value indicating word wrap
*/
public int getWordWrap(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
return prop == null ? WrapSquare : prop.getPropertyValue();
}
/**
* Specifies how the text should be wrapped
*
* @param wrap the value indicating how the text should be wrapped
*/
public void setWordWrap(int wrap){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT, wrap);
}
/**
* @return id for the text.
*/
public int getTextId(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTID);
return prop == null ? 0 : prop.getPropertyValue();
}
/**
* Sets text ID
*
* @param id of the text
*/
public void setTextId(int id){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, id);
}
/**
* The color used to fill this shape.
*
* @param color the background color
*/
public void setBackgroundColor(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__FILLBACKCOLOR, rgb);
}
/**
* @return the TextRun object for this text box
*/
public TextRun getTextRun(){
return _txtrun;
}
public void setSheet(Sheet sheet){
_sheet = sheet;
// Initialize _txtrun object.
// (We can't do it in the constructor because the sheet
// is not assigned then, it's only built once we have
// all the records)
if(_txtrun == null) initTextRun();
if(_txtrun == null) {
// No text records found, skip
_missingTextRecords = true;
return;
} else {
_missingTextRecords = false;
}
// Supply the sheet to our child RichTextRuns
_txtrun.setSheet(sheet);
RichTextRun[] rt = _txtrun.getRichTextRuns();
for (int i = 0; i < rt.length; i++) {
rt[i].supplySlideShow(_sheet.getSlideShow());
}
}
private void initTextRun(){
OutlineTextRefAtom ota = null;
// Find the interesting child records
Record[] child = _txtbox.getChildRecords();
for (int i = 0; i < child.length; i++) {
if (child[i] instanceof OutlineTextRefAtom) {
ota = (OutlineTextRefAtom)child[i];
break;
}
}
Sheet sheet = getSheet();
TextRun[] runs = sheet.getTextRuns();
if (ota != null) {
int idx = ota.getTextIndex();
for (int i = 0; i < runs.length; i++) {
if(runs[i].getIndex() == idx){
_txtrun = runs[i];
}
}
if(_txtrun == null) {
logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
}
} else {
int shapeId = _escherContainer.getChildById(EscherSpRecord.RECORD_ID).getShapeId();
if(runs != null) for (int i = 0; i < runs.length; i++) {
if(runs[i].getShapeId() == shapeId){
_txtrun = runs[i];
break;
}
}
}
}
} }

View File

@ -0,0 +1,516 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.usermodel.RichTextRun;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.util.POILogger;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.io.IOException;
/**
* A common superclass of all shapes that can hold text.
*
* @author Yegor Kozlov
*/
public abstract class TextShape extends SimpleShape {
/**
* How to anchor the text
*/
public static final int AnchorTop = 0;
public static final int AnchorMiddle = 1;
public static final int AnchorBottom = 2;
public static final int AnchorTopCentered = 3;
public static final int AnchorMiddleCentered = 4;
public static final int AnchorBottomCentered = 5;
public static final int AnchorTopBaseline = 6;
public static final int AnchorBottomBaseline = 7;
public static final int AnchorTopCenteredBaseline = 8;
public static final int AnchorBottomCenteredBaseline = 9;
/**
* How to wrap the text
*/
public static final int WrapSquare = 0;
public static final int WrapByPoints = 1;
public static final int WrapNone = 2;
public static final int WrapTopBottom = 3;
public static final int WrapThrough = 4;
/**
* How to align the text
*/
public static final int AlignLeft = 0;
public static final int AlignCenter = 1;
public static final int AlignRight = 2;
public static final int AlignJustify = 3;
/**
* TextRun object which holds actual text and format data
*/
protected TextRun _txtrun;
/**
* Escher container which holds text attributes such as
* TextHeaderAtom, TextBytesAtom ot TextCharsAtom, StyleTextPropAtom etc.
*/
protected EscherTextboxWrapper _txtbox;
/**
* Used to calculate text bounds
*/
protected static final FontRenderContext _frc = new FontRenderContext(null, true, true);
/**
* Create a TextBox object and initialize it from the supplied Record container.
*
* @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
* @param parent the parent of the shape
*/
protected TextShape(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent);
}
/**
* Create a new TextBox. This constructor is used when a new shape is created.
*
* @param parent the parent of this Shape. For example, if this text box is a cell
* in a table then the parent is Table.
*/
public TextShape(Shape parent){
super(null, parent);
_escherContainer = createSpContainer(parent instanceof ShapeGroup);
}
/**
* Create a new TextBox. This constructor is used when a new shape is created.
*
*/
public TextShape(){
this(null);
}
public TextRun createTextRun(){
_txtbox = getEscherTextboxWrapper();
if(_txtbox == null) _txtbox = new EscherTextboxWrapper();
_txtrun = getTextRun();
if(_txtrun == null){
TextHeaderAtom tha = new TextHeaderAtom();
tha.setParentRecord(_txtbox);
_txtbox.appendChildRecord(tha);
TextCharsAtom tca = new TextCharsAtom();
_txtbox.appendChildRecord(tca);
StyleTextPropAtom sta = new StyleTextPropAtom(0);
_txtbox.appendChildRecord(sta);
_txtrun = new TextRun(tha,tca,sta);
_txtrun.setText("");
_escherContainer.addChildRecord(_txtbox.getEscherRecord());
setDefaultTextProperties(_txtrun);
}
return _txtrun;
}
/**
* Set default properties for the TextRun.
* Depending on the text and shape type the defaults are different:
* TextBox: align=left, valign=top
* AutoShape: align=center, valign=middle
*
*/
protected void setDefaultTextProperties(TextRun _txtrun){
}
/**
* Returns the text contained in this text frame.
*
* @return the text string for this textbox.
*/
public String getText(){
TextRun tx = getTextRun();
return tx == null ? null : tx.getText();
}
/**
* Sets the text contained in this text frame.
*
* @param text the text string used by this object.
*/
public void setText(String text){
TextRun tx = getTextRun();
if(tx == null){
tx = createTextRun();
}
tx.setText(text);
setTextId(text.hashCode());
}
/**
* When a textbox is added to a sheet we need to tell upper-level
* <code>PPDrawing</code> about it.
*
* @param sh the sheet we are adding to
*/
protected void afterInsert(Sheet sh){
EscherTextboxWrapper _txtbox = getEscherTextboxWrapper();
if(_txtbox != null){
PPDrawing ppdrawing = sh.getPPDrawing();
ppdrawing.addTextboxWrapper(_txtbox);
// Ensure the escher layer knows about the added records
try {
_txtbox.writeOut(null);
} catch (IOException e){
throw new HSLFException(e);
}
if(getAnchor().equals(new Rectangle()) && !"".equals(getText())) resizeToFitText();
}
}
protected EscherTextboxWrapper getEscherTextboxWrapper(){
if(_txtbox == null){
EscherTextboxRecord textRecord = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);
if(textRecord != null) _txtbox = new EscherTextboxWrapper(textRecord);
}
return _txtbox;
}
/**
* Adjust the size of the TextShape so it encompasses the text inside it.
*
* @return a <code>Rectangle2D</code> that is the bounds of this <code>TextShape</code>.
*/
public Rectangle2D resizeToFitText(){
String txt = getText();
if(txt == null || txt.length() == 0) return new Rectangle2D.Float();
RichTextRun rt = getTextRun().getRichTextRuns()[0];
int size = rt.getFontSize();
int style = 0;
if (rt.isBold()) style |= Font.BOLD;
if (rt.isItalic()) style |= Font.ITALIC;
String fntname = rt.getFontName();
Font font = new Font(fntname, style, size);
float width = 0, height = 0;
String[] lines = txt.split("\r");
for (int i = 0; i < lines.length; i++) {
if(lines[i].length() == 0) continue;
TextLayout layout = new TextLayout(lines[i], font, _frc);
width = Math.max(width, layout.getAdvance());
/**
* Even if top and bottom margins are set to 0 PowerPoint
* always sets extra space between the text and its bounding box.
*
* The approximation height = ascent*2 works good enough in most cases
*/
height = Math.max(height, 2*layout.getAscent());
}
width += getMarginLeft() + getMarginRight();
height += getMarginTop() + getMarginBottom();
Rectangle2D anchor = getAnchor2D();
anchor.setRect(anchor.getX(), anchor.getY(), width, height);
setAnchor(anchor);
return anchor;
}
/**
* Returns the type of vertical alignment for the text.
* One of the <code>Anchor*</code> constants defined in this class.
*
* @return the type of alignment
*/
public int getVerticalAlignment(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
int valign;
if (prop == null){
int type = getTextRun().getRunType();
switch (type){
case TextHeaderAtom.TITLE_TYPE:
case TextHeaderAtom.CENTER_TITLE_TYPE:
valign = TextShape.AnchorMiddle;
break;
default:
valign = TextShape.AnchorTop;
break;
}
} else {
valign = prop.getPropertyValue();
}
return valign;
}
/**
* Sets the type of vertical alignment for the text.
* One of the <code>Anchor*</code> constants defined in this class.
*
* @param align - the type of alignment
*/
public void setVerticalAlignment(int align){
setEscherProperty(EscherProperties.TEXT__ANCHORTEXT, align);
}
/**
* Sets the type of horizontal alignment for the text.
* One of the <code>Align*</code> constants defined in this class.
*
* @param align - the type of horizontal alignment
*/
public void setHorizontalAlignment(int align){
TextRun tx = getTextRun();
if(tx != null) tx.getRichTextRuns()[0].setAlignment(align);
}
/**
* Gets the type of horizontal alignment for the text.
* One of the <code>Align*</code> constants defined in this class.
*
* @return align - the type of horizontal alignment
*/
public int getHorizontalAlignment(){
TextRun tx = getTextRun();
return tx == null ? -1 : tx.getRichTextRuns()[0].getAlignment();
}
/**
* Returns the distance (in points) between the bottom of the text frame
* and the bottom of the inscribed rectangle of the shape that contains the text.
* Default value is 1/20 inch.
*
* @return the botom margin
*/
public float getMarginBottom(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
return (float)val/EMU_PER_POINT;
}
/**
* Sets the botom margin.
* @see #getMarginBottom()
*
* @param margin the bottom margin
*/
public void setMarginBottom(float margin){
setEscherProperty(EscherProperties.TEXT__TEXTBOTTOM, (int)(margin*EMU_PER_POINT));
}
/**
* Returns the distance (in points) between the left edge of the text frame
* and the left edge of the inscribed rectangle of the shape that contains
* the text.
* Default value is 1/10 inch.
*
* @return the left margin
*/
public float getMarginLeft(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
return (float)val/EMU_PER_POINT;
}
/**
* Sets the left margin.
* @see #getMarginLeft()
*
* @param margin the left margin
*/
public void setMarginLeft(float margin){
setEscherProperty(EscherProperties.TEXT__TEXTLEFT, (int)(margin*EMU_PER_POINT));
}
/**
* Returns the distance (in points) between the right edge of the
* text frame and the right edge of the inscribed rectangle of the shape
* that contains the text.
* Default value is 1/10 inch.
*
* @return the right margin
*/
public float getMarginRight(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
return (float)val/EMU_PER_POINT;
}
/**
* Sets the right margin.
* @see #getMarginRight()
*
* @param margin the right margin
*/
public void setMarginRight(float margin){
setEscherProperty(EscherProperties.TEXT__TEXTRIGHT, (int)(margin*EMU_PER_POINT));
}
/**
* Returns the distance (in points) between the top of the text frame
* and the top of the inscribed rectangle of the shape that contains the text.
* Default value is 1/20 inch.
*
* @return the top margin
*/
public float getMarginTop(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
return (float)val/EMU_PER_POINT;
}
/**
* Sets the top margin.
* @see #getMarginTop()
*
* @param margin the top margin
*/
public void setMarginTop(float margin){
setEscherProperty(EscherProperties.TEXT__TEXTTOP, (int)(margin*EMU_PER_POINT));
}
/**
* Returns the value indicating word wrap.
*
* @return the value indicating word wrap.
* Must be one of the <code>Wrap*</code> constants defined in this class.
*/
public int getWordWrap(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
return prop == null ? WrapSquare : prop.getPropertyValue();
}
/**
* Specifies how the text should be wrapped
*
* @param wrap the value indicating how the text should be wrapped.
* Must be one of the <code>Wrap*</code> constants defined in this class.
*/
public void setWordWrap(int wrap){
setEscherProperty(EscherProperties.TEXT__WRAPTEXT, wrap);
}
/**
* @return id for the text.
*/
public int getTextId(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTID);
return prop == null ? 0 : prop.getPropertyValue();
}
/**
* Sets text ID
*
* @param id of the text
*/
public void setTextId(int id){
setEscherProperty(EscherProperties.TEXT__TEXTID, id);
}
/**
* @return the TextRun object for this text box
*/
public TextRun getTextRun(){
if(_txtrun == null) initTextRun();
return _txtrun;
}
public void setSheet(Sheet sheet) {
_sheet = sheet;
// Initialize _txtrun object.
// (We can't do it in the constructor because the sheet
// is not assigned then, it's only built once we have
// all the records)
TextRun tx = getTextRun();
if (tx != null) {
// Supply the sheet to our child RichTextRuns
tx.setSheet(_sheet);
RichTextRun[] rt = tx.getRichTextRuns();
for (int i = 0; i < rt.length; i++) {
rt[i].supplySlideShow(_sheet.getSlideShow());
}
}
}
protected void initTextRun(){
EscherTextboxWrapper txtbox = getEscherTextboxWrapper();
Sheet sheet = getSheet();
if(sheet == null || txtbox == null) return;
OutlineTextRefAtom ota = null;
Record[] child = txtbox.getChildRecords();
for (int i = 0; i < child.length; i++) {
if (child[i] instanceof OutlineTextRefAtom) {
ota = (OutlineTextRefAtom)child[i];
break;
}
}
TextRun[] runs = _sheet.getTextRuns();
if (ota != null) {
int idx = ota.getTextIndex();
for (int i = 0; i < runs.length; i++) {
if(runs[i].getIndex() == idx){
_txtrun = runs[i];
break;
}
}
if(_txtrun == null) {
logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
}
} else {
int shapeId = _escherContainer.getChildById(EscherSpRecord.RECORD_ID).getShapeId();
if(runs != null) for (int i = 0; i < runs.length; i++) {
if(runs[i].getShapeId() == shapeId){
_txtrun = runs[i];
break;
}
}
}
}
}

View File

@ -218,8 +218,8 @@ public class TestShapes extends TestCase {
ArrayList lst2 = new ArrayList(); ArrayList lst2 = new ArrayList();
Shape[] sh = sl[k].getShapes(); Shape[] sh = sl[k].getShapes();
for (int i = 0; i < sh.length; i++) { for (int i = 0; i < sh.length; i++) {
if (sh[i] instanceof TextBox){ if (sh[i] instanceof TextShape){
TextBox tbox = (TextBox)sh[i]; TextShape tbox = (TextShape)sh[i];
lst2.add(tbox.getText()); lst2.add(tbox.getText());
} }
} }

View File

@ -0,0 +1,160 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import junit.framework.TestCase;
import java.io.*;
import java.util.ArrayList;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hslf.record.TextHeaderAtom;
/**
* Verify behavior of <code>TextShape</code> and its sub-classes
*
* @author Yegor Kozlov
*/
public class TestTextShape extends TestCase {
protected String cwd = System.getProperty("HSLF.testdata.path");
public void testCreateAutoShape(){
TextShape shape = new AutoShape(ShapeTypes.Trapezoid);
assertNull(shape.getTextRun());
assertNull(shape.getText());
assertNull(shape.getEscherTextboxWrapper());
TextRun run = shape.createTextRun();
assertNotNull(run);
assertNotNull(shape.getTextRun());
assertNotNull(shape.getEscherTextboxWrapper());
assertEquals("", shape.getText());
assertSame(run, shape.createTextRun());
}
public void testCreateTextBox(){
TextShape shape = new TextBox();
TextRun run = shape.getTextRun();
assertNotNull(run);
assertNotNull(shape.getText());
assertNotNull(shape.getEscherTextboxWrapper());
assertSame(run, shape.createTextRun());
assertNotNull(shape.getTextRun());
assertNotNull(shape.getEscherTextboxWrapper());
assertEquals("", shape.getText());
}
/**
* Verify we can get text from TextShape in the following cases:
* - placeholders
* - normal TextBox object
* - text in auto-shapes
*/
public void testRead() throws IOException {
FileInputStream is = new FileInputStream(new File(cwd, "text_shapes.ppt"));
SlideShow ppt = new SlideShow(is);
is.close();
ArrayList lst1 = new ArrayList();
Slide slide = ppt.getSlides()[0];
Shape[] shape = slide.getShapes();
for (int i = 0; i < shape.length; i++) {
assertTrue("Expected TextShape but found " + shape[i].getClass().getName(), shape[i] instanceof TextShape);
TextShape tx = (TextShape)shape[i];
TextRun run = tx.getTextRun();
assertNotNull(run);
int runType = run.getRunType();
int type = shape[i].getShapeType();
switch (type){
case ShapeTypes.TextBox:
assertEquals("Text in a TextBox", run.getText());
break;
case ShapeTypes.Rectangle:
if(runType == TextHeaderAtom.OTHER_TYPE)
assertEquals("Rectangle", run.getText());
else if(runType == TextHeaderAtom.TITLE_TYPE)
assertEquals("Title Placeholder", run.getText());
break;
case ShapeTypes.Octagon:
assertEquals("Octagon", run.getText());
break;
case ShapeTypes.Ellipse:
assertEquals("Ellipse", run.getText());
break;
case ShapeTypes.RoundRectangle:
assertEquals("RoundRectangle", run.getText());
break;
default:
fail("Unexpected shape: " + shape[i].getShapeName());
}
lst1.add(run.getText());
}
ArrayList lst2 = new ArrayList();
TextRun[] run = slide.getTextRuns();
for (int i = 0; i < run.length; i++) {
lst2.add(run[i].getText());
}
assertTrue(lst1.containsAll(lst2));
}
public void testReadWrite() throws IOException {
SlideShow ppt = new SlideShow();
Slide slide = ppt.createSlide();
TextShape shape1 = new TextBox();
TextRun run1 = shape1.createTextRun();
run1.setText("Hello, World!");
slide.addShape(shape1);
shape1.moveTo(100, 100);
TextShape shape2 = new AutoShape(ShapeTypes.Arrow);
TextRun run2 = shape2.createTextRun();
run2.setText("Testing TextShape");
slide.addShape(shape2);
shape2.moveTo(300, 300);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ppt.write(out);
out.close();
ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
slide = ppt.getSlides()[0];
Shape[] shape = slide.getShapes();
assertTrue(shape[0] instanceof TextShape);
shape1 = (TextShape)shape[0];
assertEquals(ShapeTypes.TextBox, shape1.getShapeType());
assertEquals("Hello, World!", shape1.getTextRun().getText());
assertTrue(shape[1] instanceof TextShape);
shape1 = (TextShape)shape[1];
assertEquals(ShapeTypes.Arrow, shape1.getShapeType());
assertEquals("Testing TextShape", shape1.getTextRun().getText());
}
}

View File

@ -316,8 +316,8 @@ public class TestBugs extends TestCase {
ArrayList lst = new ArrayList(); ArrayList lst = new ArrayList();
Shape[] shape = slide.getShapes(); Shape[] shape = slide.getShapes();
for (int i = 0; i < shape.length; i++) { for (int i = 0; i < shape.length; i++) {
if( shape[i] instanceof TextBox){ if( shape[i] instanceof TextShape){
TextRun textRun = ((TextBox)shape[i]).getTextRun(); TextRun textRun = ((TextShape)shape[i]).getTextRun();
if(textRun != null) lst.add(textRun); if(textRun != null) lst.add(textRun);
} }