|
|
@@ -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; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public Iterator<XSSFTextParagraph> iterator(){ |
|
|
|
return _paragraphs.iterator(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 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 |
|
|
|
* 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 int getShapeType() { |
|
|
|
return ctShape.getSpPr().getPrstGeom().getPrst().intValue(); |
|
|
|
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(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 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)); |
|
|
|
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(); |
|
|
|
|
|
|
|
protected CTShapeProperties getShapeProperties(){ |
|
|
|
return ctShape.getSpPr(); |
|
|
|
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()); |
|
|
|
} |
|
|
|
|