diff options
author | Yegor Kozlov <yegor@apache.org> | 2008-04-15 07:54:20 +0000 |
---|---|---|
committer | Yegor Kozlov <yegor@apache.org> | 2008-04-15 07:54:20 +0000 |
commit | 95326239ee0beb11103da684d18bb184d9a6b61c (patch) | |
tree | 18d6b0be32c0db1cba0231af6562575c1aefe4e4 /src | |
parent | f98e88e70661dbf57e6217196253e5495f622feb (diff) | |
download | poi-95326239ee0beb11103da684d18bb184d9a6b61c.tar.gz poi-95326239ee0beb11103da684d18bb184d9a6b61c.zip |
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
Diffstat (limited to 'src')
16 files changed, 797 insertions, 470 deletions
diff --git a/src/scratchpad/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java index 0f28c2a8c9..962349876a 100755 --- a/src/scratchpad/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java +++ b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java @@ -459,6 +459,7 @@ public class ApacheconEU08 { TextBox box2 = new TextBox();
TextRun tr2 = box2.getTextRun();
tr2.setRunType(TextHeaderAtom.BODY_TYPE);
+ tr2.getRichTextRuns()[0].setFontSize(32);
tr2.setText(
"Support for more PowerPoint functionality\r" +
"Rendering slides into java.awt.Graphics2D");
@@ -477,6 +478,7 @@ public class ApacheconEU08 { TextBox box4 = new TextBox();
TextRun tr4 = box4.getTextRun();
tr4.setRunType(TextHeaderAtom.BODY_TYPE);
+ tr4.getRichTextRuns()[0].setFontSize(32);
tr4.setText(
"Integration with Apache FOP - Formatting Objects Processor");
box4.setAnchor(new Rectangle(36, 290, 648, 90));
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/AutoShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/AutoShape.java index b3ddce37da..cf65a9b13c 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/AutoShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/AutoShape.java @@ -20,11 +20,15 @@ package org.apache.poi.hslf.model; 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); @@ -40,23 +44,62 @@ public class AutoShape extends SimpleShape { } 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); + } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Line.java b/src/scratchpad/src/org/apache/poi/hslf/model/Line.java index 0d3f616e92..9237183689 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Line.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Line.java @@ -106,14 +106,14 @@ public class Line extends SimpleShape { } 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); @@ -123,7 +123,7 @@ public class Line extends SimpleShape { setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0xA0008); setEscherProperty(opt, EscherProperties.SHADOWSTYLE__COLOR, 0x8000002); - return spcont; + return _escherContainer; } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java b/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java index 90efd5f3ee..910d5c8503 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java @@ -120,20 +120,20 @@ public class Picture extends SimpleShape { * @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; } /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java b/src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java index dd0132ebe0..f0bc74558f 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java @@ -49,15 +49,15 @@ public class Placeholder extends TextBox { * @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); @@ -86,7 +86,7 @@ public class Placeholder extends TextBox { 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){ @@ -94,6 +94,6 @@ public class Placeholder extends TextBox { } } - return spcont; + return _escherContainer; } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java index 66c95e50cf..0c36bf053a 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java @@ -39,12 +39,7 @@ public class ShapeFactory { 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); @@ -54,9 +49,13 @@ public class ShapeFactory { 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); diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java index dbcc8069c2..b22ed8d70b 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java @@ -19,6 +19,7 @@ package org.apache.poi.hslf.model; 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; @@ -154,9 +155,10 @@ public class ShapeGroup extends Shape{ 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); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java b/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java index 135b625f1d..abf2fec589 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java @@ -257,11 +257,12 @@ public abstract class Sheet { 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); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java index 85d672fe89..0831d453b5 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java @@ -48,19 +48,19 @@ public class SimpleShape extends Shape { * @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(); @@ -75,9 +75,9 @@ public class SimpleShape extends Shape { LittleEndian.putInt(header, 4, 8); anchor.fillFields(header, 0, null); } - spContainer.addChildRecord(anchor); + _escherContainer.addChildRecord(anchor); - return spContainer; + return _escherContainer; } /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java b/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java index bb93e06b71..36789ad91a 100755 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java @@ -63,15 +63,15 @@ public class TableCell extends TextBox { }
protected EscherContainerRecord createSpContainer(boolean isChild){
- EscherContainerRecord spContainer = super.createSpContainer(isChild);
- EscherOptRecord opt = (EscherOptRecord)getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
+ _escherContainer = super.createSpContainer(isChild);
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);
setEscherProperty(opt, EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20000);
setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150001);
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000);
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000);
- return spContainer;
+ return _escherContainer;
}
protected void anchorBorder(int type, Line line){
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java index 1f9a489a78..a1d45ffbae 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java @@ -38,55 +38,7 @@ import java.io.IOException; * * @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. @@ -97,8 +49,6 @@ public class TextBox extends SimpleShape { protected TextBox(EscherContainerRecord escherRecord, Shape 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. */ public TextBox(Shape parent){ - super(null, parent); - _escherContainer = createSpContainer(parent instanceof ShapeGroup); + super(parent); } /** @@ -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 */ 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; - } - } - } - - } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java new file mode 100755 index 0000000000..3c45b34b0b --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java @@ -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;
+ }
+ }
+ }
+ }
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/text_shapes.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/text_shapes.ppt Binary files differnew file mode 100755 index 0000000000..c36183ac35 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hslf/data/text_shapes.ppt diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java index 1fe8f7e5e6..c2e081ee5c 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java @@ -218,8 +218,8 @@ public class TestShapes extends TestCase { 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()); } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextShape.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextShape.java new file mode 100755 index 0000000000..25a8db9187 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextShape.java @@ -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());
+ }
+
+}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java index 36e45501ec..19e7af6417 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java @@ -316,8 +316,8 @@ public class TestBugs extends TestCase { ArrayList lst = new ArrayList();
Shape[] shape = slide.getShapes();
for (int i = 0; i < shape.length; i++) {
- if( shape[i] instanceof TextBox){
- TextRun textRun = ((TextBox)shape[i]).getTextRun();
+ if( shape[i] instanceof TextShape){
+ TextRun textRun = ((TextShape)shape[i]).getTextRun();
if(textRun != null) lst.add(textRun);
}
|