TextShape is a common superclass of all shapes that can hold text. The subclasses are TextBox and AutoShape.
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@648156 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
82bb0bc7ef
commit
149e87cda0
@ -459,6 +459,7 @@ public class ApacheconEU08 {
|
|||||||
TextBox box2 = new TextBox();
|
TextBox box2 = new TextBox();
|
||||||
TextRun tr2 = box2.getTextRun();
|
TextRun tr2 = box2.getTextRun();
|
||||||
tr2.setRunType(TextHeaderAtom.BODY_TYPE);
|
tr2.setRunType(TextHeaderAtom.BODY_TYPE);
|
||||||
|
tr2.getRichTextRuns()[0].setFontSize(32);
|
||||||
tr2.setText(
|
tr2.setText(
|
||||||
"Support for more PowerPoint functionality\r" +
|
"Support for more PowerPoint functionality\r" +
|
||||||
"Rendering slides into java.awt.Graphics2D");
|
"Rendering slides into java.awt.Graphics2D");
|
||||||
@ -477,6 +478,7 @@ public class ApacheconEU08 {
|
|||||||
TextBox box4 = new TextBox();
|
TextBox box4 = new TextBox();
|
||||||
TextRun tr4 = box4.getTextRun();
|
TextRun tr4 = box4.getTextRun();
|
||||||
tr4.setRunType(TextHeaderAtom.BODY_TYPE);
|
tr4.setRunType(TextHeaderAtom.BODY_TYPE);
|
||||||
|
tr4.getRichTextRuns()[0].setFontSize(32);
|
||||||
tr4.setText(
|
tr4.setText(
|
||||||
"Integration with Apache FOP - Formatting Objects Processor");
|
"Integration with Apache FOP - Formatting Objects Processor");
|
||||||
box4.setAnchor(new Rectangle(36, 290, 648, 90));
|
box4.setAnchor(new Rectangle(36, 290, 648, 90));
|
||||||
|
@ -20,11 +20,15 @@ package org.apache.poi.hslf.model;
|
|||||||
import org.apache.poi.ddf.*;
|
import org.apache.poi.ddf.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a autoshape in a PowerPoint drawing
|
* Represents an AutoShape.
|
||||||
|
* <p>
|
||||||
|
* AutoShapes are drawing objects with a particular shape that may be customized through smart resizing and adjustments.
|
||||||
|
* See {@link ShapeTypes}
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Yegor Kozlov
|
* @author Yegor Kozlov
|
||||||
*/
|
*/
|
||||||
public class AutoShape extends SimpleShape {
|
public class AutoShape extends TextShape {
|
||||||
|
|
||||||
protected AutoShape(EscherContainerRecord escherRecord, Shape parent){
|
protected AutoShape(EscherContainerRecord escherRecord, Shape parent){
|
||||||
super(escherRecord, parent);
|
super(escherRecord, parent);
|
||||||
@ -40,23 +44,62 @@ public class AutoShape extends SimpleShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected EscherContainerRecord createSpContainer(int shapeType, boolean isChild){
|
protected EscherContainerRecord createSpContainer(int shapeType, boolean isChild){
|
||||||
EscherContainerRecord spcont = super.createSpContainer(isChild);
|
_escherContainer = super.createSpContainer(isChild);
|
||||||
|
|
||||||
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
|
setShapeType(shapeType);
|
||||||
short type = (short)((shapeType << 4) | 0x2);
|
|
||||||
spRecord.setOptions(type);
|
|
||||||
|
|
||||||
//set default properties for an autoshape
|
//set default properties for an autoshape
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
|
setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000);
|
||||||
|
setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004);
|
||||||
|
setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004);
|
||||||
|
setEscherProperty(EscherProperties.FILL__FILLBACKCOLOR, 0x8000000);
|
||||||
|
setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x100010);
|
||||||
|
setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001);
|
||||||
|
setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80008);
|
||||||
|
setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
|
||||||
|
|
||||||
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004));
|
return _escherContainer;
|
||||||
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__FILLBACKCOLOR, 0x8000000));
|
|
||||||
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.FILL__NOFILLHITTEST, 0x100010));
|
|
||||||
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001));
|
|
||||||
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80008));
|
|
||||||
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002));
|
|
||||||
|
|
||||||
return spcont;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setDefaultTextProperties(TextRun _txtrun){
|
||||||
|
setVerticalAlignment(TextBox.AnchorMiddle);
|
||||||
|
setHorizontalAlignment(TextBox.AlignCenter);
|
||||||
|
setWordWrap(TextBox.WrapNone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets adjust value which controls smart resizing of the auto-shape.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The adjustment values are given in shape coordinates:
|
||||||
|
* the origin is at the top-left, positive-x is to the right, positive-y is down.
|
||||||
|
* The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idx the adjust index in the [0, 9] range
|
||||||
|
* @return the adjustment value
|
||||||
|
*/
|
||||||
|
public int getAdjustmentValue(int idx){
|
||||||
|
if(idx < 0 || idx > 9) throw new IllegalArgumentException("The index of an adjustment value must be in the [0, 9] range");
|
||||||
|
|
||||||
|
return getEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets adjust value which controls smart resizing of the auto-shape.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The adjustment values are given in shape coordinates:
|
||||||
|
* the origin is at the top-left, positive-x is to the right, positive-y is down.
|
||||||
|
* The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param idx the adjust index in the [0, 9] range
|
||||||
|
* @param val the adjustment value
|
||||||
|
*/
|
||||||
|
public void setAdjustmentValue(int idx, int val){
|
||||||
|
if(idx < 0 || idx > 9) throw new IllegalArgumentException("The index of an adjustment value must be in the [0, 9] range");
|
||||||
|
|
||||||
|
setEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx), val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,14 +106,14 @@ public class Line extends SimpleShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected EscherContainerRecord createSpContainer(boolean isChild){
|
protected EscherContainerRecord createSpContainer(boolean isChild){
|
||||||
EscherContainerRecord spcont = super.createSpContainer(isChild);
|
_escherContainer = super.createSpContainer(isChild);
|
||||||
|
|
||||||
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
|
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||||||
short type = (ShapeTypes.Line << 4) | 0x2;
|
short type = (ShapeTypes.Line << 4) | 0x2;
|
||||||
spRecord.setOptions(type);
|
spRecord.setOptions(type);
|
||||||
|
|
||||||
//set default properties for a line
|
//set default properties for a line
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
|
|
||||||
//default line properties
|
//default line properties
|
||||||
setEscherProperty(opt, EscherProperties.GEOMETRY__SHAPEPATH, 4);
|
setEscherProperty(opt, EscherProperties.GEOMETRY__SHAPEPATH, 4);
|
||||||
@ -123,7 +123,7 @@ public class Line extends SimpleShape {
|
|||||||
setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0xA0008);
|
setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0xA0008);
|
||||||
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
|
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
|
||||||
|
|
||||||
return spcont;
|
return _escherContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -120,20 +120,20 @@ public class Picture extends SimpleShape {
|
|||||||
* @return the create Picture object
|
* @return the create Picture object
|
||||||
*/
|
*/
|
||||||
protected EscherContainerRecord createSpContainer(int idx, boolean isChild) {
|
protected EscherContainerRecord createSpContainer(int idx, boolean isChild) {
|
||||||
EscherContainerRecord spContainer = super.createSpContainer(isChild);
|
_escherContainer = super.createSpContainer(isChild);
|
||||||
spContainer.setOptions((short)15);
|
_escherContainer.setOptions((short)15);
|
||||||
|
|
||||||
EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID);
|
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||||||
spRecord.setOptions((short)((ShapeTypes.PictureFrame << 4) | 0x2));
|
spRecord.setOptions((short)((ShapeTypes.PictureFrame << 4) | 0x2));
|
||||||
|
|
||||||
//set default properties for a picture
|
//set default properties for a picture
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 8388736);
|
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 8388736);
|
||||||
|
|
||||||
//another weird feature of powerpoint: for picture id we must add 0x4000.
|
//another weird feature of powerpoint: for picture id we must add 0x4000.
|
||||||
setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx);
|
setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx);
|
||||||
|
|
||||||
return spContainer;
|
return _escherContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,15 +49,15 @@ public class Placeholder extends TextBox {
|
|||||||
* @return the created <code>EscherContainerRecord</code> which holds shape data
|
* @return the created <code>EscherContainerRecord</code> which holds shape data
|
||||||
*/
|
*/
|
||||||
protected EscherContainerRecord createSpContainer(boolean isChild){
|
protected EscherContainerRecord createSpContainer(boolean isChild){
|
||||||
EscherContainerRecord spcont = super.createSpContainer(isChild);
|
_escherContainer = super.createSpContainer(isChild);
|
||||||
|
|
||||||
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
|
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||||||
spRecord.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER);
|
spRecord.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER);
|
||||||
|
|
||||||
EscherClientDataRecord cldata = new EscherClientDataRecord();
|
EscherClientDataRecord cldata = new EscherClientDataRecord();
|
||||||
cldata.setOptions((short)15);
|
cldata.setOptions((short)15);
|
||||||
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
|
|
||||||
//Placeholders can't be grouped
|
//Placeholders can't be grouped
|
||||||
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144);
|
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144);
|
||||||
@ -86,7 +86,7 @@ public class Placeholder extends TextBox {
|
|||||||
cldata.setRemainingData(out.toByteArray());
|
cldata.setRemainingData(out.toByteArray());
|
||||||
|
|
||||||
//append placeholder container before EscherTextboxRecord
|
//append placeholder container before EscherTextboxRecord
|
||||||
List lst = spcont.getChildRecords();
|
List lst = _escherContainer.getChildRecords();
|
||||||
for (int i = 0; i < lst.size(); i++) {
|
for (int i = 0; i < lst.size(); i++) {
|
||||||
EscherRecord rec = (EscherRecord)lst.get(i);
|
EscherRecord rec = (EscherRecord)lst.get(i);
|
||||||
if(rec.getRecordId() == EscherTextboxRecord.RECORD_ID){
|
if(rec.getRecordId() == EscherTextboxRecord.RECORD_ID){
|
||||||
@ -94,6 +94,6 @@ public class Placeholder extends TextBox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return spcont;
|
return _escherContainer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,6 @@ public class ShapeFactory {
|
|||||||
int type = spRecord.getOptions() >> 4;
|
int type = spRecord.getOptions() >> 4;
|
||||||
switch (type){
|
switch (type){
|
||||||
case ShapeTypes.TextBox:
|
case ShapeTypes.TextBox:
|
||||||
case ShapeTypes.Rectangle:
|
|
||||||
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;
|
break;
|
||||||
case ShapeTypes.PictureFrame:
|
case ShapeTypes.PictureFrame:
|
||||||
@ -54,9 +49,13 @@ public class ShapeFactory {
|
|||||||
break;
|
break;
|
||||||
case ShapeTypes.NotPrimitive:
|
case ShapeTypes.NotPrimitive:
|
||||||
if ((spRecord.getFlags() & EscherSpRecord.FLAG_GROUP) != 0)
|
if ((spRecord.getFlags() & EscherSpRecord.FLAG_GROUP) != 0)
|
||||||
|
//TODO: check if the shape group is a Table
|
||||||
shape = new ShapeGroup(spContainer, parent);
|
shape = new ShapeGroup(spContainer, parent);
|
||||||
else
|
else {
|
||||||
|
//TODO: check if the shape has GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO properties.
|
||||||
|
//if it does, then return Freeform or Polygon
|
||||||
shape = new AutoShape(spContainer, parent);
|
shape = new AutoShape(spContainer, parent);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
shape = new AutoShape(spContainer, parent);
|
shape = new AutoShape(spContainer, parent);
|
||||||
|
@ -19,6 +19,7 @@ package org.apache.poi.hslf.model;
|
|||||||
import org.apache.poi.ddf.*;
|
import org.apache.poi.ddf.*;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
|
import org.apache.poi.hslf.record.EscherTextboxWrapper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -154,9 +155,10 @@ public class ShapeGroup extends Shape{
|
|||||||
shape.setSheet(sheet);
|
shape.setSheet(sheet);
|
||||||
shape.afterInsert(sheet);
|
shape.afterInsert(sheet);
|
||||||
|
|
||||||
if(shape instanceof TextBox) {
|
if (shape instanceof TextShape) {
|
||||||
TextBox tbox = (TextBox)shape;
|
TextShape tbox = (TextShape) shape;
|
||||||
getSheet().getPPDrawing().addTextboxWrapper(tbox._txtbox);
|
EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper();
|
||||||
|
if(txWrapper != null) getSheet().getPPDrawing().addTextboxWrapper(txWrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,11 +257,12 @@ public abstract class Sheet {
|
|||||||
shape.setSheet(this);
|
shape.setSheet(this);
|
||||||
shape.afterInsert(this);
|
shape.afterInsert(this);
|
||||||
|
|
||||||
// If it's a TextBox, we need to tell the PPDrawing, as it has to
|
// If it's a TextShape, we need to tell the PPDrawing, as it has to
|
||||||
// track TextboxWrappers specially
|
// track TextboxWrappers specially
|
||||||
if (shape instanceof TextBox) {
|
if (shape instanceof TextShape) {
|
||||||
TextBox tbox = (TextBox) shape;
|
TextShape tbox = (TextShape) shape;
|
||||||
ppdrawing.addTextboxWrapper(tbox._txtbox);
|
EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper();
|
||||||
|
if(txWrapper != null) ppdrawing.addTextboxWrapper(txWrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,19 +48,19 @@ public class SimpleShape extends Shape {
|
|||||||
* @return the record container which holds this shape
|
* @return the record container which holds this shape
|
||||||
*/
|
*/
|
||||||
protected EscherContainerRecord createSpContainer(boolean isChild) {
|
protected EscherContainerRecord createSpContainer(boolean isChild) {
|
||||||
EscherContainerRecord spContainer = new EscherContainerRecord();
|
_escherContainer = new EscherContainerRecord();
|
||||||
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
_escherContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||||
spContainer.setOptions((short)15);
|
_escherContainer.setOptions((short)15);
|
||||||
|
|
||||||
EscherSpRecord sp = new EscherSpRecord();
|
EscherSpRecord sp = new EscherSpRecord();
|
||||||
int flags = EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE;
|
int flags = EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE;
|
||||||
if (isChild) flags |= EscherSpRecord.FLAG_CHILD;
|
if (isChild) flags |= EscherSpRecord.FLAG_CHILD;
|
||||||
sp.setFlags(flags);
|
sp.setFlags(flags);
|
||||||
spContainer.addChildRecord(sp);
|
_escherContainer.addChildRecord(sp);
|
||||||
|
|
||||||
EscherOptRecord opt = new EscherOptRecord();
|
EscherOptRecord opt = new EscherOptRecord();
|
||||||
opt.setRecordId(EscherOptRecord.RECORD_ID);
|
opt.setRecordId(EscherOptRecord.RECORD_ID);
|
||||||
spContainer.addChildRecord(opt);
|
_escherContainer.addChildRecord(opt);
|
||||||
|
|
||||||
EscherRecord anchor;
|
EscherRecord anchor;
|
||||||
if(isChild) anchor = new EscherChildAnchorRecord();
|
if(isChild) anchor = new EscherChildAnchorRecord();
|
||||||
@ -75,9 +75,9 @@ public class SimpleShape extends Shape {
|
|||||||
LittleEndian.putInt(header, 4, 8);
|
LittleEndian.putInt(header, 4, 8);
|
||||||
anchor.fillFields(header, 0, null);
|
anchor.fillFields(header, 0, null);
|
||||||
}
|
}
|
||||||
spContainer.addChildRecord(anchor);
|
_escherContainer.addChildRecord(anchor);
|
||||||
|
|
||||||
return spContainer;
|
return _escherContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,15 +63,15 @@ public class TableCell extends TextBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected EscherContainerRecord createSpContainer(boolean isChild){
|
protected EscherContainerRecord createSpContainer(boolean isChild){
|
||||||
EscherContainerRecord spContainer = super.createSpContainer(isChild);
|
_escherContainer = super.createSpContainer(isChild);
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);
|
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);
|
||||||
setEscherProperty(opt, EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20000);
|
setEscherProperty(opt, EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20000);
|
||||||
setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150001);
|
setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150001);
|
||||||
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000);
|
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000);
|
||||||
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000);
|
setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000);
|
||||||
|
|
||||||
return spContainer;
|
return _escherContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void anchorBorder(int type, Line line){
|
protected void anchorBorder(int type, Line line){
|
||||||
|
@ -38,55 +38,7 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @author Yegor Kozlov
|
* @author Yegor Kozlov
|
||||||
*/
|
*/
|
||||||
public class TextBox extends SimpleShape {
|
public class TextBox extends TextShape {
|
||||||
|
|
||||||
/**
|
|
||||||
* How to anchor the text
|
|
||||||
*/
|
|
||||||
public static final int AnchorTop = 0;
|
|
||||||
public static final int AnchorMiddle = 1;
|
|
||||||
public static final int AnchorBottom = 2;
|
|
||||||
public static final int AnchorTopCentered = 3;
|
|
||||||
public static final int AnchorMiddleCentered = 4;
|
|
||||||
public static final int AnchorBottomCentered = 5;
|
|
||||||
public static final int AnchorTopBaseline = 6;
|
|
||||||
public static final int AnchorBottomBaseline = 7;
|
|
||||||
public static final int AnchorTopCenteredBaseline = 8;
|
|
||||||
public static final int AnchorBottomCenteredBaseline = 9;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How to wrap the text
|
|
||||||
*/
|
|
||||||
public static final int WrapSquare = 0;
|
|
||||||
public static final int WrapByPoints = 1;
|
|
||||||
public static final int WrapNone = 2;
|
|
||||||
public static final int WrapTopBottom = 3;
|
|
||||||
public static final int WrapThrough = 4;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How to align the text
|
|
||||||
*/
|
|
||||||
public static final int AlignLeft = 0;
|
|
||||||
public static final int AlignCenter = 1;
|
|
||||||
public static final int AlignRight = 2;
|
|
||||||
public static final int AlignJustify = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Low-level object which holds actual text and format data
|
|
||||||
*/
|
|
||||||
protected TextRun _txtrun;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Escher container which holds text attributes such as
|
|
||||||
* TextHeaderAtom, TextBytesAtom ot TextCharsAtom, StyleTextPropAtom etc.
|
|
||||||
*/
|
|
||||||
protected EscherTextboxWrapper _txtbox;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the TextBox missing the text records which actually
|
|
||||||
* store the text?
|
|
||||||
*/
|
|
||||||
private boolean _missingTextRecords = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a TextBox object and initialize it from the supplied Record container.
|
* Create a TextBox object and initialize it from the supplied Record container.
|
||||||
@ -97,8 +49,6 @@ public class TextBox extends SimpleShape {
|
|||||||
protected TextBox(EscherContainerRecord escherRecord, Shape parent){
|
protected TextBox(EscherContainerRecord escherRecord, Shape parent){
|
||||||
super(escherRecord, parent);
|
super(escherRecord, parent);
|
||||||
|
|
||||||
EscherTextboxRecord textbox = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);
|
|
||||||
_txtbox = new EscherTextboxWrapper(textbox);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,8 +58,7 @@ public class TextBox extends SimpleShape {
|
|||||||
* in a table then the parent is Table.
|
* in a table then the parent is Table.
|
||||||
*/
|
*/
|
||||||
public TextBox(Shape parent){
|
public TextBox(Shape parent){
|
||||||
super(null, parent);
|
super(parent);
|
||||||
_escherContainer = createSpContainer(parent instanceof ShapeGroup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,376 +70,31 @@ public class TextBox extends SimpleShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new textBox and initialize internal structures
|
* Create a new TextBox and initialize its internal structures
|
||||||
*
|
*
|
||||||
* @return the created <code>EscherContainerRecord</code> which holds shape data
|
* @return the created <code>EscherContainerRecord</code> which holds shape data
|
||||||
*/
|
*/
|
||||||
protected EscherContainerRecord createSpContainer(boolean isChild){
|
protected EscherContainerRecord createSpContainer(boolean isChild){
|
||||||
EscherContainerRecord spcont = super.createSpContainer(isChild);
|
_escherContainer = super.createSpContainer(isChild);
|
||||||
|
|
||||||
EscherSpRecord spRecord = spcont.getChildById(EscherSpRecord.RECORD_ID);
|
setShapeType(ShapeTypes.TextBox);
|
||||||
short type = (ShapeTypes.TextBox << 4) | 0x2;
|
|
||||||
spRecord.setOptions(type);
|
|
||||||
|
|
||||||
//set default properties for a textbox
|
//set default properties for a TextBox
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(spcont, EscherOptRecord.RECORD_ID);
|
setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004);
|
||||||
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);
|
setEscherProperty(EscherProperties.FILL__FILLBACKCOLOR, 0x8000000);
|
||||||
|
setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x100000);
|
||||||
|
setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001);
|
||||||
|
setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80000);
|
||||||
|
setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
|
||||||
|
|
||||||
setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, 0x8000004);
|
_txtrun = createTextRun();
|
||||||
setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, 0x8000000);
|
|
||||||
setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x100000);
|
|
||||||
setEscherProperty(opt, EscherProperties.LINESTYLE__COLOR, 0x8000001);
|
|
||||||
setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80000);
|
|
||||||
setEscherProperty(opt, EscherProperties.SHADOWSTYLE__COLOR, 0x8000002);
|
|
||||||
|
|
||||||
//create EscherTextboxWrapper
|
return _escherContainer;
|
||||||
_txtbox = new EscherTextboxWrapper();
|
|
||||||
|
|
||||||
TextHeaderAtom tha = new TextHeaderAtom();
|
|
||||||
tha.setParentRecord(_txtbox); // TextHeaderAtom is parent aware
|
|
||||||
_txtbox.appendChildRecord(tha);
|
|
||||||
|
|
||||||
TextCharsAtom tca = new TextCharsAtom();
|
|
||||||
_txtbox.appendChildRecord(tca);
|
|
||||||
|
|
||||||
StyleTextPropAtom sta = new StyleTextPropAtom(0);
|
|
||||||
_txtbox.appendChildRecord(sta);
|
|
||||||
|
|
||||||
_txtrun = new TextRun(tha,tca,sta);
|
|
||||||
_txtrun.setText("");
|
|
||||||
spcont.addChildRecord(_txtbox.getEscherRecord());
|
|
||||||
|
|
||||||
return spcont;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected void setDefaultTextProperties(TextRun _txtrun){
|
||||||
* Returns the text contained in this text frame.
|
setVerticalAlignment(TextBox.AnchorTop);
|
||||||
*
|
setEscherProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20002);
|
||||||
* @return the text string for this textbox.
|
|
||||||
*/
|
|
||||||
public String getText(){
|
|
||||||
return _txtrun == null ? null : _txtrun.getText();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the text contained in this text frame.
|
|
||||||
*
|
|
||||||
* @param text the text string used by this object.
|
|
||||||
*/
|
|
||||||
public void setText(String text){
|
|
||||||
_txtrun.setText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a textbox is added to a sheet we need to tell upper-level
|
|
||||||
* <code>PPDrawing</code> about it.
|
|
||||||
*
|
|
||||||
* @param sh the sheet we are adding to
|
|
||||||
*/
|
|
||||||
protected void afterInsert(Sheet sh){
|
|
||||||
PPDrawing ppdrawing = sh.getPPDrawing();
|
|
||||||
ppdrawing.addTextboxWrapper(_txtbox);
|
|
||||||
// Ensure the escher layer knows about the added records
|
|
||||||
try {
|
|
||||||
_txtbox.writeOut(null);
|
|
||||||
} catch (IOException e){
|
|
||||||
throw new HSLFException(e);
|
|
||||||
}
|
|
||||||
if(getAnchor().equals(new java.awt.Rectangle()) && !"".equals(getText())) resizeToFitText();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjust the size of the TextBox so it encompasses the text inside it.
|
|
||||||
*/
|
|
||||||
public void resizeToFitText(){
|
|
||||||
try{
|
|
||||||
FontRenderContext frc = new FontRenderContext(null, true, true);
|
|
||||||
RichTextRun rt = _txtrun.getRichTextRuns()[0];
|
|
||||||
int size = rt.getFontSize();
|
|
||||||
int style = 0;
|
|
||||||
if (rt.isBold()) style |= Font.BOLD;
|
|
||||||
if (rt.isItalic()) style |= Font.ITALIC;
|
|
||||||
String fntname = rt.getFontName();
|
|
||||||
Font font = new Font(fntname, style, size);
|
|
||||||
|
|
||||||
TextLayout layout = new TextLayout(getText(), font, frc);
|
|
||||||
int width = Math.round(layout.getAdvance());
|
|
||||||
int height = Math.round(layout.getAscent());
|
|
||||||
|
|
||||||
Dimension txsize = new Dimension(width, height);
|
|
||||||
java.awt.Rectangle anchor = getAnchor();
|
|
||||||
anchor.setSize(txsize);
|
|
||||||
setAnchor(anchor);
|
|
||||||
} catch (Exception e){
|
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the type of vertical alignment for the text.
|
|
||||||
* One of the <code>Anchor*</code> constants defined in this class.
|
|
||||||
*
|
|
||||||
* @return the type of alignment
|
|
||||||
*/
|
|
||||||
public int getVerticalAlignment(){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
|
|
||||||
int valign;
|
|
||||||
if (prop == null){
|
|
||||||
int type = getTextRun().getRunType();
|
|
||||||
switch (type){
|
|
||||||
case TextHeaderAtom.TITLE_TYPE:
|
|
||||||
case TextHeaderAtom.CENTER_TITLE_TYPE:
|
|
||||||
valign = TextBox.AnchorMiddle;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
valign = TextBox.AnchorTop;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
valign = prop.getPropertyValue();
|
|
||||||
}
|
|
||||||
return valign;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the type of vertical alignment for the text.
|
|
||||||
* One of the <code>Anchor*</code> constants defined in this class.
|
|
||||||
*
|
|
||||||
* @param align - the type of alignment
|
|
||||||
*/
|
|
||||||
public void setVerticalAlignment(int align){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
setEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT, align);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHorizontalAlignment(int align){
|
|
||||||
_txtrun.getRichTextRuns()[0].setAlignment(align);
|
|
||||||
}
|
|
||||||
public int getHorizontalAlignment(){
|
|
||||||
return _txtrun.getRichTextRuns()[0].getAlignment();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the distance (in points) between the bottom of the text frame
|
|
||||||
* and the bottom of the inscribed rectangle of the shape that contains the text.
|
|
||||||
* Default value is 1/20 inch.
|
|
||||||
*
|
|
||||||
* @return the botom margin
|
|
||||||
*/
|
|
||||||
public int getMarginBottom(){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
|
|
||||||
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
|
|
||||||
return val/EMU_PER_POINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the botom margin.
|
|
||||||
* @see #getMarginBottom()
|
|
||||||
*
|
|
||||||
* @param margin the bottom margin
|
|
||||||
*/
|
|
||||||
public void setMarginBottom(int margin){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
setEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM, margin*EMU_PER_POINT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the distance (in EMUs) between the left edge of the text frame
|
|
||||||
* and the left edge of the inscribed rectangle of the shape that contains
|
|
||||||
* the text.
|
|
||||||
* Default value is 1/10 inch.
|
|
||||||
*
|
|
||||||
* @return the left margin
|
|
||||||
*/
|
|
||||||
public int getMarginLeft(){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
|
|
||||||
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
|
|
||||||
return val/EMU_PER_POINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the left margin.
|
|
||||||
* @see #getMarginLeft()
|
|
||||||
*
|
|
||||||
* @param margin the left margin
|
|
||||||
*/
|
|
||||||
public void setMarginLeft(int margin){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
setEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT, margin*EMU_PER_POINT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the distance (in EMUs) between the right edge of the
|
|
||||||
* text frame and the right edge of the inscribed rectangle of the shape
|
|
||||||
* that contains the text.
|
|
||||||
* Default value is 1/10 inch.
|
|
||||||
*
|
|
||||||
* @return the right margin
|
|
||||||
*/
|
|
||||||
public int getMarginRight(){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);
|
|
||||||
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
|
|
||||||
return val/EMU_PER_POINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the right margin.
|
|
||||||
* @see #getMarginRight()
|
|
||||||
*
|
|
||||||
* @param margin the right margin
|
|
||||||
*/
|
|
||||||
public void setMarginRight(int margin){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
setEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT, margin*EMU_PER_POINT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the distance (in EMUs) between the top of the text frame
|
|
||||||
* and the top of the inscribed rectangle of the shape that contains the text.
|
|
||||||
* Default value is 1/20 inch.
|
|
||||||
*
|
|
||||||
* @return the top margin
|
|
||||||
*/
|
|
||||||
public int getMarginTop(){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);
|
|
||||||
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
|
|
||||||
return val/EMU_PER_POINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the top margin.
|
|
||||||
* @see #getMarginTop()
|
|
||||||
*
|
|
||||||
* @param margin the top margin
|
|
||||||
*/
|
|
||||||
public void setMarginTop(int margin){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
setEscherProperty(opt, EscherProperties.TEXT__TEXTTOP, margin*EMU_PER_POINT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value indicating word wrap.
|
|
||||||
* One of the <code>Wrap*</code> constants defined in this class.
|
|
||||||
*
|
|
||||||
* @return the value indicating word wrap
|
|
||||||
*/
|
|
||||||
public int getWordWrap(){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
|
|
||||||
return prop == null ? WrapSquare : prop.getPropertyValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies how the text should be wrapped
|
|
||||||
*
|
|
||||||
* @param wrap the value indicating how the text should be wrapped
|
|
||||||
*/
|
|
||||||
public void setWordWrap(int wrap){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
setEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT, wrap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return id for the text.
|
|
||||||
*/
|
|
||||||
public int getTextId(){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTID);
|
|
||||||
return prop == null ? 0 : prop.getPropertyValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets text ID
|
|
||||||
*
|
|
||||||
* @param id of the text
|
|
||||||
*/
|
|
||||||
public void setTextId(int id){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
setEscherProperty(opt, EscherProperties.TEXT__TEXTID, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The color used to fill this shape.
|
|
||||||
*
|
|
||||||
* @param color the background color
|
|
||||||
*/
|
|
||||||
public void setBackgroundColor(Color color){
|
|
||||||
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
|
||||||
int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB();
|
|
||||||
setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, rgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the TextRun object for this text box
|
|
||||||
*/
|
|
||||||
public TextRun getTextRun(){
|
|
||||||
return _txtrun;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSheet(Sheet sheet){
|
|
||||||
_sheet = sheet;
|
|
||||||
|
|
||||||
// Initialize _txtrun object.
|
|
||||||
// (We can't do it in the constructor because the sheet
|
|
||||||
// is not assigned then, it's only built once we have
|
|
||||||
// all the records)
|
|
||||||
if(_txtrun == null) initTextRun();
|
|
||||||
if(_txtrun == null) {
|
|
||||||
// No text records found, skip
|
|
||||||
_missingTextRecords = true;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
_missingTextRecords = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Supply the sheet to our child RichTextRuns
|
|
||||||
_txtrun.setSheet(sheet);
|
|
||||||
RichTextRun[] rt = _txtrun.getRichTextRuns();
|
|
||||||
for (int i = 0; i < rt.length; i++) {
|
|
||||||
rt[i].supplySlideShow(_sheet.getSlideShow());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initTextRun(){
|
|
||||||
OutlineTextRefAtom ota = null;
|
|
||||||
|
|
||||||
// Find the interesting child records
|
|
||||||
Record[] child = _txtbox.getChildRecords();
|
|
||||||
for (int i = 0; i < child.length; i++) {
|
|
||||||
if (child[i] instanceof OutlineTextRefAtom) {
|
|
||||||
ota = (OutlineTextRefAtom)child[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Sheet sheet = getSheet();
|
|
||||||
TextRun[] runs = sheet.getTextRuns();
|
|
||||||
if (ota != null) {
|
|
||||||
int idx = ota.getTextIndex();
|
|
||||||
for (int i = 0; i < runs.length; i++) {
|
|
||||||
if(runs[i].getIndex() == idx){
|
|
||||||
_txtrun = runs[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(_txtrun == null) {
|
|
||||||
logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int shapeId = _escherContainer.getChildById(EscherSpRecord.RECORD_ID).getShapeId();
|
|
||||||
if(runs != null) for (int i = 0; i < runs.length; i++) {
|
|
||||||
if(runs[i].getShapeId() == shapeId){
|
|
||||||
_txtrun = runs[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
516
src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
Executable file
516
src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
Executable file
@ -0,0 +1,516 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.hslf.model;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.*;
|
||||||
|
import org.apache.poi.hslf.record.*;
|
||||||
|
import org.apache.poi.hslf.usermodel.RichTextRun;
|
||||||
|
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||||
|
import org.apache.poi.util.POILogger;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.awt.font.FontRenderContext;
|
||||||
|
import java.awt.font.TextLayout;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A common superclass of all shapes that can hold text.
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public abstract class TextShape extends SimpleShape {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How to anchor the text
|
||||||
|
*/
|
||||||
|
public static final int AnchorTop = 0;
|
||||||
|
public static final int AnchorMiddle = 1;
|
||||||
|
public static final int AnchorBottom = 2;
|
||||||
|
public static final int AnchorTopCentered = 3;
|
||||||
|
public static final int AnchorMiddleCentered = 4;
|
||||||
|
public static final int AnchorBottomCentered = 5;
|
||||||
|
public static final int AnchorTopBaseline = 6;
|
||||||
|
public static final int AnchorBottomBaseline = 7;
|
||||||
|
public static final int AnchorTopCenteredBaseline = 8;
|
||||||
|
public static final int AnchorBottomCenteredBaseline = 9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How to wrap the text
|
||||||
|
*/
|
||||||
|
public static final int WrapSquare = 0;
|
||||||
|
public static final int WrapByPoints = 1;
|
||||||
|
public static final int WrapNone = 2;
|
||||||
|
public static final int WrapTopBottom = 3;
|
||||||
|
public static final int WrapThrough = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How to align the text
|
||||||
|
*/
|
||||||
|
public static final int AlignLeft = 0;
|
||||||
|
public static final int AlignCenter = 1;
|
||||||
|
public static final int AlignRight = 2;
|
||||||
|
public static final int AlignJustify = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TextRun object which holds actual text and format data
|
||||||
|
*/
|
||||||
|
protected TextRun _txtrun;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher container which holds text attributes such as
|
||||||
|
* TextHeaderAtom, TextBytesAtom ot TextCharsAtom, StyleTextPropAtom etc.
|
||||||
|
*/
|
||||||
|
protected EscherTextboxWrapper _txtbox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to calculate text bounds
|
||||||
|
*/
|
||||||
|
protected static final FontRenderContext _frc = new FontRenderContext(null, true, true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a TextBox object and initialize it from the supplied Record container.
|
||||||
|
*
|
||||||
|
* @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
|
||||||
|
* @param parent the parent of the shape
|
||||||
|
*/
|
||||||
|
protected TextShape(EscherContainerRecord escherRecord, Shape parent){
|
||||||
|
super(escherRecord, parent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new TextBox. This constructor is used when a new shape is created.
|
||||||
|
*
|
||||||
|
* @param parent the parent of this Shape. For example, if this text box is a cell
|
||||||
|
* in a table then the parent is Table.
|
||||||
|
*/
|
||||||
|
public TextShape(Shape parent){
|
||||||
|
super(null, parent);
|
||||||
|
_escherContainer = createSpContainer(parent instanceof ShapeGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new TextBox. This constructor is used when a new shape is created.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public TextShape(){
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextRun createTextRun(){
|
||||||
|
_txtbox = getEscherTextboxWrapper();
|
||||||
|
if(_txtbox == null) _txtbox = new EscherTextboxWrapper();
|
||||||
|
|
||||||
|
_txtrun = getTextRun();
|
||||||
|
if(_txtrun == null){
|
||||||
|
TextHeaderAtom tha = new TextHeaderAtom();
|
||||||
|
tha.setParentRecord(_txtbox);
|
||||||
|
_txtbox.appendChildRecord(tha);
|
||||||
|
|
||||||
|
TextCharsAtom tca = new TextCharsAtom();
|
||||||
|
_txtbox.appendChildRecord(tca);
|
||||||
|
|
||||||
|
StyleTextPropAtom sta = new StyleTextPropAtom(0);
|
||||||
|
_txtbox.appendChildRecord(sta);
|
||||||
|
|
||||||
|
_txtrun = new TextRun(tha,tca,sta);
|
||||||
|
_txtrun.setText("");
|
||||||
|
|
||||||
|
_escherContainer.addChildRecord(_txtbox.getEscherRecord());
|
||||||
|
|
||||||
|
setDefaultTextProperties(_txtrun);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _txtrun;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set default properties for the TextRun.
|
||||||
|
* Depending on the text and shape type the defaults are different:
|
||||||
|
* TextBox: align=left, valign=top
|
||||||
|
* AutoShape: align=center, valign=middle
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected void setDefaultTextProperties(TextRun _txtrun){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text contained in this text frame.
|
||||||
|
*
|
||||||
|
* @return the text string for this textbox.
|
||||||
|
*/
|
||||||
|
public String getText(){
|
||||||
|
TextRun tx = getTextRun();
|
||||||
|
return tx == null ? null : tx.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text contained in this text frame.
|
||||||
|
*
|
||||||
|
* @param text the text string used by this object.
|
||||||
|
*/
|
||||||
|
public void setText(String text){
|
||||||
|
TextRun tx = getTextRun();
|
||||||
|
if(tx == null){
|
||||||
|
tx = createTextRun();
|
||||||
|
}
|
||||||
|
tx.setText(text);
|
||||||
|
setTextId(text.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a textbox is added to a sheet we need to tell upper-level
|
||||||
|
* <code>PPDrawing</code> about it.
|
||||||
|
*
|
||||||
|
* @param sh the sheet we are adding to
|
||||||
|
*/
|
||||||
|
protected void afterInsert(Sheet sh){
|
||||||
|
EscherTextboxWrapper _txtbox = getEscherTextboxWrapper();
|
||||||
|
if(_txtbox != null){
|
||||||
|
PPDrawing ppdrawing = sh.getPPDrawing();
|
||||||
|
ppdrawing.addTextboxWrapper(_txtbox);
|
||||||
|
// Ensure the escher layer knows about the added records
|
||||||
|
try {
|
||||||
|
_txtbox.writeOut(null);
|
||||||
|
} catch (IOException e){
|
||||||
|
throw new HSLFException(e);
|
||||||
|
}
|
||||||
|
if(getAnchor().equals(new Rectangle()) && !"".equals(getText())) resizeToFitText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EscherTextboxWrapper getEscherTextboxWrapper(){
|
||||||
|
if(_txtbox == null){
|
||||||
|
EscherTextboxRecord textRecord = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);
|
||||||
|
if(textRecord != null) _txtbox = new EscherTextboxWrapper(textRecord);
|
||||||
|
}
|
||||||
|
return _txtbox;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adjust the size of the TextShape so it encompasses the text inside it.
|
||||||
|
*
|
||||||
|
* @return a <code>Rectangle2D</code> that is the bounds of this <code>TextShape</code>.
|
||||||
|
*/
|
||||||
|
public Rectangle2D resizeToFitText(){
|
||||||
|
String txt = getText();
|
||||||
|
if(txt == null || txt.length() == 0) return new Rectangle2D.Float();
|
||||||
|
|
||||||
|
RichTextRun rt = getTextRun().getRichTextRuns()[0];
|
||||||
|
int size = rt.getFontSize();
|
||||||
|
int style = 0;
|
||||||
|
if (rt.isBold()) style |= Font.BOLD;
|
||||||
|
if (rt.isItalic()) style |= Font.ITALIC;
|
||||||
|
String fntname = rt.getFontName();
|
||||||
|
Font font = new Font(fntname, style, size);
|
||||||
|
|
||||||
|
float width = 0, height = 0;
|
||||||
|
String[] lines = txt.split("\r");
|
||||||
|
for (int i = 0; i < lines.length; i++) {
|
||||||
|
if(lines[i].length() == 0) continue;
|
||||||
|
|
||||||
|
TextLayout layout = new TextLayout(lines[i], font, _frc);
|
||||||
|
|
||||||
|
width = Math.max(width, layout.getAdvance());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Even if top and bottom margins are set to 0 PowerPoint
|
||||||
|
* always sets extra space between the text and its bounding box.
|
||||||
|
*
|
||||||
|
* The approximation height = ascent*2 works good enough in most cases
|
||||||
|
*/
|
||||||
|
height = Math.max(height, 2*layout.getAscent());
|
||||||
|
}
|
||||||
|
|
||||||
|
width += getMarginLeft() + getMarginRight();
|
||||||
|
height += getMarginTop() + getMarginBottom();
|
||||||
|
|
||||||
|
Rectangle2D anchor = getAnchor2D();
|
||||||
|
anchor.setRect(anchor.getX(), anchor.getY(), width, height);
|
||||||
|
setAnchor(anchor);
|
||||||
|
|
||||||
|
return anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of vertical alignment for the text.
|
||||||
|
* One of the <code>Anchor*</code> constants defined in this class.
|
||||||
|
*
|
||||||
|
* @return the type of alignment
|
||||||
|
*/
|
||||||
|
public int getVerticalAlignment(){
|
||||||
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
|
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
|
||||||
|
int valign;
|
||||||
|
if (prop == null){
|
||||||
|
int type = getTextRun().getRunType();
|
||||||
|
switch (type){
|
||||||
|
case TextHeaderAtom.TITLE_TYPE:
|
||||||
|
case TextHeaderAtom.CENTER_TITLE_TYPE:
|
||||||
|
valign = TextShape.AnchorMiddle;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
valign = TextShape.AnchorTop;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
valign = prop.getPropertyValue();
|
||||||
|
}
|
||||||
|
return valign;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the type of vertical alignment for the text.
|
||||||
|
* One of the <code>Anchor*</code> constants defined in this class.
|
||||||
|
*
|
||||||
|
* @param align - the type of alignment
|
||||||
|
*/
|
||||||
|
public void setVerticalAlignment(int align){
|
||||||
|
setEscherProperty(EscherProperties.TEXT__ANCHORTEXT, align);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the type of horizontal alignment for the text.
|
||||||
|
* One of the <code>Align*</code> constants defined in this class.
|
||||||
|
*
|
||||||
|
* @param align - the type of horizontal alignment
|
||||||
|
*/
|
||||||
|
public void setHorizontalAlignment(int align){
|
||||||
|
TextRun tx = getTextRun();
|
||||||
|
if(tx != null) tx.getRichTextRuns()[0].setAlignment(align);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of horizontal alignment for the text.
|
||||||
|
* One of the <code>Align*</code> constants defined in this class.
|
||||||
|
*
|
||||||
|
* @return align - the type of horizontal alignment
|
||||||
|
*/
|
||||||
|
public int getHorizontalAlignment(){
|
||||||
|
TextRun tx = getTextRun();
|
||||||
|
return tx == null ? -1 : tx.getRichTextRuns()[0].getAlignment();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the distance (in points) between the bottom of the text frame
|
||||||
|
* and the bottom of the inscribed rectangle of the shape that contains the text.
|
||||||
|
* Default value is 1/20 inch.
|
||||||
|
*
|
||||||
|
* @return the botom margin
|
||||||
|
*/
|
||||||
|
public float getMarginBottom(){
|
||||||
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
|
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
|
||||||
|
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
|
||||||
|
return (float)val/EMU_PER_POINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the botom margin.
|
||||||
|
* @see #getMarginBottom()
|
||||||
|
*
|
||||||
|
* @param margin the bottom margin
|
||||||
|
*/
|
||||||
|
public void setMarginBottom(float margin){
|
||||||
|
setEscherProperty(EscherProperties.TEXT__TEXTBOTTOM, (int)(margin*EMU_PER_POINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the distance (in points) between the left edge of the text frame
|
||||||
|
* and the left edge of the inscribed rectangle of the shape that contains
|
||||||
|
* the text.
|
||||||
|
* Default value is 1/10 inch.
|
||||||
|
*
|
||||||
|
* @return the left margin
|
||||||
|
*/
|
||||||
|
public float getMarginLeft(){
|
||||||
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
|
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
|
||||||
|
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
|
||||||
|
return (float)val/EMU_PER_POINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the left margin.
|
||||||
|
* @see #getMarginLeft()
|
||||||
|
*
|
||||||
|
* @param margin the left margin
|
||||||
|
*/
|
||||||
|
public void setMarginLeft(float margin){
|
||||||
|
setEscherProperty(EscherProperties.TEXT__TEXTLEFT, (int)(margin*EMU_PER_POINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the distance (in points) between the right edge of the
|
||||||
|
* text frame and the right edge of the inscribed rectangle of the shape
|
||||||
|
* that contains the text.
|
||||||
|
* Default value is 1/10 inch.
|
||||||
|
*
|
||||||
|
* @return the right margin
|
||||||
|
*/
|
||||||
|
public float getMarginRight(){
|
||||||
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
|
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);
|
||||||
|
int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
|
||||||
|
return (float)val/EMU_PER_POINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the right margin.
|
||||||
|
* @see #getMarginRight()
|
||||||
|
*
|
||||||
|
* @param margin the right margin
|
||||||
|
*/
|
||||||
|
public void setMarginRight(float margin){
|
||||||
|
setEscherProperty(EscherProperties.TEXT__TEXTRIGHT, (int)(margin*EMU_PER_POINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the distance (in points) between the top of the text frame
|
||||||
|
* and the top of the inscribed rectangle of the shape that contains the text.
|
||||||
|
* Default value is 1/20 inch.
|
||||||
|
*
|
||||||
|
* @return the top margin
|
||||||
|
*/
|
||||||
|
public float getMarginTop(){
|
||||||
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
|
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);
|
||||||
|
int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
|
||||||
|
return (float)val/EMU_PER_POINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the top margin.
|
||||||
|
* @see #getMarginTop()
|
||||||
|
*
|
||||||
|
* @param margin the top margin
|
||||||
|
*/
|
||||||
|
public void setMarginTop(float margin){
|
||||||
|
setEscherProperty(EscherProperties.TEXT__TEXTTOP, (int)(margin*EMU_PER_POINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value indicating word wrap.
|
||||||
|
*
|
||||||
|
* @return the value indicating word wrap.
|
||||||
|
* Must be one of the <code>Wrap*</code> constants defined in this class.
|
||||||
|
*/
|
||||||
|
public int getWordWrap(){
|
||||||
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
|
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
|
||||||
|
return prop == null ? WrapSquare : prop.getPropertyValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies how the text should be wrapped
|
||||||
|
*
|
||||||
|
* @param wrap the value indicating how the text should be wrapped.
|
||||||
|
* Must be one of the <code>Wrap*</code> constants defined in this class.
|
||||||
|
*/
|
||||||
|
public void setWordWrap(int wrap){
|
||||||
|
setEscherProperty(EscherProperties.TEXT__WRAPTEXT, wrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return id for the text.
|
||||||
|
*/
|
||||||
|
public int getTextId(){
|
||||||
|
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
|
||||||
|
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTID);
|
||||||
|
return prop == null ? 0 : prop.getPropertyValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets text ID
|
||||||
|
*
|
||||||
|
* @param id of the text
|
||||||
|
*/
|
||||||
|
public void setTextId(int id){
|
||||||
|
setEscherProperty(EscherProperties.TEXT__TEXTID, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the TextRun object for this text box
|
||||||
|
*/
|
||||||
|
public TextRun getTextRun(){
|
||||||
|
if(_txtrun == null) initTextRun();
|
||||||
|
return _txtrun;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSheet(Sheet sheet) {
|
||||||
|
_sheet = sheet;
|
||||||
|
|
||||||
|
// Initialize _txtrun object.
|
||||||
|
// (We can't do it in the constructor because the sheet
|
||||||
|
// is not assigned then, it's only built once we have
|
||||||
|
// all the records)
|
||||||
|
TextRun tx = getTextRun();
|
||||||
|
if (tx != null) {
|
||||||
|
// Supply the sheet to our child RichTextRuns
|
||||||
|
tx.setSheet(_sheet);
|
||||||
|
RichTextRun[] rt = tx.getRichTextRuns();
|
||||||
|
for (int i = 0; i < rt.length; i++) {
|
||||||
|
rt[i].supplySlideShow(_sheet.getSlideShow());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initTextRun(){
|
||||||
|
EscherTextboxWrapper txtbox = getEscherTextboxWrapper();
|
||||||
|
Sheet sheet = getSheet();
|
||||||
|
|
||||||
|
if(sheet == null || txtbox == null) return;
|
||||||
|
|
||||||
|
OutlineTextRefAtom ota = null;
|
||||||
|
|
||||||
|
Record[] child = txtbox.getChildRecords();
|
||||||
|
for (int i = 0; i < child.length; i++) {
|
||||||
|
if (child[i] instanceof OutlineTextRefAtom) {
|
||||||
|
ota = (OutlineTextRefAtom)child[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextRun[] runs = _sheet.getTextRuns();
|
||||||
|
if (ota != null) {
|
||||||
|
int idx = ota.getTextIndex();
|
||||||
|
for (int i = 0; i < runs.length; i++) {
|
||||||
|
if(runs[i].getIndex() == idx){
|
||||||
|
_txtrun = runs[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(_txtrun == null) {
|
||||||
|
logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int shapeId = _escherContainer.getChildById(EscherSpRecord.RECORD_ID).getShapeId();
|
||||||
|
if(runs != null) for (int i = 0; i < runs.length; i++) {
|
||||||
|
if(runs[i].getShapeId() == shapeId){
|
||||||
|
_txtrun = runs[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
src/scratchpad/testcases/org/apache/poi/hslf/data/text_shapes.ppt
Executable file
BIN
src/scratchpad/testcases/org/apache/poi/hslf/data/text_shapes.ppt
Executable file
Binary file not shown.
@ -218,8 +218,8 @@ public class TestShapes extends TestCase {
|
|||||||
ArrayList lst2 = new ArrayList();
|
ArrayList lst2 = new ArrayList();
|
||||||
Shape[] sh = sl[k].getShapes();
|
Shape[] sh = sl[k].getShapes();
|
||||||
for (int i = 0; i < sh.length; i++) {
|
for (int i = 0; i < sh.length; i++) {
|
||||||
if (sh[i] instanceof TextBox){
|
if (sh[i] instanceof TextShape){
|
||||||
TextBox tbox = (TextBox)sh[i];
|
TextShape tbox = (TextShape)sh[i];
|
||||||
lst2.add(tbox.getText());
|
lst2.add(tbox.getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
160
src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextShape.java
Executable file
160
src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextShape.java
Executable file
@ -0,0 +1,160 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.poi.hslf.model;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||||
|
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify behavior of <code>TextShape</code> and its sub-classes
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public class TestTextShape extends TestCase {
|
||||||
|
protected String cwd = System.getProperty("HSLF.testdata.path");
|
||||||
|
|
||||||
|
public void testCreateAutoShape(){
|
||||||
|
TextShape shape = new AutoShape(ShapeTypes.Trapezoid);
|
||||||
|
assertNull(shape.getTextRun());
|
||||||
|
assertNull(shape.getText());
|
||||||
|
assertNull(shape.getEscherTextboxWrapper());
|
||||||
|
|
||||||
|
TextRun run = shape.createTextRun();
|
||||||
|
assertNotNull(run);
|
||||||
|
assertNotNull(shape.getTextRun());
|
||||||
|
assertNotNull(shape.getEscherTextboxWrapper());
|
||||||
|
assertEquals("", shape.getText());
|
||||||
|
assertSame(run, shape.createTextRun());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateTextBox(){
|
||||||
|
TextShape shape = new TextBox();
|
||||||
|
TextRun run = shape.getTextRun();
|
||||||
|
assertNotNull(run);
|
||||||
|
assertNotNull(shape.getText());
|
||||||
|
assertNotNull(shape.getEscherTextboxWrapper());
|
||||||
|
|
||||||
|
assertSame(run, shape.createTextRun());
|
||||||
|
assertNotNull(shape.getTextRun());
|
||||||
|
assertNotNull(shape.getEscherTextboxWrapper());
|
||||||
|
assertEquals("", shape.getText());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify we can get text from TextShape in the following cases:
|
||||||
|
* - placeholders
|
||||||
|
* - normal TextBox object
|
||||||
|
* - text in auto-shapes
|
||||||
|
*/
|
||||||
|
public void testRead() throws IOException {
|
||||||
|
FileInputStream is = new FileInputStream(new File(cwd, "text_shapes.ppt"));
|
||||||
|
SlideShow ppt = new SlideShow(is);
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
ArrayList lst1 = new ArrayList();
|
||||||
|
Slide slide = ppt.getSlides()[0];
|
||||||
|
Shape[] shape = slide.getShapes();
|
||||||
|
for (int i = 0; i < shape.length; i++) {
|
||||||
|
assertTrue("Expected TextShape but found " + shape[i].getClass().getName(), shape[i] instanceof TextShape);
|
||||||
|
TextShape tx = (TextShape)shape[i];
|
||||||
|
TextRun run = tx.getTextRun();
|
||||||
|
assertNotNull(run);
|
||||||
|
int runType = run.getRunType();
|
||||||
|
|
||||||
|
int type = shape[i].getShapeType();
|
||||||
|
switch (type){
|
||||||
|
case ShapeTypes.TextBox:
|
||||||
|
assertEquals("Text in a TextBox", run.getText());
|
||||||
|
break;
|
||||||
|
case ShapeTypes.Rectangle:
|
||||||
|
if(runType == TextHeaderAtom.OTHER_TYPE)
|
||||||
|
assertEquals("Rectangle", run.getText());
|
||||||
|
else if(runType == TextHeaderAtom.TITLE_TYPE)
|
||||||
|
assertEquals("Title Placeholder", run.getText());
|
||||||
|
break;
|
||||||
|
case ShapeTypes.Octagon:
|
||||||
|
assertEquals("Octagon", run.getText());
|
||||||
|
break;
|
||||||
|
case ShapeTypes.Ellipse:
|
||||||
|
assertEquals("Ellipse", run.getText());
|
||||||
|
break;
|
||||||
|
case ShapeTypes.RoundRectangle:
|
||||||
|
assertEquals("RoundRectangle", run.getText());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fail("Unexpected shape: " + shape[i].getShapeName());
|
||||||
|
|
||||||
|
}
|
||||||
|
lst1.add(run.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList lst2 = new ArrayList();
|
||||||
|
TextRun[] run = slide.getTextRuns();
|
||||||
|
for (int i = 0; i < run.length; i++) {
|
||||||
|
lst2.add(run[i].getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(lst1.containsAll(lst2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadWrite() throws IOException {
|
||||||
|
SlideShow ppt = new SlideShow();
|
||||||
|
Slide slide = ppt.createSlide();
|
||||||
|
|
||||||
|
TextShape shape1 = new TextBox();
|
||||||
|
TextRun run1 = shape1.createTextRun();
|
||||||
|
run1.setText("Hello, World!");
|
||||||
|
slide.addShape(shape1);
|
||||||
|
|
||||||
|
shape1.moveTo(100, 100);
|
||||||
|
|
||||||
|
TextShape shape2 = new AutoShape(ShapeTypes.Arrow);
|
||||||
|
TextRun run2 = shape2.createTextRun();
|
||||||
|
run2.setText("Testing TextShape");
|
||||||
|
slide.addShape(shape2);
|
||||||
|
shape2.moveTo(300, 300);
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
ppt.write(out);
|
||||||
|
out.close();
|
||||||
|
|
||||||
|
ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
|
||||||
|
slide = ppt.getSlides()[0];
|
||||||
|
Shape[] shape = slide.getShapes();
|
||||||
|
|
||||||
|
assertTrue(shape[0] instanceof TextShape);
|
||||||
|
shape1 = (TextShape)shape[0];
|
||||||
|
assertEquals(ShapeTypes.TextBox, shape1.getShapeType());
|
||||||
|
assertEquals("Hello, World!", shape1.getTextRun().getText());
|
||||||
|
|
||||||
|
assertTrue(shape[1] instanceof TextShape);
|
||||||
|
shape1 = (TextShape)shape[1];
|
||||||
|
assertEquals(ShapeTypes.Arrow, shape1.getShapeType());
|
||||||
|
assertEquals("Testing TextShape", shape1.getTextRun().getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -316,8 +316,8 @@ public class TestBugs extends TestCase {
|
|||||||
ArrayList lst = new ArrayList();
|
ArrayList lst = new ArrayList();
|
||||||
Shape[] shape = slide.getShapes();
|
Shape[] shape = slide.getShapes();
|
||||||
for (int i = 0; i < shape.length; i++) {
|
for (int i = 0; i < shape.length; i++) {
|
||||||
if( shape[i] instanceof TextBox){
|
if( shape[i] instanceof TextShape){
|
||||||
TextRun textRun = ((TextBox)shape[i]).getTextRun();
|
TextRun textRun = ((TextShape)shape[i]).getTextRun();
|
||||||
if(textRun != null) lst.add(textRun);
|
if(textRun != null) lst.add(textRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user