POI-55292
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1508691 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
b21ad9dbd2
commit
09555c446b
@ -17,6 +17,11 @@
|
||||
|
||||
package org.apache.poi.xssf.usermodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.*;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
|
||||
@ -24,15 +29,19 @@ import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonV
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRElt;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRPrElt;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.Units;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnderlineValues;
|
||||
|
||||
/**
|
||||
* Represents a shape with a predefined geometry in a SpreadsheetML drawing.
|
||||
* Possible shape types are defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class XSSFSimpleShape extends XSSFShape { // TODO - instantiable superclass
|
||||
public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParagraph> { // TODO - instantiable superclass
|
||||
/**
|
||||
* List of the paragraphs that make up the text in this shape
|
||||
*/
|
||||
private final List<XSSFTextParagraph> _paragraphs;
|
||||
/**
|
||||
* A default instance of CTShape used for creating new shapes.
|
||||
*/
|
||||
@ -46,6 +55,15 @@ public class XSSFSimpleShape extends XSSFShape { // TODO - instantiable supercla
|
||||
protected XSSFSimpleShape(XSSFDrawing drawing, CTShape ctShape) {
|
||||
this.drawing = drawing;
|
||||
this.ctShape = ctShape;
|
||||
|
||||
_paragraphs = new ArrayList<XSSFTextParagraph>();
|
||||
|
||||
// initialize any existing paragraphs - this will be the default body paragraph in a new shape,
|
||||
// or existing paragraphs that have been loaded from the file
|
||||
CTTextBody body = ctShape.getTxBody();
|
||||
for(int i = 0; i < body.sizeOfPArray(); i++) {
|
||||
_paragraphs.add(new XSSFTextParagraph(body.getPArray(i), ctShape));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,34 +92,18 @@ public class XSSFSimpleShape extends XSSFShape { // TODO - instantiable supercla
|
||||
geom.setPrst(STShapeType.RECT);
|
||||
geom.addNewAvLst();
|
||||
|
||||
CTShapeStyle style = shape.addNewStyle();
|
||||
CTSchemeColor scheme = style.addNewLnRef().addNewSchemeClr();
|
||||
scheme.setVal(STSchemeColorVal.ACCENT_1);
|
||||
scheme.addNewShade().setVal(50000);
|
||||
style.getLnRef().setIdx(2);
|
||||
|
||||
CTStyleMatrixReference fillref = style.addNewFillRef();
|
||||
fillref.setIdx(1);
|
||||
fillref.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1);
|
||||
|
||||
CTStyleMatrixReference effectRef = style.addNewEffectRef();
|
||||
effectRef.setIdx(0);
|
||||
effectRef.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1);
|
||||
|
||||
CTFontReference fontRef = style.addNewFontRef();
|
||||
fontRef.setIdx(STFontCollectionIndex.MINOR);
|
||||
fontRef.addNewSchemeClr().setVal(STSchemeColorVal.LT_1);
|
||||
|
||||
CTTextBody body = shape.addNewTxBody();
|
||||
CTTextBodyProperties bodypr = body.addNewBodyPr();
|
||||
bodypr.setAnchor(STTextAnchoringType.CTR);
|
||||
bodypr.setAnchor(STTextAnchoringType.T);
|
||||
bodypr.setRtlCol(false);
|
||||
CTTextParagraph p = body.addNewP();
|
||||
p.addNewPPr().setAlgn(STTextAlignType.CTR);
|
||||
p.addNewPPr().setAlgn(STTextAlignType.L);
|
||||
CTTextCharacterProperties endPr = p.addNewEndParaRPr();
|
||||
endPr.setLang("en-US");
|
||||
endPr.setSz(1100);
|
||||
|
||||
endPr.setSz(1100);
|
||||
CTSolidColorFillProperties scfpr = endPr.addNewSolidFill();
|
||||
scfpr.addNewSrgbClr().setVal(new byte[] { 0, 0, 0 });
|
||||
|
||||
body.addNewLstStyle();
|
||||
|
||||
prototype = shape;
|
||||
@ -114,30 +116,255 @@ public class XSSFSimpleShape extends XSSFShape { // TODO - instantiable supercla
|
||||
return ctShape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
|
||||
*
|
||||
* @return the shape type
|
||||
* @see org.apache.poi.ss.usermodel.ShapeTypes
|
||||
*/
|
||||
public int getShapeType() {
|
||||
return ctShape.getSpPr().getPrstGeom().getPrst().intValue();
|
||||
|
||||
public Iterator<XSSFTextParagraph> iterator(){
|
||||
return _paragraphs.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the shape types.
|
||||
*
|
||||
* @param type the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
|
||||
* @see org.apache.poi.ss.usermodel.ShapeTypes
|
||||
* Returns the text from all paragraphs in the shape. Paragraphs are separated by new lines.
|
||||
*
|
||||
* @return text contained within this shape or empty string
|
||||
*/
|
||||
public void setShapeType(int type) {
|
||||
ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type));
|
||||
public String getText() {
|
||||
final int MAX_LEVELS = 9;
|
||||
StringBuilder out = new StringBuilder();
|
||||
List<Integer> levelCount = new ArrayList<Integer>(MAX_LEVELS); // maximum 9 levels
|
||||
XSSFTextParagraph p = null;
|
||||
|
||||
// initialise the levelCount array - this maintains a record of the numbering to be used at each level
|
||||
for (int k = 0; k < MAX_LEVELS; k++){
|
||||
levelCount.add(0);
|
||||
}
|
||||
|
||||
for(int i = 0; i < _paragraphs.size(); i++) {
|
||||
if (out.length() > 0) out.append('\n');
|
||||
p = _paragraphs.get(i);
|
||||
|
||||
if(p.isBullet() && p.getText().length() > 0){
|
||||
|
||||
int level = Math.min(p.getLevel(), MAX_LEVELS - 1);
|
||||
|
||||
if(p.isBulletAutoNumber()){
|
||||
i = processAutoNumGroup(i, level, levelCount, out);
|
||||
} else {
|
||||
// indent appropriately for the level
|
||||
for(int j = 0; j < level; j++){
|
||||
out.append('\t');
|
||||
}
|
||||
String character = p.getBulletCharacter();
|
||||
out.append(character.length() > 0 ? character + " " : "- ");
|
||||
out.append(p.getText());
|
||||
}
|
||||
} else {
|
||||
out.append(p.getText());
|
||||
|
||||
// this paragraph is not a bullet, so reset the count array
|
||||
for (int k = 0; k < MAX_LEVELS; k++){
|
||||
levelCount.set(k, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
protected CTShapeProperties getShapeProperties(){
|
||||
return ctShape.getSpPr();
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private int processAutoNumGroup(int index, int level, List<Integer> levelCount, StringBuilder out){
|
||||
XSSFTextParagraph p = null;
|
||||
XSSFTextParagraph nextp = null;
|
||||
ListAutoNumber scheme, nextScheme;
|
||||
int startAt, nextStartAt;
|
||||
|
||||
p = _paragraphs.get(index);
|
||||
|
||||
// The rules for generating the auto numbers are as follows. If the following paragraph is also
|
||||
// an auto-number, has the same type/scheme (and startAt if defined on this paragraph) then they are
|
||||
// considered part of the same group. An empty bullet paragraph is counted as part of the same
|
||||
// group but does not increment the count for the group. A change of type, startAt or the paragraph
|
||||
// not being a bullet resets the count for that level to 1.
|
||||
|
||||
// first auto-number paragraph so initialise to 1 or the bullets startAt if present
|
||||
startAt = p.getBulletAutoNumberStart();
|
||||
scheme = p.getBulletAutoNumberScheme();
|
||||
if(levelCount.get(level) == 0) {
|
||||
levelCount.set(level, startAt == 0 ? 1 : startAt);
|
||||
}
|
||||
// indent appropriately for the level
|
||||
for(int j = 0; j < level; j++){
|
||||
out.append('\t');
|
||||
}
|
||||
if (p.getText().length() > 0){
|
||||
out.append(getBulletPrefix(scheme, levelCount.get(level)));
|
||||
out.append(p.getText());
|
||||
}
|
||||
while(true) {
|
||||
nextp = (index + 1) == _paragraphs.size() ? null : _paragraphs.get(index + 1);
|
||||
if(nextp == null) break; // out of paragraphs
|
||||
if(!(nextp.isBullet() && p.isBulletAutoNumber())) break; // not an auto-number bullet
|
||||
if(nextp.getLevel() > level) {
|
||||
// recurse into the new level group
|
||||
if (out.length() > 0) out.append('\n');
|
||||
index = processAutoNumGroup(index + 1, nextp.getLevel(), levelCount, out);
|
||||
continue; // restart the loop given the new index
|
||||
} else if(nextp.getLevel() < level) {
|
||||
break; // changed level
|
||||
}
|
||||
nextScheme = nextp.getBulletAutoNumberScheme();
|
||||
nextStartAt = nextp.getBulletAutoNumberStart();
|
||||
|
||||
if(nextScheme == scheme && nextStartAt == startAt) {
|
||||
// bullet is valid, so increment i
|
||||
++index;
|
||||
if (out.length() > 0) out.append('\n');
|
||||
// indent for the level
|
||||
for(int j = 0; j < level; j++){
|
||||
out.append('\t');
|
||||
}
|
||||
// check for empty text - only output a bullet if there is text, but it is still part of the group
|
||||
if(nextp.getText().length() > 0) {
|
||||
// increment the count for this level
|
||||
levelCount.set(level, levelCount.get(level) + 1);
|
||||
out.append(getBulletPrefix(nextScheme, levelCount.get(level)));
|
||||
out.append(nextp.getText());
|
||||
}
|
||||
} else {
|
||||
// something doesn't match so stop
|
||||
break;
|
||||
}
|
||||
}
|
||||
// end of the group so reset the count for this level
|
||||
levelCount.set(level, 0);
|
||||
|
||||
return index;
|
||||
}
|
||||
/**
|
||||
* Returns a string containing an appropriate prefix for an auto-numbering bullet
|
||||
* @param scheme the auto-numbering scheme used by the bullet
|
||||
* @param value the value of the bullet
|
||||
* @return
|
||||
*/
|
||||
private String getBulletPrefix(ListAutoNumber scheme, int value){
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
switch(scheme) {
|
||||
case ALPHA_LC_PARENT_BOTH:
|
||||
case ALPHA_LC_PARENT_R:
|
||||
if(scheme == ListAutoNumber.ALPHA_LC_PARENT_BOTH) out.append('(');
|
||||
out.append(valueToAlpha(value).toLowerCase());
|
||||
out.append(')');
|
||||
break;
|
||||
case ALPHA_UC_PARENT_BOTH:
|
||||
case ALPHA_UC_PARENT_R:
|
||||
if(scheme == ListAutoNumber.ALPHA_UC_PARENT_BOTH) out.append('(');
|
||||
out.append(valueToAlpha(value));
|
||||
out.append(')');
|
||||
break;
|
||||
case ALPHA_LC_PERIOD:
|
||||
out.append(valueToAlpha(value).toLowerCase());
|
||||
out.append('.');
|
||||
break;
|
||||
case ALPHA_UC_PERIOD:
|
||||
out.append(valueToAlpha(value));
|
||||
out.append('.');
|
||||
break;
|
||||
case ARABIC_PARENT_BOTH:
|
||||
case ARABIC_PARENT_R:
|
||||
if(scheme == ListAutoNumber.ARABIC_PARENT_BOTH) out.append('(');
|
||||
out.append(value);
|
||||
out.append(')');
|
||||
break;
|
||||
case ARABIC_PERIOD:
|
||||
out.append(value);
|
||||
out.append('.');
|
||||
break;
|
||||
case ARABIC_PLAIN:
|
||||
out.append(value);
|
||||
break;
|
||||
case ROMAN_LC_PARENT_BOTH:
|
||||
case ROMAN_LC_PARENT_R:
|
||||
if(scheme == ListAutoNumber.ROMAN_LC_PARENT_BOTH) out.append('(');
|
||||
out.append(valueToRoman(value).toLowerCase());
|
||||
out.append(')');
|
||||
break;
|
||||
case ROMAN_UC_PARENT_BOTH:
|
||||
case ROMAN_UC_PARENT_R:
|
||||
if(scheme == ListAutoNumber.ROMAN_UC_PARENT_BOTH) out.append('(');
|
||||
out.append(valueToRoman(value));
|
||||
out.append(')');
|
||||
break;
|
||||
case ROMAN_LC_PERIOD:
|
||||
out.append(valueToRoman(value).toLowerCase());
|
||||
out.append('.');
|
||||
break;
|
||||
case ROMAN_UC_PERIOD:
|
||||
out.append(valueToRoman(value));
|
||||
out.append('.');
|
||||
break;
|
||||
default:
|
||||
out.append('\u2022'); // can't set the font to wingdings so use the default bullet character
|
||||
break;
|
||||
}
|
||||
out.append(" ");
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an integer to its alpha equivalent e.g. 1 = A, 2 = B, 27 = AA etc
|
||||
*/
|
||||
private String valueToAlpha(int value) {
|
||||
String alpha = "";
|
||||
int modulo;
|
||||
while (value > 0) {
|
||||
modulo = (value - 1) % 26;
|
||||
alpha = (char)(65 + modulo) + alpha;
|
||||
value = (int)((value - modulo) / 26);
|
||||
}
|
||||
return alpha;
|
||||
}
|
||||
|
||||
private static String[] _romanChars = new String[] { "M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I" };
|
||||
private static int[] _romanAlphaValues = new int[] { 1000,900,500,400,100,90,50,40,10,9,5,4,1 };
|
||||
|
||||
/**
|
||||
* Convert an integer to its roman equivalent e.g. 1 = I, 9 = IX etc
|
||||
*/
|
||||
private String valueToRoman(int value) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
for(int i = 0; value > 0 && i < _romanChars.length; i++) {
|
||||
while(_romanAlphaValues[i] <= value) {
|
||||
out.append(_romanChars[i]);
|
||||
value -= _romanAlphaValues[i];
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all text from this shape
|
||||
*/
|
||||
public void clearText(){
|
||||
_paragraphs.clear();
|
||||
CTTextBody txBody = ctShape.getTxBody();
|
||||
txBody.setPArray(null); // remove any existing paragraphs
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single paragraph of text on the shape. Note this will replace all existing paragraphs created on the shape.
|
||||
* @param text string representing the paragraph text
|
||||
*/
|
||||
public void setText(String text){
|
||||
clearText();
|
||||
|
||||
addNewTextParagraph().addNewTextRun().setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single paragraph of text on the shape. Note this will replace all existing paragraphs created on the shape.
|
||||
* @param str rich text string representing the paragraph text
|
||||
*/
|
||||
public void setText(XSSFRichTextString str){
|
||||
|
||||
XSSFWorkbook wb = (XSSFWorkbook)getDrawing().getParent().getParent();
|
||||
@ -166,12 +393,426 @@ public class XSSFSimpleShape extends XSSFShape { // TODO - instantiable supercla
|
||||
r.setT(lt.getT());
|
||||
}
|
||||
}
|
||||
|
||||
clearText();
|
||||
ctShape.getTxBody().setPArray(new CTTextParagraph[]{p});
|
||||
_paragraphs.add(new XSSFTextParagraph(ctShape.getTxBody().getPArray(0), ctShape));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of the XSSFTextParagraphs that are attached to this shape
|
||||
*
|
||||
* @return text paragraphs in this shape
|
||||
*/
|
||||
public List<XSSFTextParagraph> getTextParagraphs() {
|
||||
return _paragraphs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new paragraph run to this shape
|
||||
*
|
||||
* @return created paragraph run
|
||||
*/
|
||||
public XSSFTextParagraph addNewTextParagraph() {
|
||||
CTTextBody txBody = ctShape.getTxBody();
|
||||
CTTextParagraph p = txBody.addNewP();
|
||||
XSSFTextParagraph paragraph = new XSSFTextParagraph(p, ctShape);
|
||||
_paragraphs.add(paragraph);
|
||||
return paragraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new paragraph run to this shape, set to the provided string
|
||||
*
|
||||
* @return created paragraph run
|
||||
*/
|
||||
public XSSFTextParagraph addNewTextParagraph(String text) {
|
||||
XSSFTextParagraph paragraph = addNewTextParagraph();
|
||||
paragraph.addNewTextRun().setText(text);
|
||||
return paragraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new paragraph run to this shape, set to the provided rich text string
|
||||
*
|
||||
* @return created paragraph run
|
||||
*/
|
||||
public XSSFTextParagraph addNewTextParagraph(XSSFRichTextString str) {
|
||||
CTTextBody txBody = ctShape.getTxBody();
|
||||
CTTextParagraph p = txBody.addNewP();
|
||||
|
||||
if(str.numFormattingRuns() == 0){
|
||||
CTRegularTextRun r = p.addNewR();
|
||||
CTTextCharacterProperties rPr = r.addNewRPr();
|
||||
rPr.setLang("en-US");
|
||||
rPr.setSz(1100);
|
||||
r.setT(str.getString());
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) {
|
||||
CTRElt lt = str.getCTRst().getRArray(i);
|
||||
CTRPrElt ltPr = lt.getRPr();
|
||||
if(ltPr == null) ltPr = lt.addNewRPr();
|
||||
|
||||
CTRegularTextRun r = p.addNewR();
|
||||
CTTextCharacterProperties rPr = r.addNewRPr();
|
||||
rPr.setLang("en-US");
|
||||
|
||||
applyAttributes(ltPr, rPr);
|
||||
|
||||
r.setT(lt.getT());
|
||||
}
|
||||
}
|
||||
|
||||
// Note: the XSSFTextParagraph constructor will create its required XSSFTextRuns from the provided CTTextParagraph
|
||||
XSSFTextParagraph paragraph = new XSSFTextParagraph(p, ctShape);
|
||||
_paragraphs.add(paragraph);
|
||||
|
||||
return paragraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of horizontal overflow for the text.
|
||||
*
|
||||
* @param overflow - the type of horizontal overflow.
|
||||
* A <code>null</code> values unsets this property.
|
||||
*/
|
||||
public void setTextHorizontalOverflow(TextHorizontalOverflow overflow){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(anchor == null) {
|
||||
if(bodyPr.isSetHorzOverflow()) bodyPr.unsetHorzOverflow();
|
||||
} else {
|
||||
bodyPr.setHorzOverflow(STTextHorzOverflowType.Enum.forInt(overflow.ordinal() + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of horizontal overflow for the text.
|
||||
*
|
||||
* @return the type of horizontal overflow
|
||||
*/
|
||||
public TextHorizontalOverflow getTextHorizontalOverflow(){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if(bodyPr != null) {
|
||||
if(bodyPr.isSetHorzOverflow()){
|
||||
return TextHorizontalOverflow.values()[bodyPr.getVertOverflow().intValue() - 1];
|
||||
}
|
||||
}
|
||||
return TextHorizontalOverflow.OVERFLOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of vertical overflow for the text.
|
||||
*
|
||||
* @param overflow - the type of vertical overflow.
|
||||
* A <code>null</code> values unsets this property.
|
||||
*/
|
||||
public void setTextVerticalOverflow(TextVerticalOverflow overflow){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(anchor == null) {
|
||||
if(bodyPr.isSetVertOverflow()) bodyPr.unsetVertOverflow();
|
||||
} else {
|
||||
bodyPr.setVertOverflow(STTextVertOverflowType.Enum.forInt(overflow.ordinal() + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of vertical overflow for the text.
|
||||
*
|
||||
* @return the type of vertical overflow
|
||||
*/
|
||||
public TextVerticalOverflow getTextVerticalOverflow(){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if(bodyPr != null) {
|
||||
if(bodyPr.isSetVertOverflow()){
|
||||
return TextVerticalOverflow.values()[bodyPr.getVertOverflow().intValue() - 1];
|
||||
}
|
||||
}
|
||||
return TextVerticalOverflow.OVERFLOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of vertical alignment for the text within the shape.
|
||||
*
|
||||
* @param anchor - the type of alignment.
|
||||
* A <code>null</code> values unsets this property.
|
||||
*/
|
||||
public void setVerticalAlignment(VerticalAlignment anchor){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(anchor == null) {
|
||||
if(bodyPr.isSetAnchor()) bodyPr.unsetAnchor();
|
||||
} else {
|
||||
bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of vertical alignment for the text within the shape.
|
||||
*
|
||||
* @return the type of vertical alignment
|
||||
*/
|
||||
public VerticalAlignment getVerticalAlignment(){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if(bodyPr != null) {
|
||||
if(bodyPr.isSetAnchor()){
|
||||
return VerticalAlignment.values()[bodyPr.getAnchor().intValue() - 1];
|
||||
}
|
||||
}
|
||||
return VerticalAlignment.TOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the vertical orientation of the text
|
||||
*
|
||||
* @param orientation vertical orientation of the text
|
||||
* A <code>null</code> values unsets this property.
|
||||
*/
|
||||
public void setTextDirection(TextDirection orientation){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(orientation == null) {
|
||||
if(bodyPr.isSetVert()) bodyPr.unsetVert();
|
||||
} else {
|
||||
bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the vertical orientation of the text
|
||||
*
|
||||
* @return vertical orientation of the text
|
||||
*/
|
||||
public TextDirection getTextDirection(){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
STTextVerticalType.Enum val = bodyPr.getVert();
|
||||
if(val != null){
|
||||
return TextDirection.values()[val.intValue() - 1];
|
||||
}
|
||||
}
|
||||
return TextDirection.HORIZONTAL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return the bottom inset in points
|
||||
*/
|
||||
public double getBottomInset(){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(bodyPr.isSetBIns()){
|
||||
return Units.toPoints(bodyPr.getBIns());
|
||||
}
|
||||
}
|
||||
// If this attribute is omitted, then a value of 0.05 inches is implied
|
||||
return 3.6;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return the left inset in points
|
||||
*/
|
||||
public double getLeftInset(){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(bodyPr.isSetLIns()){
|
||||
return Units.toPoints(bodyPr.getLIns());
|
||||
}
|
||||
}
|
||||
// If this attribute is omitted, then a value of 0.05 inches is implied
|
||||
return 3.6;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return the right inset in points
|
||||
*/
|
||||
public double getRightInset(){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(bodyPr.isSetRIns()){
|
||||
return Units.toPoints(bodyPr.getRIns());
|
||||
}
|
||||
}
|
||||
// If this attribute is omitted, then a value of 0.05 inches is implied
|
||||
return 3.6;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return the top inset in points
|
||||
*/
|
||||
public double getTopInset(){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(bodyPr.isSetTIns()){
|
||||
return Units.toPoints(bodyPr.getTIns());
|
||||
}
|
||||
}
|
||||
// If this attribute is omitted, then a value of 0.05 inches is implied
|
||||
return 3.6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bottom inset.
|
||||
* @see #getBottomInset()
|
||||
*
|
||||
* @param margin the bottom margin
|
||||
*/
|
||||
public void setBottomInset(double margin){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(margin == -1) bodyPr.unsetBIns();
|
||||
else bodyPr.setBIns(Units.toEMU(margin));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the left inset.
|
||||
* @see #getLeftInset()
|
||||
*
|
||||
* @param margin the left margin
|
||||
*/
|
||||
public void setLeftInset(double margin){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(margin == -1) bodyPr.unsetLIns();
|
||||
else bodyPr.setLIns(Units.toEMU(margin));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the right inset.
|
||||
* @see #getRightInset()
|
||||
*
|
||||
* @param margin the right margin
|
||||
*/
|
||||
public void setRightInset(double margin){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(margin == -1) bodyPr.unsetRIns();
|
||||
else bodyPr.setRIns(Units.toEMU(margin));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the top inset.
|
||||
* @see #getTopInset()
|
||||
*
|
||||
* @param margin the top margin
|
||||
*/
|
||||
public void setTopInset(double margin){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(margin == -1) bodyPr.unsetTIns();
|
||||
else bodyPr.setTIns(Units.toEMU(margin));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return whether to wrap words within the bounding rectangle
|
||||
*/
|
||||
public boolean getWordWrap(){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(bodyPr.isSetWrap()){
|
||||
return bodyPr.getWrap() == STTextWrappingType.SQUARE;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param wrap whether to wrap words within the bounding rectangle
|
||||
*/
|
||||
public void setWordWrap(boolean wrap){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
bodyPr.setWrap(wrap ? STTextWrappingType.SQUARE : STTextWrappingType.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Specifies that a shape should be auto-fit to fully contain the text described within it.
|
||||
* Auto-fitting is when text within a shape is scaled in order to contain all the text inside
|
||||
*
|
||||
* @param value type of autofit
|
||||
*/
|
||||
public void setTextAutofit(TextAutofit value){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(bodyPr.isSetSpAutoFit()) bodyPr.unsetSpAutoFit();
|
||||
if(bodyPr.isSetNoAutofit()) bodyPr.unsetNoAutofit();
|
||||
if(bodyPr.isSetNormAutofit()) bodyPr.unsetNormAutofit();
|
||||
|
||||
switch(value){
|
||||
case NONE: bodyPr.addNewNoAutofit(); break;
|
||||
case NORMAL: bodyPr.addNewNormAutofit(); break;
|
||||
case SHAPE: bodyPr.addNewSpAutoFit(); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return type of autofit
|
||||
*/
|
||||
public TextAutofit getTextAutofit(){
|
||||
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(bodyPr.isSetNoAutofit()) return TextAutofit.NONE;
|
||||
else if (bodyPr.isSetNormAutofit()) return TextAutofit.NORMAL;
|
||||
else if (bodyPr.isSetSpAutoFit()) return TextAutofit.SHAPE;
|
||||
}
|
||||
return TextAutofit.NORMAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
|
||||
*
|
||||
* @return the shape type
|
||||
* @see org.apache.poi.ss.usermodel.ShapeTypes
|
||||
*/
|
||||
public int getShapeType() {
|
||||
return ctShape.getSpPr().getPrstGeom().getPrst().intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the shape types.
|
||||
*
|
||||
* @param type the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
|
||||
* @see org.apache.poi.ss.usermodel.ShapeTypes
|
||||
*/
|
||||
public void setShapeType(int type) {
|
||||
ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type));
|
||||
}
|
||||
|
||||
protected CTShapeProperties getShapeProperties(){
|
||||
return ctShape.getSpPr();
|
||||
}
|
||||
|
||||
/**
|
||||
* org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRPrElt to
|
||||
* org.openxmlformats.schemas.drawingml.x2006.main.CTFont adapter
|
||||
*/
|
||||
@ -186,8 +827,8 @@ public class XSSFSimpleShape extends XSSFShape { // TODO - instantiable supercla
|
||||
}
|
||||
if(pr.sizeOfIArray() > 0) rPr.setI(pr.getIArray(0).getVal());
|
||||
|
||||
if(pr.sizeOfFamilyArray() > 0) {
|
||||
CTTextFont rFont = rPr.addNewLatin();
|
||||
if(pr.sizeOfRFontArray() > 0) {
|
||||
CTTextFont rFont = rPr.isSetLatin() ? rPr.getLatin() : rPr.addNewLatin();
|
||||
rFont.setTypeface(pr.getRFontArray(0).getVal());
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,10 @@
|
||||
package org.apache.poi.xssf.usermodel;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@ -243,4 +247,426 @@ public class TestXSSFDrawing extends TestCase {
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ensure that font and color rich text attributes defined in a XSSFRichTextString
|
||||
* are passed to XSSFSimpleShape.
|
||||
*
|
||||
* See Bugzilla 54969.
|
||||
*/
|
||||
public void testRichTextFontAndColor() {
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
XSSFSheet sheet = wb.createSheet();
|
||||
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||
|
||||
XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
|
||||
XSSFRichTextString rt = new XSSFRichTextString("Test String");
|
||||
|
||||
XSSFFont font = wb.createFont();
|
||||
font.setColor(new XSSFColor(new Color(0, 128, 128)));
|
||||
font.setFontName("Arial");
|
||||
rt.applyFont(font);
|
||||
|
||||
shape.setText(rt);
|
||||
|
||||
CTTextParagraph pr = shape.getCTShape().getTxBody().getPArray(0);
|
||||
assertEquals(1, pr.sizeOfRArray());
|
||||
|
||||
CTTextCharacterProperties rPr = pr.getRArray(0).getRPr();
|
||||
assertEquals("Arial", rPr.getLatin().getTypeface());
|
||||
assertTrue(Arrays.equals(
|
||||
new byte[]{0, (byte)128, (byte)128} ,
|
||||
rPr.getSolidFill().getSrgbClr().getVal()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setText single paragraph to ensure backwards compatibility
|
||||
*/
|
||||
public void testSetTextSingleParagraph() {
|
||||
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
XSSFSheet sheet = wb.createSheet();
|
||||
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||
|
||||
XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
|
||||
XSSFRichTextString rt = new XSSFRichTextString("Test String");
|
||||
|
||||
XSSFFont font = wb.createFont();
|
||||
font.setColor(new XSSFColor(new Color(0, 255, 255)));
|
||||
font.setFontName("Arial");
|
||||
rt.applyFont(font);
|
||||
|
||||
shape.setText(rt);
|
||||
|
||||
List<XSSFTextParagraph> paras = shape.getTextParagraphs();
|
||||
assertEquals(1, paras.size());
|
||||
assertEquals("Test String", paras.get(0).getText());
|
||||
|
||||
List<XSSFTextRun> runs = paras.get(0).getTextRuns();
|
||||
assertEquals(1, runs.size());
|
||||
assertEquals("Arial", runs.get(0).getFontFamily());
|
||||
|
||||
Color clr = runs.get(0).getFontColor();
|
||||
assertTrue(Arrays.equals(
|
||||
new int[] { 0, 255, 255 } ,
|
||||
new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test addNewTextParagraph
|
||||
*/
|
||||
public void testAddNewTextParagraph() {
|
||||
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
XSSFSheet sheet = wb.createSheet();
|
||||
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||
|
||||
XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
|
||||
|
||||
XSSFTextParagraph para = shape.addNewTextParagraph();
|
||||
para.addNewTextRun().setText("Line 1");
|
||||
|
||||
List<XSSFTextParagraph> paras = shape.getTextParagraphs();
|
||||
assertEquals(2, paras.size()); // this should be 2 as XSSFSimpleShape creates a default paragraph (no text), and then we add a string to that.
|
||||
|
||||
List<XSSFTextRun> runs = para.getTextRuns();
|
||||
assertEquals(1, runs.size());
|
||||
assertEquals("Line 1", runs.get(0).getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test addNewTextParagraph using RichTextString
|
||||
*/
|
||||
public void testAddNewTextParagraphWithRTS() {
|
||||
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
XSSFSheet sheet = wb.createSheet();
|
||||
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||
|
||||
XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
|
||||
XSSFRichTextString rt = new XSSFRichTextString("Test Rich Text String");
|
||||
|
||||
XSSFFont font = wb.createFont();
|
||||
font.setColor(new XSSFColor(new Color(0, 255, 255)));
|
||||
font.setFontName("Arial");
|
||||
rt.applyFont(font);
|
||||
|
||||
XSSFFont midfont = wb.createFont();
|
||||
midfont.setColor(new XSSFColor(new Color(0, 255, 0)));
|
||||
rt.applyFont(5, 14, midfont); // set the text "Rich Text" to be green and the default font
|
||||
|
||||
XSSFTextParagraph para = shape.addNewTextParagraph(rt);
|
||||
|
||||
// Save and re-load it
|
||||
wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||
sheet = wb.getSheetAt(0);
|
||||
|
||||
// Check
|
||||
drawing = sheet.createDrawingPatriarch();
|
||||
|
||||
List<XSSFShape> shapes = drawing.getShapes();
|
||||
assertEquals(1, shapes.size());
|
||||
assertTrue(shapes.get(0) instanceof XSSFSimpleShape);
|
||||
|
||||
XSSFSimpleShape sshape = (XSSFSimpleShape) shapes.get(0);
|
||||
|
||||
List<XSSFTextParagraph> paras = sshape.getTextParagraphs();
|
||||
assertEquals(2, paras.size()); // this should be 2 as XSSFSimpleShape creates a default paragraph (no text), and then we add a string to that.
|
||||
|
||||
List<XSSFTextRun> runs = para.getTextRuns();
|
||||
assertEquals(3, runs.size());
|
||||
|
||||
// first run properties
|
||||
assertEquals("Test ", runs.get(0).getText());
|
||||
assertEquals("Arial", runs.get(0).getFontFamily());
|
||||
|
||||
Color clr = runs.get(0).getFontColor();
|
||||
assertTrue(Arrays.equals(
|
||||
new int[] { 0, 255, 255 } ,
|
||||
new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
|
||||
|
||||
// second run properties
|
||||
assertEquals("Rich Text", runs.get(1).getText());
|
||||
assertEquals(XSSFFont.DEFAULT_FONT_NAME, runs.get(1).getFontFamily());
|
||||
|
||||
clr = runs.get(1).getFontColor();
|
||||
assertTrue(Arrays.equals(
|
||||
new int[] { 0, 255, 0 } ,
|
||||
new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
|
||||
|
||||
// third run properties
|
||||
assertEquals(" String", runs.get(2).getText());
|
||||
assertEquals("Arial", runs.get(2).getFontFamily());
|
||||
clr = runs.get(2).getFontColor();
|
||||
assertTrue(Arrays.equals(
|
||||
new int[] { 0, 255, 255 } ,
|
||||
new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test add multiple paragraphs and retrieve text
|
||||
*/
|
||||
public void testAddMultipleParagraphs() {
|
||||
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
XSSFSheet sheet = wb.createSheet();
|
||||
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||
|
||||
XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
|
||||
|
||||
XSSFTextParagraph para = shape.addNewTextParagraph();
|
||||
para.addNewTextRun().setText("Line 1");
|
||||
|
||||
para = shape.addNewTextParagraph();
|
||||
para.addNewTextRun().setText("Line 2");
|
||||
|
||||
para = shape.addNewTextParagraph();
|
||||
para.addNewTextRun().setText("Line 3");
|
||||
|
||||
List<XSSFTextParagraph> paras = shape.getTextParagraphs();
|
||||
assertEquals(4, paras.size()); // this should be 4 as XSSFSimpleShape creates a default paragraph (no text), and then we added 3 paragraphs
|
||||
assertEquals("Line 1\nLine 2\nLine 3", shape.getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting the text, then adding multiple paragraphs and retrieve text
|
||||
*/
|
||||
public void testSetAddMultipleParagraphs() {
|
||||
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
XSSFSheet sheet = wb.createSheet();
|
||||
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||
|
||||
XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
|
||||
|
||||
shape.setText("Line 1");
|
||||
|
||||
XSSFTextParagraph para = shape.addNewTextParagraph();
|
||||
para.addNewTextRun().setText("Line 2");
|
||||
|
||||
para = shape.addNewTextParagraph();
|
||||
para.addNewTextRun().setText("Line 3");
|
||||
|
||||
List<XSSFTextParagraph> paras = shape.getTextParagraphs();
|
||||
assertEquals(3, paras.size()); // this should be 3 as we overwrote the default paragraph with setText, then added 2 new paragraphs
|
||||
assertEquals("Line 1\nLine 2\nLine 3", shape.getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test reading text from a textbox in an existing file
|
||||
*/
|
||||
public void testReadTextBox(){
|
||||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithDrawing.xlsx");
|
||||
XSSFSheet sheet = wb.getSheetAt(0);
|
||||
//the sheet has one relationship and it is XSSFDrawing
|
||||
List<POIXMLDocumentPart> rels = sheet.getRelations();
|
||||
assertEquals(1, rels.size());
|
||||
assertTrue(rels.get(0) instanceof XSSFDrawing);
|
||||
|
||||
XSSFDrawing drawing = (XSSFDrawing)rels.get(0);
|
||||
//sheet.createDrawingPatriarch() should return the same instance of XSSFDrawing
|
||||
assertSame(drawing, sheet.createDrawingPatriarch());
|
||||
String drawingId = drawing.getPackageRelationship().getId();
|
||||
|
||||
//there should be a relation to this drawing in the worksheet
|
||||
assertTrue(sheet.getCTWorksheet().isSetDrawing());
|
||||
assertEquals(drawingId, sheet.getCTWorksheet().getDrawing().getId());
|
||||
|
||||
List<XSSFShape> shapes = drawing.getShapes();
|
||||
assertEquals(6, shapes.size());
|
||||
|
||||
assertTrue(shapes.get(4) instanceof XSSFSimpleShape);
|
||||
|
||||
XSSFSimpleShape textbox = (XSSFSimpleShape) shapes.get(4);
|
||||
assertEquals("Sheet with various pictures\n(jpeg, png, wmf, emf and pict)", textbox.getText());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test reading multiple paragraphs from a textbox in an existing file
|
||||
*/
|
||||
public void testReadTextBoxParagraphs(){
|
||||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithTextBox.xlsx");
|
||||
XSSFSheet sheet = wb.getSheetAt(0);
|
||||
//the sheet has one relationship and it is XSSFDrawing
|
||||
List<POIXMLDocumentPart> rels = sheet.getRelations();
|
||||
assertEquals(1, rels.size());
|
||||
|
||||
assertTrue(rels.get(0) instanceof XSSFDrawing);
|
||||
|
||||
XSSFDrawing drawing = (XSSFDrawing)rels.get(0);
|
||||
|
||||
//sheet.createDrawingPatriarch() should return the same instance of XSSFDrawing
|
||||
assertSame(drawing, sheet.createDrawingPatriarch());
|
||||
String drawingId = drawing.getPackageRelationship().getId();
|
||||
|
||||
//there should be a relation to this drawing in the worksheet
|
||||
assertTrue(sheet.getCTWorksheet().isSetDrawing());
|
||||
assertEquals(drawingId, sheet.getCTWorksheet().getDrawing().getId());
|
||||
|
||||
List<XSSFShape> shapes = drawing.getShapes();
|
||||
assertEquals(1, shapes.size());
|
||||
|
||||
assertTrue(shapes.get(0) instanceof XSSFSimpleShape);
|
||||
|
||||
XSSFSimpleShape textbox = (XSSFSimpleShape) shapes.get(0);
|
||||
|
||||
List<XSSFTextParagraph> paras = textbox.getTextParagraphs();
|
||||
assertEquals(3, paras.size());
|
||||
|
||||
assertEquals("Line 2", paras.get(1).getText()); // check content of second paragraph
|
||||
|
||||
assertEquals("Line 1\nLine 2\nLine 3", textbox.getText()); // check content of entire textbox
|
||||
|
||||
// check attributes of paragraphs
|
||||
assertEquals(TextAlign.LEFT, paras.get(0).getTextAlign());
|
||||
assertEquals(TextAlign.CENTER, paras.get(1).getTextAlign());
|
||||
assertEquals(TextAlign.RIGHT, paras.get(2).getTextAlign());
|
||||
|
||||
Color clr = paras.get(0).getTextRuns().get(0).getFontColor();
|
||||
assertTrue(Arrays.equals(
|
||||
new int[] { 255, 0, 0 } ,
|
||||
new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
|
||||
|
||||
clr = paras.get(1).getTextRuns().get(0).getFontColor();
|
||||
assertTrue(Arrays.equals(
|
||||
new int[] { 0, 255, 0 } ,
|
||||
new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
|
||||
|
||||
clr = paras.get(2).getTextRuns().get(0).getFontColor();
|
||||
assertTrue(Arrays.equals(
|
||||
new int[] { 0, 0, 255 } ,
|
||||
new int[] { clr.getRed(), clr.getGreen(), clr.getBlue() }));
|
||||
}
|
||||
/**
|
||||
* Test adding and reading back paragraphs as bullet points
|
||||
*/
|
||||
public void testAddBulletParagraphs() {
|
||||
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
XSSFSheet sheet = wb.createSheet();
|
||||
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||
|
||||
XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 10, 20));
|
||||
|
||||
String paraString1 = "A normal paragraph";
|
||||
String paraString2 = "First bullet";
|
||||
String paraString3 = "Second bullet (level 1)";
|
||||
String paraString4 = "Third bullet";
|
||||
String paraString5 = "Another normal paragraph";
|
||||
String paraString6 = "First numbered bullet";
|
||||
String paraString7 = "Second bullet (level 1)";
|
||||
String paraString8 = "Third bullet (level 1)";
|
||||
String paraString9 = "Fourth bullet (level 1)";
|
||||
String paraString10 = "Fifth Bullet";
|
||||
|
||||
XSSFTextParagraph para = shape.addNewTextParagraph(paraString1);
|
||||
para = shape.addNewTextParagraph(paraString2);
|
||||
para.setBullet(true);
|
||||
|
||||
para = shape.addNewTextParagraph(paraString3);
|
||||
para.setBullet(true);
|
||||
para.setLevel(1);
|
||||
|
||||
para = shape.addNewTextParagraph(paraString4);
|
||||
para.setBullet(true);
|
||||
|
||||
para = shape.addNewTextParagraph(paraString5);
|
||||
para = shape.addNewTextParagraph(paraString6);
|
||||
para.setBullet(ListAutoNumber.ARABIC_PERIOD);
|
||||
|
||||
para = shape.addNewTextParagraph(paraString7);
|
||||
para.setBullet(ListAutoNumber.ARABIC_PERIOD, 3);
|
||||
para.setLevel(1);
|
||||
|
||||
para = shape.addNewTextParagraph(paraString8);
|
||||
para.setBullet(ListAutoNumber.ARABIC_PERIOD, 3);
|
||||
para.setLevel(1);
|
||||
|
||||
para = shape.addNewTextParagraph("");
|
||||
para.setBullet(ListAutoNumber.ARABIC_PERIOD, 3);
|
||||
para.setLevel(1);
|
||||
|
||||
para = shape.addNewTextParagraph(paraString9);
|
||||
para.setBullet(ListAutoNumber.ARABIC_PERIOD, 3);
|
||||
para.setLevel(1);
|
||||
|
||||
para = shape.addNewTextParagraph(paraString10);
|
||||
para.setBullet(ListAutoNumber.ARABIC_PERIOD);
|
||||
|
||||
// Save and re-load it
|
||||
wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||
sheet = wb.getSheetAt(0);
|
||||
|
||||
// Check
|
||||
drawing = sheet.createDrawingPatriarch();
|
||||
|
||||
List<XSSFShape> shapes = drawing.getShapes();
|
||||
assertEquals(1, shapes.size());
|
||||
assertTrue(shapes.get(0) instanceof XSSFSimpleShape);
|
||||
|
||||
XSSFSimpleShape sshape = (XSSFSimpleShape) shapes.get(0);
|
||||
|
||||
List<XSSFTextParagraph> paras = sshape.getTextParagraphs();
|
||||
assertEquals(12, paras.size()); // this should be 12 as XSSFSimpleShape creates a default paragraph (no text), and then we added to that
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append(paraString1);
|
||||
builder.append("\n");
|
||||
builder.append("\u2022 ");
|
||||
builder.append(paraString2);
|
||||
builder.append("\n");
|
||||
builder.append("\t\u2022 ");
|
||||
builder.append(paraString3);
|
||||
builder.append("\n");
|
||||
builder.append("\u2022 ");
|
||||
builder.append(paraString4);
|
||||
builder.append("\n");
|
||||
builder.append(paraString5);
|
||||
builder.append("\n");
|
||||
builder.append("1. ");
|
||||
builder.append(paraString6);
|
||||
builder.append("\n");
|
||||
builder.append("\t3. ");
|
||||
builder.append(paraString7);
|
||||
builder.append("\n");
|
||||
builder.append("\t4. ");
|
||||
builder.append(paraString8);
|
||||
builder.append("\n");
|
||||
builder.append("\t"); // should be empty
|
||||
builder.append("\n");
|
||||
builder.append("\t5. ");
|
||||
builder.append(paraString9);
|
||||
builder.append("\n");
|
||||
builder.append("2. ");
|
||||
builder.append(paraString10);
|
||||
|
||||
assertEquals(builder.toString(), sshape.getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test reading bullet numbering from a textbox in an existing file
|
||||
*/
|
||||
public void testReadTextBox2(){
|
||||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithTextBox2.xlsx");
|
||||
XSSFSheet sheet = wb.getSheetAt(0);
|
||||
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||
List<XSSFShape> shapes = drawing.getShapes();
|
||||
XSSFSimpleShape textbox = (XSSFSimpleShape) shapes.get(0);
|
||||
String extracted = textbox.getText();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("1. content1A\n");
|
||||
sb.append("\t1. content1B\n");
|
||||
sb.append("\t2. content2B\n");
|
||||
sb.append("\t3. content3B\n");
|
||||
sb.append("2. content2A\n");
|
||||
sb.append("\t3. content2BStartAt3\n");
|
||||
sb.append("\t\n\t\n\t");
|
||||
sb.append("4. content2BStartAt3Incremented\n");
|
||||
sb.append("\t\n\t\n\t\n\t");
|
||||
|
||||
assertEquals(sb.toString(), extracted);
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
BIN
test-data/spreadsheet/WithTextBox2.xlsx
Normal file
BIN
test-data/spreadsheet/WithTextBox2.xlsx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user