TextBox box2 = new TextBox();\r
TextRun tr2 = box2.getTextRun();\r
tr2.setRunType(TextHeaderAtom.BODY_TYPE);\r
+ tr2.getRichTextRuns()[0].setFontSize(32);\r
tr2.setText(\r
"Support for more PowerPoint functionality\r" +\r
"Rendering slides into java.awt.Graphics2D");\r
TextBox box4 = new TextBox();\r
TextRun tr4 = box4.getTextRun();\r
tr4.setRunType(TextHeaderAtom.BODY_TYPE);\r
+ tr4.getRichTextRuns()[0].setFontSize(32);\r
tr4.setText(\r
"Integration with Apache FOP - Formatting Objects Processor");\r
box4.setAnchor(new Rectangle(36, 290, 648, 90));\r
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
*/
-public class AutoShape extends SimpleShape {
+public class AutoShape extends TextShape {
protected AutoShape(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent);
}
protected EscherContainerRecord createSpContainer(int shapeType, boolean isChild){
- EscherContainerRecord spcont = super.createSpContainer(isChild);
+ _escherContainer = super.createSpContainer(isChild);
- EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
- short type = (short)((shapeType << 4) | 0x2);
- spRecord.setOptions(type);
+ setShapeType(shapeType);
//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));
- 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 _escherContainer;
+ }
+
+ protected void setDefaultTextProperties(TextRun _txtrun){
+ setVerticalAlignment(TextBox.AnchorMiddle);
+ setHorizontalAlignment(TextBox.AlignCenter);
+ setWordWrap(TextBox.WrapNone);
+ }
- return spcont;
+ /**
+ * 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);
+ }
}
}
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;
spRecord.setOptions(type);
//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
setEscherProperty(opt, EscherProperties.GEOMETRY__SHAPEPATH, 4);
setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0xA0008);
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
- return spcont;
+ return _escherContainer;
}
}
* @return the create Picture object
*/
protected EscherContainerRecord createSpContainer(int idx, boolean isChild) {
- EscherContainerRecord spContainer = super.createSpContainer(isChild);
- spContainer.setOptions((short)15);
+ _escherContainer = super.createSpContainer(isChild);
+ _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));
//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);
//another weird feature of powerpoint: for picture id we must add 0x4000.
setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx);
- return spContainer;
+ return _escherContainer;
}
/**
* @return the created <code>EscherContainerRecord</code> which holds shape data
*/
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);
EscherClientDataRecord cldata = new EscherClientDataRecord();
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
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144);
cldata.setRemainingData(out.toByteArray());
//append placeholder container before EscherTextboxRecord
- List lst = spcont.getChildRecords();
+ List lst = _escherContainer.getChildRecords();
for (int i = 0; i < lst.size(); i++) {
EscherRecord rec = (EscherRecord)lst.get(i);
if(rec.getRecordId() == EscherTextboxRecord.RECORD_ID){
}
}
- return spcont;
+ return _escherContainer;
}
}
int type = spRecord.getOptions() >> 4;
switch (type){
case ShapeTypes.TextBox:
- case ShapeTypes.Rectangle:
- EscherTextboxRecord txtbox = (EscherTextboxRecord)Shape.getEscherChild(spContainer, EscherTextboxRecord.RECORD_ID);
- if (txtbox == null)
- shape = new AutoShape(spContainer, parent);
- else
- shape = new TextBox(spContainer, parent);
+ shape = new TextBox(spContainer, parent);
break;
case ShapeTypes.PictureFrame:
shape = new Picture(spContainer, parent);
break;
case ShapeTypes.NotPrimitive:
if ((spRecord.getFlags() & EscherSpRecord.FLAG_GROUP) != 0)
- shape = new ShapeGroup(spContainer, parent);
- else
+ //TODO: check if the shape group is a Table
+ 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);
+ }
break;
default:
shape = new AutoShape(spContainer, parent);
import org.apache.poi.ddf.*;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
+import org.apache.poi.hslf.record.EscherTextboxWrapper;
import java.util.ArrayList;
import java.util.List;
shape.setSheet(sheet);
shape.afterInsert(sheet);
- if(shape instanceof TextBox) {
- TextBox tbox = (TextBox)shape;
- getSheet().getPPDrawing().addTextboxWrapper(tbox._txtbox);
+ if (shape instanceof TextShape) {
+ TextShape tbox = (TextShape) shape;
+ EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper();
+ if(txWrapper != null) getSheet().getPPDrawing().addTextboxWrapper(txWrapper);
}
}
shape.setSheet(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
- if (shape instanceof TextBox) {
- TextBox tbox = (TextBox) shape;
- ppdrawing.addTextboxWrapper(tbox._txtbox);
+ if (shape instanceof TextShape) {
+ TextShape tbox = (TextShape) shape;
+ EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper();
+ if(txWrapper != null) ppdrawing.addTextboxWrapper(txWrapper);
}
}
* @return the record container which holds this shape
*/
protected EscherContainerRecord createSpContainer(boolean isChild) {
- EscherContainerRecord spContainer = new EscherContainerRecord();
- spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
- spContainer.setOptions((short)15);
+ _escherContainer = new EscherContainerRecord();
+ _escherContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
+ _escherContainer.setOptions((short)15);
EscherSpRecord sp = new EscherSpRecord();
int flags = EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE;
if (isChild) flags |= EscherSpRecord.FLAG_CHILD;
sp.setFlags(flags);
- spContainer.addChildRecord(sp);
+ _escherContainer.addChildRecord(sp);
EscherOptRecord opt = new EscherOptRecord();
opt.setRecordId(EscherOptRecord.RECORD_ID);
- spContainer.addChildRecord(opt);
+ _escherContainer.addChildRecord(opt);
EscherRecord anchor;
if(isChild) anchor = new EscherChildAnchorRecord();
LittleEndian.putInt(header, 4, 8);
anchor.fillFields(header, 0, null);
}
- spContainer.addChildRecord(anchor);
+ _escherContainer.addChildRecord(anchor);
- return spContainer;
+ return _escherContainer;
}
/**
}\r
\r
protected EscherContainerRecord createSpContainer(boolean isChild){\r
- EscherContainerRecord spContainer = super.createSpContainer(isChild);\r
- EscherOptRecord opt = (EscherOptRecord)getEscherChild(spContainer, EscherOptRecord.RECORD_ID);\r
+ _escherContainer = super.createSpContainer(isChild);\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);\r
setEscherProperty(opt, EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20000);\r
setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150001);\r
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000);\r
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000);\r
\r
- return spContainer;\r
+ return _escherContainer;\r
}\r
\r
protected void anchorBorder(int type, Line line){\r
*
* @author Yegor Kozlov
*/
-public class TextBox 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;
-
- /**
- * 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;
+public class TextBox extends TextShape {
/**
* Create a TextBox object and initialize it from the supplied Record container.
protected TextBox(EscherContainerRecord escherRecord, Shape parent){
super(escherRecord, parent);
- EscherTextboxRecord textbox = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);
- _txtbox = new EscherTextboxWrapper(textbox);
}
/**
* in a table then the parent is Table.
*/
public TextBox(Shape parent){
- super(null, parent);
- _escherContainer = createSpContainer(parent instanceof ShapeGroup);
+ super(parent);
}
/**
}
/**
- * 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
*/
protected EscherContainerRecord createSpContainer(boolean isChild){
- EscherContainerRecord spcont = super.createSpContainer(isChild);
-
- EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
- short type = (ShapeTypes.TextBox << 4) | 0x2;
- spRecord.setOptions(type);
-
- //set default properties for a textbox
- EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
- setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);
-
- setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, 0x8000004);
- 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
- _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;
- }
-
- /**
- * Returns the text contained in this text frame.
- *
- * @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;
- }
+ _escherContainer = super.createSpContainer(isChild);
- /**
- * 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);
- }
+ setShapeType(ShapeTypes.TextBox);
- /**
- * 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;
- }
+ //set default properties for a TextBox
+ setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004);
+ 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);
- /**
- * 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);
- }
+ _txtrun = createTextRun();
- /**
- * 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;
+ return _escherContainer;
}
- /**
- * 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);
+ protected void setDefaultTextProperties(TextRun _txtrun){
+ setVerticalAlignment(TextBox.AnchorTop);
+ setEscherProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20002);
}
-
- /**
- * 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;
- }
- }
- }
-
- }
}
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. 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.*;\r
+import org.apache.poi.hslf.usermodel.RichTextRun;\r
+import org.apache.poi.hslf.exceptions.HSLFException;\r
+import org.apache.poi.util.POILogger;\r
+\r
+import java.awt.*;\r
+import java.awt.geom.Rectangle2D;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.font.FontRenderContext;\r
+import java.awt.font.TextLayout;\r
+import java.io.IOException;\r
+\r
+/**\r
+ * A common superclass of all shapes that can hold text.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public abstract class TextShape extends SimpleShape {\r
+\r
+ /**\r
+ * How to anchor the text\r
+ */\r
+ public static final int AnchorTop = 0;\r
+ public static final int AnchorMiddle = 1;\r
+ public static final int AnchorBottom = 2;\r
+ public static final int AnchorTopCentered = 3;\r
+ public static final int AnchorMiddleCentered = 4;\r
+ public static final int AnchorBottomCentered = 5;\r
+ public static final int AnchorTopBaseline = 6;\r
+ public static final int AnchorBottomBaseline = 7;\r
+ public static final int AnchorTopCenteredBaseline = 8;\r
+ public static final int AnchorBottomCenteredBaseline = 9;\r
+\r
+ /**\r
+ * How to wrap the text\r
+ */\r
+ public static final int WrapSquare = 0;\r
+ public static final int WrapByPoints = 1;\r
+ public static final int WrapNone = 2;\r
+ public static final int WrapTopBottom = 3;\r
+ public static final int WrapThrough = 4;\r
+\r
+ /**\r
+ * How to align the text\r
+ */\r
+ public static final int AlignLeft = 0;\r
+ public static final int AlignCenter = 1;\r
+ public static final int AlignRight = 2;\r
+ public static final int AlignJustify = 3;\r
+\r
+ /**\r
+ * TextRun object which holds actual text and format data\r
+ */\r
+ protected TextRun _txtrun;\r
+\r
+ /**\r
+ * Escher container which holds text attributes such as\r
+ * TextHeaderAtom, TextBytesAtom ot TextCharsAtom, StyleTextPropAtom etc.\r
+ */\r
+ protected EscherTextboxWrapper _txtbox;\r
+\r
+ /**\r
+ * Used to calculate text bounds\r
+ */\r
+ protected static final FontRenderContext _frc = new FontRenderContext(null, true, true);\r
+\r
+ /**\r
+ * Create a TextBox object and initialize it from the supplied Record container.\r
+ * \r
+ * @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape\r
+ * @param parent the parent of the shape\r
+ */\r
+ protected TextShape(EscherContainerRecord escherRecord, Shape parent){\r
+ super(escherRecord, parent);\r
+\r
+ }\r
+\r
+ /**\r
+ * Create a new TextBox. This constructor is used when a new shape is created.\r
+ *\r
+ * @param parent the parent of this Shape. For example, if this text box is a cell\r
+ * in a table then the parent is Table.\r
+ */\r
+ public TextShape(Shape parent){\r
+ super(null, parent);\r
+ _escherContainer = createSpContainer(parent instanceof ShapeGroup);\r
+ }\r
+\r
+ /**\r
+ * Create a new TextBox. This constructor is used when a new shape is created.\r
+ *\r
+ */\r
+ public TextShape(){\r
+ this(null);\r
+ }\r
+\r
+ public TextRun createTextRun(){\r
+ _txtbox = getEscherTextboxWrapper();\r
+ if(_txtbox == null) _txtbox = new EscherTextboxWrapper();\r
+\r
+ _txtrun = getTextRun();\r
+ if(_txtrun == null){\r
+ TextHeaderAtom tha = new TextHeaderAtom();\r
+ tha.setParentRecord(_txtbox);\r
+ _txtbox.appendChildRecord(tha);\r
+\r
+ TextCharsAtom tca = new TextCharsAtom();\r
+ _txtbox.appendChildRecord(tca);\r
+\r
+ StyleTextPropAtom sta = new StyleTextPropAtom(0);\r
+ _txtbox.appendChildRecord(sta);\r
+\r
+ _txtrun = new TextRun(tha,tca,sta);\r
+ _txtrun.setText("");\r
+\r
+ _escherContainer.addChildRecord(_txtbox.getEscherRecord());\r
+\r
+ setDefaultTextProperties(_txtrun);\r
+ }\r
+\r
+ return _txtrun;\r
+ }\r
+\r
+ /**\r
+ * Set default properties for the TextRun.\r
+ * Depending on the text and shape type the defaults are different:\r
+ * TextBox: align=left, valign=top\r
+ * AutoShape: align=center, valign=middle\r
+ *\r
+ */\r
+ protected void setDefaultTextProperties(TextRun _txtrun){\r
+\r
+ }\r
+\r
+ /**\r
+ * Returns the text contained in this text frame.\r
+ *\r
+ * @return the text string for this textbox.\r
+ */\r
+ public String getText(){\r
+ TextRun tx = getTextRun();\r
+ return tx == null ? null : tx.getText();\r
+ }\r
+\r
+ /**\r
+ * Sets the text contained in this text frame.\r
+ *\r
+ * @param text the text string used by this object.\r
+ */\r
+ public void setText(String text){\r
+ TextRun tx = getTextRun();\r
+ if(tx == null){\r
+ tx = createTextRun();\r
+ }\r
+ tx.setText(text);\r
+ setTextId(text.hashCode());\r
+ }\r
+\r
+ /**\r
+ * When a textbox is added to a sheet we need to tell upper-level\r
+ * <code>PPDrawing</code> about it.\r
+ *\r
+ * @param sh the sheet we are adding to\r
+ */\r
+ protected void afterInsert(Sheet sh){\r
+ EscherTextboxWrapper _txtbox = getEscherTextboxWrapper();\r
+ if(_txtbox != null){\r
+ PPDrawing ppdrawing = sh.getPPDrawing();\r
+ ppdrawing.addTextboxWrapper(_txtbox);\r
+ // Ensure the escher layer knows about the added records\r
+ try {\r
+ _txtbox.writeOut(null);\r
+ } catch (IOException e){\r
+ throw new HSLFException(e);\r
+ }\r
+ if(getAnchor().equals(new Rectangle()) && !"".equals(getText())) resizeToFitText();\r
+ }\r
+ }\r
+\r
+ protected EscherTextboxWrapper getEscherTextboxWrapper(){\r
+ if(_txtbox == null){\r
+ EscherTextboxRecord textRecord = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);\r
+ if(textRecord != null) _txtbox = new EscherTextboxWrapper(textRecord);\r
+ }\r
+ return _txtbox;\r
+ }\r
+ /**\r
+ * Adjust the size of the TextShape so it encompasses the text inside it.\r
+ *\r
+ * @return a <code>Rectangle2D</code> that is the bounds of this <code>TextShape</code>.\r
+ */\r
+ public Rectangle2D resizeToFitText(){\r
+ String txt = getText();\r
+ if(txt == null || txt.length() == 0) return new Rectangle2D.Float();\r
+\r
+ RichTextRun rt = getTextRun().getRichTextRuns()[0];\r
+ int size = rt.getFontSize();\r
+ int style = 0;\r
+ if (rt.isBold()) style |= Font.BOLD;\r
+ if (rt.isItalic()) style |= Font.ITALIC;\r
+ String fntname = rt.getFontName();\r
+ Font font = new Font(fntname, style, size);\r
+\r
+ float width = 0, height = 0;\r
+ String[] lines = txt.split("\r");\r
+ for (int i = 0; i < lines.length; i++) {\r
+ if(lines[i].length() == 0) continue;\r
+\r
+ TextLayout layout = new TextLayout(lines[i], font, _frc);\r
+\r
+ width = Math.max(width, layout.getAdvance());\r
+\r
+ /**\r
+ * Even if top and bottom margins are set to 0 PowerPoint\r
+ * always sets extra space between the text and its bounding box.\r
+ *\r
+ * The approximation height = ascent*2 works good enough in most cases\r
+ */\r
+ height = Math.max(height, 2*layout.getAscent());\r
+ }\r
+\r
+ width += getMarginLeft() + getMarginRight();\r
+ height += getMarginTop() + getMarginBottom();\r
+\r
+ Rectangle2D anchor = getAnchor2D();\r
+ anchor.setRect(anchor.getX(), anchor.getY(), width, height);\r
+ setAnchor(anchor);\r
+\r
+ return anchor;\r
+ }\r
+\r
+ /**\r
+ * Returns the type of vertical alignment for the text.\r
+ * One of the <code>Anchor*</code> constants defined in this class.\r
+ *\r
+ * @return the type of alignment\r
+ */\r
+ public int getVerticalAlignment(){\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);\r
+ int valign;\r
+ if (prop == null){\r
+ int type = getTextRun().getRunType();\r
+ switch (type){\r
+ case TextHeaderAtom.TITLE_TYPE:\r
+ case TextHeaderAtom.CENTER_TITLE_TYPE:\r
+ valign = TextShape.AnchorMiddle;\r
+ break;\r
+ default:\r
+ valign = TextShape.AnchorTop;\r
+ break;\r
+ }\r
+ } else {\r
+ valign = prop.getPropertyValue();\r
+ }\r
+ return valign;\r
+ }\r
+\r
+ /**\r
+ * Sets the type of vertical alignment for the text.\r
+ * One of the <code>Anchor*</code> constants defined in this class.\r
+ *\r
+ * @param align - the type of alignment\r
+ */\r
+ public void setVerticalAlignment(int align){\r
+ setEscherProperty(EscherProperties.TEXT__ANCHORTEXT, align);\r
+ }\r
+\r
+ /**\r
+ * Sets the type of horizontal alignment for the text.\r
+ * One of the <code>Align*</code> constants defined in this class.\r
+ *\r
+ * @param align - the type of horizontal alignment\r
+ */\r
+ public void setHorizontalAlignment(int align){\r
+ TextRun tx = getTextRun();\r
+ if(tx != null) tx.getRichTextRuns()[0].setAlignment(align);\r
+ }\r
+\r
+ /**\r
+ * Gets the type of horizontal alignment for the text.\r
+ * One of the <code>Align*</code> constants defined in this class.\r
+ *\r
+ * @return align - the type of horizontal alignment\r
+ */\r
+ public int getHorizontalAlignment(){\r
+ TextRun tx = getTextRun();\r
+ return tx == null ? -1 : tx.getRichTextRuns()[0].getAlignment();\r
+ }\r
+\r
+ /**\r
+ * Returns the distance (in points) between the bottom of the text frame\r
+ * and the bottom of the inscribed rectangle of the shape that contains the text.\r
+ * Default value is 1/20 inch.\r
+ *\r
+ * @return the botom margin\r
+ */\r
+ public float getMarginBottom(){\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);\r
+ int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();\r
+ return (float)val/EMU_PER_POINT;\r
+ }\r
+\r
+ /**\r
+ * Sets the botom margin.\r
+ * @see #getMarginBottom()\r
+ *\r
+ * @param margin the bottom margin\r
+ */\r
+ public void setMarginBottom(float margin){\r
+ setEscherProperty(EscherProperties.TEXT__TEXTBOTTOM, (int)(margin*EMU_PER_POINT));\r
+ }\r
+\r
+ /**\r
+ * Returns the distance (in points) between the left edge of the text frame\r
+ * and the left edge of the inscribed rectangle of the shape that contains\r
+ * the text.\r
+ * Default value is 1/10 inch.\r
+ *\r
+ * @return the left margin\r
+ */\r
+ public float getMarginLeft(){\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);\r
+ int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();\r
+ return (float)val/EMU_PER_POINT;\r
+ }\r
+\r
+ /**\r
+ * Sets the left margin.\r
+ * @see #getMarginLeft()\r
+ *\r
+ * @param margin the left margin\r
+ */\r
+ public void setMarginLeft(float margin){\r
+ setEscherProperty(EscherProperties.TEXT__TEXTLEFT, (int)(margin*EMU_PER_POINT));\r
+ }\r
+\r
+ /**\r
+ * Returns the distance (in points) between the right edge of the\r
+ * text frame and the right edge of the inscribed rectangle of the shape\r
+ * that contains the text.\r
+ * Default value is 1/10 inch.\r
+ *\r
+ * @return the right margin\r
+ */\r
+ public float getMarginRight(){\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);\r
+ int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();\r
+ return (float)val/EMU_PER_POINT;\r
+ }\r
+\r
+ /**\r
+ * Sets the right margin.\r
+ * @see #getMarginRight()\r
+ *\r
+ * @param margin the right margin\r
+ */\r
+ public void setMarginRight(float margin){\r
+ setEscherProperty(EscherProperties.TEXT__TEXTRIGHT, (int)(margin*EMU_PER_POINT));\r
+ }\r
+\r
+ /**\r
+ * Returns the distance (in points) between the top of the text frame\r
+ * and the top of the inscribed rectangle of the shape that contains the text.\r
+ * Default value is 1/20 inch.\r
+ *\r
+ * @return the top margin\r
+ */\r
+ public float getMarginTop(){\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);\r
+ int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();\r
+ return (float)val/EMU_PER_POINT;\r
+ }\r
+\r
+ /**\r
+ * Sets the top margin.\r
+ * @see #getMarginTop()\r
+ *\r
+ * @param margin the top margin\r
+ */\r
+ public void setMarginTop(float margin){\r
+ setEscherProperty(EscherProperties.TEXT__TEXTTOP, (int)(margin*EMU_PER_POINT));\r
+ }\r
+\r
+\r
+ /**\r
+ * Returns the value indicating word wrap.\r
+ *\r
+ * @return the value indicating word wrap.\r
+ * Must be one of the <code>Wrap*</code> constants defined in this class.\r
+ */\r
+ public int getWordWrap(){\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);\r
+ return prop == null ? WrapSquare : prop.getPropertyValue();\r
+ }\r
+\r
+ /**\r
+ * Specifies how the text should be wrapped\r
+ *\r
+ * @param wrap the value indicating how the text should be wrapped.\r
+ * Must be one of the <code>Wrap*</code> constants defined in this class.\r
+ */\r
+ public void setWordWrap(int wrap){\r
+ setEscherProperty(EscherProperties.TEXT__WRAPTEXT, wrap);\r
+ }\r
+\r
+ /**\r
+ * @return id for the text.\r
+ */\r
+ public int getTextId(){\r
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);\r
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTID);\r
+ return prop == null ? 0 : prop.getPropertyValue();\r
+ }\r
+\r
+ /**\r
+ * Sets text ID\r
+ *\r
+ * @param id of the text\r
+ */\r
+ public void setTextId(int id){\r
+ setEscherProperty(EscherProperties.TEXT__TEXTID, id);\r
+ }\r
+\r
+ /**\r
+ * @return the TextRun object for this text box\r
+ */\r
+ public TextRun getTextRun(){\r
+ if(_txtrun == null) initTextRun();\r
+ return _txtrun;\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\r
+ // is not assigned then, it's only built once we have\r
+ // all the records)\r
+ TextRun tx = getTextRun();\r
+ if (tx != null) {\r
+ // Supply the sheet to our child RichTextRuns\r
+ tx.setSheet(_sheet);\r
+ RichTextRun[] rt = tx.getRichTextRuns();\r
+ for (int i = 0; i < rt.length; i++) {\r
+ rt[i].supplySlideShow(_sheet.getSlideShow());\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ protected void initTextRun(){\r
+ EscherTextboxWrapper txtbox = getEscherTextboxWrapper();\r
+ Sheet sheet = getSheet();\r
+\r
+ if(sheet == null || txtbox == null) return;\r
+\r
+ OutlineTextRefAtom ota = null;\r
+\r
+ Record[] child = txtbox.getChildRecords();\r
+ for (int i = 0; i < child.length; i++) {\r
+ if (child[i] instanceof OutlineTextRefAtom) {\r
+ ota = (OutlineTextRefAtom)child[i];\r
+ break;\r
+ }\r
+ }\r
+\r
+ TextRun[] runs = _sheet.getTextRuns();\r
+ if (ota != null) {\r
+ int idx = ota.getTextIndex();\r
+ for (int i = 0; i < runs.length; i++) {\r
+ if(runs[i].getIndex() == idx){\r
+ _txtrun = runs[i];\r
+ break;\r
+ }\r
+ }\r
+ if(_txtrun == null) {\r
+ logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);\r
+ }\r
+ } else {\r
+ int shapeId = _escherContainer.getChildById(EscherSpRecord.RECORD_ID).getShapeId();\r
+ if(runs != null) for (int i = 0; i < runs.length; i++) {\r
+ if(runs[i].getShapeId() == shapeId){\r
+ _txtrun = runs[i];\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
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];
+ if (sh[i] instanceof TextShape){
+ TextShape tbox = (TextShape)sh[i];
lst2.add(tbox.getText());
}
}
--- /dev/null
+\r
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. 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.model;\r
+\r
+import junit.framework.TestCase;\r
+\r
+import java.io.*;\r
+import java.util.ArrayList;\r
+\r
+import org.apache.poi.hslf.usermodel.SlideShow;\r
+import org.apache.poi.hslf.record.TextHeaderAtom;\r
+\r
+/**\r
+ * Verify behavior of <code>TextShape</code> and its sub-classes\r
+ * \r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestTextShape extends TestCase {\r
+ protected String cwd = System.getProperty("HSLF.testdata.path");\r
+\r
+ public void testCreateAutoShape(){\r
+ TextShape shape = new AutoShape(ShapeTypes.Trapezoid);\r
+ assertNull(shape.getTextRun());\r
+ assertNull(shape.getText());\r
+ assertNull(shape.getEscherTextboxWrapper());\r
+\r
+ TextRun run = shape.createTextRun();\r
+ assertNotNull(run);\r
+ assertNotNull(shape.getTextRun());\r
+ assertNotNull(shape.getEscherTextboxWrapper());\r
+ assertEquals("", shape.getText());\r
+ assertSame(run, shape.createTextRun());\r
+\r
+ }\r
+\r
+ public void testCreateTextBox(){\r
+ TextShape shape = new TextBox();\r
+ TextRun run = shape.getTextRun();\r
+ assertNotNull(run);\r
+ assertNotNull(shape.getText());\r
+ assertNotNull(shape.getEscherTextboxWrapper());\r
+\r
+ assertSame(run, shape.createTextRun());\r
+ assertNotNull(shape.getTextRun());\r
+ assertNotNull(shape.getEscherTextboxWrapper());\r
+ assertEquals("", shape.getText());\r
+\r
+ }\r
+\r
+ /**\r
+ * Verify we can get text from TextShape in the following cases:\r
+ * - placeholders\r
+ * - normal TextBox object\r
+ * - text in auto-shapes\r
+ */\r
+ public void testRead() throws IOException {\r
+ FileInputStream is = new FileInputStream(new File(cwd, "text_shapes.ppt"));\r
+ SlideShow ppt = new SlideShow(is);\r
+ is.close();\r
+\r
+ ArrayList lst1 = new ArrayList();\r
+ Slide slide = ppt.getSlides()[0];\r
+ Shape[] shape = slide.getShapes();\r
+ for (int i = 0; i < shape.length; i++) {\r
+ assertTrue("Expected TextShape but found " + shape[i].getClass().getName(), shape[i] instanceof TextShape);\r
+ TextShape tx = (TextShape)shape[i];\r
+ TextRun run = tx.getTextRun();\r
+ assertNotNull(run);\r
+ int runType = run.getRunType();\r
+\r
+ int type = shape[i].getShapeType();\r
+ switch (type){\r
+ case ShapeTypes.TextBox:\r
+ assertEquals("Text in a TextBox", run.getText());\r
+ break;\r
+ case ShapeTypes.Rectangle:\r
+ if(runType == TextHeaderAtom.OTHER_TYPE)\r
+ assertEquals("Rectangle", run.getText());\r
+ else if(runType == TextHeaderAtom.TITLE_TYPE)\r
+ assertEquals("Title Placeholder", run.getText());\r
+ break;\r
+ case ShapeTypes.Octagon:\r
+ assertEquals("Octagon", run.getText());\r
+ break;\r
+ case ShapeTypes.Ellipse:\r
+ assertEquals("Ellipse", run.getText());\r
+ break;\r
+ case ShapeTypes.RoundRectangle:\r
+ assertEquals("RoundRectangle", run.getText());\r
+ break;\r
+ default:\r
+ fail("Unexpected shape: " + shape[i].getShapeName());\r
+\r
+ }\r
+ lst1.add(run.getText());\r
+ }\r
+\r
+ ArrayList lst2 = new ArrayList();\r
+ TextRun[] run = slide.getTextRuns();\r
+ for (int i = 0; i < run.length; i++) {\r
+ lst2.add(run[i].getText());\r
+ }\r
+\r
+ assertTrue(lst1.containsAll(lst2));\r
+ }\r
+\r
+ public void testReadWrite() throws IOException {\r
+ SlideShow ppt = new SlideShow();\r
+ Slide slide = ppt.createSlide();\r
+\r
+ TextShape shape1 = new TextBox();\r
+ TextRun run1 = shape1.createTextRun();\r
+ run1.setText("Hello, World!");\r
+ slide.addShape(shape1);\r
+\r
+ shape1.moveTo(100, 100);\r
+\r
+ TextShape shape2 = new AutoShape(ShapeTypes.Arrow);\r
+ TextRun run2 = shape2.createTextRun();\r
+ run2.setText("Testing TextShape");\r
+ slide.addShape(shape2);\r
+ shape2.moveTo(300, 300);\r
+\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ ppt.write(out);\r
+ out.close();\r
+\r
+ ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));\r
+ slide = ppt.getSlides()[0];\r
+ Shape[] shape = slide.getShapes();\r
+\r
+ assertTrue(shape[0] instanceof TextShape);\r
+ shape1 = (TextShape)shape[0];\r
+ assertEquals(ShapeTypes.TextBox, shape1.getShapeType());\r
+ assertEquals("Hello, World!", shape1.getTextRun().getText());\r
+\r
+ assertTrue(shape[1] instanceof TextShape);\r
+ shape1 = (TextShape)shape[1];\r
+ assertEquals(ShapeTypes.Arrow, shape1.getShapeType());\r
+ assertEquals("Testing TextShape", shape1.getTextRun().getText());\r
+ }\r
+\r
+}\r
ArrayList lst = new ArrayList();\r
Shape[] shape = slide.getShapes();\r
for (int i = 0; i < shape.length; i++) {\r
- if( shape[i] instanceof TextBox){\r
- TextRun textRun = ((TextBox)shape[i]).getTextRun();\r
+ if( shape[i] instanceof TextShape){\r
+ TextRun textRun = ((TextShape)shape[i]).getTextRun();\r
if(textRun != null) lst.add(textRun);\r
}\r
\r