diff options
21 files changed, 890 insertions, 261 deletions
diff --git a/src/java/org/apache/poi/sl/draw/DrawFactory.java b/src/java/org/apache/poi/sl/draw/DrawFactory.java index d0584dadb3..f06ccdc1b0 100644 --- a/src/java/org/apache/poi/sl/draw/DrawFactory.java +++ b/src/java/org/apache/poi/sl/draw/DrawFactory.java @@ -56,6 +56,14 @@ public class DrawFactory { 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) {
// first try to find the factory over the rendering hint
DrawFactory factory = null;
diff --git a/src/java/org/apache/poi/sl/draw/DrawShape.java b/src/java/org/apache/poi/sl/draw/DrawShape.java index 0c465bc52a..f4f53b52d2 100644 --- a/src/java/org/apache/poi/sl/draw/DrawShape.java +++ b/src/java/org/apache/poi/sl/draw/DrawShape.java @@ -17,6 +17,7 @@ package org.apache.poi.sl.draw;
+import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
@@ -24,6 +25,9 @@ import java.util.Locale; import org.apache.poi.sl.usermodel.PlaceableShape;
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 {
@@ -157,4 +161,44 @@ public class DrawShape implements Drawable { protected Shape<?,?> getShape() {
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);
+ }
}
diff --git a/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java b/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java index 748b691dba..1032750690 100644 --- a/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java +++ b/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java @@ -53,9 +53,6 @@ import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.Shadow;
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;
@@ -282,45 +279,7 @@ public class DrawSimpleShape extends DrawShape { }
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(
diff --git a/src/java/org/apache/poi/sl/draw/DrawTableShape.java b/src/java/org/apache/poi/sl/draw/DrawTableShape.java index b44427838a..970c9b4e0b 100644 --- a/src/java/org/apache/poi/sl/draw/DrawTableShape.java +++ b/src/java/org/apache/poi/sl/draw/DrawTableShape.java @@ -19,21 +19,31 @@ package org.apache.poi.sl.draw; import java.awt.Color;
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.StrokeStyle;
import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
import org.apache.poi.sl.usermodel.TableCell;
import org.apache.poi.sl.usermodel.TableCell.BorderEdge;
+import org.apache.poi.util.Internal;
import org.apache.poi.sl.usermodel.TableShape;
public class DrawTableShape extends DrawShape {
- // to be implemented ...
+ /**
+ * Additional spacing between cells
+ */
+ @Internal
+ public static final int borderSize = 2;
+
public DrawTableShape(TableShape<?,?> shape) {
super(shape);
}
-
- protected Drawable getDrawable(Graphics2D graphics) {
+
+ protected Drawable getGroupShape(Graphics2D graphics) {
if (shape instanceof GroupShape) {
DrawFactory df = DrawFactory.getInstance(graphics);
return df.getDrawable((GroupShape<?,?>)shape);
@@ -42,31 +52,102 @@ public class DrawTableShape extends DrawShape { }
public void applyTransform(Graphics2D graphics) {
- Drawable d = getDrawable(graphics);
+ Drawable d = getGroupShape(graphics);
if (d != null) {
d.applyTransform(graphics);
+ } else {
+ super.applyTransform(graphics);
}
}
public void draw(Graphics2D graphics) {
- Drawable d = getDrawable(graphics);
+ Drawable d = getGroupShape(graphics);
if (d != null) {
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) {
- Drawable d = getDrawable(graphics);
+ Drawable d = getGroupShape(graphics);
if (d != null) {
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
protected TableShape<?,?> getShape() {
return (TableShape<?,?>)shape;
- }
-
+ }
+
/**
* Format the table and apply the specified Line to all cell boundaries,
* both outside and inside.
@@ -79,7 +160,7 @@ public class DrawTableShape extends DrawShape { TableShape<?,?> table = getShape();
final int rows = table.getNumberOfRows();
final int cols = table.getNumberOfColumns();
-
+
BorderEdge edges[] = { BorderEdge.top, BorderEdge.left, null, null };
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
@@ -99,11 +180,11 @@ public class DrawTableShape extends DrawShape { */
public void setOutsideBorders(Object... args){
if (args.length == 0) return;
-
+
TableShape<?,?> table = getShape();
final int rows = table.getNumberOfRows();
final int cols = table.getNumberOfColumns();
-
+
BorderEdge edges[] = new BorderEdge[4];
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
@@ -125,11 +206,11 @@ public class DrawTableShape extends DrawShape { */
public void setInsideBorders(Object... args) {
if (args.length == 0) return;
-
+
TableShape<?,?> table = getShape();
final int rows = table.getNumberOfRows();
final int cols = table.getNumberOfColumns();
-
+
BorderEdge edges[] = new BorderEdge[2];
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
@@ -139,7 +220,7 @@ public class DrawTableShape extends DrawShape { }
}
}
-
+
/**
* Apply the border attributes (args) to the given cell and edges
*
@@ -168,5 +249,4 @@ public class DrawTableShape extends DrawShape { }
}
}
-
}
diff --git a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java index 1ffa3cb94c..efdd7f4dae 100644 --- a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java +++ b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java @@ -17,6 +17,7 @@ package org.apache.poi.sl.draw;
+import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.font.FontRenderContext;
@@ -45,9 +46,11 @@ import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.sl.usermodel.TextRun.TextCap;
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.Units;
+
public class DrawTextParagraph implements Drawable {
/** Keys for passing hyperlinks to the graphics context */
public static final XlinkAttribute HYPERLINK_HREF = new XlinkAttribute("href");
@@ -390,14 +393,13 @@ public class DrawTextParagraph implements Drawable { * @return wrapping width in points
*/
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 rightInset = insets.right;
- Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());
-
int indentLevel = paragraph.getIndentLevel();
if (indentLevel == -1) {
// default to 0, if indentLevel is not set
@@ -417,13 +419,33 @@ public class DrawTextParagraph implements Drawable { rightMargin = 0d;
}
+ Rectangle2D anchor = DrawShape.getAnchor(graphics, ts);
+ TextDirection textDir = ts.getTextDirection();
double width;
- TextShape<?,?> ts = paragraph.getParentShape();
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 {
- 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 (bullet != null){
if (indent > 0) width -= indent;
diff --git a/src/java/org/apache/poi/sl/draw/DrawTextShape.java b/src/java/org/apache/poi/sl/draw/DrawTextShape.java index 24944c83b0..b1179349d7 100644 --- a/src/java/org/apache/poi/sl/draw/DrawTextShape.java +++ b/src/java/org/apache/poi/sl/draw/DrawTextShape.java @@ -30,6 +30,7 @@ import org.apache.poi.sl.usermodel.TextParagraph; import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle;
import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.sl.usermodel.TextShape;
+import org.apache.poi.sl.usermodel.TextShape.TextDirection;
public class DrawTextShape extends DrawSimpleShape {
@@ -50,7 +51,7 @@ public class DrawTextShape extends DrawSimpleShape { // remember the initial transform
AffineTransform tx = graphics.getTransform();
-
+
// Transform of text in flipped shapes is special.
// 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".
@@ -73,7 +74,7 @@ public class DrawTextShape extends DrawSimpleShape { graphics.scale(-1, 1);
graphics.translate(-anchor.getX(), -anchor.getY());
}
-
+
Double textRot = s.getTextRotation();
if (textRot != null && textRot != 0) {
graphics.translate(anchor.getCenterX(), anchor.getCenterY());
@@ -98,6 +99,20 @@ public class DrawTextShape extends DrawSimpleShape { 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);
// restore the transform
diff --git a/src/java/org/apache/poi/sl/usermodel/TableCell.java b/src/java/org/apache/poi/sl/usermodel/TableCell.java index 0b8d7dc549..9516196de9 100644 --- a/src/java/org/apache/poi/sl/usermodel/TableCell.java +++ b/src/java/org/apache/poi/sl/usermodel/TableCell.java @@ -83,4 +83,32 @@ public interface TableCell< * @param edge the border edge to be cleared
*/
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();
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java index e9a889d766..43034a2d1c 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java @@ -29,6 +29,7 @@ import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger;
import org.apache.xmlbeans.XmlObject;
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.CTPositiveFixedPercentage;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetColor;
@@ -165,6 +166,8 @@ public class XSLFColor { color = Color.black;
}
}
+ } else if (ch instanceof CTFontReference) {
+ // try next ...
} else {
throw new IllegalArgumentException("Unexpected color choice: " + ch.getClass());
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java index 5db266e42a..6dfe1d0c93 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java @@ -65,8 +65,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; /**
* Base super-class class for all shapes in PresentationML
- *
- * @author Yegor Kozlov
*/
@Beta
public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
@@ -150,6 +148,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { }
protected PaintStyle getFillPaint() {
+ final XSLFTheme theme = getSheet().getTheme();
PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {
public boolean fetch(XSLFShape shape) {
XmlObject pr = null;
@@ -178,7 +177,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { PaintStyle paint = null;
PackagePart pp = getSheet().getPackagePart();
for (XmlObject obj : pr.selectPath("*")) {
- paint = selectPaint(obj, null, pp);
+ paint = selectPaint(obj, null, pp, theme);
if (paint != null) {
setValue(paint);
return true;
@@ -203,7 +202,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { if (fillRef == null) {
fillRef = getBgRef();
}
- paint = selectPaint(fillRef);
+ paint = selectPaint(fillRef, theme);
return paint;
}
@@ -365,9 +364,11 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { protected PaintStyle getPaint(XmlObject spPr, CTSchemeColor phClr) {
PaintStyle paint = null;
- PackagePart pp = getSheet().getPackagePart();
+ XSLFSheet sheet = getSheet();
+ PackagePart pp = sheet.getPackagePart();
+ XSLFTheme theme = sheet.getTheme();
for (XmlObject obj : spPr.selectPath("*")) {
- paint = selectPaint(obj, phClr, pp);
+ paint = selectPaint(obj, phClr, pp, theme);
if(paint != null) break;
}
return paint;
@@ -392,24 +393,23 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { *
* @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) {
return null;
} else if (obj instanceof CTSolidColorFillProperties) {
- return selectPaint((CTSolidColorFillProperties)obj, phClr);
+ return selectPaint((CTSolidColorFillProperties)obj, phClr, theme);
} else if (obj instanceof CTBlipFillProperties) {
return selectPaint((CTBlipFillProperties)obj, parentPart);
} else if (obj instanceof CTGradientFillProperties) {
- return selectPaint((CTGradientFillProperties) obj, phClr);
+ return selectPaint((CTGradientFillProperties) obj, phClr, theme);
} else if (obj instanceof CTStyleMatrixReference) {
- return selectPaint((CTStyleMatrixReference)obj);
+ return selectPaint((CTStyleMatrixReference)obj, theme);
} else {
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()) {
phClr = solidFill.getSchemeClr();
}
@@ -417,7 +417,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { 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();
return new TexturePaint() {
private PackagePart getPart() {
@@ -451,7 +451,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { };
}
- 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();
@@ -465,7 +465,6 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { final ColorStyle cs[] = new ColorStyle[gs.length];
final float fractions[] = new float[gs.length];
- XSLFTheme theme = getSheet().getTheme();
int i=0;
for (CTGradientStop cgs : gs) {
@@ -519,7 +518,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { };
}
- protected PaintStyle selectPaint(CTStyleMatrixReference fillRef) {
+ protected static PaintStyle selectPaint(CTStyleMatrixReference fillRef, final XSLFTheme theme) {
if (fillRef == null) return null;
// The idx attribute refers to the index of a fill style or
@@ -529,8 +528,6 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { // values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element.
int idx = (int)fillRef.getIdx();
CTSchemeColor phClr = fillRef.getSchemeClr();
- XSLFSheet sheet = getSheet();
- XSLFTheme theme = sheet.getTheme();
XmlObject fillProps = null;
CTStyleMatrix matrix = theme.getXmlObject().getThemeElements().getFmtScheme();
if (idx >= 1 && idx <= 999) {
@@ -538,7 +535,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { } else if (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
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java index 1f3393d1f0..b90fbb0672 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java @@ -77,8 +77,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; /**
* Represents a single (non-group) shape in a .pptx slide show
- *
- * @author Yegor Kozlov
*/
@Beta
public abstract class XSLFSimpleShape extends XSLFShape
@@ -259,6 +257,7 @@ public abstract class XSLFSimpleShape extends XSLFShape }
protected PaintStyle getLinePaint() {
+ final XSLFTheme theme = getSheet().getTheme();
PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {
public boolean fetch(XSLFShape shape) {
CTLineProperties spPr = shape.getSpPr().getLn();
@@ -271,7 +270,7 @@ public abstract class XSLFSimpleShape extends XSLFShape PaintStyle paint = null;
PackagePart pp = getSheet().getPackagePart();
for (XmlObject obj : spPr.selectPath("*")) {
- paint = selectPaint(obj, null, pp);
+ paint = selectPaint(obj, null, pp, theme);
if (paint != null) {
setValue(paint);
return true;
@@ -280,7 +279,7 @@ public abstract class XSLFSimpleShape extends XSLFShape CTShapeStyle style = shape.getSpStyle();
if (style != null) {
- paint = selectPaint(style.getLnRef());
+ paint = selectPaint(style.getLnRef(), theme);
if (paint != null) {
setValue(paint);
return true;
@@ -305,7 +304,6 @@ public abstract class XSLFSimpleShape extends XSLFShape int idx = (int)lnRef.getIdx();
CTSchemeColor phClr = lnRef.getSchemeClr();
if(idx > 0){
- XSLFTheme theme = getSheet().getTheme();
XmlObject lnProps = theme.getXmlObject().
getThemeElements().getFmtScheme().getLnStyleLst().selectPath("*")[idx - 1];
paint = getPaint(lnProps, phClr);
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java index 21472d709b..023c8f7b4e 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java @@ -21,6 +21,7 @@ package org.apache.poi.xslf.usermodel; import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
+import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -29,6 +30,9 @@ import java.util.List; import javax.xml.namespace.QName;
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.util.Internal;
import org.apache.poi.util.Units;
@@ -45,12 +49,10 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFra /**
* Represents a table in a .pptx presentation
- *
- * @author Yegor Kozlov
*/
public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow>,
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 List<XSLFTableRow> _rows;
@@ -77,7 +79,11 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow _table = (CTTable) rs[0];
CTTableRow[] trArray = _table.getTrArray();
_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
@@ -146,8 +152,10 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow public XSLFTableRow addRow(){
CTTableRow tr = _table.addNewTr();
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);
+ updateRowColIndexes();
return row;
}
@@ -224,4 +232,110 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow }
}
}
+
+ /**
+ * 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);
+ }
+ }
+
+ }
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java index d4c3822fe5..fc77468731 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java @@ -20,6 +20,7 @@ package org.apache.poi.xslf.usermodel;
import java.awt.Color;
+import java.awt.geom.Rectangle2D;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.PaintStyle;
@@ -30,18 +31,32 @@ import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; import org.apache.poi.sl.usermodel.TableCell;
import org.apache.poi.sl.usermodel.VerticalAlignment;
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.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.CTTable;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell;
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.CTTextParagraph;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
import org.openxmlformats.schemas.drawingml.x2006.main.STCompoundLine;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType;
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.STPresetLineDashVal;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;
@@ -52,14 +67,22 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType; */
public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,XSLFTextParagraph> {
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
protected CTTextBody getTextBody(boolean create){
- CTTableCell cell = (CTTableCell)getXmlObject();
+ CTTableCell cell = getCell();
CTTextBody txBody = cell.getTxBody();
if (txBody == null && create) {
txBody = cell.addNewTxBody();
@@ -80,7 +103,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, protected CTTableCellProperties getCellProperties(boolean create) {
if (_tcPr == null) {
- CTTableCell cell = (CTTableCell)getXmlObject();
+ CTTableCell cell = getCell();
_tcPr = cell.getTcPr();
if (_tcPr == null && create) {
_tcPr = cell.addNewTcPr();
@@ -190,28 +213,28 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, }
};
}
-
+
@Override
public void setBorderStyle(BorderEdge edge, StrokeStyle style) {
if (style == null) {
throw new IllegalArgumentException("StrokeStyle needs to be specified.");
}
-
+
LineCap cap = style.getLineCap();
if (cap != null) {
setBorderCap(edge, cap);
}
-
+
LineCompound compound = style.getLineCompound();
if (compound != null) {
setBorderCompound(edge, compound);
}
-
+
LineDash dash = style.getLineDash();
if (dash != null) {
setBorderDash(edge, dash);
}
-
+
double width = style.getLineWidth();
setBorderWidth(edge, width);
}
@@ -273,10 +296,9 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, }
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) {
@@ -284,12 +306,8 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill()) return null;
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) {
@@ -335,7 +353,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill() || !ln.isSetCap()) {
return null;
}
-
+
return LineCap.fromOoxmlId(ln.getCap().intValue());
}
@@ -361,14 +379,10 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, CTTableCellProperties spPr = getCellProperties(true);
if (color == null) {
if(spPr.isSetSolidFill()) spPr.unsetSolidFill();
- }
- else {
+ } else {
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);
}
}
@@ -379,31 +393,126 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, @Override
public Color getFillColor(){
CTTableCellProperties spPr = getCellProperties(false);
- if (spPr == null || !spPr.isSetSolidFill()) return null;
+ if (spPr == null || !spPr.isSetSolidFill()) {
+ return null;
+ }
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;
}
- 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_) {
- ((CTTableCell)getXmlObject()).setGridSpan(gridSpan_);
+ getCell().setGridSpan(gridSpan_);
+ }
+
+ @Override
+ public int getGridSpan() {
+ CTTableCell c = getCell();
+ return (c.isSetGridSpan()) ? c.getGridSpan() : 1;
}
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_) {
- ((CTTableCell)getXmlObject()).setHMerge(merge_);
+ getCell().setHMerge(merge_);
}
void setVMerge(boolean merge_) {
- ((CTTableCell)getXmlObject()).setVMerge(merge_);
+ getCell().setVMerge(merge_);
}
@Override
@@ -457,7 +566,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, vt = STTextVerticalType.WORD_ART_VERT;
break;
}
-
+
cellProps.setVert(vt);
}
}
@@ -475,7 +584,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, } else {
orientation = STTextVerticalType.HORZ;
}
-
+
switch (orientation.intValue()) {
default:
case STTextVerticalType.INT_HORZ:
@@ -491,4 +600,142 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, 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();
+ }
+ }
+}
\ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableRow.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableRow.java index 491583f5aa..5326d9e784 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableRow.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableRow.java @@ -30,8 +30,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow; /**
* Represents a table in a .pptx presentation
- *
- * @author Yegor Kozlov
*/
public class XSLFTableRow implements Iterable<XSLFTableCell> {
private CTTableRow _row;
@@ -44,7 +42,7 @@ public class XSLFTableRow implements Iterable<XSLFTableCell> { CTTableCell[] tcArray = _row.getTcArray();
_cells = new ArrayList<XSLFTableCell>(tcArray.length);
for(CTTableCell cell : tcArray) {
- _cells.add(new XSLFTableCell(cell, table.getSheet()));
+ _cells.add(new XSLFTableCell(cell, table));
}
}
@@ -71,12 +69,13 @@ public class XSLFTableRow implements Iterable<XSLFTableCell> { public XSLFTableCell addCell(){
CTTableCell c = _row.addNewTc();
c.set(XSLFTableCell.prototype());
- XSLFTableCell cell = new XSLFTableCell(c, _table.getSheet());
+ XSLFTableCell cell = new XSLFTableCell(c, _table);
_cells.add(cell);
if(_table.getNumberOfColumns() < _row.sizeOfTcArray()) {
_table.getCTTable().getTblGrid().addNewGridCol().setW(Units.toEMU(100.0));
}
+ _table.updateRowColIndexes();
return cell;
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyle.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyle.java index 31840314b9..b3bcdfabd9 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyle.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyle.java @@ -19,16 +19,19 @@ package org.apache.poi.xslf.usermodel;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTablePartStyle;
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 {
private CTTableStyle _tblStyle;
+ public enum TablePartStyle {
+ wholeTbl, band1H, band2H, band1V, band2V, firstCol, lastCol, firstRow, lastRow, seCell, swCell, neCell, nwCell;
+ }
+
/*package*/ XSLFTableStyle(CTTableStyle style){
_tblStyle = style;
}
@@ -44,4 +47,39 @@ public class XSLFTableStyle { public String 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();
+ }
+ }
}
\ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyles.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyles.java index 76455d64df..410f84101d 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyles.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyles.java @@ -16,9 +16,8 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; - import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -31,6 +30,7 @@ import org.apache.poi.util.Beta; import org.apache.xmlbeans.XmlException; import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle; import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyleList; +import org.openxmlformats.schemas.drawingml.x2006.main.TblStyleLstDocument; @Beta public class XSLFTableStyles extends POIXMLDocumentPart implements Iterable<XSLFTableStyle>{ @@ -47,7 +47,10 @@ public class XSLFTableStyles extends POIXMLDocumentPart implements Iterable<XSLF public XSLFTableStyles(PackagePart part) throws IOException, XmlException { 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(); _styles = new ArrayList<XSLFTableStyle>(tblStyleArray.length); for(CTTableStyle c : tblStyleArray){ diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java index 9576eea3c2..b2a8b3314b 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java @@ -59,7 +59,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; * Represents a paragraph of text within the containing text body.
* The paragraph is the highest level text separation mechanism.
*
- * @author Yegor Kozlov
* @since POI-3.8
*/
@Beta
@@ -76,19 +75,19 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr for(XmlObject ch : _p.selectPath("*")){
if(ch instanceof CTRegularTextRun){
CTRegularTextRun r = (CTRegularTextRun)ch;
- _runs.add(new XSLFTextRun(r, this));
+ _runs.add(newTextRun(r));
} else if (ch instanceof CTTextLineBreak){
CTTextLineBreak br = (CTTextLineBreak)ch;
CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();
r.setRPr(br.getRPr());
r.setT("\n");
- _runs.add(new XSLFTextRun(r, this));
+ _runs.add(newTextRun(r));
} else if (ch instanceof CTTextField){
CTTextField f = (CTTextField)ch;
CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();
r.setRPr(f.getRPr());
r.setT(f.getT());
- _runs.add(new XSLFTextRun(r, this));
+ _runs.add(newTextRun(r));
}
}
}
@@ -137,7 +136,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr CTRegularTextRun r = _p.addNewR();
CTTextCharacterProperties rPr = r.addNewRPr();
rPr.setLang("en-US");
- XSLFTextRun run = new XSLFTextRun(r, this);
+ XSLFTextRun run = newTextRun(r);
_runs.add(run);
return run;
}
@@ -774,22 +773,23 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr int level = getIndentLevel();
// 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();
for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) {
masterSheet = m;
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();
}
}
@@ -880,7 +880,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr List<XSLFTextRun> otherRs = other.getTextRuns();
int i=0;
for(CTRegularTextRun rtr : thisP.getRArray()) {
- XSLFTextRun run = new XSLFTextRun(rtr, this);
+ XSLFTextRun run = newTextRun(rtr);
run.copy(otherRs.get(i++));
_runs.add(run);
}
@@ -949,6 +949,9 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr @Override
public Double getDefaultFontSize() {
CTTextCharacterProperties endPr = _p.getEndParaRPr();
+ if (endPr == null || !endPr.isSetSz()) {
+ endPr = getDefaultMasterStyle().getDefRPr();
+ }
return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100.);
}
@@ -1062,4 +1065,17 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr 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);
+ }
}
\ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java index 1a6bcc384a..c374c4016b 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java @@ -30,15 +30,13 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; /**
* Represents a run of text within the containing text body. The run element is the
* lowest level text separation mechanism within a text body.
- *
- * @author Yegor Kozlov
*/
@Beta
public class XSLFTextRun implements TextRun {
private final CTRegularTextRun _r;
private final XSLFTextParagraph _p;
- XSLFTextRun(CTRegularTextRun r, XSLFTextParagraph p){
+ protected XSLFTextRun(CTRegularTextRun r, XSLFTextParagraph p){
_r = r;
_p = p;
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java index f38ea9701e..a4400d21ba 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java @@ -62,7 +62,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape CTTextBody txBody = getTextBody(false); if (txBody != null) { for (CTTextParagraph p : txBody.getPArray()) { - _paragraphs.add(new XSLFTextParagraph(p, this)); + _paragraphs.add(newTextParagraph(p)); } } } @@ -100,13 +100,13 @@ public abstract class XSLFTextShape extends XSLFSimpleShape txBody.removeP(i-1); _paragraphs.remove(i-1); } - + _paragraphs.get(0).clearButKeepProperties(); } - + return appendText(text, false); } - + @Override public XSLFTextRun appendText(String text, boolean newParagraph) { if (text == null) return null; @@ -114,7 +114,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape // copy properties from last paragraph / textrun or paragraph end marker CTTextParagraphProperties pPr = null; CTTextCharacterProperties rPr = null; - + boolean firstPara; XSLFTextParagraph para; if (_paragraphs.isEmpty()) { @@ -133,7 +133,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape rPr = ctp.getEndParaRPr(); } } - + XSLFTextRun run = null; for (String lineTxt : text.split("\\r\\n?|\\n")) { if (!firstPara) { @@ -159,7 +159,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape } firstPara = false; } - + assert(run != null); return run; } @@ -184,7 +184,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape } else { p = txBody.addNewP(); } - XSLFTextParagraph paragraph = new XSLFTextParagraph(p, this); + XSLFTextParagraph paragraph = newTextParagraph(p); _paragraphs.add(paragraph); return paragraph; } @@ -243,7 +243,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape fetchShapeProperty(fetcher); return fetcher.getValue() == null ? false : fetcher.getValue(); } - + @Override public void setTextDirection(TextDirection orientation){ CTTextBodyProperties bodyPr = getTextBodyPr(true); @@ -274,9 +274,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape if (bodyPr != null && bodyPr.isSetRot()) { return bodyPr.getRot() / 60000.; } - return null; + return null; } - + @Override public void setTextRotation(Double rotation) { CTTextBodyProperties bodyPr = getTextBodyPr(true); @@ -284,8 +284,8 @@ public abstract class XSLFTextShape extends XSLFSimpleShape bodyPr.setRot((int)(rotation * 60000.)); } } - - + + /** * 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. @@ -437,7 +437,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape Insets2D insets = new Insets2D(getTopInset(), getLeftInset(), getBottomInset(), getRightInset()); return insets; } - + @Override public void setInsets(Insets2D insets) { setTopInset(insets.top); @@ -445,7 +445,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape setBottomInset(insets.bottom); setRightInset(insets.right); } - + @Override public boolean getWordWrap(){ PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){ @@ -520,14 +520,14 @@ public abstract class XSLFTextShape extends XSLFSimpleShape } return textBodyPr; } - + protected abstract CTTextBody getTextBody(boolean create); @Override public void setPlaceholder(Placeholder placeholder) { super.setPlaceholder(placeholder); } - + public Placeholder getTextType(){ CTPlaceholder ph = getCTPlaceholder(); if (ph == null) return null; @@ -552,15 +552,15 @@ public abstract class XSLFTextShape extends XSLFSimpleShape Rectangle2D anchor = getAnchor(); if(anchor.getWidth() == 0.) throw new POIXMLException( "Anchor of the shape was not set."); - double height = getTextHeight(); + double height = getTextHeight(); height += 1; // add a pixel to compensate rounding errors - + anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height); setAnchor(anchor); - + return anchor; - } - + } + @Override void copy(XSLFShape other){ @@ -572,14 +572,14 @@ public abstract class XSLFTextShape extends XSLFSimpleShape if (otherTB == null) { return; } - + thisTB.setBodyPr((CTTextBodyProperties)otherTB.getBodyPr().copy()); if (thisTB.isSetLstStyle()) thisTB.unsetLstStyle(); if (otherTB.isSetLstStyle()) { thisTB.setLstStyle((CTTextListStyle)otherTB.getLstStyle().copy()); } - + boolean srcWordWrap = otherTS.getWordWrap(); if(srcWordWrap != getWordWrap()){ setWordWrap(srcWordWrap); @@ -608,7 +608,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape } clearText(); - + for (XSLFTextParagraph srcP : otherTS.getTextParagraphs()) { XSLFTextParagraph tgtP = addNewTextParagraph(); tgtP.copy(srcP); @@ -621,7 +621,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape default: case NOTES: case HALF_BODY: - case QUARTER_BODY: + case QUARTER_BODY: case BODY: setPlaceholder(Placeholder.BODY); break; @@ -651,8 +651,19 @@ public abstract class XSLFTextShape extends XSLFSimpleShape case CENTERED_TITLE: return TextPlaceholder.CENTER_TITLE; default: 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); } - - }
\ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java index 49b5fd4944..12369937ea 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java @@ -19,27 +19,20 @@ package org.apache.poi.xslf.usermodel; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import java.io.IOException;
+
import org.junit.Test;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle;
-/**
- * @author Yegor Kozlov
- */
public class TestXSLFTableStyles {
@Test
- public void testRead(){
+ public void testRead() throws IOException {
XMLSlideShow ppt = new XMLSlideShow();
XSLFTableStyles tblStyles = ppt.getTableStyles();
assertNotNull(tblStyles);
assertEquals(0, tblStyles.getStyles().size());
- }
-
- @SuppressWarnings("unused")
- @Test
- public void testStyle(){
- CTTableStyle obj = CTTableStyle.Factory.newInstance();
- XSLFTableStyle style = new XSLFTableStyle(obj);
+
+ ppt.close();
}
}
\ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTable.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTable.java index a1944c6aed..f007dd9877 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTable.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTable.java @@ -18,13 +18,12 @@ package org.apache.poi.hslf.usermodel; import java.awt.geom.Rectangle2D; -import java.io.Serializable; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import org.apache.poi.ddf.AbstractEscherOptRecord; import org.apache.poi.ddf.EscherArrayProperty; @@ -170,23 +169,6 @@ implements HSLFShapeContainer, TableShape<HSLFShape,HSLFTextParagraph> { 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() { List<HSLFTableCell> htc = new ArrayList<HSLFTableCell>(); for (HSLFShape h : getShapes()) { @@ -198,28 +180,52 @@ implements HSLFShapeContainer, TableShape<HSLFShape,HSLFTextParagraph> { if (htc.isEmpty()) { 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) { 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 { final HSLFLine l; final double lx1, lx2, ly1, ly2; @@ -258,6 +264,9 @@ implements HSLFShapeContainer, TableShape<HSLFShape,HSLFTextParagraph> { // TODO: this only works for non-rotated tables for (HSLFTableCell[] tca : cells) { for (HSLFTableCell tc : tca) { + if (tc == null) { + continue; + } final Rectangle2D cellAnchor = tc.getAnchor(); /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java index aee8994832..a8e3294d1d 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java @@ -33,8 +33,6 @@ import org.apache.poi.sl.usermodel.TableCell; /** * Represents a cell in a ppt table - * - * @author Yegor Kozlov */ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFShape,HSLFTextParagraph> { protected static final int DEFAULT_WIDTH = 100; @@ -46,6 +44,16 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh /* 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. * * @param escherRecord EscherSpContainer which holds information about this shape @@ -129,7 +137,7 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh @Override public StrokeStyle getBorderStyle(final BorderEdge edge) { - final Double width = getBorderWidth(edge); + final Double width = getBorderWidth(edge); return (width == null) ? null : new StrokeStyle() { public PaintStyle getPaint() { return DrawPaint.createSolidPaint(getBorderColor(edge)); @@ -158,24 +166,24 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh if (style == null) { throw new IllegalArgumentException("StrokeStyle needs to be specified."); } - + // setting the line cap is not implemented, as the border lines aren't connected - + LineCompound compound = style.getLineCompound(); if (compound != null) { setBorderCompound(edge, compound); } - + LineDash dash = style.getLineDash(); if (dash != null) { setBorderDash(edge, dash); } - + double width = style.getLineWidth(); setBorderWidth(edge, width); } - + public Double getBorderWidth(BorderEdge edge) { HSLFLine l; switch (edge) { @@ -187,7 +195,7 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh } return (l == null) ? null : l.getLineWidth(); } - + @Override public void setBorderWidth(BorderEdge edge, double width) { HSLFLine l = addLine(edge); @@ -211,7 +219,7 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh if (edge == null || color == null) { throw new IllegalArgumentException("BorderEdge and/or Color need to be specified."); } - + HSLFLine l = addLine(edge); l.setLineColor(color); } @@ -225,15 +233,15 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh case left: l = borderLeft; break; default: throw new IllegalArgumentException(); } - return (l == null) ? null : l.getLineDash(); + return (l == null) ? null : l.getLineDash(); } - + @Override public void setBorderDash(BorderEdge edge, LineDash dash) { if (edge == null || dash == null) { throw new IllegalArgumentException("BorderEdge and/or LineDash need to be specified."); } - + HSLFLine l = addLine(edge); l.setLineDash(dash); } @@ -247,15 +255,15 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh case left: l = borderLeft; break; default: throw new IllegalArgumentException(); } - return (l == null) ? null : l.getLineCompound(); + return (l == null) ? null : l.getLineCompound(); } - + @Override public void setBorderCompound(BorderEdge edge, LineCompound compound) { if (edge == null || compound == null) { throw new IllegalArgumentException("BorderEdge and/or LineCompound need to be specified."); } - + HSLFLine l = addLine(edge); l.setLineCompound(compound); } @@ -381,7 +389,7 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh setEscherProperty(opt, EscherProperties.THREED__LIGHTFACE, 0x80000); anchorBorder(edge, line); - + return line; } @@ -397,4 +405,43 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh public HSLFTable 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; + } } |