git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1746856 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_15_BETA2
defaultFactory.set(factory); | defaultFactory.set(factory); | ||||
} | } | ||||
/** | |||||
* Returns the DrawFactory, preferably via a graphics instance. | |||||
* If graphics is null, the current thread local is checked or | |||||
* if it is not set, a new factory is created. | |||||
* | |||||
* @param graphics the current graphics context or null | |||||
* @return the draw factory | |||||
*/ | |||||
public static DrawFactory getInstance(Graphics2D graphics) { | public static DrawFactory getInstance(Graphics2D graphics) { | ||||
// first try to find the factory over the rendering hint | // first try to find the factory over the rendering hint | ||||
DrawFactory factory = null; | DrawFactory factory = null; |
package org.apache.poi.sl.draw; | package org.apache.poi.sl.draw; | ||||
import java.awt.BasicStroke; | |||||
import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||
import java.awt.geom.AffineTransform; | import java.awt.geom.AffineTransform; | ||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
import org.apache.poi.sl.usermodel.PlaceableShape; | import org.apache.poi.sl.usermodel.PlaceableShape; | ||||
import org.apache.poi.sl.usermodel.Shape; | import org.apache.poi.sl.usermodel.Shape; | ||||
import org.apache.poi.sl.usermodel.StrokeStyle; | |||||
import org.apache.poi.sl.usermodel.StrokeStyle.LineCap; | |||||
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; | |||||
public class DrawShape implements Drawable { | public class DrawShape implements Drawable { | ||||
protected Shape<?,?> getShape() { | protected Shape<?,?> getShape() { | ||||
return shape; | return shape; | ||||
} | } | ||||
protected static BasicStroke getStroke(StrokeStyle strokeStyle) { | |||||
float lineWidth = (float) strokeStyle.getLineWidth(); | |||||
if (lineWidth == 0.0f) lineWidth = 0.25f; // Both PowerPoint and OOo draw zero-length lines as 0.25pt | |||||
LineDash lineDash = strokeStyle.getLineDash(); | |||||
if (lineDash == null) { | |||||
lineDash = LineDash.SOLID; | |||||
} | |||||
int dashPatI[] = lineDash.pattern; | |||||
final float dash_phase = 0; | |||||
float[] dashPatF = null; | |||||
if (dashPatI != null) { | |||||
dashPatF = new float[dashPatI.length]; | |||||
for (int i=0; i<dashPatI.length; i++) { | |||||
dashPatF[i] = dashPatI[i]*Math.max(1, lineWidth); | |||||
} | |||||
} | |||||
LineCap lineCapE = strokeStyle.getLineCap(); | |||||
if (lineCapE == null) lineCapE = LineCap.FLAT; | |||||
int lineCap; | |||||
switch (lineCapE) { | |||||
case ROUND: | |||||
lineCap = BasicStroke.CAP_ROUND; | |||||
break; | |||||
case SQUARE: | |||||
lineCap = BasicStroke.CAP_SQUARE; | |||||
break; | |||||
default: | |||||
case FLAT: | |||||
lineCap = BasicStroke.CAP_BUTT; | |||||
break; | |||||
} | |||||
int lineJoin = BasicStroke.JOIN_ROUND; | |||||
return new BasicStroke(lineWidth, lineCap, lineJoin, lineWidth, dashPatF, dash_phase); | |||||
} | |||||
} | } |
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; | import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; | ||||
import org.apache.poi.sl.usermodel.Shadow; | import org.apache.poi.sl.usermodel.Shadow; | ||||
import org.apache.poi.sl.usermodel.SimpleShape; | import org.apache.poi.sl.usermodel.SimpleShape; | ||||
import org.apache.poi.sl.usermodel.StrokeStyle; | |||||
import org.apache.poi.sl.usermodel.StrokeStyle.LineCap; | |||||
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; | |||||
import org.apache.poi.util.Units; | import org.apache.poi.util.Units; | ||||
} | } | ||||
public BasicStroke getStroke() { | public BasicStroke getStroke() { | ||||
StrokeStyle strokeStyle = getShape().getStrokeStyle(); | |||||
float lineWidth = (float) strokeStyle.getLineWidth(); | |||||
if (lineWidth == 0.0f) lineWidth = 0.25f; // Both PowerPoint and OOo draw zero-length lines as 0.25pt | |||||
LineDash lineDash = strokeStyle.getLineDash(); | |||||
if (lineDash == null) { | |||||
lineDash = LineDash.SOLID; | |||||
} | |||||
int dashPatI[] = lineDash.pattern; | |||||
final float dash_phase = 0; | |||||
float[] dashPatF = null; | |||||
if (dashPatI != null) { | |||||
dashPatF = new float[dashPatI.length]; | |||||
for (int i=0; i<dashPatI.length; i++) { | |||||
dashPatF[i] = dashPatI[i]*Math.max(1, lineWidth); | |||||
} | |||||
} | |||||
LineCap lineCapE = strokeStyle.getLineCap(); | |||||
if (lineCapE == null) lineCapE = LineCap.FLAT; | |||||
int lineCap; | |||||
switch (lineCapE) { | |||||
case ROUND: | |||||
lineCap = BasicStroke.CAP_ROUND; | |||||
break; | |||||
case SQUARE: | |||||
lineCap = BasicStroke.CAP_SQUARE; | |||||
break; | |||||
default: | |||||
case FLAT: | |||||
lineCap = BasicStroke.CAP_BUTT; | |||||
break; | |||||
} | |||||
int lineJoin = BasicStroke.JOIN_ROUND; | |||||
return new BasicStroke(lineWidth, lineCap, lineJoin, lineWidth, dashPatF, dash_phase); | |||||
return getStroke(getShape().getStrokeStyle()); | |||||
} | } | ||||
protected void drawShadow( | protected void drawShadow( |
import java.awt.Color; | import java.awt.Color; | ||||
import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||
import java.awt.Paint; | |||||
import java.awt.geom.Line2D; | |||||
import java.awt.geom.Rectangle2D; | |||||
import org.apache.poi.sl.usermodel.GroupShape; | import org.apache.poi.sl.usermodel.GroupShape; | ||||
import org.apache.poi.sl.usermodel.StrokeStyle; | |||||
import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound; | import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound; | ||||
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; | import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; | ||||
import org.apache.poi.sl.usermodel.TableCell; | import org.apache.poi.sl.usermodel.TableCell; | ||||
import org.apache.poi.sl.usermodel.TableCell.BorderEdge; | import org.apache.poi.sl.usermodel.TableCell.BorderEdge; | ||||
import org.apache.poi.util.Internal; | |||||
import org.apache.poi.sl.usermodel.TableShape; | import org.apache.poi.sl.usermodel.TableShape; | ||||
public class DrawTableShape extends DrawShape { | public class DrawTableShape extends DrawShape { | ||||
// to be implemented ... | |||||
/** | |||||
* Additional spacing between cells | |||||
*/ | |||||
@Internal | |||||
public static final int borderSize = 2; | |||||
public DrawTableShape(TableShape<?,?> shape) { | public DrawTableShape(TableShape<?,?> shape) { | ||||
super(shape); | super(shape); | ||||
} | } | ||||
protected Drawable getDrawable(Graphics2D graphics) { | |||||
protected Drawable getGroupShape(Graphics2D graphics) { | |||||
if (shape instanceof GroupShape) { | if (shape instanceof GroupShape) { | ||||
DrawFactory df = DrawFactory.getInstance(graphics); | DrawFactory df = DrawFactory.getInstance(graphics); | ||||
return df.getDrawable((GroupShape<?,?>)shape); | return df.getDrawable((GroupShape<?,?>)shape); | ||||
} | } | ||||
public void applyTransform(Graphics2D graphics) { | public void applyTransform(Graphics2D graphics) { | ||||
Drawable d = getDrawable(graphics); | |||||
Drawable d = getGroupShape(graphics); | |||||
if (d != null) { | if (d != null) { | ||||
d.applyTransform(graphics); | d.applyTransform(graphics); | ||||
} else { | |||||
super.applyTransform(graphics); | |||||
} | } | ||||
} | } | ||||
public void draw(Graphics2D graphics) { | public void draw(Graphics2D graphics) { | ||||
Drawable d = getDrawable(graphics); | |||||
Drawable d = getGroupShape(graphics); | |||||
if (d != null) { | if (d != null) { | ||||
d.draw(graphics); | d.draw(graphics); | ||||
return; | |||||
} | } | ||||
TableShape<?,?> ts = getShape(); | |||||
DrawPaint drawPaint = DrawFactory.getInstance(graphics).getPaint(ts); | |||||
final int rows = ts.getNumberOfRows(); | |||||
final int cols = ts.getNumberOfColumns(); | |||||
// draw background boxes | |||||
for (int row=0; row<rows; row++) { | |||||
for (int col=0; col<cols; col++) { | |||||
TableCell<?,?> tc = ts.getCell(row, col); | |||||
if (tc == null || tc.isMerged()) { | |||||
continue; | |||||
} | |||||
Paint fillPaint = drawPaint.getPaint(graphics, tc.getFillStyle().getPaint()); | |||||
graphics.setPaint(fillPaint); | |||||
Rectangle2D cellAnc = tc.getAnchor(); | |||||
graphics.fill(cellAnc); | |||||
for (BorderEdge edge : BorderEdge.values()) { | |||||
StrokeStyle stroke = tc.getBorderStyle(edge); | |||||
if (stroke == null) { | |||||
continue; | |||||
} | |||||
graphics.setStroke(getStroke(stroke)); | |||||
Paint linePaint = drawPaint.getPaint(graphics, stroke.getPaint()); | |||||
graphics.setPaint(linePaint); | |||||
double x=cellAnc.getX(), y=cellAnc.getY(), w=cellAnc.getWidth(), h=cellAnc.getHeight(); | |||||
Line2D line; | |||||
switch (edge) { | |||||
default: | |||||
case bottom: | |||||
line = new Line2D.Double(x-borderSize, y+h, x+w+borderSize, y+h); | |||||
break; | |||||
case left: | |||||
line = new Line2D.Double(x, y, x, y+h+borderSize); | |||||
break; | |||||
case right: | |||||
line = new Line2D.Double(x+w, y, x+w, y+h+borderSize); | |||||
break; | |||||
case top: | |||||
line = new Line2D.Double(x-borderSize, y, x+w+borderSize, y); | |||||
break; | |||||
} | |||||
graphics.draw(line); | |||||
} | |||||
} | |||||
} | |||||
// draw text | |||||
drawContent(graphics); | |||||
} | } | ||||
public void drawContent(Graphics2D graphics) { | public void drawContent(Graphics2D graphics) { | ||||
Drawable d = getDrawable(graphics); | |||||
Drawable d = getGroupShape(graphics); | |||||
if (d != null) { | if (d != null) { | ||||
d.drawContent(graphics); | d.drawContent(graphics); | ||||
return; | |||||
} | |||||
TableShape<?,?> ts = getShape(); | |||||
DrawFactory df = DrawFactory.getInstance(graphics); | |||||
final int rows = ts.getNumberOfRows(); | |||||
final int cols = ts.getNumberOfColumns(); | |||||
for (int row=0; row<rows; row++) { | |||||
for (int col=0; col<cols; col++) { | |||||
TableCell<?,?> tc = ts.getCell(row, col); | |||||
DrawTextShape dts = df.getDrawable(tc); | |||||
dts.drawContent(graphics); | |||||
} | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
protected TableShape<?,?> getShape() { | protected TableShape<?,?> getShape() { | ||||
return (TableShape<?,?>)shape; | return (TableShape<?,?>)shape; | ||||
} | |||||
} | |||||
/** | /** | ||||
* Format the table and apply the specified Line to all cell boundaries, | * Format the table and apply the specified Line to all cell boundaries, | ||||
* both outside and inside. | * both outside and inside. | ||||
TableShape<?,?> table = getShape(); | TableShape<?,?> table = getShape(); | ||||
final int rows = table.getNumberOfRows(); | final int rows = table.getNumberOfRows(); | ||||
final int cols = table.getNumberOfColumns(); | final int cols = table.getNumberOfColumns(); | ||||
BorderEdge edges[] = { BorderEdge.top, BorderEdge.left, null, null }; | BorderEdge edges[] = { BorderEdge.top, BorderEdge.left, null, null }; | ||||
for (int row = 0; row < rows; row++) { | for (int row = 0; row < rows; row++) { | ||||
for (int col = 0; col < cols; col++) { | for (int col = 0; col < cols; col++) { | ||||
*/ | */ | ||||
public void setOutsideBorders(Object... args){ | public void setOutsideBorders(Object... args){ | ||||
if (args.length == 0) return; | if (args.length == 0) return; | ||||
TableShape<?,?> table = getShape(); | TableShape<?,?> table = getShape(); | ||||
final int rows = table.getNumberOfRows(); | final int rows = table.getNumberOfRows(); | ||||
final int cols = table.getNumberOfColumns(); | final int cols = table.getNumberOfColumns(); | ||||
BorderEdge edges[] = new BorderEdge[4]; | BorderEdge edges[] = new BorderEdge[4]; | ||||
for (int row = 0; row < rows; row++) { | for (int row = 0; row < rows; row++) { | ||||
for (int col = 0; col < cols; col++) { | for (int col = 0; col < cols; col++) { | ||||
*/ | */ | ||||
public void setInsideBorders(Object... args) { | public void setInsideBorders(Object... args) { | ||||
if (args.length == 0) return; | if (args.length == 0) return; | ||||
TableShape<?,?> table = getShape(); | TableShape<?,?> table = getShape(); | ||||
final int rows = table.getNumberOfRows(); | final int rows = table.getNumberOfRows(); | ||||
final int cols = table.getNumberOfColumns(); | final int cols = table.getNumberOfColumns(); | ||||
BorderEdge edges[] = new BorderEdge[2]; | BorderEdge edges[] = new BorderEdge[2]; | ||||
for (int row = 0; row < rows; row++) { | for (int row = 0; row < rows; row++) { | ||||
for (int col = 0; col < cols; col++) { | for (int col = 0; col < cols; col++) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Apply the border attributes (args) to the given cell and edges | * Apply the border attributes (args) to the given cell and edges | ||||
* | * | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } |
package org.apache.poi.sl.draw; | package org.apache.poi.sl.draw; | ||||
import java.awt.Dimension; | |||||
import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||
import java.awt.Paint; | import java.awt.Paint; | ||||
import java.awt.font.FontRenderContext; | import java.awt.font.FontRenderContext; | ||||
import org.apache.poi.sl.usermodel.TextRun; | import org.apache.poi.sl.usermodel.TextRun; | ||||
import org.apache.poi.sl.usermodel.TextRun.TextCap; | import org.apache.poi.sl.usermodel.TextRun.TextCap; | ||||
import org.apache.poi.sl.usermodel.TextShape; | import org.apache.poi.sl.usermodel.TextShape; | ||||
import org.apache.poi.sl.usermodel.TextShape.TextDirection; | |||||
import org.apache.poi.util.StringUtil; | import org.apache.poi.util.StringUtil; | ||||
import org.apache.poi.util.Units; | import org.apache.poi.util.Units; | ||||
public class DrawTextParagraph implements Drawable { | public class DrawTextParagraph implements Drawable { | ||||
/** Keys for passing hyperlinks to the graphics context */ | /** Keys for passing hyperlinks to the graphics context */ | ||||
public static final XlinkAttribute HYPERLINK_HREF = new XlinkAttribute("href"); | public static final XlinkAttribute HYPERLINK_HREF = new XlinkAttribute("href"); | ||||
* @return wrapping width in points | * @return wrapping width in points | ||||
*/ | */ | ||||
protected double getWrappingWidth(boolean firstLine, Graphics2D graphics){ | protected double getWrappingWidth(boolean firstLine, Graphics2D graphics){ | ||||
// internal margins for the text box | |||||
TextShape<?,?> ts = paragraph.getParentShape(); | |||||
Insets2D insets = paragraph.getParentShape().getInsets(); | |||||
// internal margins for the text box | |||||
Insets2D insets = ts.getInsets(); | |||||
double leftInset = insets.left; | double leftInset = insets.left; | ||||
double rightInset = insets.right; | double rightInset = insets.right; | ||||
Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape()); | |||||
int indentLevel = paragraph.getIndentLevel(); | int indentLevel = paragraph.getIndentLevel(); | ||||
if (indentLevel == -1) { | if (indentLevel == -1) { | ||||
// default to 0, if indentLevel is not set | // default to 0, if indentLevel is not set | ||||
rightMargin = 0d; | rightMargin = 0d; | ||||
} | } | ||||
Rectangle2D anchor = DrawShape.getAnchor(graphics, ts); | |||||
TextDirection textDir = ts.getTextDirection(); | |||||
double width; | double width; | ||||
TextShape<?,?> ts = paragraph.getParentShape(); | |||||
if (!ts.getWordWrap()) { | if (!ts.getWordWrap()) { | ||||
// if wordWrap == false then we return the advance to the right border of the sheet | |||||
width = ts.getSheet().getSlideShow().getPageSize().getWidth() - anchor.getX(); | |||||
Dimension pageDim = ts.getSheet().getSlideShow().getPageSize(); | |||||
// if wordWrap == false then we return the advance to the (right) border of the sheet | |||||
switch (textDir) { | |||||
default: | |||||
width = pageDim.getWidth() - anchor.getX(); | |||||
break; | |||||
case VERTICAL: | |||||
width = pageDim.getHeight() - anchor.getX(); | |||||
break; | |||||
case VERTICAL_270: | |||||
width = anchor.getX(); | |||||
break; | |||||
} | |||||
} else { | } else { | ||||
width = anchor.getWidth() - leftInset - rightInset - leftMargin - rightMargin; | |||||
switch (textDir) { | |||||
default: | |||||
width = anchor.getWidth() - leftInset - rightInset - leftMargin - rightMargin; | |||||
break; | |||||
case VERTICAL: | |||||
case VERTICAL_270: | |||||
width = anchor.getHeight() - leftInset - rightInset - leftMargin - rightMargin; | |||||
break; | |||||
} | |||||
if (firstLine && !isHSLF()) { | if (firstLine && !isHSLF()) { | ||||
if (bullet != null){ | if (bullet != null){ | ||||
if (indent > 0) width -= indent; | if (indent > 0) width -= indent; |
import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle; | import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle; | ||||
import org.apache.poi.sl.usermodel.TextRun; | import org.apache.poi.sl.usermodel.TextRun; | ||||
import org.apache.poi.sl.usermodel.TextShape; | import org.apache.poi.sl.usermodel.TextShape; | ||||
import org.apache.poi.sl.usermodel.TextShape.TextDirection; | |||||
public class DrawTextShape extends DrawSimpleShape { | public class DrawTextShape extends DrawSimpleShape { | ||||
// remember the initial transform | // remember the initial transform | ||||
AffineTransform tx = graphics.getTransform(); | AffineTransform tx = graphics.getTransform(); | ||||
// Transform of text in flipped shapes is special. | // Transform of text in flipped shapes is special. | ||||
// At this point the flip and rotation transform is already applied | // At this point the flip and rotation transform is already applied | ||||
// (see DrawShape#applyTransform ), but we need to restore it to avoid painting "upside down". | // (see DrawShape#applyTransform ), but we need to restore it to avoid painting "upside down". | ||||
graphics.scale(-1, 1); | graphics.scale(-1, 1); | ||||
graphics.translate(-anchor.getX(), -anchor.getY()); | graphics.translate(-anchor.getX(), -anchor.getY()); | ||||
} | } | ||||
Double textRot = s.getTextRotation(); | Double textRot = s.getTextRotation(); | ||||
if (textRot != null && textRot != 0) { | if (textRot != null && textRot != 0) { | ||||
graphics.translate(anchor.getCenterX(), anchor.getCenterY()); | graphics.translate(anchor.getCenterX(), anchor.getCenterY()); | ||||
break; | break; | ||||
} | } | ||||
TextDirection textDir = s.getTextDirection(); | |||||
if (textDir == TextDirection.VERTICAL || textDir == TextDirection.VERTICAL_270) { | |||||
double deg = (textDir == TextDirection.VERTICAL) ? 90 : 270; | |||||
graphics.translate(anchor.getCenterX(), anchor.getCenterY()); | |||||
graphics.rotate(Math.toRadians(deg)); | |||||
graphics.translate(-anchor.getCenterX(), -anchor.getCenterY()); | |||||
// old top/left edge is now bottom/left or top/right - as we operate on the already | |||||
// rotated drawing context, both verticals can be moved in the same direction | |||||
double w = anchor.getWidth(); | |||||
double h = anchor.getHeight(); | |||||
graphics.translate((w-h)/2d,(h-w)/2d); | |||||
} | |||||
drawParagraphs(graphics, x, y); | drawParagraphs(graphics, x, y); | ||||
// restore the transform | // restore the transform |
* @param edge the border edge to be cleared | * @param edge the border edge to be cleared | ||||
*/ | */ | ||||
void removeBorder(BorderEdge edge); | void removeBorder(BorderEdge edge); | ||||
/** | |||||
* Get the number of columns to be spanned/merged | |||||
* | |||||
* @return the grid span | |||||
* | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
int getGridSpan(); | |||||
/** | |||||
* Get the number of rows to be spanned/merged | |||||
* | |||||
* @return the row span | |||||
* | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
int getRowSpan(); | |||||
/** | |||||
* Return if this cell is part of a merged cell. The top/left cell of a merged region is not regarded as merged - | |||||
* its grid and/or row span is greater than one. | |||||
* | |||||
* @return true if this a merged cell | |||||
* | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
boolean isMerged(); | |||||
} | } |
import org.apache.poi.util.POILogger; | import org.apache.poi.util.POILogger; | ||||
import org.apache.xmlbeans.XmlObject; | import org.apache.xmlbeans.XmlObject; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; | import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTFontReference; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTHslColor; | import org.openxmlformats.schemas.drawingml.x2006.main.CTHslColor; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveFixedPercentage; | import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveFixedPercentage; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetColor; | import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetColor; | ||||
color = Color.black; | color = Color.black; | ||||
} | } | ||||
} | } | ||||
} else if (ch instanceof CTFontReference) { | |||||
// try next ... | |||||
} else { | } else { | ||||
throw new IllegalArgumentException("Unexpected color choice: " + ch.getClass()); | throw new IllegalArgumentException("Unexpected color choice: " + ch.getClass()); | ||||
} | } |
/** | /** | ||||
* Base super-class class for all shapes in PresentationML | * Base super-class class for all shapes in PresentationML | ||||
* | |||||
* @author Yegor Kozlov | |||||
*/ | */ | ||||
@Beta | @Beta | ||||
public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { | public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { | ||||
} | } | ||||
protected PaintStyle getFillPaint() { | protected PaintStyle getFillPaint() { | ||||
final XSLFTheme theme = getSheet().getTheme(); | |||||
PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() { | PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() { | ||||
public boolean fetch(XSLFShape shape) { | public boolean fetch(XSLFShape shape) { | ||||
XmlObject pr = null; | XmlObject pr = null; | ||||
PaintStyle paint = null; | PaintStyle paint = null; | ||||
PackagePart pp = getSheet().getPackagePart(); | PackagePart pp = getSheet().getPackagePart(); | ||||
for (XmlObject obj : pr.selectPath("*")) { | for (XmlObject obj : pr.selectPath("*")) { | ||||
paint = selectPaint(obj, null, pp); | |||||
paint = selectPaint(obj, null, pp, theme); | |||||
if (paint != null) { | if (paint != null) { | ||||
setValue(paint); | setValue(paint); | ||||
return true; | return true; | ||||
if (fillRef == null) { | if (fillRef == null) { | ||||
fillRef = getBgRef(); | fillRef = getBgRef(); | ||||
} | } | ||||
paint = selectPaint(fillRef); | |||||
paint = selectPaint(fillRef, theme); | |||||
return paint; | return paint; | ||||
} | } | ||||
protected PaintStyle getPaint(XmlObject spPr, CTSchemeColor phClr) { | protected PaintStyle getPaint(XmlObject spPr, CTSchemeColor phClr) { | ||||
PaintStyle paint = null; | PaintStyle paint = null; | ||||
PackagePart pp = getSheet().getPackagePart(); | |||||
XSLFSheet sheet = getSheet(); | |||||
PackagePart pp = sheet.getPackagePart(); | |||||
XSLFTheme theme = sheet.getTheme(); | |||||
for (XmlObject obj : spPr.selectPath("*")) { | for (XmlObject obj : spPr.selectPath("*")) { | ||||
paint = selectPaint(obj, phClr, pp); | |||||
paint = selectPaint(obj, phClr, pp, theme); | |||||
if(paint != null) break; | if(paint != null) break; | ||||
} | } | ||||
return paint; | return paint; | ||||
* | * | ||||
* @return the applied Paint or null if none was applied | * @return the applied Paint or null if none was applied | ||||
*/ | */ | ||||
protected PaintStyle selectPaint(XmlObject obj, final CTSchemeColor phClr, final PackagePart parentPart) { | |||||
protected static PaintStyle selectPaint(XmlObject obj, final CTSchemeColor phClr, final PackagePart parentPart, final XSLFTheme theme) { | |||||
if (obj instanceof CTNoFillProperties) { | if (obj instanceof CTNoFillProperties) { | ||||
return null; | return null; | ||||
} else if (obj instanceof CTSolidColorFillProperties) { | } else if (obj instanceof CTSolidColorFillProperties) { | ||||
return selectPaint((CTSolidColorFillProperties)obj, phClr); | |||||
return selectPaint((CTSolidColorFillProperties)obj, phClr, theme); | |||||
} else if (obj instanceof CTBlipFillProperties) { | } else if (obj instanceof CTBlipFillProperties) { | ||||
return selectPaint((CTBlipFillProperties)obj, parentPart); | return selectPaint((CTBlipFillProperties)obj, parentPart); | ||||
} else if (obj instanceof CTGradientFillProperties) { | } else if (obj instanceof CTGradientFillProperties) { | ||||
return selectPaint((CTGradientFillProperties) obj, phClr); | |||||
return selectPaint((CTGradientFillProperties) obj, phClr, theme); | |||||
} else if (obj instanceof CTStyleMatrixReference) { | } else if (obj instanceof CTStyleMatrixReference) { | ||||
return selectPaint((CTStyleMatrixReference)obj); | |||||
return selectPaint((CTStyleMatrixReference)obj, theme); | |||||
} else { | } else { | ||||
return null; | return null; | ||||
} | } | ||||
} | } | ||||
protected PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr) { | |||||
final XSLFTheme theme = getSheet().getTheme(); | |||||
protected static PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr, final XSLFTheme theme) { | |||||
if (phClr == null && solidFill.isSetSchemeClr()) { | if (phClr == null && solidFill.isSetSchemeClr()) { | ||||
phClr = solidFill.getSchemeClr(); | phClr = solidFill.getSchemeClr(); | ||||
} | } | ||||
return DrawPaint.createSolidPaint(c.getColorStyle()); | return DrawPaint.createSolidPaint(c.getColorStyle()); | ||||
} | } | ||||
protected PaintStyle selectPaint(final CTBlipFillProperties blipFill, final PackagePart parentPart) { | |||||
protected static PaintStyle selectPaint(final CTBlipFillProperties blipFill, final PackagePart parentPart) { | |||||
final CTBlip blip = blipFill.getBlip(); | final CTBlip blip = blipFill.getBlip(); | ||||
return new TexturePaint() { | return new TexturePaint() { | ||||
private PackagePart getPart() { | private PackagePart getPart() { | ||||
}; | }; | ||||
} | } | ||||
protected PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr) { | |||||
protected static PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme) { | |||||
final CTGradientStop[] gs = gradFill.getGsLst().getGsArray(); | final CTGradientStop[] gs = gradFill.getGsLst().getGsArray(); | ||||
final ColorStyle cs[] = new ColorStyle[gs.length]; | final ColorStyle cs[] = new ColorStyle[gs.length]; | ||||
final float fractions[] = new float[gs.length]; | final float fractions[] = new float[gs.length]; | ||||
XSLFTheme theme = getSheet().getTheme(); | |||||
int i=0; | int i=0; | ||||
for (CTGradientStop cgs : gs) { | for (CTGradientStop cgs : gs) { | ||||
}; | }; | ||||
} | } | ||||
protected PaintStyle selectPaint(CTStyleMatrixReference fillRef) { | |||||
protected static PaintStyle selectPaint(CTStyleMatrixReference fillRef, final XSLFTheme theme) { | |||||
if (fillRef == null) return null; | if (fillRef == null) return null; | ||||
// The idx attribute refers to the index of a fill style or | // The idx attribute refers to the index of a fill style or | ||||
// values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element. | // values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element. | ||||
int idx = (int)fillRef.getIdx(); | int idx = (int)fillRef.getIdx(); | ||||
CTSchemeColor phClr = fillRef.getSchemeClr(); | CTSchemeColor phClr = fillRef.getSchemeClr(); | ||||
XSLFSheet sheet = getSheet(); | |||||
XSLFTheme theme = sheet.getTheme(); | |||||
XmlObject fillProps = null; | XmlObject fillProps = null; | ||||
CTStyleMatrix matrix = theme.getXmlObject().getThemeElements().getFmtScheme(); | CTStyleMatrix matrix = theme.getXmlObject().getThemeElements().getFmtScheme(); | ||||
if (idx >= 1 && idx <= 999) { | if (idx >= 1 && idx <= 999) { | ||||
} else if (idx >= 1001 ){ | } else if (idx >= 1001 ){ | ||||
fillProps = matrix.getBgFillStyleLst().selectPath("*")[idx - 1001]; | fillProps = matrix.getBgFillStyleLst().selectPath("*")[idx - 1001]; | ||||
} | } | ||||
return (fillProps == null) ? null : selectPaint(fillProps, phClr, theme.getPackagePart()); | |||||
return (fillProps == null) ? null : selectPaint(fillProps, phClr, theme.getPackagePart(), theme); | |||||
} | } | ||||
@Override | @Override |
/** | /** | ||||
* Represents a single (non-group) shape in a .pptx slide show | * Represents a single (non-group) shape in a .pptx slide show | ||||
* | |||||
* @author Yegor Kozlov | |||||
*/ | */ | ||||
@Beta | @Beta | ||||
public abstract class XSLFSimpleShape extends XSLFShape | public abstract class XSLFSimpleShape extends XSLFShape | ||||
} | } | ||||
protected PaintStyle getLinePaint() { | protected PaintStyle getLinePaint() { | ||||
final XSLFTheme theme = getSheet().getTheme(); | |||||
PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() { | PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() { | ||||
public boolean fetch(XSLFShape shape) { | public boolean fetch(XSLFShape shape) { | ||||
CTLineProperties spPr = shape.getSpPr().getLn(); | CTLineProperties spPr = shape.getSpPr().getLn(); | ||||
PaintStyle paint = null; | PaintStyle paint = null; | ||||
PackagePart pp = getSheet().getPackagePart(); | PackagePart pp = getSheet().getPackagePart(); | ||||
for (XmlObject obj : spPr.selectPath("*")) { | for (XmlObject obj : spPr.selectPath("*")) { | ||||
paint = selectPaint(obj, null, pp); | |||||
paint = selectPaint(obj, null, pp, theme); | |||||
if (paint != null) { | if (paint != null) { | ||||
setValue(paint); | setValue(paint); | ||||
return true; | return true; | ||||
CTShapeStyle style = shape.getSpStyle(); | CTShapeStyle style = shape.getSpStyle(); | ||||
if (style != null) { | if (style != null) { | ||||
paint = selectPaint(style.getLnRef()); | |||||
paint = selectPaint(style.getLnRef(), theme); | |||||
if (paint != null) { | if (paint != null) { | ||||
setValue(paint); | setValue(paint); | ||||
return true; | return true; | ||||
int idx = (int)lnRef.getIdx(); | int idx = (int)lnRef.getIdx(); | ||||
CTSchemeColor phClr = lnRef.getSchemeClr(); | CTSchemeColor phClr = lnRef.getSchemeClr(); | ||||
if(idx > 0){ | if(idx > 0){ | ||||
XSLFTheme theme = getSheet().getTheme(); | |||||
XmlObject lnProps = theme.getXmlObject(). | XmlObject lnProps = theme.getXmlObject(). | ||||
getThemeElements().getFmtScheme().getLnStyleLst().selectPath("*")[idx - 1]; | getThemeElements().getFmtScheme().getLnStyleLst().selectPath("*")[idx - 1]; | ||||
paint = getPaint(lnProps, phClr); | paint = getPaint(lnProps, phClr); |
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; | import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; | ||||
import java.awt.geom.Rectangle2D; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import javax.xml.namespace.QName; | import javax.xml.namespace.QName; | ||||
import org.apache.poi.POIXMLException; | import org.apache.poi.POIXMLException; | ||||
import org.apache.poi.sl.draw.DrawFactory; | |||||
import org.apache.poi.sl.draw.DrawTableShape; | |||||
import org.apache.poi.sl.draw.DrawTextShape; | |||||
import org.apache.poi.sl.usermodel.TableShape; | import org.apache.poi.sl.usermodel.TableShape; | ||||
import org.apache.poi.util.Internal; | import org.apache.poi.util.Internal; | ||||
import org.apache.poi.util.Units; | import org.apache.poi.util.Units; | ||||
/** | /** | ||||
* Represents a table in a .pptx presentation | * Represents a table in a .pptx presentation | ||||
* | |||||
* @author Yegor Kozlov | |||||
*/ | */ | ||||
public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow>, | public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow>, | ||||
TableShape<XSLFShape,XSLFTextParagraph> { | TableShape<XSLFShape,XSLFTextParagraph> { | ||||
static String TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table"; | |||||
/* package */ static final String TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table"; | |||||
private CTTable _table; | private CTTable _table; | ||||
private List<XSLFTableRow> _rows; | private List<XSLFTableRow> _rows; | ||||
_table = (CTTable) rs[0]; | _table = (CTTable) rs[0]; | ||||
CTTableRow[] trArray = _table.getTrArray(); | CTTableRow[] trArray = _table.getTrArray(); | ||||
_rows = new ArrayList<XSLFTableRow>(trArray.length); | _rows = new ArrayList<XSLFTableRow>(trArray.length); | ||||
for(CTTableRow row : trArray) _rows.add(new XSLFTableRow(row, this)); | |||||
for(CTTableRow row : trArray) { | |||||
XSLFTableRow xr = new XSLFTableRow(row, this); | |||||
_rows.add(xr); | |||||
} | |||||
updateRowColIndexes(); | |||||
} | } | ||||
@Override | @Override | ||||
public XSLFTableRow addRow(){ | public XSLFTableRow addRow(){ | ||||
CTTableRow tr = _table.addNewTr(); | CTTableRow tr = _table.addNewTr(); | ||||
XSLFTableRow row = new XSLFTableRow(tr, this); | XSLFTableRow row = new XSLFTableRow(tr, this); | ||||
row.setHeight(20.0); // default height is 20 points | |||||
// default height is 20 points | |||||
row.setHeight(20.0); | |||||
_rows.add(row); | _rows.add(row); | ||||
updateRowColIndexes(); | |||||
return row; | return row; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/** | |||||
* Get assigned TableStyle | |||||
* | |||||
* @return the assigned TableStyle | |||||
* | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
protected XSLFTableStyle getTableStyle() { | |||||
CTTable tab = getCTTable(); | |||||
// TODO: support inline table style | |||||
if (!tab.isSetTblPr() || !tab.getTblPr().isSetTableStyleId()) { | |||||
return null; | |||||
} | |||||
String styleId = tab.getTblPr().getTableStyleId(); | |||||
XSLFTableStyles styles = getSheet().getSlideShow().getTableStyles(); | |||||
for (XSLFTableStyle style : styles.getStyles()) { | |||||
if (style.getStyleId().equals(styleId)) { | |||||
return style; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
/* package */ void updateRowColIndexes() { | |||||
int rowIdx = 0; | |||||
for (XSLFTableRow xr : this) { | |||||
int colIdx = 0; | |||||
for (XSLFTableCell tc : xr) { | |||||
tc.setRowColIndex(rowIdx, colIdx); | |||||
colIdx++; | |||||
} | |||||
rowIdx++; | |||||
} | |||||
} | |||||
/* package */ void updateCellAnchor() { | |||||
int rows = getNumberOfRows(); | |||||
int cols = getNumberOfColumns(); | |||||
double colWidths[] = new double[cols]; | |||||
double rowHeights[] = new double[rows]; | |||||
for (int row=0; row<rows; row++) { | |||||
rowHeights[row] = getRowHeight(row); | |||||
} | |||||
for (int col=0; col<cols; col++) { | |||||
colWidths[col] = getColumnWidth(col); | |||||
} | |||||
Rectangle2D tblAnc = getAnchor(); | |||||
DrawFactory df = DrawFactory.getInstance(null); | |||||
double newY = tblAnc.getY(); | |||||
// #1 pass - determine row heights, the height values might be too low or 0 ... | |||||
for (int row=0; row<rows; row++) { | |||||
double maxHeight = 0; | |||||
for (int col=0; col<cols; col++) { | |||||
XSLFTableCell tc = getCell(row, col); | |||||
if (tc.getGridSpan() != 1 || tc.getRowSpan() != 1) { | |||||
continue; | |||||
} | |||||
// need to set the anchor before height calculation | |||||
tc.setAnchor(new Rectangle2D.Double(0,0,colWidths[col],0)); | |||||
DrawTextShape dts = df.getDrawable(tc); | |||||
maxHeight = Math.max(maxHeight, dts.getTextHeight()); | |||||
} | |||||
rowHeights[row] = Math.max(rowHeights[row],maxHeight); | |||||
} | |||||
// #2 pass - init properties | |||||
for (int row=0; row<rows; row++) { | |||||
double newX = tblAnc.getX(); | |||||
for (int col=0; col<cols; col++) { | |||||
Rectangle2D bounds = new Rectangle2D.Double(newX, newY, colWidths[col], rowHeights[row]); | |||||
XSLFTableCell tc = getCell(row, col); | |||||
tc.setAnchor(bounds); | |||||
newX += colWidths[col]+DrawTableShape.borderSize; | |||||
} | |||||
newY += rowHeights[row]+DrawTableShape.borderSize; | |||||
} | |||||
// #3 pass - update merge info | |||||
for (int row=0; row<rows; row++) { | |||||
for (int col=0; col<cols; col++) { | |||||
XSLFTableCell tc = getCell(row, col); | |||||
Rectangle2D mergedBounds = tc.getAnchor(); | |||||
for (int col2=col+1; col2<col+tc.getGridSpan(); col2++) { | |||||
assert(col2 < cols); | |||||
XSLFTableCell tc2 = getCell(row, col2); | |||||
assert(tc2.getGridSpan() == 1 && tc2.getRowSpan() == 1); | |||||
mergedBounds.add(tc2.getAnchor()); | |||||
} | |||||
for (int row2=row+1; row2<row+tc.getRowSpan(); row2++) { | |||||
assert(row2 < rows); | |||||
XSLFTableCell tc2 = getCell(row2, col); | |||||
assert(tc2.getGridSpan() == 1 && tc2.getRowSpan() == 1); | |||||
mergedBounds.add(tc2.getAnchor()); | |||||
} | |||||
tc.setAnchor(mergedBounds); | |||||
} | |||||
} | |||||
} | |||||
} | } |
package org.apache.poi.xslf.usermodel; | package org.apache.poi.xslf.usermodel; | ||||
import java.awt.Color; | import java.awt.Color; | ||||
import java.awt.geom.Rectangle2D; | |||||
import org.apache.poi.sl.draw.DrawPaint; | import org.apache.poi.sl.draw.DrawPaint; | ||||
import org.apache.poi.sl.usermodel.PaintStyle; | import org.apache.poi.sl.usermodel.PaintStyle; | ||||
import org.apache.poi.sl.usermodel.TableCell; | import org.apache.poi.sl.usermodel.TableCell; | ||||
import org.apache.poi.sl.usermodel.VerticalAlignment; | import org.apache.poi.sl.usermodel.VerticalAlignment; | ||||
import org.apache.poi.util.Units; | import org.apache.poi.util.Units; | ||||
import org.apache.poi.xslf.usermodel.XSLFTableStyle.TablePartStyle; | |||||
import org.apache.xmlbeans.XmlObject; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTFillProperties; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTFontReference; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties; | import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; | import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties; | import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTable; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCellProperties; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCellProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTablePartStyle; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableProperties; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyleTextStyle; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.STCompoundLine; | import org.openxmlformats.schemas.drawingml.x2006.main.STCompoundLine; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap; | import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength; | import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType; | import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth; | import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STOnOffStyleType; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.STPenAlignment; | import org.openxmlformats.schemas.drawingml.x2006.main.STPenAlignment; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal; | import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType; | import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType; | ||||
*/ | */ | ||||
public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,XSLFTextParagraph> { | public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,XSLFTextParagraph> { | ||||
private CTTableCellProperties _tcPr = null; | private CTTableCellProperties _tcPr = null; | ||||
private final XSLFTable table; | |||||
private int row = 0, col = 0; | |||||
/*package*/ XSLFTableCell(CTTableCell cell, XSLFSheet sheet){ | |||||
super(cell, sheet); | |||||
/** | |||||
* Volatile/temporary anchor - e.g. for rendering | |||||
*/ | |||||
private Rectangle2D anchor = null; | |||||
/*package*/ XSLFTableCell(CTTableCell cell, XSLFTable table){ | |||||
super(cell, table.getSheet()); | |||||
this.table = table; | |||||
} | } | ||||
@Override | @Override | ||||
protected CTTextBody getTextBody(boolean create){ | protected CTTextBody getTextBody(boolean create){ | ||||
CTTableCell cell = (CTTableCell)getXmlObject(); | |||||
CTTableCell cell = getCell(); | |||||
CTTextBody txBody = cell.getTxBody(); | CTTextBody txBody = cell.getTxBody(); | ||||
if (txBody == null && create) { | if (txBody == null && create) { | ||||
txBody = cell.addNewTxBody(); | txBody = cell.addNewTxBody(); | ||||
protected CTTableCellProperties getCellProperties(boolean create) { | protected CTTableCellProperties getCellProperties(boolean create) { | ||||
if (_tcPr == null) { | if (_tcPr == null) { | ||||
CTTableCell cell = (CTTableCell)getXmlObject(); | |||||
CTTableCell cell = getCell(); | |||||
_tcPr = cell.getTcPr(); | _tcPr = cell.getTcPr(); | ||||
if (_tcPr == null && create) { | if (_tcPr == null && create) { | ||||
_tcPr = cell.addNewTcPr(); | _tcPr = cell.addNewTcPr(); | ||||
} | } | ||||
}; | }; | ||||
} | } | ||||
@Override | @Override | ||||
public void setBorderStyle(BorderEdge edge, StrokeStyle style) { | public void setBorderStyle(BorderEdge edge, StrokeStyle style) { | ||||
if (style == null) { | if (style == null) { | ||||
throw new IllegalArgumentException("StrokeStyle needs to be specified."); | throw new IllegalArgumentException("StrokeStyle needs to be specified."); | ||||
} | } | ||||
LineCap cap = style.getLineCap(); | LineCap cap = style.getLineCap(); | ||||
if (cap != null) { | if (cap != null) { | ||||
setBorderCap(edge, cap); | setBorderCap(edge, cap); | ||||
} | } | ||||
LineCompound compound = style.getLineCompound(); | LineCompound compound = style.getLineCompound(); | ||||
if (compound != null) { | if (compound != null) { | ||||
setBorderCompound(edge, compound); | setBorderCompound(edge, compound); | ||||
} | } | ||||
LineDash dash = style.getLineDash(); | LineDash dash = style.getLineDash(); | ||||
if (dash != null) { | if (dash != null) { | ||||
setBorderDash(edge, dash); | setBorderDash(edge, dash); | ||||
} | } | ||||
double width = style.getLineWidth(); | double width = style.getLineWidth(); | ||||
setBorderWidth(edge, width); | setBorderWidth(edge, width); | ||||
} | } | ||||
} | } | ||||
CTLineProperties ln = setBorderDefaults(edge); | CTLineProperties ln = setBorderDefaults(edge); | ||||
CTSRgbColor rgb = CTSRgbColor.Factory.newInstance(); | |||||
rgb.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()}); | |||||
ln.addNewSolidFill().setSrgbClr(rgb); | |||||
CTSolidColorFillProperties fill = ln.addNewSolidFill(); | |||||
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr()); | |||||
c.setColor(color); | |||||
} | } | ||||
public Color getBorderColor(BorderEdge edge) { | public Color getBorderColor(BorderEdge edge) { | ||||
if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill()) return null; | if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill()) return null; | ||||
CTSolidColorFillProperties fill = ln.getSolidFill(); | CTSolidColorFillProperties fill = ln.getSolidFill(); | ||||
if (!fill.isSetSrgbClr()) { | |||||
// TODO for now return null for all colors except explicit RGB | |||||
return null; | |||||
} | |||||
byte[] val = fill.getSrgbClr().getVal(); | |||||
return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]); | |||||
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr()); | |||||
return c.getColor(); | |||||
} | } | ||||
public LineCompound getBorderCompound(BorderEdge edge) { | public LineCompound getBorderCompound(BorderEdge edge) { | ||||
if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill() || !ln.isSetCap()) { | if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill() || !ln.isSetCap()) { | ||||
return null; | return null; | ||||
} | } | ||||
return LineCap.fromOoxmlId(ln.getCap().intValue()); | return LineCap.fromOoxmlId(ln.getCap().intValue()); | ||||
} | } | ||||
CTTableCellProperties spPr = getCellProperties(true); | CTTableCellProperties spPr = getCellProperties(true); | ||||
if (color == null) { | if (color == null) { | ||||
if(spPr.isSetSolidFill()) spPr.unsetSolidFill(); | if(spPr.isSetSolidFill()) spPr.unsetSolidFill(); | ||||
} | |||||
else { | |||||
} else { | |||||
CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr.getSolidFill() : spPr.addNewSolidFill(); | CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr.getSolidFill() : spPr.addNewSolidFill(); | ||||
CTSRgbColor rgb = CTSRgbColor.Factory.newInstance(); | |||||
rgb.setVal(new byte[]{(byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()}); | |||||
fill.setSrgbClr(rgb); | |||||
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr()); | |||||
c.setColor(color); | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public Color getFillColor(){ | public Color getFillColor(){ | ||||
CTTableCellProperties spPr = getCellProperties(false); | CTTableCellProperties spPr = getCellProperties(false); | ||||
if (spPr == null || !spPr.isSetSolidFill()) return null; | |||||
if (spPr == null || !spPr.isSetSolidFill()) { | |||||
return null; | |||||
} | |||||
CTSolidColorFillProperties fill = spPr.getSolidFill(); | CTSolidColorFillProperties fill = spPr.getSolidFill(); | ||||
if (!fill.isSetSrgbClr()) { | |||||
// TODO for now return null for all colors except explicit RGB | |||||
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr()); | |||||
return c.getColor(); | |||||
} | |||||
@SuppressWarnings("resource") | |||||
@Override | |||||
public PaintStyle getFillPaint() { | |||||
Color c = getFillColor(); | |||||
if (c != null) { | |||||
return DrawPaint.createSolidPaint(c); | |||||
} | |||||
CTTablePartStyle tps = getTablePartStyle(null); | |||||
if (tps == null || !tps.isSetTcStyle()) { | |||||
tps = getTablePartStyle(TablePartStyle.wholeTbl); | |||||
if (tps == null || !tps.isSetTcStyle()) { | |||||
return null; | |||||
} | |||||
} | |||||
XMLSlideShow slideShow = table.getSheet().getSlideShow(); | |||||
assert(slideShow != null); | |||||
XSLFTheme theme = slideShow.getSlides().get(0).getTheme(); | |||||
CTFillProperties pr = tps.getTcStyle().getFill(); | |||||
for (XmlObject obj : pr.selectPath("*")) { | |||||
PaintStyle paint = XSLFShape.selectPaint(obj, null, slideShow.getPackagePart(), theme); | |||||
if (paint != null) { | |||||
return paint; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
/** | |||||
* Retrieves the part style depending on the location of this cell | |||||
* | |||||
* @param tablePartStyle the part to be returned, usually this is null | |||||
* and only set when used as a helper method | |||||
* @return the table part style | |||||
*/ | |||||
private CTTablePartStyle getTablePartStyle(TablePartStyle tablePartStyle) { | |||||
CTTable ct = table.getCTTable(); | |||||
if (!ct.isSetTblPr()) { | |||||
return null; | |||||
} | |||||
CTTableProperties pr = ct.getTblPr(); | |||||
boolean bandRow = (pr.isSetBandRow() && pr.getBandRow()); | |||||
boolean firstRow = (pr.isSetFirstRow() && pr.getFirstRow()); | |||||
boolean lastRow = (pr.isSetLastRow() && pr.getLastRow()); | |||||
boolean bandCol = (pr.isSetBandCol() && pr.getBandCol()); | |||||
boolean firstCol = (pr.isSetFirstCol() && pr.getFirstCol()); | |||||
boolean lastCol = (pr.isSetLastCol() && pr.getLastCol()); | |||||
TablePartStyle tps; | |||||
if (tablePartStyle != null) { | |||||
tps = tablePartStyle; | |||||
} else if (row == 0 && firstRow) { | |||||
tps = TablePartStyle.firstRow; | |||||
} else if (row == table.getNumberOfRows()-1 && lastRow) { | |||||
tps = TablePartStyle.lastRow; | |||||
} else if (col == 0 && firstCol) { | |||||
tps = TablePartStyle.firstCol; | |||||
} else if (col == table.getNumberOfColumns()-1 && lastCol) { | |||||
tps = TablePartStyle.lastCol; | |||||
} else { | |||||
tps = TablePartStyle.wholeTbl; | |||||
int br = row + (firstRow ? 1 : 0); | |||||
int bc = col + (firstCol ? 1 : 0); | |||||
if (bandRow && (br & 1) == 0) { | |||||
tps = TablePartStyle.band1H; | |||||
} else if (bandCol && (bc & 1) == 0) { | |||||
tps = TablePartStyle.band1V; | |||||
} | |||||
} | |||||
XSLFTableStyle tabStyle = table.getTableStyle(); | |||||
if (tabStyle == null) { | |||||
return null; | return null; | ||||
} | } | ||||
byte[] val = fill.getSrgbClr().getVal(); | |||||
return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]); | |||||
CTTablePartStyle part = tabStyle.getTablePartStyle(tps); | |||||
return (part == null) ? tabStyle.getTablePartStyle(TablePartStyle.wholeTbl) : part; | |||||
} | } | ||||
void setGridSpan(int gridSpan_) { | void setGridSpan(int gridSpan_) { | ||||
((CTTableCell)getXmlObject()).setGridSpan(gridSpan_); | |||||
getCell().setGridSpan(gridSpan_); | |||||
} | |||||
@Override | |||||
public int getGridSpan() { | |||||
CTTableCell c = getCell(); | |||||
return (c.isSetGridSpan()) ? c.getGridSpan() : 1; | |||||
} | } | ||||
void setRowSpan(int rowSpan_) { | void setRowSpan(int rowSpan_) { | ||||
((CTTableCell)getXmlObject()).setRowSpan(rowSpan_); | |||||
getCell().setRowSpan(rowSpan_); | |||||
} | |||||
@Override | |||||
public int getRowSpan() { | |||||
CTTableCell c = getCell(); | |||||
return (c.isSetRowSpan()) ? c.getRowSpan() : 1; | |||||
} | } | ||||
void setHMerge(boolean merge_) { | void setHMerge(boolean merge_) { | ||||
((CTTableCell)getXmlObject()).setHMerge(merge_); | |||||
getCell().setHMerge(merge_); | |||||
} | } | ||||
void setVMerge(boolean merge_) { | void setVMerge(boolean merge_) { | ||||
((CTTableCell)getXmlObject()).setVMerge(merge_); | |||||
getCell().setVMerge(merge_); | |||||
} | } | ||||
@Override | @Override | ||||
vt = STTextVerticalType.WORD_ART_VERT; | vt = STTextVerticalType.WORD_ART_VERT; | ||||
break; | break; | ||||
} | } | ||||
cellProps.setVert(vt); | cellProps.setVert(vt); | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
orientation = STTextVerticalType.HORZ; | orientation = STTextVerticalType.HORZ; | ||||
} | } | ||||
switch (orientation.intValue()) { | switch (orientation.intValue()) { | ||||
default: | default: | ||||
case STTextVerticalType.INT_HORZ: | case STTextVerticalType.INT_HORZ: | ||||
return TextDirection.STACKED; | return TextDirection.STACKED; | ||||
} | } | ||||
} | } | ||||
} | |||||
private CTTableCell getCell() { | |||||
return (CTTableCell)getXmlObject(); | |||||
} | |||||
/* package */ void setRowColIndex(int row, int col) { | |||||
this.row = row; | |||||
this.col = col; | |||||
} | |||||
/** | |||||
* Return a fake-xfrm which is used for calculating the text height | |||||
*/ | |||||
protected CTTransform2D getXfrm() { | |||||
Rectangle2D anc = getAnchor(); | |||||
CTTransform2D xfrm = CTTransform2D.Factory.newInstance(); | |||||
CTPoint2D off = xfrm.addNewOff(); | |||||
off.setX(Units.toEMU(anc.getX())); | |||||
off.setY(Units.toEMU(anc.getY())); | |||||
CTPositiveSize2D size = xfrm.addNewExt(); | |||||
size.setCx(Units.toEMU(anc.getWidth())); | |||||
size.setCy(Units.toEMU(anc.getHeight())); | |||||
return xfrm; | |||||
} | |||||
/** | |||||
* There's no real anchor for table cells - this method is used to temporarily store the location | |||||
* of the cell for a later retrieval, e.g. for rendering | |||||
* | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
@Override | |||||
public void setAnchor(Rectangle2D anchor) { | |||||
if (this.anchor == null) { | |||||
this.anchor = (Rectangle2D)anchor.clone(); | |||||
} else { | |||||
this.anchor.setRect(anchor); | |||||
} | |||||
} | |||||
/** | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
@Override | |||||
public Rectangle2D getAnchor() { | |||||
if (anchor == null) { | |||||
table.updateCellAnchor(); | |||||
} | |||||
// anchor should be set, after updateCellAnchor is through | |||||
assert(anchor != null); | |||||
return anchor; | |||||
} | |||||
/** | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
@Override | |||||
public boolean isMerged() { | |||||
CTTableCell c = getCell(); | |||||
return (c.isSetHMerge() && c.getHMerge()) || (c.isSetVMerge() && c.getVMerge()); | |||||
} | |||||
/** | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
@Override | |||||
protected XSLFCellTextParagraph newTextParagraph(CTTextParagraph p) { | |||||
return new XSLFCellTextParagraph(p, this); | |||||
} | |||||
/** | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
private class XSLFCellTextParagraph extends XSLFTextParagraph { | |||||
protected XSLFCellTextParagraph(CTTextParagraph p, XSLFTextShape shape) { | |||||
super(p, shape); | |||||
} | |||||
@Override | |||||
protected XSLFCellTextRun newTextRun(CTRegularTextRun r) { | |||||
return new XSLFCellTextRun(r, this); | |||||
} | |||||
} | |||||
/** | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
private class XSLFCellTextRun extends XSLFTextRun { | |||||
protected XSLFCellTextRun(CTRegularTextRun r, XSLFTextParagraph p) { | |||||
super(r, p); | |||||
} | |||||
@Override | |||||
public PaintStyle getFontColor(){ | |||||
CTTableStyleTextStyle txStyle = getTextStyle(); | |||||
if (txStyle == null) { | |||||
return super.getFontColor(); | |||||
} | |||||
CTSchemeColor phClr = null; | |||||
CTFontReference fontRef = txStyle.getFontRef(); | |||||
if (fontRef != null) { | |||||
phClr = fontRef.getSchemeClr(); | |||||
} | |||||
XSLFTheme theme = getSheet().getTheme(); | |||||
final XSLFColor c = new XSLFColor(txStyle, theme, phClr); | |||||
return DrawPaint.createSolidPaint(c.getColorStyle()); | |||||
} | |||||
@Override | |||||
public boolean isBold() { | |||||
CTTableStyleTextStyle txStyle = getTextStyle(); | |||||
if (txStyle == null) { | |||||
return super.isBold(); | |||||
} else { | |||||
return txStyle.isSetB() && txStyle.getB().intValue() == STOnOffStyleType.INT_ON; | |||||
} | |||||
} | |||||
@Override | |||||
public boolean isItalic() { | |||||
CTTableStyleTextStyle txStyle = getTextStyle(); | |||||
if (txStyle == null) { | |||||
return super.isItalic(); | |||||
} else { | |||||
return txStyle.isSetI() && txStyle.getI().intValue() == STOnOffStyleType.INT_ON; | |||||
} | |||||
} | |||||
private CTTableStyleTextStyle getTextStyle() { | |||||
CTTablePartStyle tps = getTablePartStyle(null); | |||||
if (tps == null || !tps.isSetTcTxStyle()) { | |||||
tps = getTablePartStyle(TablePartStyle.wholeTbl); | |||||
} | |||||
return (tps == null) ? null : tps.getTcTxStyle(); | |||||
} | |||||
} | |||||
} |
/** | /** | ||||
* Represents a table in a .pptx presentation | * Represents a table in a .pptx presentation | ||||
* | |||||
* @author Yegor Kozlov | |||||
*/ | */ | ||||
public class XSLFTableRow implements Iterable<XSLFTableCell> { | public class XSLFTableRow implements Iterable<XSLFTableCell> { | ||||
private CTTableRow _row; | private CTTableRow _row; | ||||
CTTableCell[] tcArray = _row.getTcArray(); | CTTableCell[] tcArray = _row.getTcArray(); | ||||
_cells = new ArrayList<XSLFTableCell>(tcArray.length); | _cells = new ArrayList<XSLFTableCell>(tcArray.length); | ||||
for(CTTableCell cell : tcArray) { | for(CTTableCell cell : tcArray) { | ||||
_cells.add(new XSLFTableCell(cell, table.getSheet())); | |||||
_cells.add(new XSLFTableCell(cell, table)); | |||||
} | } | ||||
} | } | ||||
public XSLFTableCell addCell(){ | public XSLFTableCell addCell(){ | ||||
CTTableCell c = _row.addNewTc(); | CTTableCell c = _row.addNewTc(); | ||||
c.set(XSLFTableCell.prototype()); | c.set(XSLFTableCell.prototype()); | ||||
XSLFTableCell cell = new XSLFTableCell(c, _table.getSheet()); | |||||
XSLFTableCell cell = new XSLFTableCell(c, _table); | |||||
_cells.add(cell); | _cells.add(cell); | ||||
if(_table.getNumberOfColumns() < _row.sizeOfTcArray()) { | if(_table.getNumberOfColumns() < _row.sizeOfTcArray()) { | ||||
_table.getCTTable().getTblGrid().addNewGridCol().setW(Units.toEMU(100.0)); | _table.getCTTable().getTblGrid().addNewGridCol().setW(Units.toEMU(100.0)); | ||||
} | } | ||||
_table.updateRowColIndexes(); | |||||
return cell; | return cell; | ||||
} | } | ||||
package org.apache.poi.xslf.usermodel; | package org.apache.poi.xslf.usermodel; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTablePartStyle; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle; | ||||
/** | /** | ||||
* Represents a table in a .pptx presentation | |||||
* | |||||
* @author Yegor Kozlov | |||||
* Represents a table style in a .pptx presentation | |||||
*/ | */ | ||||
public class XSLFTableStyle { | public class XSLFTableStyle { | ||||
private CTTableStyle _tblStyle; | private CTTableStyle _tblStyle; | ||||
public enum TablePartStyle { | |||||
wholeTbl, band1H, band2H, band1V, band2V, firstCol, lastCol, firstRow, lastRow, seCell, swCell, neCell, nwCell; | |||||
} | |||||
/*package*/ XSLFTableStyle(CTTableStyle style){ | /*package*/ XSLFTableStyle(CTTableStyle style){ | ||||
_tblStyle = style; | _tblStyle = style; | ||||
} | } | ||||
public String getStyleId(){ | public String getStyleId(){ | ||||
return _tblStyle.getStyleId(); | return _tblStyle.getStyleId(); | ||||
} | } | ||||
/** | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
protected CTTablePartStyle getTablePartStyle(TablePartStyle tps) { | |||||
switch (tps) { | |||||
default: | |||||
case wholeTbl: | |||||
return _tblStyle.getWholeTbl(); | |||||
case band1H: | |||||
return _tblStyle.getBand1H(); | |||||
case band2H: | |||||
return _tblStyle.getBand2H(); | |||||
case band1V: | |||||
return _tblStyle.getBand1V(); | |||||
case band2V: | |||||
return _tblStyle.getBand2V(); | |||||
case firstCol: | |||||
return _tblStyle.getFirstCol(); | |||||
case lastCol: | |||||
return _tblStyle.getLastCol(); | |||||
case firstRow: | |||||
return _tblStyle.getFirstRow(); | |||||
case lastRow: | |||||
return _tblStyle.getLastRow(); | |||||
case seCell: | |||||
return _tblStyle.getSeCell(); | |||||
case swCell: | |||||
return _tblStyle.getSwCell(); | |||||
case neCell: | |||||
return _tblStyle.getNeCell(); | |||||
case nwCell: | |||||
return _tblStyle.getNwCell(); | |||||
} | |||||
} | |||||
} | } |
==================================================================== */ | ==================================================================== */ | ||||
package org.apache.poi.xslf.usermodel; | package org.apache.poi.xslf.usermodel; | ||||
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import org.apache.xmlbeans.XmlException; | import org.apache.xmlbeans.XmlException; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyleList; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyleList; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.TblStyleLstDocument; | |||||
@Beta | @Beta | ||||
public class XSLFTableStyles extends POIXMLDocumentPart implements Iterable<XSLFTableStyle>{ | public class XSLFTableStyles extends POIXMLDocumentPart implements Iterable<XSLFTableStyle>{ | ||||
public XSLFTableStyles(PackagePart part) throws IOException, XmlException { | public XSLFTableStyles(PackagePart part) throws IOException, XmlException { | ||||
super(part); | super(part); | ||||
_tblStyleLst = CTTableStyleList.Factory.parse(getPackagePart().getInputStream(), DEFAULT_XML_OPTIONS); | |||||
InputStream is = getPackagePart().getInputStream(); | |||||
TblStyleLstDocument styleDoc = TblStyleLstDocument.Factory.parse(is); | |||||
is.close(); | |||||
_tblStyleLst = styleDoc.getTblStyleLst(); | |||||
CTTableStyle[] tblStyleArray = _tblStyleLst.getTblStyleArray(); | CTTableStyle[] tblStyleArray = _tblStyleLst.getTblStyleArray(); | ||||
_styles = new ArrayList<XSLFTableStyle>(tblStyleArray.length); | _styles = new ArrayList<XSLFTableStyle>(tblStyleArray.length); | ||||
for(CTTableStyle c : tblStyleArray){ | for(CTTableStyle c : tblStyleArray){ |
* Represents a paragraph of text within the containing text body. | * Represents a paragraph of text within the containing text body. | ||||
* The paragraph is the highest level text separation mechanism. | * The paragraph is the highest level text separation mechanism. | ||||
* | * | ||||
* @author Yegor Kozlov | |||||
* @since POI-3.8 | * @since POI-3.8 | ||||
*/ | */ | ||||
@Beta | @Beta | ||||
for(XmlObject ch : _p.selectPath("*")){ | for(XmlObject ch : _p.selectPath("*")){ | ||||
if(ch instanceof CTRegularTextRun){ | if(ch instanceof CTRegularTextRun){ | ||||
CTRegularTextRun r = (CTRegularTextRun)ch; | CTRegularTextRun r = (CTRegularTextRun)ch; | ||||
_runs.add(new XSLFTextRun(r, this)); | |||||
_runs.add(newTextRun(r)); | |||||
} else if (ch instanceof CTTextLineBreak){ | } else if (ch instanceof CTTextLineBreak){ | ||||
CTTextLineBreak br = (CTTextLineBreak)ch; | CTTextLineBreak br = (CTTextLineBreak)ch; | ||||
CTRegularTextRun r = CTRegularTextRun.Factory.newInstance(); | CTRegularTextRun r = CTRegularTextRun.Factory.newInstance(); | ||||
r.setRPr(br.getRPr()); | r.setRPr(br.getRPr()); | ||||
r.setT("\n"); | r.setT("\n"); | ||||
_runs.add(new XSLFTextRun(r, this)); | |||||
_runs.add(newTextRun(r)); | |||||
} else if (ch instanceof CTTextField){ | } else if (ch instanceof CTTextField){ | ||||
CTTextField f = (CTTextField)ch; | CTTextField f = (CTTextField)ch; | ||||
CTRegularTextRun r = CTRegularTextRun.Factory.newInstance(); | CTRegularTextRun r = CTRegularTextRun.Factory.newInstance(); | ||||
r.setRPr(f.getRPr()); | r.setRPr(f.getRPr()); | ||||
r.setT(f.getT()); | r.setT(f.getT()); | ||||
_runs.add(new XSLFTextRun(r, this)); | |||||
_runs.add(newTextRun(r)); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
CTRegularTextRun r = _p.addNewR(); | CTRegularTextRun r = _p.addNewR(); | ||||
CTTextCharacterProperties rPr = r.addNewRPr(); | CTTextCharacterProperties rPr = r.addNewRPr(); | ||||
rPr.setLang("en-US"); | rPr.setLang("en-US"); | ||||
XSLFTextRun run = new XSLFTextRun(r, this); | |||||
XSLFTextRun run = newTextRun(r); | |||||
_runs.add(run); | _runs.add(run); | ||||
return run; | return run; | ||||
} | } | ||||
int level = getIndentLevel(); | int level = getIndentLevel(); | ||||
// wind up and find the root master sheet which must be slide master | // wind up and find the root master sheet which must be slide master | ||||
final String nsDecl = | |||||
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " + | |||||
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' "; | |||||
final String xpaths[] = { | |||||
nsDecl+".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr", | |||||
nsDecl+".//p:notesStyle/a:lvl" +(level+1)+ "pPr" | |||||
}; | |||||
final String nsPML = "http://schemas.openxmlformats.org/presentationml/2006/main"; | |||||
final String nsDML = "http://schemas.openxmlformats.org/drawingml/2006/main"; | |||||
XSLFSheet masterSheet = _shape.getSheet(); | XSLFSheet masterSheet = _shape.getSheet(); | ||||
for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) { | for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) { | ||||
masterSheet = m; | masterSheet = m; | ||||
XmlObject xo = masterSheet.getXmlObject(); | XmlObject xo = masterSheet.getXmlObject(); | ||||
for (String xpath : xpaths) { | |||||
XmlObject[] o = xo.selectPath(xpath); | |||||
if (o.length == 1) { | |||||
return (CTTextParagraphProperties)o[0]; | |||||
XmlCursor cur = xo.newCursor(); | |||||
try { | |||||
cur.push(); | |||||
if ((cur.toChild(nsPML, "txStyles") && cur.toChild(nsPML, defaultStyleSelector)) || | |||||
(cur.pop() && cur.toChild(nsPML, "notesStyle"))) { | |||||
if (cur.toChild(nsDML, "lvl" +(level+1)+ "pPr")) { | |||||
return (CTTextParagraphProperties)cur.getObject(); | |||||
} | |||||
} | } | ||||
} finally { | |||||
cur.dispose(); | |||||
} | } | ||||
} | } | ||||
List<XSLFTextRun> otherRs = other.getTextRuns(); | List<XSLFTextRun> otherRs = other.getTextRuns(); | ||||
int i=0; | int i=0; | ||||
for(CTRegularTextRun rtr : thisP.getRArray()) { | for(CTRegularTextRun rtr : thisP.getRArray()) { | ||||
XSLFTextRun run = new XSLFTextRun(rtr, this); | |||||
XSLFTextRun run = newTextRun(rtr); | |||||
run.copy(otherRs.get(i++)); | run.copy(otherRs.get(i++)); | ||||
_runs.add(run); | _runs.add(run); | ||||
} | } | ||||
@Override | @Override | ||||
public Double getDefaultFontSize() { | public Double getDefaultFontSize() { | ||||
CTTextCharacterProperties endPr = _p.getEndParaRPr(); | CTTextCharacterProperties endPr = _p.getEndParaRPr(); | ||||
if (endPr == null || !endPr.isSetSz()) { | |||||
endPr = getDefaultMasterStyle().getDefRPr(); | |||||
} | |||||
return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100.); | return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100.); | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
/** | |||||
* Helper method to allow subclasses to provide their own text run | |||||
* | |||||
* @param r the xml reference | |||||
* | |||||
* @return a new text paragraph | |||||
* | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
protected XSLFTextRun newTextRun(CTRegularTextRun r) { | |||||
return new XSLFTextRun(r, this); | |||||
} | |||||
} | } |
/** | /** | ||||
* Represents a run of text within the containing text body. The run element is the | * Represents a run of text within the containing text body. The run element is the | ||||
* lowest level text separation mechanism within a text body. | * lowest level text separation mechanism within a text body. | ||||
* | |||||
* @author Yegor Kozlov | |||||
*/ | */ | ||||
@Beta | @Beta | ||||
public class XSLFTextRun implements TextRun { | public class XSLFTextRun implements TextRun { | ||||
private final CTRegularTextRun _r; | private final CTRegularTextRun _r; | ||||
private final XSLFTextParagraph _p; | private final XSLFTextParagraph _p; | ||||
XSLFTextRun(CTRegularTextRun r, XSLFTextParagraph p){ | |||||
protected XSLFTextRun(CTRegularTextRun r, XSLFTextParagraph p){ | |||||
_r = r; | _r = r; | ||||
_p = p; | _p = p; | ||||
} | } |
CTTextBody txBody = getTextBody(false); | CTTextBody txBody = getTextBody(false); | ||||
if (txBody != null) { | if (txBody != null) { | ||||
for (CTTextParagraph p : txBody.getPArray()) { | for (CTTextParagraph p : txBody.getPArray()) { | ||||
_paragraphs.add(new XSLFTextParagraph(p, this)); | |||||
_paragraphs.add(newTextParagraph(p)); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
txBody.removeP(i-1); | txBody.removeP(i-1); | ||||
_paragraphs.remove(i-1); | _paragraphs.remove(i-1); | ||||
} | } | ||||
_paragraphs.get(0).clearButKeepProperties(); | _paragraphs.get(0).clearButKeepProperties(); | ||||
} | } | ||||
return appendText(text, false); | return appendText(text, false); | ||||
} | } | ||||
@Override | @Override | ||||
public XSLFTextRun appendText(String text, boolean newParagraph) { | public XSLFTextRun appendText(String text, boolean newParagraph) { | ||||
if (text == null) return null; | if (text == null) return null; | ||||
// copy properties from last paragraph / textrun or paragraph end marker | // copy properties from last paragraph / textrun or paragraph end marker | ||||
CTTextParagraphProperties pPr = null; | CTTextParagraphProperties pPr = null; | ||||
CTTextCharacterProperties rPr = null; | CTTextCharacterProperties rPr = null; | ||||
boolean firstPara; | boolean firstPara; | ||||
XSLFTextParagraph para; | XSLFTextParagraph para; | ||||
if (_paragraphs.isEmpty()) { | if (_paragraphs.isEmpty()) { | ||||
rPr = ctp.getEndParaRPr(); | rPr = ctp.getEndParaRPr(); | ||||
} | } | ||||
} | } | ||||
XSLFTextRun run = null; | XSLFTextRun run = null; | ||||
for (String lineTxt : text.split("\\r\\n?|\\n")) { | for (String lineTxt : text.split("\\r\\n?|\\n")) { | ||||
if (!firstPara) { | if (!firstPara) { | ||||
} | } | ||||
firstPara = false; | firstPara = false; | ||||
} | } | ||||
assert(run != null); | assert(run != null); | ||||
return run; | return run; | ||||
} | } | ||||
} else { | } else { | ||||
p = txBody.addNewP(); | p = txBody.addNewP(); | ||||
} | } | ||||
XSLFTextParagraph paragraph = new XSLFTextParagraph(p, this); | |||||
XSLFTextParagraph paragraph = newTextParagraph(p); | |||||
_paragraphs.add(paragraph); | _paragraphs.add(paragraph); | ||||
return paragraph; | return paragraph; | ||||
} | } | ||||
fetchShapeProperty(fetcher); | fetchShapeProperty(fetcher); | ||||
return fetcher.getValue() == null ? false : fetcher.getValue(); | return fetcher.getValue() == null ? false : fetcher.getValue(); | ||||
} | } | ||||
@Override | @Override | ||||
public void setTextDirection(TextDirection orientation){ | public void setTextDirection(TextDirection orientation){ | ||||
CTTextBodyProperties bodyPr = getTextBodyPr(true); | CTTextBodyProperties bodyPr = getTextBodyPr(true); | ||||
if (bodyPr != null && bodyPr.isSetRot()) { | if (bodyPr != null && bodyPr.isSetRot()) { | ||||
return bodyPr.getRot() / 60000.; | return bodyPr.getRot() / 60000.; | ||||
} | } | ||||
return null; | |||||
return null; | |||||
} | } | ||||
@Override | @Override | ||||
public void setTextRotation(Double rotation) { | public void setTextRotation(Double rotation) { | ||||
CTTextBodyProperties bodyPr = getTextBodyPr(true); | CTTextBodyProperties bodyPr = getTextBodyPr(true); | ||||
bodyPr.setRot((int)(rotation * 60000.)); | bodyPr.setRot((int)(rotation * 60000.)); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Returns the distance (in points) between the bottom of the text frame | * 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. | * and the bottom of the inscribed rectangle of the shape that contains the text. | ||||
Insets2D insets = new Insets2D(getTopInset(), getLeftInset(), getBottomInset(), getRightInset()); | Insets2D insets = new Insets2D(getTopInset(), getLeftInset(), getBottomInset(), getRightInset()); | ||||
return insets; | return insets; | ||||
} | } | ||||
@Override | @Override | ||||
public void setInsets(Insets2D insets) { | public void setInsets(Insets2D insets) { | ||||
setTopInset(insets.top); | setTopInset(insets.top); | ||||
setBottomInset(insets.bottom); | setBottomInset(insets.bottom); | ||||
setRightInset(insets.right); | setRightInset(insets.right); | ||||
} | } | ||||
@Override | @Override | ||||
public boolean getWordWrap(){ | public boolean getWordWrap(){ | ||||
PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){ | PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){ | ||||
} | } | ||||
return textBodyPr; | return textBodyPr; | ||||
} | } | ||||
protected abstract CTTextBody getTextBody(boolean create); | protected abstract CTTextBody getTextBody(boolean create); | ||||
@Override | @Override | ||||
public void setPlaceholder(Placeholder placeholder) { | public void setPlaceholder(Placeholder placeholder) { | ||||
super.setPlaceholder(placeholder); | super.setPlaceholder(placeholder); | ||||
} | } | ||||
public Placeholder getTextType(){ | public Placeholder getTextType(){ | ||||
CTPlaceholder ph = getCTPlaceholder(); | CTPlaceholder ph = getCTPlaceholder(); | ||||
if (ph == null) return null; | if (ph == null) return null; | ||||
Rectangle2D anchor = getAnchor(); | Rectangle2D anchor = getAnchor(); | ||||
if(anchor.getWidth() == 0.) throw new POIXMLException( | if(anchor.getWidth() == 0.) throw new POIXMLException( | ||||
"Anchor of the shape was not set."); | "Anchor of the shape was not set."); | ||||
double height = getTextHeight(); | |||||
double height = getTextHeight(); | |||||
height += 1; // add a pixel to compensate rounding errors | height += 1; // add a pixel to compensate rounding errors | ||||
anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height); | anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height); | ||||
setAnchor(anchor); | setAnchor(anchor); | ||||
return anchor; | return anchor; | ||||
} | |||||
} | |||||
@Override | @Override | ||||
void copy(XSLFShape other){ | void copy(XSLFShape other){ | ||||
if (otherTB == null) { | if (otherTB == null) { | ||||
return; | return; | ||||
} | } | ||||
thisTB.setBodyPr((CTTextBodyProperties)otherTB.getBodyPr().copy()); | thisTB.setBodyPr((CTTextBodyProperties)otherTB.getBodyPr().copy()); | ||||
if (thisTB.isSetLstStyle()) thisTB.unsetLstStyle(); | if (thisTB.isSetLstStyle()) thisTB.unsetLstStyle(); | ||||
if (otherTB.isSetLstStyle()) { | if (otherTB.isSetLstStyle()) { | ||||
thisTB.setLstStyle((CTTextListStyle)otherTB.getLstStyle().copy()); | thisTB.setLstStyle((CTTextListStyle)otherTB.getLstStyle().copy()); | ||||
} | } | ||||
boolean srcWordWrap = otherTS.getWordWrap(); | boolean srcWordWrap = otherTS.getWordWrap(); | ||||
if(srcWordWrap != getWordWrap()){ | if(srcWordWrap != getWordWrap()){ | ||||
setWordWrap(srcWordWrap); | setWordWrap(srcWordWrap); | ||||
} | } | ||||
clearText(); | clearText(); | ||||
for (XSLFTextParagraph srcP : otherTS.getTextParagraphs()) { | for (XSLFTextParagraph srcP : otherTS.getTextParagraphs()) { | ||||
XSLFTextParagraph tgtP = addNewTextParagraph(); | XSLFTextParagraph tgtP = addNewTextParagraph(); | ||||
tgtP.copy(srcP); | tgtP.copy(srcP); | ||||
default: | default: | ||||
case NOTES: | case NOTES: | ||||
case HALF_BODY: | case HALF_BODY: | ||||
case QUARTER_BODY: | |||||
case QUARTER_BODY: | |||||
case BODY: | case BODY: | ||||
setPlaceholder(Placeholder.BODY); | setPlaceholder(Placeholder.BODY); | ||||
break; | break; | ||||
case CENTERED_TITLE: return TextPlaceholder.CENTER_TITLE; | case CENTERED_TITLE: return TextPlaceholder.CENTER_TITLE; | ||||
default: | default: | ||||
case CONTENT: return TextPlaceholder.OTHER; | case CONTENT: return TextPlaceholder.OTHER; | ||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Helper method to allow subclasses to provide their own text paragraph | |||||
* | |||||
* @param p the xml reference | |||||
* | |||||
* @return a new text paragraph | |||||
* | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
protected XSLFTextParagraph newTextParagraph(CTTextParagraph p) { | |||||
return new XSLFTextParagraph(p, this); | |||||
} | } | ||||
} | } |
import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||
import static org.junit.Assert.assertNotNull; | import static org.junit.Assert.assertNotNull; | ||||
import java.io.IOException; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle; | |||||
/** | |||||
* @author Yegor Kozlov | |||||
*/ | |||||
public class TestXSLFTableStyles { | public class TestXSLFTableStyles { | ||||
@Test | @Test | ||||
public void testRead(){ | |||||
public void testRead() throws IOException { | |||||
XMLSlideShow ppt = new XMLSlideShow(); | XMLSlideShow ppt = new XMLSlideShow(); | ||||
XSLFTableStyles tblStyles = ppt.getTableStyles(); | XSLFTableStyles tblStyles = ppt.getTableStyles(); | ||||
assertNotNull(tblStyles); | assertNotNull(tblStyles); | ||||
assertEquals(0, tblStyles.getStyles().size()); | assertEquals(0, tblStyles.getStyles().size()); | ||||
} | |||||
@SuppressWarnings("unused") | |||||
@Test | |||||
public void testStyle(){ | |||||
CTTableStyle obj = CTTableStyle.Factory.newInstance(); | |||||
XSLFTableStyle style = new XSLFTableStyle(obj); | |||||
ppt.close(); | |||||
} | } | ||||
} | } |
package org.apache.poi.hslf.usermodel; | package org.apache.poi.hslf.usermodel; | ||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
import java.io.Serializable; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Collections; | |||||
import java.util.Comparator; | |||||
import java.util.HashSet; | import java.util.HashSet; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.SortedSet; | |||||
import java.util.TreeSet; | |||||
import org.apache.poi.ddf.AbstractEscherOptRecord; | import org.apache.poi.ddf.AbstractEscherOptRecord; | ||||
import org.apache.poi.ddf.EscherArrayProperty; | import org.apache.poi.ddf.EscherArrayProperty; | ||||
updateRowHeightsProperty(); | updateRowHeightsProperty(); | ||||
} | } | ||||
private static class TableCellComparator implements Comparator<HSLFShape>, Serializable { | |||||
public int compare( HSLFShape o1, HSLFShape o2 ) { | |||||
Rectangle2D anchor1 = o1.getAnchor(); | |||||
Rectangle2D anchor2 = o2.getAnchor(); | |||||
double delta = anchor1.getY() - anchor2.getY(); | |||||
if (delta == 0) { | |||||
delta = anchor1.getX() - anchor2.getX(); | |||||
} | |||||
// descending size | |||||
if (delta == 0) { | |||||
delta = (anchor2.getWidth()*anchor2.getHeight())-(anchor1.getWidth()*anchor1.getHeight()); | |||||
} | |||||
return (int)Math.signum(delta); | |||||
} | |||||
} | |||||
private void cellListToArray() { | private void cellListToArray() { | ||||
List<HSLFTableCell> htc = new ArrayList<HSLFTableCell>(); | List<HSLFTableCell> htc = new ArrayList<HSLFTableCell>(); | ||||
for (HSLFShape h : getShapes()) { | for (HSLFShape h : getShapes()) { | ||||
if (htc.isEmpty()) { | if (htc.isEmpty()) { | ||||
throw new IllegalStateException("HSLFTable without HSLFTableCells"); | throw new IllegalStateException("HSLFTable without HSLFTableCells"); | ||||
} | } | ||||
Collections.sort(htc, new TableCellComparator()); | |||||
List<HSLFTableCell[]> lst = new ArrayList<HSLFTableCell[]>(); | |||||
List<HSLFTableCell> row = new ArrayList<HSLFTableCell>(); | |||||
double y0 = htc.get(0).getAnchor().getY(); | |||||
SortedSet<Double> colSet = new TreeSet<Double>(); | |||||
SortedSet<Double> rowSet = new TreeSet<Double>(); | |||||
// #1 pass - determine cols and rows | |||||
for (HSLFTableCell sh : htc) { | for (HSLFTableCell sh : htc) { | ||||
Rectangle2D anchor = sh.getAnchor(); | Rectangle2D anchor = sh.getAnchor(); | ||||
boolean isNextRow = (anchor.getY() > y0); | |||||
if (isNextRow) { | |||||
y0 = anchor.getY(); | |||||
lst.add(row.toArray(new HSLFTableCell[row.size()])); | |||||
row.clear(); | |||||
} | |||||
row.add(sh); | |||||
colSet.add(anchor.getX()); | |||||
rowSet.add(anchor.getY()); | |||||
} | } | ||||
lst.add(row.toArray(new HSLFTableCell[row.size()])); | |||||
cells = lst.toArray(new HSLFTableCell[lst.size()][]); | |||||
cells = new HSLFTableCell[rowSet.size()][colSet.size()]; | |||||
List<Double> colLst = new ArrayList<Double>(colSet); | |||||
List<Double> rowLst = new ArrayList<Double>(rowSet); | |||||
// #2 pass - assign shape to table cells | |||||
for (HSLFTableCell sh : htc) { | |||||
Rectangle2D anchor = sh.getAnchor(); | |||||
int row = rowLst.indexOf(anchor.getY()); | |||||
int col = colLst.indexOf(anchor.getX()); | |||||
assert(row != -1 && col != -1); | |||||
cells[row][col] = sh; | |||||
// determine gridSpan / rowSpan | |||||
int gridSpan = calcSpan(colLst, anchor.getWidth(), col); | |||||
int rowSpan = calcSpan(rowLst, anchor.getHeight(), row); | |||||
sh.setGridSpan(gridSpan); | |||||
sh.setRowSpan(rowSpan); | |||||
} | |||||
} | } | ||||
private int calcSpan(List<Double> spaces, double totalSpace, int idx) { | |||||
if (idx == spaces.size()-1) { | |||||
return 1; | |||||
} | |||||
int span = 0; | |||||
double remainingSpace = totalSpace; | |||||
while (idx+1 < spaces.size() && remainingSpace > 0) { | |||||
remainingSpace -= spaces.get(idx+1)-spaces.get(idx); | |||||
span++; | |||||
idx++; | |||||
} | |||||
return span; | |||||
} | |||||
static class LineRect { | static class LineRect { | ||||
final HSLFLine l; | final HSLFLine l; | ||||
final double lx1, lx2, ly1, ly2; | final double lx1, lx2, ly1, ly2; | ||||
// TODO: this only works for non-rotated tables | // TODO: this only works for non-rotated tables | ||||
for (HSLFTableCell[] tca : cells) { | for (HSLFTableCell[] tca : cells) { | ||||
for (HSLFTableCell tc : tca) { | for (HSLFTableCell tc : tca) { | ||||
if (tc == null) { | |||||
continue; | |||||
} | |||||
final Rectangle2D cellAnchor = tc.getAnchor(); | final Rectangle2D cellAnchor = tc.getAnchor(); | ||||
/** | /** |
/** | /** | ||||
* Represents a cell in a ppt table | * Represents a cell in a ppt table | ||||
* | |||||
* @author Yegor Kozlov | |||||
*/ | */ | ||||
public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFShape,HSLFTextParagraph> { | public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFShape,HSLFTextParagraph> { | ||||
protected static final int DEFAULT_WIDTH = 100; | protected static final int DEFAULT_WIDTH = 100; | ||||
/* package */ HSLFLine borderTop; | /* package */ HSLFLine borderTop; | ||||
/* package */ HSLFLine borderBottom; | /* package */ HSLFLine borderBottom; | ||||
/** | |||||
* The number of columns to be spanned/merged | |||||
*/ | |||||
private int gridSpan = 1; | |||||
/** | |||||
* The number of columns to be spanned/merged | |||||
*/ | |||||
private int rowSpan = 1; | |||||
/** | /** | ||||
* Create a TableCell object and initialize it from the supplied Record container. | * Create a TableCell object and initialize it from the supplied Record container. | ||||
* | * | ||||
@Override | @Override | ||||
public StrokeStyle getBorderStyle(final BorderEdge edge) { | public StrokeStyle getBorderStyle(final BorderEdge edge) { | ||||
final Double width = getBorderWidth(edge); | |||||
final Double width = getBorderWidth(edge); | |||||
return (width == null) ? null : new StrokeStyle() { | return (width == null) ? null : new StrokeStyle() { | ||||
public PaintStyle getPaint() { | public PaintStyle getPaint() { | ||||
return DrawPaint.createSolidPaint(getBorderColor(edge)); | return DrawPaint.createSolidPaint(getBorderColor(edge)); | ||||
if (style == null) { | if (style == null) { | ||||
throw new IllegalArgumentException("StrokeStyle needs to be specified."); | throw new IllegalArgumentException("StrokeStyle needs to be specified."); | ||||
} | } | ||||
// setting the line cap is not implemented, as the border lines aren't connected | // setting the line cap is not implemented, as the border lines aren't connected | ||||
LineCompound compound = style.getLineCompound(); | LineCompound compound = style.getLineCompound(); | ||||
if (compound != null) { | if (compound != null) { | ||||
setBorderCompound(edge, compound); | setBorderCompound(edge, compound); | ||||
} | } | ||||
LineDash dash = style.getLineDash(); | LineDash dash = style.getLineDash(); | ||||
if (dash != null) { | if (dash != null) { | ||||
setBorderDash(edge, dash); | setBorderDash(edge, dash); | ||||
} | } | ||||
double width = style.getLineWidth(); | double width = style.getLineWidth(); | ||||
setBorderWidth(edge, width); | setBorderWidth(edge, width); | ||||
} | } | ||||
public Double getBorderWidth(BorderEdge edge) { | public Double getBorderWidth(BorderEdge edge) { | ||||
HSLFLine l; | HSLFLine l; | ||||
switch (edge) { | switch (edge) { | ||||
} | } | ||||
return (l == null) ? null : l.getLineWidth(); | return (l == null) ? null : l.getLineWidth(); | ||||
} | } | ||||
@Override | @Override | ||||
public void setBorderWidth(BorderEdge edge, double width) { | public void setBorderWidth(BorderEdge edge, double width) { | ||||
HSLFLine l = addLine(edge); | HSLFLine l = addLine(edge); | ||||
if (edge == null || color == null) { | if (edge == null || color == null) { | ||||
throw new IllegalArgumentException("BorderEdge and/or Color need to be specified."); | throw new IllegalArgumentException("BorderEdge and/or Color need to be specified."); | ||||
} | } | ||||
HSLFLine l = addLine(edge); | HSLFLine l = addLine(edge); | ||||
l.setLineColor(color); | l.setLineColor(color); | ||||
} | } | ||||
case left: l = borderLeft; break; | case left: l = borderLeft; break; | ||||
default: throw new IllegalArgumentException(); | default: throw new IllegalArgumentException(); | ||||
} | } | ||||
return (l == null) ? null : l.getLineDash(); | |||||
return (l == null) ? null : l.getLineDash(); | |||||
} | } | ||||
@Override | @Override | ||||
public void setBorderDash(BorderEdge edge, LineDash dash) { | public void setBorderDash(BorderEdge edge, LineDash dash) { | ||||
if (edge == null || dash == null) { | if (edge == null || dash == null) { | ||||
throw new IllegalArgumentException("BorderEdge and/or LineDash need to be specified."); | throw new IllegalArgumentException("BorderEdge and/or LineDash need to be specified."); | ||||
} | } | ||||
HSLFLine l = addLine(edge); | HSLFLine l = addLine(edge); | ||||
l.setLineDash(dash); | l.setLineDash(dash); | ||||
} | } | ||||
case left: l = borderLeft; break; | case left: l = borderLeft; break; | ||||
default: throw new IllegalArgumentException(); | default: throw new IllegalArgumentException(); | ||||
} | } | ||||
return (l == null) ? null : l.getLineCompound(); | |||||
return (l == null) ? null : l.getLineCompound(); | |||||
} | } | ||||
@Override | @Override | ||||
public void setBorderCompound(BorderEdge edge, LineCompound compound) { | public void setBorderCompound(BorderEdge edge, LineCompound compound) { | ||||
if (edge == null || compound == null) { | if (edge == null || compound == null) { | ||||
throw new IllegalArgumentException("BorderEdge and/or LineCompound need to be specified."); | throw new IllegalArgumentException("BorderEdge and/or LineCompound need to be specified."); | ||||
} | } | ||||
HSLFLine l = addLine(edge); | HSLFLine l = addLine(edge); | ||||
l.setLineCompound(compound); | l.setLineCompound(compound); | ||||
} | } | ||||
setEscherProperty(opt, EscherProperties.THREED__LIGHTFACE, 0x80000); | setEscherProperty(opt, EscherProperties.THREED__LIGHTFACE, 0x80000); | ||||
anchorBorder(edge, line); | anchorBorder(edge, line); | ||||
return line; | return line; | ||||
} | } | ||||
public HSLFTable getParent() { | public HSLFTable getParent() { | ||||
return (HSLFTable)super.getParent(); | return (HSLFTable)super.getParent(); | ||||
} | } | ||||
/** | |||||
* Set the gridSpan (aka col-span) | |||||
* | |||||
* @param gridSpan the number of columns to be spanned/merged | |||||
* | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
protected void setGridSpan(int gridSpan) { | |||||
this.gridSpan = gridSpan; | |||||
} | |||||
/** | |||||
* Set the rowSpan | |||||
* | |||||
* @param rowSpan the number of rows to be spanned/merged | |||||
* | |||||
* @since POI 3.15-beta2 | |||||
*/ | |||||
protected void setRowSpan(int rowSpan) { | |||||
this.rowSpan = rowSpan; | |||||
} | |||||
@Override | |||||
public int getGridSpan() { | |||||
return gridSpan; | |||||
} | |||||
@Override | |||||
public int getRowSpan() { | |||||
return rowSpan; | |||||
} | |||||
@Override | |||||
public boolean isMerged() { | |||||
// if a hslf cell is merged, it won't appear in the cell matrix, i.e. it doesn't exist | |||||
// therefore this is always false | |||||
return false; | |||||
} | |||||
} | } |