You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@poi.apache.org by Simon Davey <si...@simondavey.me.uk> on 2022/02/17 11:39:16 UTC

POI XSLFTable::mergeCells ineffective in single column tables

Hi POI team,

We have found an issue where the POI XSLFTable::mergeCells method seems 
ineffective at setting rowspans if the table only has a single column.

We have seen that POI is setting the rowspan=... attribute in the output 
Slide XML, however MS PowerPoint is ignoring it. Trying the same cell 
merging manually in PowerPoint reveals that instead of setting rowspan, 
PowerPoint will remove the spanned-over rows and set the height of the 
first row to the total of the spanned over rows.

This makes me wonder if the POI XSLFTable::mergeCells method needs an 
update to mimick this technique?

Here's a java testcase showing the problem and our workaround:

=== BEGIN TestMergeCells.java ===

import java.awt.Color;
import java.awt.Rectangle;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.sl.usermodel.TableCell.BorderEdge;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFTable;
import org.apache.poi.xslf.usermodel.XSLFTableCell;
import org.apache.poi.xslf.usermodel.XSLFTableRow;

/**
  * Demonstrate problem with mergeCell rowspan in single column table
  * (POI writes out the rowspan=... to XML, but MS PowerPoint ignores it)
  */
public final class TestMergeCells {
   private TestMergeCells() {}

   // Populate a table
   private static void fillTable(XSLFTable tbl, int numRows, int 
numColumns, Color clr) {
     for (int r = 0; r < numRows; r++) {
       XSLFTableRow tr = tbl.addRow();
       tr.setHeight(50);
       for (int c = 0; c < numColumns; c++) {
         XSLFTableCell cell = tr.addCell();
         cell.setText("Row" + r + " Col" + c);

         cell.setBorderColor(BorderEdge.bottom, clr);
         cell.setBorderColor(BorderEdge.left, clr);
         cell.setBorderColor(BorderEdge.top, clr);
         cell.setBorderColor(BorderEdge.right, clr);
       }
     }
   }

   // Workaround function - should POI be doing this internally?
   private static void mergeCellsMod(XSLFTable tbl, int fromRow, int 
toRow, int fromCol, int toCol) {
     if (tbl.getNumberOfColumns() == 1) {
       double h = tbl.getRowHeight(fromRow);
       // accumulate spanned-over row heights as we remove them
       for (int r = toRow; r > fromRow; --r) {
         h += tbl.getRowHeight(r);
         tbl.removeRow(r);
       }
       tbl.setRowHeight(fromRow, h);
     }
     else {
       tbl.mergeCells(fromRow, toRow, fromCol, toCol);
     }
   }

   public static void main(String[] args) throws IOException{
     try (XMLSlideShow ppt = new XMLSlideShow()) {
       XSLFSlide slide = ppt.createSlide();

       // Red table has 2 columns, shows that merging rows works (and in 
2nd column we demonstrate workaround function)
       XSLFTable ta = slide.createTable();
       ta.setAnchor(new Rectangle(50, 50, 300, 200));
       fillTable(ta, 4, 2, Color.red); // 4 rows, 2 cols

       // Blue Table has 1 column, shows that mergeCells is ineffective 
here when viewed in MS PowerPoint v2108
       XSLFTable tb = slide.createTable();
       tb.setAnchor(new Rectangle(400, 50, 150, 200));
       fillTable(tb, 4, 1, Color.blue); // 4 rows, 1 col

       // Green table, demonstrate basic workaround technique for row 
spans in single column tables
       XSLFTable tc = slide.createTable();
       tc.setAnchor(new Rectangle(200, 300, 150, 200));
       fillTable(tc, 4, 1, Color.green); // 4 rows, 1 col
       tc.removeRow(2);
       tc.setRowHeight(1, 100); // set height to 2x50

       // Magenta table demonstrates use a function to apply the workaround
       XSLFTable td = slide.createTable();
       td.setAnchor(new Rectangle(500, 300, 150, 200));
       fillTable(td, 4, 1, Color.magenta); // 4 rows, 1 col

       // Merge middle cells in first columns
       ta.mergeCells(1,2,0,0); // has the desired effect in 2-col table
       mergeCellsMod(ta, 0,1,1,1); // test workaround function on 2-col 
table
       mergeCellsMod(ta, 2,3,1,1); // ...and again

       tb.mergeCells(1,2,0,0); // MS PowerPoint ignores rowspan request 
in single column table!

       mergeCellsMod(td, 1, 2, 0, 0); // Workaround function is 
effective though

       try (FileOutputStream out = new 
FileOutputStream("TestMergeCells.pptx")) {
         ppt.write(out);
       }
     }
   }
}
=== END TestMergeCells.java ===

Thanks (and sorry if I've submitted this report/observation/suggestion 
the wrong way!),

Simon Davey


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@poi.apache.org
For additional commands, e-mail: dev-help@poi.apache.org