]> source.dussan.org Git - poi.git/commitdiff
#57766 - XSLFTable isn't exported on convert slides of a .pptx slide show to a PNG...
authorAndreas Beeker <kiwiwings@apache.org>
Sat, 4 Jun 2016 22:53:00 +0000 (22:53 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sat, 4 Jun 2016 22:53:00 +0000 (22:53 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1746856 13f79535-47bb-0310-9956-ffa450edef68

21 files changed:
src/java/org/apache/poi/sl/draw/DrawFactory.java
src/java/org/apache/poi/sl/draw/DrawShape.java
src/java/org/apache/poi/sl/draw/DrawSimpleShape.java
src/java/org/apache/poi/sl/draw/DrawTableShape.java
src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
src/java/org/apache/poi/sl/draw/DrawTextShape.java
src/java/org/apache/poi/sl/usermodel/TableCell.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableRow.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyle.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableStyles.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTable.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java

index d0584dadb3069bdcab860a932e1f7fd9a8011db9..f06ccdc1b092126262942c0ba31b81bfc2839e3c 100644 (file)
@@ -56,6 +56,14 @@ public class DrawFactory {
         defaultFactory.set(factory);\r
     }\r
 \r
+    /**\r
+     * Returns the DrawFactory, preferably via a graphics instance.\r
+     * If graphics is null, the current thread local is checked or\r
+     * if it is not set, a new factory is created. \r
+     *\r
+     * @param graphics the current graphics context or null\r
+     * @return the draw factory\r
+     */\r
     public static DrawFactory getInstance(Graphics2D graphics) {\r
         // first try to find the factory over the rendering hint\r
         DrawFactory factory = null;\r
index 0c465bc52a6f4d58368813e269adfb4e6fab6d65..f4f53b52d20aecc707bb7ffdb2afdd16250d6fe8 100644 (file)
@@ -17,6 +17,7 @@
 \r
 package org.apache.poi.sl.draw;\r
 \r
+import java.awt.BasicStroke;\r
 import java.awt.Graphics2D;\r
 import java.awt.geom.AffineTransform;\r
 import java.awt.geom.Rectangle2D;\r
@@ -24,6 +25,9 @@ import java.util.Locale;
 \r
 import org.apache.poi.sl.usermodel.PlaceableShape;\r
 import org.apache.poi.sl.usermodel.Shape;\r
+import org.apache.poi.sl.usermodel.StrokeStyle;\r
+import org.apache.poi.sl.usermodel.StrokeStyle.LineCap;\r
+import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;\r
 \r
 \r
 public class DrawShape implements Drawable {\r
@@ -157,4 +161,44 @@ public class DrawShape implements Drawable {
     protected Shape<?,?> getShape() {\r
         return shape;\r
     }\r
+    \r
+    protected static BasicStroke getStroke(StrokeStyle strokeStyle) {\r
+        float lineWidth = (float) strokeStyle.getLineWidth();\r
+        if (lineWidth == 0.0f) lineWidth = 0.25f; // Both PowerPoint and OOo draw zero-length lines as 0.25pt\r
+\r
+        LineDash lineDash = strokeStyle.getLineDash();\r
+        if (lineDash == null) {\r
+            lineDash = LineDash.SOLID;\r
+        }\r
+\r
+        int dashPatI[] = lineDash.pattern;\r
+        final float dash_phase = 0;\r
+        float[] dashPatF = null;\r
+        if (dashPatI != null) {\r
+            dashPatF = new float[dashPatI.length];\r
+            for (int i=0; i<dashPatI.length; i++) {\r
+                dashPatF[i] = dashPatI[i]*Math.max(1, lineWidth);\r
+            }\r
+        }\r
+\r
+        LineCap lineCapE = strokeStyle.getLineCap();\r
+        if (lineCapE == null) lineCapE = LineCap.FLAT;\r
+        int lineCap;\r
+        switch (lineCapE) {\r
+            case ROUND:\r
+                lineCap = BasicStroke.CAP_ROUND;\r
+                break;\r
+            case SQUARE:\r
+                lineCap = BasicStroke.CAP_SQUARE;\r
+                break;\r
+            default:\r
+            case FLAT:\r
+                lineCap = BasicStroke.CAP_BUTT;\r
+                break;\r
+        }\r
+\r
+        int lineJoin = BasicStroke.JOIN_ROUND;\r
+\r
+        return new BasicStroke(lineWidth, lineCap, lineJoin, lineWidth, dashPatF, dash_phase);\r
+    }\r
 }\r
index 748b691dba489dfb293e3016fe6d0ebf48bac7b0..1032750690a41d93db9c11df0e342c0e2a208e42 100644 (file)
@@ -53,9 +53,6 @@ import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
 import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;\r
 import org.apache.poi.sl.usermodel.Shadow;\r
 import org.apache.poi.sl.usermodel.SimpleShape;\r
-import org.apache.poi.sl.usermodel.StrokeStyle;\r
-import org.apache.poi.sl.usermodel.StrokeStyle.LineCap;\r
-import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;\r
 import org.apache.poi.util.Units;\r
 \r
 \r
@@ -282,45 +279,7 @@ public class DrawSimpleShape extends DrawShape {
     }\r
 \r
     public BasicStroke getStroke() {\r
-        StrokeStyle strokeStyle = getShape().getStrokeStyle();\r
-\r
-        float lineWidth = (float) strokeStyle.getLineWidth();\r
-        if (lineWidth == 0.0f) lineWidth = 0.25f; // Both PowerPoint and OOo draw zero-length lines as 0.25pt\r
-\r
-        LineDash lineDash = strokeStyle.getLineDash();\r
-        if (lineDash == null) {\r
-               lineDash = LineDash.SOLID;\r
-        }\r
-\r
-        int dashPatI[] = lineDash.pattern;\r
-        final float dash_phase = 0;\r
-        float[] dashPatF = null;\r
-        if (dashPatI != null) {\r
-            dashPatF = new float[dashPatI.length];\r
-            for (int i=0; i<dashPatI.length; i++) {\r
-                dashPatF[i] = dashPatI[i]*Math.max(1, lineWidth);\r
-            }\r
-        }\r
-\r
-        LineCap lineCapE = strokeStyle.getLineCap();\r
-        if (lineCapE == null) lineCapE = LineCap.FLAT;\r
-        int lineCap;\r
-        switch (lineCapE) {\r
-            case ROUND:\r
-                lineCap = BasicStroke.CAP_ROUND;\r
-                break;\r
-            case SQUARE:\r
-                lineCap = BasicStroke.CAP_SQUARE;\r
-                break;\r
-            default:\r
-            case FLAT:\r
-                lineCap = BasicStroke.CAP_BUTT;\r
-                break;\r
-        }\r
-\r
-        int lineJoin = BasicStroke.JOIN_ROUND;\r
-\r
-        return new BasicStroke(lineWidth, lineCap, lineJoin, lineWidth, dashPatF, dash_phase);\r
+        return getStroke(getShape().getStrokeStyle());\r
     }\r
 \r
     protected void drawShadow(\r
index b44427838a43b7285e765dd3be21e234ab9c1c8f..970c9b4e0b67ab73a8fdbd6243eeeb4fd01b3011 100644 (file)
@@ -19,21 +19,31 @@ package org.apache.poi.sl.draw;
 \r
 import java.awt.Color;\r
 import java.awt.Graphics2D;\r
+import java.awt.Paint;\r
+import java.awt.geom.Line2D;\r
+import java.awt.geom.Rectangle2D;\r
 \r
 import org.apache.poi.sl.usermodel.GroupShape;\r
+import org.apache.poi.sl.usermodel.StrokeStyle;\r
 import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;\r
 import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;\r
 import org.apache.poi.sl.usermodel.TableCell;\r
 import org.apache.poi.sl.usermodel.TableCell.BorderEdge;\r
+import org.apache.poi.util.Internal;\r
 import org.apache.poi.sl.usermodel.TableShape;\r
 \r
 public class DrawTableShape extends DrawShape {\r
-    // to be implemented ...\r
+    /**\r
+     * Additional spacing between cells\r
+     */\r
+    @Internal\r
+    public static final int borderSize = 2;\r
+    \r
     public DrawTableShape(TableShape<?,?> shape) {\r
         super(shape);\r
     }\r
-    \r
-    protected Drawable getDrawable(Graphics2D graphics) {\r
+\r
+    protected Drawable getGroupShape(Graphics2D graphics) {\r
         if (shape instanceof GroupShape) {\r
             DrawFactory df = DrawFactory.getInstance(graphics);\r
             return df.getDrawable((GroupShape<?,?>)shape);\r
@@ -42,31 +52,102 @@ public class DrawTableShape extends DrawShape {
     }\r
 \r
     public void applyTransform(Graphics2D graphics) {\r
-        Drawable d = getDrawable(graphics);\r
+        Drawable d = getGroupShape(graphics);\r
         if (d != null) {\r
             d.applyTransform(graphics);\r
+        } else {\r
+            super.applyTransform(graphics);\r
         }\r
     }\r
 \r
     public void draw(Graphics2D graphics) {\r
-        Drawable d = getDrawable(graphics);\r
+        Drawable d = getGroupShape(graphics);\r
         if (d != null) {\r
             d.draw(graphics);\r
+            return;\r
         }\r
+\r
+        TableShape<?,?> ts = getShape();\r
+        DrawPaint drawPaint = DrawFactory.getInstance(graphics).getPaint(ts);\r
+        final int rows = ts.getNumberOfRows();\r
+        final int cols = ts.getNumberOfColumns();\r
+        \r
+        // draw background boxes\r
+        for (int row=0; row<rows; row++) {\r
+            for (int col=0; col<cols; col++) {\r
+                TableCell<?,?> tc = ts.getCell(row, col);\r
+                if (tc == null || tc.isMerged()) {\r
+                    continue;\r
+                }\r
+\r
+                Paint fillPaint = drawPaint.getPaint(graphics, tc.getFillStyle().getPaint());\r
+                graphics.setPaint(fillPaint);\r
+                Rectangle2D cellAnc = tc.getAnchor();\r
+                graphics.fill(cellAnc);\r
+                \r
+                for (BorderEdge edge : BorderEdge.values()) {\r
+                    StrokeStyle stroke = tc.getBorderStyle(edge);\r
+                    if (stroke == null) {\r
+                        continue;\r
+                    }\r
+                    graphics.setStroke(getStroke(stroke));\r
+                    Paint linePaint = drawPaint.getPaint(graphics, stroke.getPaint());\r
+                    graphics.setPaint(linePaint);\r
+\r
+                    double x=cellAnc.getX(), y=cellAnc.getY(), w=cellAnc.getWidth(), h=cellAnc.getHeight();\r
+                    Line2D line;\r
+                    switch (edge) {\r
+                        default:\r
+                        case bottom:\r
+                            line = new Line2D.Double(x-borderSize, y+h, x+w+borderSize, y+h);\r
+                            break;\r
+                        case left:\r
+                            line = new Line2D.Double(x, y, x, y+h+borderSize);\r
+                            break;\r
+                        case right:\r
+                            line = new Line2D.Double(x+w, y, x+w, y+h+borderSize);\r
+                            break;\r
+                        case top:\r
+                            line = new Line2D.Double(x-borderSize, y, x+w+borderSize, y);\r
+                            break;\r
+                    }\r
+\r
+                    graphics.draw(line);\r
+                }\r
+            }\r
+        }\r
+\r
+        // draw text\r
+        drawContent(graphics);\r
     }\r
 \r
     public void drawContent(Graphics2D graphics) {\r
-        Drawable d = getDrawable(graphics);\r
+        Drawable d = getGroupShape(graphics);\r
         if (d != null) {\r
             d.drawContent(graphics);\r
+            return;\r
+        }\r
+        \r
+        TableShape<?,?> ts = getShape();\r
+        DrawFactory df = DrawFactory.getInstance(graphics);\r
+\r
+        final int rows = ts.getNumberOfRows();\r
+        final int cols = ts.getNumberOfColumns();\r
+        \r
+        for (int row=0; row<rows; row++) {\r
+            for (int col=0; col<cols; col++) {\r
+                TableCell<?,?> tc = ts.getCell(row, col);\r
+                DrawTextShape dts = df.getDrawable(tc);\r
+                dts.drawContent(graphics);\r
+            }\r
         }\r
     }\r
 \r
     @Override\r
     protected TableShape<?,?> getShape() {\r
         return (TableShape<?,?>)shape;\r
-    }    \r
-    \r
+    }\r
+\r
     /**\r
      * Format the table and apply the specified Line to all cell boundaries,\r
      * both outside and inside.\r
@@ -79,7 +160,7 @@ public class DrawTableShape extends DrawShape {
         TableShape<?,?> table = getShape();\r
         final int rows = table.getNumberOfRows();\r
         final int cols = table.getNumberOfColumns();\r
-        \r
+\r
         BorderEdge edges[] = { BorderEdge.top, BorderEdge.left, null, null };\r
         for (int row = 0; row < rows; row++) {\r
             for (int col = 0; col < cols; col++) {\r
@@ -99,11 +180,11 @@ public class DrawTableShape extends DrawShape {
      */\r
     public void setOutsideBorders(Object... args){\r
         if (args.length == 0) return;\r
-        \r
+\r
         TableShape<?,?> table = getShape();\r
         final int rows = table.getNumberOfRows();\r
         final int cols = table.getNumberOfColumns();\r
-        \r
+\r
         BorderEdge edges[] = new BorderEdge[4];\r
         for (int row = 0; row < rows; row++) {\r
             for (int col = 0; col < cols; col++) {\r
@@ -125,11 +206,11 @@ public class DrawTableShape extends DrawShape {
      */\r
     public void setInsideBorders(Object... args) {\r
         if (args.length == 0) return;\r
-        \r
+\r
         TableShape<?,?> table = getShape();\r
         final int rows = table.getNumberOfRows();\r
         final int cols = table.getNumberOfColumns();\r
-        \r
+\r
         BorderEdge edges[] = new BorderEdge[2];\r
         for (int row = 0; row < rows; row++) {\r
             for (int col = 0; col < cols; col++) {\r
@@ -139,7 +220,7 @@ public class DrawTableShape extends DrawShape {
             }\r
         }\r
     }\r
-    \r
+\r
     /**\r
      * Apply the border attributes (args) to the given cell and edges\r
      *\r
@@ -168,5 +249,4 @@ public class DrawTableShape extends DrawShape {
             }\r
         }\r
     }\r
-    \r
 }\r
index 1ffa3cb94ce6448239f75d60b2ac1a2110499e6e..efdd7f4dae8a1a31631cdb03bc8126cdae3ff752 100644 (file)
@@ -17,6 +17,7 @@
 \r
 package org.apache.poi.sl.draw;\r
 \r
+import java.awt.Dimension;\r
 import java.awt.Graphics2D;\r
 import java.awt.Paint;\r
 import java.awt.font.FontRenderContext;\r
@@ -45,9 +46,11 @@ import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
 import org.apache.poi.sl.usermodel.TextRun;\r
 import org.apache.poi.sl.usermodel.TextRun.TextCap;\r
 import org.apache.poi.sl.usermodel.TextShape;\r
+import org.apache.poi.sl.usermodel.TextShape.TextDirection;\r
 import org.apache.poi.util.StringUtil;\r
 import org.apache.poi.util.Units;\r
 \r
+\r
 public class DrawTextParagraph implements Drawable {\r
     /** Keys for passing hyperlinks to the graphics context */\r
     public static final XlinkAttribute HYPERLINK_HREF = new XlinkAttribute("href");\r
@@ -390,14 +393,13 @@ public class DrawTextParagraph implements Drawable {
      * @return  wrapping width in points\r
      */\r
     protected double getWrappingWidth(boolean firstLine, Graphics2D graphics){\r
-        // internal margins for the text box\r
+        TextShape<?,?> ts = paragraph.getParentShape();\r
 \r
-        Insets2D insets = paragraph.getParentShape().getInsets();\r
+        // internal margins for the text box\r
+        Insets2D insets = ts.getInsets();\r
         double leftInset = insets.left;\r
         double rightInset = insets.right;\r
 \r
-        Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());\r
-\r
         int indentLevel = paragraph.getIndentLevel();\r
         if (indentLevel == -1) {\r
             // default to 0, if indentLevel is not set\r
@@ -417,13 +419,33 @@ public class DrawTextParagraph implements Drawable {
             rightMargin = 0d;\r
         }\r
 \r
+        Rectangle2D anchor = DrawShape.getAnchor(graphics, ts);\r
+        TextDirection textDir = ts.getTextDirection();\r
         double width;\r
-        TextShape<?,?> ts = paragraph.getParentShape();\r
         if (!ts.getWordWrap()) {\r
-            // if wordWrap == false then we return the advance to the right border of the sheet\r
-            width = ts.getSheet().getSlideShow().getPageSize().getWidth() - anchor.getX();\r
+            Dimension pageDim = ts.getSheet().getSlideShow().getPageSize();\r
+            // if wordWrap == false then we return the advance to the (right) border of the sheet\r
+            switch (textDir) {\r
+                default:\r
+                    width = pageDim.getWidth() - anchor.getX();\r
+                    break;\r
+                case VERTICAL:\r
+                    width = pageDim.getHeight() - anchor.getX();\r
+                    break;\r
+                case VERTICAL_270:\r
+                    width = anchor.getX();\r
+                    break;\r
+            }\r
         } else {\r
-            width = anchor.getWidth() - leftInset - rightInset - leftMargin - rightMargin;\r
+            switch (textDir) {\r
+                default:\r
+                    width = anchor.getWidth() - leftInset - rightInset - leftMargin - rightMargin;\r
+                    break;\r
+                case VERTICAL:\r
+                case VERTICAL_270:\r
+                    width = anchor.getHeight() - leftInset - rightInset - leftMargin - rightMargin;\r
+                    break;\r
+            }\r
             if (firstLine && !isHSLF()) {\r
                 if (bullet != null){\r
                     if (indent > 0) width -= indent;\r
index 24944c83b022a6e733c7c4a5fa3ab523f7da0bb1..b1179349d72faf17e72a3c80c3c92964c1d0798b 100644 (file)
@@ -30,6 +30,7 @@ import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle;\r
 import org.apache.poi.sl.usermodel.TextRun;\r
 import org.apache.poi.sl.usermodel.TextShape;\r
+import org.apache.poi.sl.usermodel.TextShape.TextDirection;\r
 \r
 public class DrawTextShape extends DrawSimpleShape {\r
 \r
@@ -50,7 +51,7 @@ public class DrawTextShape extends DrawSimpleShape {
 \r
         // remember the initial transform\r
         AffineTransform tx = graphics.getTransform();\r
-\r
+    \r
         // Transform of text in flipped shapes is special.\r
         // At this point the flip and rotation transform is already applied\r
         // (see DrawShape#applyTransform ), but we need to restore it to avoid painting "upside down".\r
@@ -73,7 +74,7 @@ public class DrawTextShape extends DrawSimpleShape {
             graphics.scale(-1, 1);\r
             graphics.translate(-anchor.getX(), -anchor.getY());\r
         }\r
-        \r
+\r
         Double textRot = s.getTextRotation();\r
         if (textRot != null && textRot != 0) {\r
             graphics.translate(anchor.getCenterX(), anchor.getCenterY());\r
@@ -98,6 +99,20 @@ public class DrawTextShape extends DrawSimpleShape {
                 break;\r
         }\r
 \r
+        TextDirection textDir = s.getTextDirection();\r
+        if (textDir == TextDirection.VERTICAL || textDir == TextDirection.VERTICAL_270) {\r
+            double deg = (textDir == TextDirection.VERTICAL) ? 90 : 270;\r
+            graphics.translate(anchor.getCenterX(), anchor.getCenterY());\r
+            graphics.rotate(Math.toRadians(deg));\r
+            graphics.translate(-anchor.getCenterX(), -anchor.getCenterY());\r
+            \r
+            // old top/left edge is now bottom/left or top/right - as we operate on the already\r
+            // rotated drawing context, both verticals can be moved in the same direction\r
+            double w = anchor.getWidth();\r
+            double h = anchor.getHeight();\r
+            graphics.translate((w-h)/2d,(h-w)/2d);\r
+        }\r
+\r
         drawParagraphs(graphics, x, y);\r
 \r
         // restore the transform\r
index 0b8d7dc549e0c0cf9450a129f5d47ea48d221185..9516196de92ea5c1c90172b4469e2f35684d04d9 100644 (file)
@@ -83,4 +83,32 @@ public interface TableCell<
      * @param edge the border edge to be cleared\r
      */\r
     void removeBorder(BorderEdge edge);\r
+\r
+    /**\r
+     * Get the number of columns to be spanned/merged\r
+     *\r
+     * @return the grid span\r
+     * \r
+     * @since POI 3.15-beta2\r
+     */\r
+    int getGridSpan();\r
+    \r
+    /**\r
+     * Get the number of rows to be spanned/merged\r
+     *\r
+     * @return the row span\r
+     * \r
+     * @since POI 3.15-beta2\r
+     */\r
+    int getRowSpan();\r
+\r
+    /**\r
+     * Return if this cell is part of a merged cell. The top/left cell of a merged region is not regarded as merged -\r
+     * its grid and/or row span is greater than one. \r
+     *\r
+     * @return true if this a merged cell\r
+     * \r
+     * @since POI 3.15-beta2\r
+     */\r
+    boolean isMerged();\r
 }\r
index e9a889d766032bcc7877612b391032528c8d89cb..43034a2d1c71220247359327680c2edc6c408f8f 100644 (file)
@@ -29,6 +29,7 @@ import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;\r
 import org.apache.xmlbeans.XmlObject;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTFontReference;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTHslColor;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveFixedPercentage;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetColor;\r
@@ -165,6 +166,8 @@ public class XSLFColor {
                         color = Color.black;\r
                     }\r
                 }\r
+            } else if (ch instanceof CTFontReference) {\r
+                // try next ...\r
             } else {\r
                 throw new IllegalArgumentException("Unexpected color choice: " + ch.getClass());\r
             }\r
index 5db266e42a682f372aadbded660f5c5ca0e595c9..6dfe1d0c935882a4c3ffdeb2a58582eaa145c079 100644 (file)
@@ -65,8 +65,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
 \r
 /**\r
  * Base super-class class for all shapes in PresentationML\r
- *\r
- * @author Yegor Kozlov\r
  */\r
 @Beta\r
 public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {\r
@@ -150,6 +148,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
     }\r
     \r
     protected PaintStyle getFillPaint() {\r
+        final XSLFTheme theme = getSheet().getTheme();\r
         PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {\r
             public boolean fetch(XSLFShape shape) {\r
                 XmlObject pr = null;\r
@@ -178,7 +177,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
                 PaintStyle paint = null;\r
                 PackagePart pp = getSheet().getPackagePart();\r
                 for (XmlObject obj : pr.selectPath("*")) {\r
-                    paint = selectPaint(obj, null, pp);\r
+                    paint = selectPaint(obj, null, pp, theme);\r
                     if (paint != null) {\r
                         setValue(paint);\r
                         return true;\r
@@ -203,7 +202,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         if (fillRef == null) {\r
             fillRef = getBgRef();\r
         }\r
-        paint = selectPaint(fillRef);\r
+        paint = selectPaint(fillRef, theme);\r
 \r
         return paint;\r
     }\r
@@ -365,9 +364,11 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
 \r
     protected PaintStyle getPaint(XmlObject spPr, CTSchemeColor phClr) {\r
         PaintStyle paint = null;\r
-        PackagePart pp = getSheet().getPackagePart();\r
+        XSLFSheet sheet = getSheet(); \r
+        PackagePart pp = sheet.getPackagePart();\r
+        XSLFTheme theme = sheet.getTheme();\r
         for (XmlObject obj : spPr.selectPath("*")) {\r
-            paint = selectPaint(obj, phClr, pp);\r
+            paint = selectPaint(obj, phClr, pp, theme);\r
             if(paint != null) break;\r
         }\r
         return paint;\r
@@ -392,24 +393,23 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
      *\r
      * @return  the applied Paint or null if none was applied\r
      */\r
-    protected PaintStyle selectPaint(XmlObject obj, final CTSchemeColor phClr, final PackagePart parentPart) {\r
+    protected static PaintStyle selectPaint(XmlObject obj, final CTSchemeColor phClr, final PackagePart parentPart, final XSLFTheme theme) {\r
         if (obj instanceof CTNoFillProperties) {\r
             return null;\r
         } else if (obj instanceof CTSolidColorFillProperties) {\r
-            return selectPaint((CTSolidColorFillProperties)obj, phClr);\r
+            return selectPaint((CTSolidColorFillProperties)obj, phClr, theme);\r
         } else if (obj instanceof CTBlipFillProperties) {\r
             return selectPaint((CTBlipFillProperties)obj, parentPart);\r
         } else if (obj instanceof CTGradientFillProperties) {\r
-            return selectPaint((CTGradientFillProperties) obj, phClr);\r
+            return selectPaint((CTGradientFillProperties) obj, phClr, theme);\r
         } else if (obj instanceof CTStyleMatrixReference) {\r
-            return selectPaint((CTStyleMatrixReference)obj);\r
+            return selectPaint((CTStyleMatrixReference)obj, theme);\r
         } else {\r
             return null;\r
         }\r
     }\r
 \r
-    protected PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr) {\r
-        final XSLFTheme theme = getSheet().getTheme();\r
+    protected static PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr, final XSLFTheme theme) {\r
         if (phClr == null && solidFill.isSetSchemeClr()) {\r
             phClr = solidFill.getSchemeClr();\r
         }\r
@@ -417,7 +417,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         return DrawPaint.createSolidPaint(c.getColorStyle());\r
     }\r
     \r
-    protected PaintStyle selectPaint(final CTBlipFillProperties blipFill, final PackagePart parentPart) {\r
+    protected static PaintStyle selectPaint(final CTBlipFillProperties blipFill, final PackagePart parentPart) {\r
         final CTBlip blip = blipFill.getBlip();\r
         return new TexturePaint() {\r
             private PackagePart getPart() {\r
@@ -451,7 +451,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         };        \r
     }\r
     \r
-    protected PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr) {\r
+    protected static PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme) {\r
 \r
         final CTGradientStop[] gs = gradFill.getGsLst().getGsArray();\r
 \r
@@ -465,7 +465,6 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
 \r
         final ColorStyle cs[] = new ColorStyle[gs.length];\r
         final float fractions[] = new float[gs.length];\r
-        XSLFTheme theme = getSheet().getTheme();\r
         \r
         int i=0;\r
         for (CTGradientStop cgs : gs) {\r
@@ -519,7 +518,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         };        \r
     }\r
     \r
-    protected PaintStyle selectPaint(CTStyleMatrixReference fillRef) {\r
+    protected static PaintStyle selectPaint(CTStyleMatrixReference fillRef, final XSLFTheme theme) {\r
         if (fillRef == null) return null;\r
         \r
         // The idx attribute refers to the index of a fill style or\r
@@ -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.\r
         int idx = (int)fillRef.getIdx();\r
         CTSchemeColor phClr = fillRef.getSchemeClr();\r
-        XSLFSheet sheet = getSheet();\r
-        XSLFTheme theme = sheet.getTheme();\r
         XmlObject fillProps = null;\r
         CTStyleMatrix matrix = theme.getXmlObject().getThemeElements().getFmtScheme();\r
         if (idx >= 1 && idx <= 999) {\r
@@ -538,7 +535,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         } else if (idx >= 1001 ){\r
             fillProps = matrix.getBgFillStyleLst().selectPath("*")[idx - 1001];\r
         }\r
-        return (fillProps == null) ? null : selectPaint(fillProps, phClr, theme.getPackagePart());\r
+        return (fillProps == null) ? null : selectPaint(fillProps, phClr, theme.getPackagePart(), theme);\r
     }\r
     \r
     @Override\r
index 1f3393d1f0bfbc8cb6ba5ef9b444a1b6e7c4386d..b90fbb06721aaec05db75d18600123dd773ee2eb 100644 (file)
@@ -77,8 +77,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
 \r
 /**\r
  * Represents a single (non-group) shape in a .pptx slide show\r
- *\r
- * @author Yegor Kozlov\r
  */\r
 @Beta\r
 public abstract class XSLFSimpleShape extends XSLFShape\r
@@ -259,6 +257,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
     }\r
 \r
     protected PaintStyle getLinePaint() {\r
+        final XSLFTheme theme = getSheet().getTheme();\r
         PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {\r
             public boolean fetch(XSLFShape shape) {\r
                 CTLineProperties spPr = shape.getSpPr().getLn();\r
@@ -271,7 +270,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
                     PaintStyle paint = null;\r
                     PackagePart pp = getSheet().getPackagePart();\r
                     for (XmlObject obj : spPr.selectPath("*")) {\r
-                        paint = selectPaint(obj, null, pp);\r
+                        paint = selectPaint(obj, null, pp, theme);\r
                         if (paint != null) {\r
                             setValue(paint);\r
                             return true;\r
@@ -280,7 +279,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
 \r
                     CTShapeStyle style = shape.getSpStyle();\r
                     if (style != null) {\r
-                        paint = selectPaint(style.getLnRef());\r
+                        paint = selectPaint(style.getLnRef(), theme);\r
                         if (paint != null) {\r
                             setValue(paint);\r
                             return true;\r
@@ -305,7 +304,6 @@ public abstract class XSLFSimpleShape extends XSLFShape
         int idx = (int)lnRef.getIdx();\r
         CTSchemeColor phClr = lnRef.getSchemeClr();\r
         if(idx > 0){\r
-            XSLFTheme theme = getSheet().getTheme();\r
             XmlObject lnProps = theme.getXmlObject().\r
                     getThemeElements().getFmtScheme().getLnStyleLst().selectPath("*")[idx - 1];\r
             paint = getPaint(lnProps, phClr);\r
index 21472d709b7a022c974691b28d1551f715bde3ae..023c8f7b4e6c40f3dd24870720570af9bf035d97 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.poi.xslf.usermodel;
 \r
 import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;\r
 \r
+import java.awt.geom.Rectangle2D;\r
 import java.util.ArrayList;\r
 import java.util.Collections;\r
 import java.util.Iterator;\r
@@ -29,6 +30,9 @@ import java.util.List;
 import javax.xml.namespace.QName;\r
 \r
 import org.apache.poi.POIXMLException;\r
+import org.apache.poi.sl.draw.DrawFactory;\r
+import org.apache.poi.sl.draw.DrawTableShape;\r
+import org.apache.poi.sl.draw.DrawTextShape;\r
 import org.apache.poi.sl.usermodel.TableShape;\r
 import org.apache.poi.util.Internal;\r
 import org.apache.poi.util.Units;\r
@@ -45,12 +49,10 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFra
 \r
 /**\r
  * Represents a table in a .pptx presentation\r
- *\r
- * @author Yegor Kozlov\r
  */\r
 public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow>,\r
     TableShape<XSLFShape,XSLFTextParagraph> {\r
-    static String TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";\r
+    /* package */ static final String TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";\r
 \r
     private CTTable _table;\r
     private List<XSLFTableRow> _rows;\r
@@ -77,7 +79,11 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
         _table = (CTTable) rs[0];\r
         CTTableRow[] trArray = _table.getTrArray();\r
         _rows = new ArrayList<XSLFTableRow>(trArray.length);\r
-        for(CTTableRow row : trArray) _rows.add(new XSLFTableRow(row, this));\r
+        for(CTTableRow row : trArray) {\r
+            XSLFTableRow xr = new XSLFTableRow(row, this);\r
+            _rows.add(xr);\r
+        }\r
+        updateRowColIndexes();\r
     }\r
 \r
     @Override\r
@@ -146,8 +152,10 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
     public XSLFTableRow addRow(){\r
         CTTableRow tr = _table.addNewTr();\r
         XSLFTableRow row = new XSLFTableRow(tr, this);\r
-        row.setHeight(20.0);    // default height is 20 points\r
+        // default height is 20 points\r
+        row.setHeight(20.0);    \r
         _rows.add(row);\r
+        updateRowColIndexes();\r
         return row;\r
     }\r
 \r
@@ -224,4 +232,110 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
                }\r
        }\r
     }\r
+    \r
+    /**\r
+     * Get assigned TableStyle\r
+     *\r
+     * @return the assigned TableStyle\r
+     * \r
+     * @since POI 3.15-beta2\r
+     */\r
+    protected XSLFTableStyle getTableStyle() {\r
+        CTTable tab = getCTTable();\r
+        // TODO: support inline table style\r
+        if (!tab.isSetTblPr() || !tab.getTblPr().isSetTableStyleId()) {\r
+            return null;\r
+        }\r
+        \r
+        String styleId = tab.getTblPr().getTableStyleId();\r
+        XSLFTableStyles styles = getSheet().getSlideShow().getTableStyles();\r
+        for (XSLFTableStyle style : styles.getStyles()) {\r
+            if (style.getStyleId().equals(styleId)) {\r
+                return style;\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+    \r
+    /* package */ void updateRowColIndexes() {\r
+        int rowIdx = 0;\r
+        for (XSLFTableRow xr : this) {\r
+            int colIdx = 0;\r
+            for (XSLFTableCell tc : xr) {\r
+                tc.setRowColIndex(rowIdx, colIdx);\r
+                colIdx++;\r
+            }\r
+            rowIdx++;\r
+        }\r
+    }\r
+\r
+    /* package */ void updateCellAnchor() {\r
+        int rows = getNumberOfRows();\r
+        int cols = getNumberOfColumns();\r
+\r
+        double colWidths[] = new double[cols];\r
+        double rowHeights[] = new double[rows];\r
+\r
+        for (int row=0; row<rows; row++) {\r
+            rowHeights[row] = getRowHeight(row);\r
+        }\r
+        for (int col=0; col<cols; col++) {\r
+            colWidths[col] = getColumnWidth(col);\r
+        }\r
+\r
+        Rectangle2D tblAnc = getAnchor();\r
+        DrawFactory df = DrawFactory.getInstance(null);\r
+        \r
+        double newY = tblAnc.getY();\r
+\r
+        // #1 pass - determine row heights, the height values might be too low or 0 ...\r
+        for (int row=0; row<rows; row++) {\r
+            double maxHeight = 0;\r
+            for (int col=0; col<cols; col++) {\r
+                XSLFTableCell tc = getCell(row, col);\r
+                if (tc.getGridSpan() != 1 || tc.getRowSpan() != 1) {\r
+                    continue;\r
+                }\r
+                // need to set the anchor before height calculation\r
+                tc.setAnchor(new Rectangle2D.Double(0,0,colWidths[col],0));\r
+                DrawTextShape dts = df.getDrawable(tc);\r
+                maxHeight = Math.max(maxHeight, dts.getTextHeight());\r
+            }\r
+            rowHeights[row] = Math.max(rowHeights[row],maxHeight);\r
+        }\r
+        \r
+        // #2 pass - init properties\r
+        for (int row=0; row<rows; row++) {\r
+            double newX = tblAnc.getX();\r
+            for (int col=0; col<cols; col++) {\r
+                Rectangle2D bounds = new Rectangle2D.Double(newX, newY, colWidths[col], rowHeights[row]);\r
+                XSLFTableCell tc = getCell(row, col);\r
+                tc.setAnchor(bounds);\r
+                newX += colWidths[col]+DrawTableShape.borderSize;\r
+            }\r
+            newY += rowHeights[row]+DrawTableShape.borderSize;\r
+        }\r
+        \r
+        // #3 pass - update merge info\r
+        for (int row=0; row<rows; row++) {\r
+            for (int col=0; col<cols; col++) {\r
+                XSLFTableCell tc = getCell(row, col);\r
+                Rectangle2D mergedBounds = tc.getAnchor();\r
+                for (int col2=col+1; col2<col+tc.getGridSpan(); col2++) {\r
+                    assert(col2 < cols);\r
+                    XSLFTableCell tc2 = getCell(row, col2);\r
+                    assert(tc2.getGridSpan() == 1 && tc2.getRowSpan() == 1);\r
+                    mergedBounds.add(tc2.getAnchor());\r
+                }\r
+                for (int row2=row+1; row2<row+tc.getRowSpan(); row2++) {\r
+                    assert(row2 < rows);\r
+                    XSLFTableCell tc2 = getCell(row2, col);\r
+                    assert(tc2.getGridSpan() == 1 && tc2.getRowSpan() == 1);\r
+                    mergedBounds.add(tc2.getAnchor());\r
+                }\r
+                tc.setAnchor(mergedBounds);\r
+            }\r
+        }\r
+        \r
+    }\r
 }\r
index d4c3822fe54e41f9fd9c1322137bf64399ffd681..fc774687317c17f56b42fbdc1e7451244273e504 100644 (file)
@@ -20,6 +20,7 @@
 package org.apache.poi.xslf.usermodel;\r
 \r
 import java.awt.Color;\r
+import java.awt.geom.Rectangle2D;\r
 \r
 import org.apache.poi.sl.draw.DrawPaint;\r
 import org.apache.poi.sl.usermodel.PaintStyle;\r
@@ -30,18 +31,32 @@ import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
 import org.apache.poi.sl.usermodel.TableCell;\r
 import org.apache.poi.sl.usermodel.VerticalAlignment;\r
 import org.apache.poi.util.Units;\r
+import org.apache.poi.xslf.usermodel.XSLFTableStyle.TablePartStyle;\r
+import org.apache.xmlbeans.XmlObject;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTFillProperties;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTFontReference;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTable;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCellProperties;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTablePartStyle;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTableProperties;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyleTextStyle;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STCompoundLine;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.STOnOffStyleType;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STPenAlignment;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;\r
@@ -52,14 +67,22 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType;
  */\r
 public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,XSLFTextParagraph> {\r
     private CTTableCellProperties _tcPr = null;\r
+    private final XSLFTable table;\r
+    private int row = 0, col = 0;\r
 \r
-    /*package*/ XSLFTableCell(CTTableCell cell, XSLFSheet sheet){\r
-        super(cell, sheet);\r
+    /**\r
+     * Volatile/temporary anchor - e.g. for rendering\r
+     */\r
+    private Rectangle2D anchor = null;\r
+\r
+    /*package*/ XSLFTableCell(CTTableCell cell, XSLFTable table){\r
+        super(cell, table.getSheet());\r
+        this.table = table;\r
     }\r
 \r
     @Override\r
     protected CTTextBody getTextBody(boolean create){\r
-        CTTableCell cell = (CTTableCell)getXmlObject();\r
+        CTTableCell cell = getCell();\r
         CTTextBody txBody = cell.getTxBody();\r
         if (txBody == null && create) {\r
             txBody = cell.addNewTxBody();\r
@@ -80,7 +103,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
 \r
     protected CTTableCellProperties getCellProperties(boolean create) {\r
         if (_tcPr == null) {\r
-            CTTableCell cell = (CTTableCell)getXmlObject();\r
+            CTTableCell cell = getCell();\r
             _tcPr = cell.getTcPr();\r
             if (_tcPr == null && create) {\r
                 _tcPr = cell.addNewTcPr();\r
@@ -190,28 +213,28 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
             }\r
         };\r
     }\r
-    \r
+\r
     @Override\r
     public void setBorderStyle(BorderEdge edge, StrokeStyle style) {\r
         if (style == null) {\r
             throw new IllegalArgumentException("StrokeStyle needs to be specified.");\r
         }\r
-        \r
+\r
         LineCap cap = style.getLineCap();\r
         if (cap != null) {\r
             setBorderCap(edge, cap);\r
         }\r
-        \r
+\r
         LineCompound compound = style.getLineCompound();\r
         if (compound != null) {\r
             setBorderCompound(edge, compound);\r
         }\r
-        \r
+\r
         LineDash dash = style.getLineDash();\r
         if (dash != null) {\r
             setBorderDash(edge, dash);\r
         }\r
-        \r
+\r
         double width = style.getLineWidth();\r
         setBorderWidth(edge, width);\r
     }\r
@@ -273,10 +296,9 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         }\r
 \r
         CTLineProperties ln = setBorderDefaults(edge);\r
-\r
-        CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();\r
-        rgb.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()});\r
-        ln.addNewSolidFill().setSrgbClr(rgb);\r
+        CTSolidColorFillProperties fill = ln.addNewSolidFill();\r
+        XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());\r
+        c.setColor(color);\r
     }\r
 \r
     public Color getBorderColor(BorderEdge edge) {\r
@@ -284,12 +306,8 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill()) return null;\r
 \r
         CTSolidColorFillProperties fill = ln.getSolidFill();\r
-        if (!fill.isSetSrgbClr()) {\r
-            // TODO for now return null for all colors except explicit RGB\r
-            return null;\r
-        }\r
-        byte[] val = fill.getSrgbClr().getVal();\r
-        return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);\r
+        XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());\r
+        return c.getColor();\r
     }\r
 \r
     public LineCompound getBorderCompound(BorderEdge edge) {\r
@@ -335,7 +353,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill() || !ln.isSetCap()) {\r
             return null;\r
         }\r
-        \r
+\r
         return LineCap.fromOoxmlId(ln.getCap().intValue());\r
     }\r
 \r
@@ -361,14 +379,10 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         CTTableCellProperties spPr = getCellProperties(true);\r
         if (color == null) {\r
             if(spPr.isSetSolidFill()) spPr.unsetSolidFill();\r
-        }\r
-        else {\r
+        } else {\r
             CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr.getSolidFill() : spPr.addNewSolidFill();\r
-\r
-            CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();\r
-            rgb.setVal(new byte[]{(byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()});\r
-\r
-            fill.setSrgbClr(rgb);\r
+            XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());\r
+            c.setColor(color);\r
         }\r
     }\r
 \r
@@ -379,31 +393,126 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
     @Override\r
     public Color getFillColor(){\r
         CTTableCellProperties spPr = getCellProperties(false);\r
-        if (spPr == null || !spPr.isSetSolidFill()) return null;\r
+        if (spPr == null || !spPr.isSetSolidFill()) {\r
+            return null;\r
+        }\r
 \r
         CTSolidColorFillProperties fill = spPr.getSolidFill();\r
-        if (!fill.isSetSrgbClr()) {\r
-            // TODO for now return null for all colors except explicit RGB\r
+        XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());\r
+        return c.getColor();\r
+    }\r
+\r
+    @SuppressWarnings("resource")\r
+    @Override\r
+    public PaintStyle getFillPaint() {\r
+        Color c = getFillColor();\r
+        if (c != null) {\r
+            return DrawPaint.createSolidPaint(c);\r
+        }\r
+\r
+        CTTablePartStyle tps = getTablePartStyle(null);\r
+        if (tps == null || !tps.isSetTcStyle()) {\r
+            tps = getTablePartStyle(TablePartStyle.wholeTbl);\r
+            if (tps == null || !tps.isSetTcStyle()) {\r
+                return null;\r
+            }\r
+        }\r
+\r
+        XMLSlideShow slideShow = table.getSheet().getSlideShow();\r
+        assert(slideShow != null);\r
+        XSLFTheme theme = slideShow.getSlides().get(0).getTheme();\r
+        CTFillProperties pr = tps.getTcStyle().getFill();\r
+\r
+          for (XmlObject obj : pr.selectPath("*")) {\r
+              PaintStyle paint = XSLFShape.selectPaint(obj, null, slideShow.getPackagePart(), theme);\r
+\r
+              if (paint != null) {\r
+                  return paint;\r
+              }\r
+          }\r
+\r
+          return null;\r
+    }\r
+\r
+    /**\r
+     * Retrieves the part style depending on the location of this cell\r
+     *\r
+     * @param tablePartStyle the part to be returned, usually this is null\r
+     *  and only set when used as a helper method\r
+     * @return the table part style\r
+     */\r
+    private CTTablePartStyle getTablePartStyle(TablePartStyle tablePartStyle) {\r
+        CTTable ct = table.getCTTable();\r
+        if (!ct.isSetTblPr()) {\r
+            return null;\r
+        }\r
+\r
+        CTTableProperties pr = ct.getTblPr();\r
+        boolean bandRow = (pr.isSetBandRow() && pr.getBandRow());\r
+        boolean firstRow = (pr.isSetFirstRow() && pr.getFirstRow());\r
+        boolean lastRow = (pr.isSetLastRow() && pr.getLastRow());\r
+        boolean bandCol = (pr.isSetBandCol() && pr.getBandCol());\r
+        boolean firstCol = (pr.isSetFirstCol() && pr.getFirstCol());\r
+        boolean lastCol = (pr.isSetLastCol() && pr.getLastCol());\r
+\r
+        TablePartStyle tps;\r
+        if (tablePartStyle != null) {\r
+            tps = tablePartStyle;\r
+        } else if (row == 0 && firstRow) {\r
+            tps = TablePartStyle.firstRow;\r
+        } else if (row == table.getNumberOfRows()-1 && lastRow) {\r
+            tps = TablePartStyle.lastRow;\r
+        } else if (col == 0 && firstCol) {\r
+            tps = TablePartStyle.firstCol;\r
+        } else if (col == table.getNumberOfColumns()-1 && lastCol) {\r
+            tps = TablePartStyle.lastCol;\r
+        } else {\r
+            tps = TablePartStyle.wholeTbl;\r
+\r
+            int br = row + (firstRow ? 1 : 0);\r
+            int bc = col + (firstCol ? 1 : 0);\r
+            if (bandRow && (br & 1) == 0) {\r
+                tps = TablePartStyle.band1H;\r
+            } else if (bandCol && (bc & 1) == 0) {\r
+                tps = TablePartStyle.band1V;\r
+            }\r
+        }\r
+\r
+        XSLFTableStyle tabStyle = table.getTableStyle();\r
+        if (tabStyle == null) {\r
             return null;\r
         }\r
-        byte[] val = fill.getSrgbClr().getVal();\r
-        return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);\r
+\r
+        CTTablePartStyle part = tabStyle.getTablePartStyle(tps);\r
+        return (part == null) ? tabStyle.getTablePartStyle(TablePartStyle.wholeTbl) : part;\r
     }\r
 \r
     void setGridSpan(int gridSpan_) {\r
-        ((CTTableCell)getXmlObject()).setGridSpan(gridSpan_);\r
+        getCell().setGridSpan(gridSpan_);\r
+    }\r
+\r
+    @Override\r
+    public int getGridSpan() {\r
+        CTTableCell c = getCell();\r
+        return (c.isSetGridSpan()) ? c.getGridSpan() : 1;\r
     }\r
 \r
     void setRowSpan(int rowSpan_) {\r
-        ((CTTableCell)getXmlObject()).setRowSpan(rowSpan_);\r
+        getCell().setRowSpan(rowSpan_);\r
+    }\r
+\r
+    @Override\r
+    public int getRowSpan() {\r
+        CTTableCell c = getCell();\r
+        return (c.isSetRowSpan()) ? c.getRowSpan() : 1;\r
     }\r
 \r
     void setHMerge(boolean merge_) {\r
-        ((CTTableCell)getXmlObject()).setHMerge(merge_);\r
+        getCell().setHMerge(merge_);\r
     }\r
 \r
     void setVMerge(boolean merge_) {\r
-        ((CTTableCell)getXmlObject()).setVMerge(merge_);\r
+        getCell().setVMerge(merge_);\r
     }\r
 \r
     @Override\r
@@ -457,7 +566,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
                 vt = STTextVerticalType.WORD_ART_VERT;\r
                 break;\r
             }\r
-            \r
+\r
             cellProps.setVert(vt);\r
         }\r
     }\r
@@ -475,7 +584,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         } else {\r
             orientation = STTextVerticalType.HORZ;\r
         }\r
-                \r
+\r
         switch (orientation.intValue()) {\r
             default:\r
             case STTextVerticalType.INT_HORZ:\r
@@ -491,4 +600,142 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
                 return TextDirection.STACKED;\r
         }\r
     }\r
-}\r
+\r
+    private CTTableCell getCell() {\r
+        return (CTTableCell)getXmlObject();\r
+    }\r
+\r
+    /* package */ void setRowColIndex(int row, int col) {\r
+        this.row = row;\r
+        this.col = col;\r
+    }\r
+\r
+    /**\r
+     * Return a fake-xfrm which is used for calculating the text height\r
+     */\r
+    protected CTTransform2D getXfrm() {\r
+        Rectangle2D anc = getAnchor();\r
+        CTTransform2D xfrm = CTTransform2D.Factory.newInstance();\r
+        CTPoint2D off = xfrm.addNewOff();\r
+        off.setX(Units.toEMU(anc.getX()));\r
+        off.setY(Units.toEMU(anc.getY()));\r
+        CTPositiveSize2D size = xfrm.addNewExt();\r
+        size.setCx(Units.toEMU(anc.getWidth()));\r
+        size.setCy(Units.toEMU(anc.getHeight()));\r
+        return xfrm;\r
+    }\r
+\r
+    /**\r
+     * There's no real anchor for table cells - this method is used to temporarily store the location\r
+     * of the cell for a later retrieval, e.g. for rendering\r
+     *\r
+     * @since POI 3.15-beta2\r
+     */\r
+    @Override\r
+    public void setAnchor(Rectangle2D anchor) {\r
+        if (this.anchor == null) {\r
+            this.anchor = (Rectangle2D)anchor.clone();\r
+        } else {\r
+            this.anchor.setRect(anchor);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * @since POI 3.15-beta2\r
+     */\r
+    @Override\r
+    public Rectangle2D getAnchor() {\r
+        if (anchor == null) {\r
+            table.updateCellAnchor();\r
+        }\r
+        // anchor should be set, after updateCellAnchor is through\r
+        assert(anchor != null);\r
+        return anchor;\r
+    }\r
+\r
+    /**\r
+     * @since POI 3.15-beta2\r
+     */\r
+    @Override\r
+    public boolean isMerged() {\r
+        CTTableCell c = getCell();\r
+        return (c.isSetHMerge() && c.getHMerge()) || (c.isSetVMerge() && c.getVMerge());\r
+    }\r
+\r
+    /**\r
+     * @since POI 3.15-beta2\r
+     */\r
+    @Override\r
+    protected XSLFCellTextParagraph newTextParagraph(CTTextParagraph p) {\r
+        return new XSLFCellTextParagraph(p, this);\r
+    }\r
+\r
+    /**\r
+     * @since POI 3.15-beta2\r
+     */\r
+    private class XSLFCellTextParagraph extends XSLFTextParagraph {\r
+        protected XSLFCellTextParagraph(CTTextParagraph p, XSLFTextShape shape) {\r
+            super(p, shape);\r
+        }\r
+\r
+        @Override\r
+        protected XSLFCellTextRun newTextRun(CTRegularTextRun r) {\r
+            return new XSLFCellTextRun(r, this);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * @since POI 3.15-beta2\r
+     */\r
+    private class XSLFCellTextRun extends XSLFTextRun {\r
+        protected XSLFCellTextRun(CTRegularTextRun r, XSLFTextParagraph p) {\r
+            super(r, p);\r
+        }\r
+\r
+        @Override\r
+        public PaintStyle getFontColor(){\r
+            CTTableStyleTextStyle txStyle = getTextStyle();\r
+            if (txStyle == null) {\r
+                return super.getFontColor();\r
+            }\r
+\r
+            CTSchemeColor phClr = null;\r
+            CTFontReference fontRef = txStyle.getFontRef();\r
+            if (fontRef != null) {\r
+                phClr = fontRef.getSchemeClr();\r
+            }\r
+            \r
+            XSLFTheme theme = getSheet().getTheme();\r
+            final XSLFColor c = new XSLFColor(txStyle, theme, phClr);\r
+            return DrawPaint.createSolidPaint(c.getColorStyle());\r
+        }\r
+\r
+        @Override\r
+        public boolean isBold() {\r
+            CTTableStyleTextStyle txStyle = getTextStyle();\r
+            if (txStyle == null) {\r
+                return super.isBold();\r
+            } else {\r
+                return txStyle.isSetB() && txStyle.getB().intValue() == STOnOffStyleType.INT_ON;\r
+            }\r
+        }\r
+\r
+        @Override\r
+        public boolean isItalic() {\r
+            CTTableStyleTextStyle txStyle = getTextStyle();\r
+            if (txStyle == null) {\r
+                return super.isItalic();\r
+            } else {\r
+                return txStyle.isSetI() && txStyle.getI().intValue() == STOnOffStyleType.INT_ON;\r
+            }\r
+        }\r
\r
+        private CTTableStyleTextStyle getTextStyle() {\r
+            CTTablePartStyle tps = getTablePartStyle(null);\r
+            if (tps == null || !tps.isSetTcTxStyle()) {\r
+                tps = getTablePartStyle(TablePartStyle.wholeTbl);\r
+            }\r
+            return (tps == null) ? null : tps.getTcTxStyle();\r
+        }\r
+    }\r
+}
\ No newline at end of file
index 491583f5aa29e70f5e78b31188051146f93b59c9..5326d9e784a29cff89defeaff197e7a6d5145dea 100644 (file)
@@ -30,8 +30,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow;
 \r
 /**\r
  * Represents a table in a .pptx presentation\r
- *\r
- * @author Yegor Kozlov\r
  */\r
 public class XSLFTableRow implements Iterable<XSLFTableCell> {\r
     private CTTableRow _row;\r
@@ -44,7 +42,7 @@ public class XSLFTableRow implements Iterable<XSLFTableCell> {
         CTTableCell[] tcArray = _row.getTcArray();\r
         _cells = new ArrayList<XSLFTableCell>(tcArray.length);\r
         for(CTTableCell cell : tcArray) {\r
-            _cells.add(new XSLFTableCell(cell, table.getSheet()));\r
+            _cells.add(new XSLFTableCell(cell, table));\r
         }\r
     }\r
 \r
@@ -71,12 +69,13 @@ public class XSLFTableRow implements Iterable<XSLFTableCell> {
     public XSLFTableCell addCell(){\r
         CTTableCell c = _row.addNewTc();\r
         c.set(XSLFTableCell.prototype());\r
-        XSLFTableCell cell = new XSLFTableCell(c, _table.getSheet());\r
+        XSLFTableCell cell = new XSLFTableCell(c, _table);\r
         _cells.add(cell);\r
 \r
         if(_table.getNumberOfColumns() < _row.sizeOfTcArray()) {\r
             _table.getCTTable().getTblGrid().addNewGridCol().setW(Units.toEMU(100.0));    \r
         }\r
+        _table.updateRowColIndexes();\r
         return cell;\r
     }\r
 \r
index 31840314b95e19bc438bbdb537c7fb3f8700fefd..b3bcdfabd91e7658c2c6ee0047a98ebd86fccf3d 100644 (file)
 \r
 package org.apache.poi.xslf.usermodel;\r
 \r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTablePartStyle;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle;\r
 \r
 /**\r
- * Represents a table in a .pptx presentation\r
- *\r
- * @author Yegor Kozlov\r
+ * Represents a table style in a .pptx presentation\r
  */\r
 public class XSLFTableStyle {\r
     private CTTableStyle _tblStyle;\r
 \r
+    public enum TablePartStyle {\r
+        wholeTbl, band1H, band2H, band1V, band2V, firstCol, lastCol, firstRow, lastRow, seCell, swCell, neCell, nwCell;\r
+    }\r
+    \r
     /*package*/ XSLFTableStyle(CTTableStyle style){\r
         _tblStyle = style;\r
     }\r
@@ -44,4 +47,39 @@ public class XSLFTableStyle {
     public String getStyleId(){\r
         return _tblStyle.getStyleId();\r
     }\r
+\r
+    /**\r
+     * @since POI 3.15-beta2\r
+     */\r
+    protected CTTablePartStyle getTablePartStyle(TablePartStyle tps) {\r
+        switch (tps) {\r
+        default:\r
+        case wholeTbl:\r
+            return _tblStyle.getWholeTbl();\r
+        case band1H:\r
+            return _tblStyle.getBand1H();\r
+        case band2H:\r
+            return _tblStyle.getBand2H();\r
+        case band1V:\r
+            return _tblStyle.getBand1V();\r
+        case band2V:\r
+            return _tblStyle.getBand2V();\r
+        case firstCol:\r
+            return _tblStyle.getFirstCol();\r
+        case lastCol:\r
+            return _tblStyle.getLastCol();\r
+        case firstRow:\r
+            return _tblStyle.getFirstRow();\r
+        case lastRow:\r
+            return _tblStyle.getLastRow();\r
+        case seCell:\r
+            return _tblStyle.getSeCell();\r
+        case swCell:\r
+            return _tblStyle.getSwCell();\r
+        case neCell:\r
+            return _tblStyle.getNeCell();\r
+        case nwCell:\r
+            return _tblStyle.getNwCell();\r
+        }\r
+    }\r
 }
\ No newline at end of file
index 76455d64df81d113dbfefcdc40bbc5b8e8652841..410f84101d2dcce13b2b046c968e365087fe57d7 100644 (file)
@@ -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){
index 9576eea3c2346ceca995510a1e1c68a4b1f289b4..b2a8b3314b823228cf5b37c8e21b56eb8e30029b 100644 (file)
@@ -59,7 +59,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
  * Represents a paragraph of text within the containing text body.\r
  * The paragraph is the highest level text separation mechanism.\r
  *\r
- * @author Yegor Kozlov\r
  * @since POI-3.8\r
  */\r
 @Beta\r
@@ -76,19 +75,19 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
         for(XmlObject ch : _p.selectPath("*")){\r
             if(ch instanceof CTRegularTextRun){\r
                 CTRegularTextRun r = (CTRegularTextRun)ch;\r
-                _runs.add(new XSLFTextRun(r, this));\r
+                _runs.add(newTextRun(r));\r
             } else if (ch instanceof CTTextLineBreak){\r
                 CTTextLineBreak br = (CTTextLineBreak)ch;\r
                 CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();\r
                 r.setRPr(br.getRPr());\r
                 r.setT("\n");\r
-                _runs.add(new XSLFTextRun(r, this));\r
+                _runs.add(newTextRun(r));\r
             } else if (ch instanceof CTTextField){\r
                 CTTextField f = (CTTextField)ch;\r
                 CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();\r
                 r.setRPr(f.getRPr());\r
                 r.setT(f.getT());\r
-                _runs.add(new XSLFTextRun(r, this));\r
+                _runs.add(newTextRun(r));\r
             }\r
         }\r
     }\r
@@ -137,7 +136,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
         CTRegularTextRun r = _p.addNewR();\r
         CTTextCharacterProperties rPr = r.addNewRPr();\r
         rPr.setLang("en-US");\r
-        XSLFTextRun run = new XSLFTextRun(r, this);\r
+        XSLFTextRun run = newTextRun(r);\r
         _runs.add(run);\r
         return run;\r
     }\r
@@ -774,22 +773,23 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
         int level = getIndentLevel();\r
 \r
         // wind up and find the root master sheet which must be slide master\r
-        final String nsDecl =\r
-            "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +\r
-            "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' ";\r
-        final String xpaths[] = {\r
-            nsDecl+".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr",\r
-            nsDecl+".//p:notesStyle/a:lvl" +(level+1)+ "pPr"\r
-        };\r
+        final String nsPML = "http://schemas.openxmlformats.org/presentationml/2006/main";\r
+        final String nsDML = "http://schemas.openxmlformats.org/drawingml/2006/main";\r
         XSLFSheet masterSheet = _shape.getSheet();\r
         for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) {\r
             masterSheet = m;\r
             XmlObject xo = masterSheet.getXmlObject();\r
-            for (String xpath : xpaths) {\r
-                XmlObject[] o = xo.selectPath(xpath);\r
-                if (o.length == 1) {\r
-                    return (CTTextParagraphProperties)o[0];\r
+            XmlCursor cur = xo.newCursor();\r
+            try {\r
+                cur.push();\r
+                if ((cur.toChild(nsPML, "txStyles") && cur.toChild(nsPML, defaultStyleSelector)) ||\r
+                       (cur.pop() && cur.toChild(nsPML, "notesStyle"))) {\r
+                       if (cur.toChild(nsDML, "lvl" +(level+1)+ "pPr")) {\r
+                               return (CTTextParagraphProperties)cur.getObject();\r
+                       }\r
                 }\r
+            } finally {\r
+               cur.dispose();\r
             }\r
         }\r
 \r
@@ -880,7 +880,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
         List<XSLFTextRun> otherRs = other.getTextRuns();\r
         int i=0;\r
         for(CTRegularTextRun rtr : thisP.getRArray()) {\r
-            XSLFTextRun run = new XSLFTextRun(rtr, this);\r
+            XSLFTextRun run = newTextRun(rtr);\r
             run.copy(otherRs.get(i++));\r
             _runs.add(run);\r
         }\r
@@ -949,6 +949,9 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
     @Override\r
     public Double getDefaultFontSize() {\r
         CTTextCharacterProperties endPr = _p.getEndParaRPr();\r
+        if (endPr == null || !endPr.isSetSz()) {\r
+            endPr = getDefaultMasterStyle().getDefRPr();\r
+        }\r
         return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100.);\r
     }\r
 \r
@@ -1062,4 +1065,17 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
                 return false;\r
         }\r
     }\r
+\r
+    /**\r
+     * Helper method to allow subclasses to provide their own text run\r
+     *\r
+     * @param r the xml reference\r
+     * \r
+     * @return a new text paragraph\r
+     * \r
+     * @since POI 3.15-beta2\r
+     */\r
+    protected XSLFTextRun newTextRun(CTRegularTextRun r) {\r
+        return new XSLFTextRun(r, this);\r
+    }\r
 }
\ No newline at end of file
index 1a6bcc384a7edf16fc320829f3bccefac2c9f280..c374c4016bebf3b1704d720e30b57853b4b9189f 100644 (file)
@@ -30,15 +30,13 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
 /**\r
  * Represents a run of text within the containing text body. The run element is the\r
  * lowest level text separation mechanism within a text body.\r
- *\r
- * @author Yegor Kozlov\r
  */\r
 @Beta\r
 public class XSLFTextRun implements TextRun {\r
     private final CTRegularTextRun _r;\r
     private final XSLFTextParagraph _p;\r
 \r
-    XSLFTextRun(CTRegularTextRun r, XSLFTextParagraph p){\r
+    protected XSLFTextRun(CTRegularTextRun r, XSLFTextParagraph p){\r
         _r = r;\r
         _p = p;\r
     }\r
index f38ea9701e9f9aa90d05e26ce1a097f2dc25d556..a4400d21ba6ac58254fb4f6e324ff21ed97f63bc 100644 (file)
@@ -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
index 49b5fd4944264777e861edd828a4e0232bdfc543..12369937ea62348204f8bf3700c5c0bce1e0ec47 100644 (file)
@@ -19,27 +19,20 @@ package org.apache.poi.xslf.usermodel;
 import static org.junit.Assert.assertEquals;\r
 import static org.junit.Assert.assertNotNull;\r
 \r
+import java.io.IOException;\r
+\r
 import org.junit.Test;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle;\r
 \r
-/**\r
- * @author Yegor Kozlov\r
- */\r
 public class TestXSLFTableStyles {\r
 \r
     @Test\r
-    public void testRead(){\r
+    public void testRead() throws IOException {\r
         XMLSlideShow  ppt = new XMLSlideShow();\r
         XSLFTableStyles tblStyles = ppt.getTableStyles();\r
         assertNotNull(tblStyles);\r
 \r
         assertEquals(0, tblStyles.getStyles().size());\r
-    }\r
-\r
-    @SuppressWarnings("unused")\r
-    @Test\r
-    public void testStyle(){\r
-        CTTableStyle obj = CTTableStyle.Factory.newInstance();\r
-        XSLFTableStyle style = new XSLFTableStyle(obj);\r
+        \r
+        ppt.close();\r
     }\r
 }
\ No newline at end of file
index a1944c6aed49f0fdaf9e600ead1e8f30f968d727..f007dd98774d6fea380519514ab08e5f96382b95 100644 (file)
 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();
 
                 /**
index aee8994832000ed376ab55419242845545094c64..a8e3294d1df712d2316d4c6a0a9c5a29f30f0634 100644 (file)
@@ -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;
@@ -45,6 +43,16 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh
     /* package */ HSLFLine borderTop;
     /* 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.
      *
@@ -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;
+    }
 }