diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 9d87903135..29d223a0e7 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 52561 - Added methods to set table inside borders and cell margins in XWPF 52569 - Support DConRefRecord in HSSF 52575 - added an option to ignore missing workbook references in formula evaluator Validate address of hyperlinks in XSSF diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java index 324a40b278..22e798df2b 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java @@ -18,14 +18,20 @@ package org.apache.poi.xwpf.usermodel; import java.math.BigInteger; import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; import java.util.List; import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.util.Internal; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblBorders; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblCellMar; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc; @@ -39,6 +45,15 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth; * of paragraphs (and other block-level content) arranged in rows and columns. * * @author Yury Batrakov (batrakov at gmail.com) + * @author Gregg Morris (gregg dot morris at gmail dot com) - added + * setStyleID() + * getRowBandSize(), setRowBandSize() + * getColBandSize(), setColBandSize() + * getInsideHBorderType(), getInsideHBorderSize(), getInsideHBorderSpace(), getInsideHBorderColor() + * getInsideVBorderType(), getInsideVBorderSize(), getInsideVBorderSpace(), getInsideVBorderColor() + * setInsideHBorder(), setInsideVBorder() + * getCellMarginTop(), getCellMarginLeft(), getCellMarginBottom(), getCellMarginRight() + * setCellMargins() */ public class XWPFTable implements IBodyElement{ @@ -46,15 +61,47 @@ public class XWPFTable implements IBodyElement{ private CTTbl ctTbl; protected List tableRows; protected List styleIDs; + + // Create a map from this XWPF-level enum to the STBorder.Enum values + public static enum XWPFBorderType { NIL, NONE, SINGLE, THICK, DOUBLE, DOTTED, DASHED, DOT_DASH }; + private static EnumMap xwpfBorderTypeMap; + // Create a map from the STBorder.Enum values to the XWPF-level enums + private static HashMap stBorderTypeMap; + protected IBody part; + static { + // populate enum maps + xwpfBorderTypeMap = new EnumMap(XWPFBorderType.class); + xwpfBorderTypeMap.put(XWPFBorderType.NIL, STBorder.Enum.forInt(STBorder.INT_NIL)); + xwpfBorderTypeMap.put(XWPFBorderType.NONE, STBorder.Enum.forInt(STBorder.INT_NONE)); + xwpfBorderTypeMap.put(XWPFBorderType.SINGLE, STBorder.Enum.forInt(STBorder.INT_SINGLE)); + xwpfBorderTypeMap.put(XWPFBorderType.THICK, STBorder.Enum.forInt(STBorder.INT_THICK)); + xwpfBorderTypeMap.put(XWPFBorderType.DOUBLE, STBorder.Enum.forInt(STBorder.INT_DOUBLE)); + xwpfBorderTypeMap.put(XWPFBorderType.DOTTED, STBorder.Enum.forInt(STBorder.INT_DOTTED)); + xwpfBorderTypeMap.put(XWPFBorderType.DASHED, STBorder.Enum.forInt(STBorder.INT_DASHED)); + xwpfBorderTypeMap.put(XWPFBorderType.DOT_DASH, STBorder.Enum.forInt(STBorder.INT_DOT_DASH)); + + stBorderTypeMap = new HashMap(); + stBorderTypeMap.put(STBorder.INT_NIL, XWPFBorderType.NIL); + stBorderTypeMap.put(STBorder.INT_NONE, XWPFBorderType.NONE); + stBorderTypeMap.put(STBorder.INT_SINGLE, XWPFBorderType.SINGLE); + stBorderTypeMap.put(STBorder.INT_THICK, XWPFBorderType.THICK); + stBorderTypeMap.put(STBorder.INT_DOUBLE, XWPFBorderType.DOUBLE); + stBorderTypeMap.put(STBorder.INT_DOTTED, XWPFBorderType.DOTTED); + stBorderTypeMap.put(STBorder.INT_DASHED, XWPFBorderType.DASHED); + stBorderTypeMap.put(STBorder.INT_DOT_DASH, XWPFBorderType.DOT_DASH); + } + public XWPFTable(CTTbl table, IBody part, int row, int col) { this(table, part); + for (int i = 0; i < row; i++) { XWPFTableRow tabRow = (getRow(i) == null) ? createRow() : getRow(i); for (int k = 0; k < col; k++) { - XWPFTableCell tabCell = (tabRow.getCell(k) == null) ? tabRow - .createCell() : null; + if (tabRow.getCell(k) == null) { + tabRow.createCell(); + } } } } @@ -218,7 +265,266 @@ public class XWPFTable implements IBodyElement{ * @return style-ID of the table */ public String getStyleID(){ - return ctTbl.getTblPr().getTblStyle().getVal(); + String styleId = null; + CTTblPr tblPr = ctTbl.getTblPr(); + if (tblPr != null) { + CTString styleStr = tblPr.getTblStyle(); + if (styleStr != null) { + styleId = styleStr.getVal(); + } + } + return styleId; + } + + /** + * Set the table style. If the style is not defined in the document, MS Word + * will set the table style to "Normal". + * @param styleName - the style name to apply to this table + */ + public void setStyleID(String styleName) { + CTTblPr tblPr = getTrPr(); + CTString styleStr = tblPr.getTblStyle(); + if (styleStr == null) { + styleStr = tblPr.addNewTblStyle(); + } + styleStr.setVal(styleName); + } + + public XWPFBorderType getInsideHBorderType() { + XWPFBorderType bt = null; + + CTTblPr tblPr = getTrPr(); + if (tblPr.isSetTblBorders()) { + CTTblBorders ctb = tblPr.getTblBorders(); + if (ctb.isSetInsideH()) { + CTBorder border = ctb.getInsideH(); + bt = stBorderTypeMap.get(border.getVal().intValue()); + } + } + return bt; + } + + public int getInsideHBorderSize() { + int size = -1; + + CTTblPr tblPr = getTrPr(); + if (tblPr.isSetTblBorders()) { + CTTblBorders ctb = tblPr.getTblBorders(); + if (ctb.isSetInsideH()) { + CTBorder border = ctb.getInsideH(); + size = border.getSz().intValue(); + } + } + return size; + } + + public int getInsideHBorderSpace() { + int space = -1; + + CTTblPr tblPr = getTrPr(); + if (tblPr.isSetTblBorders()) { + CTTblBorders ctb = tblPr.getTblBorders(); + if (ctb.isSetInsideH()) { + CTBorder border = ctb.getInsideH(); + space = border.getSpace().intValue(); + } + } + return space; + } + + public String getInsideHBorderColor() { + String color = null; + + CTTblPr tblPr = getTrPr(); + if (tblPr.isSetTblBorders()) { + CTTblBorders ctb = tblPr.getTblBorders(); + if (ctb.isSetInsideH()) { + CTBorder border = ctb.getInsideH(); + color = border.xgetColor().getStringValue(); + } + } + return color; + } + + public XWPFBorderType getInsideVBorderType() { + XWPFBorderType bt = null; + + CTTblPr tblPr = getTrPr(); + if (tblPr.isSetTblBorders()) { + CTTblBorders ctb = tblPr.getTblBorders(); + if (ctb.isSetInsideV()) { + CTBorder border = ctb.getInsideV(); + bt = stBorderTypeMap.get(border.getVal().intValue()); + } + } + return bt; + } + + public int getInsideVBorderSize() { + int size = -1; + + CTTblPr tblPr = getTrPr(); + if (tblPr.isSetTblBorders()) { + CTTblBorders ctb = tblPr.getTblBorders(); + if (ctb.isSetInsideV()) { + CTBorder border = ctb.getInsideV(); + size = border.getSz().intValue(); + } + } + return size; + } + + public int getInsideVBorderSpace() { + int space = -1; + + CTTblPr tblPr = getTrPr(); + if (tblPr.isSetTblBorders()) { + CTTblBorders ctb = tblPr.getTblBorders(); + if (ctb.isSetInsideV()) { + CTBorder border = ctb.getInsideV(); + space = border.getSpace().intValue(); + } + } + return space; + } + + public String getInsideVBorderColor() { + String color = null; + + CTTblPr tblPr = getTrPr(); + if (tblPr.isSetTblBorders()) { + CTTblBorders ctb = tblPr.getTblBorders(); + if (ctb.isSetInsideV()) { + CTBorder border = ctb.getInsideV(); + color = border.xgetColor().getStringValue(); + } + } + return color; + } + + public int getRowBandSize() { + int size = 0; + CTTblPr tblPr = getTrPr(); + if (tblPr.isSetTblStyleRowBandSize()) { + CTDecimalNumber rowSize = tblPr.getTblStyleRowBandSize(); + size = rowSize.getVal().intValue(); + } + return size; + } + + public void setRowBandSize(int size) { + CTTblPr tblPr = getTrPr(); + CTDecimalNumber rowSize = tblPr.isSetTblStyleRowBandSize() ? tblPr.getTblStyleRowBandSize() : tblPr.addNewTblStyleRowBandSize(); + rowSize.setVal(BigInteger.valueOf(size)); + } + + public int getColBandSize() { + int size = 0; + CTTblPr tblPr = getTrPr(); + if (tblPr.isSetTblStyleColBandSize()) { + CTDecimalNumber colSize = tblPr.getTblStyleColBandSize(); + size = colSize.getVal().intValue(); + } + return size; + } + + public void setColBandSize(int size) { + CTTblPr tblPr = getTrPr(); + CTDecimalNumber colSize = tblPr.isSetTblStyleColBandSize() ? tblPr.getTblStyleColBandSize() : tblPr.addNewTblStyleColBandSize(); + colSize.setVal(BigInteger.valueOf(size)); + } + + public void setInsideHBorder(XWPFBorderType type, int size, int space, String rgbColor) { + CTTblPr tblPr = getTrPr(); + CTTblBorders ctb = tblPr.isSetTblBorders() ? tblPr.getTblBorders() : tblPr.addNewTblBorders(); + CTBorder b = ctb.isSetInsideH() ? ctb.getInsideH() : ctb.addNewInsideH(); + b.setVal(xwpfBorderTypeMap.get(type)); + b.setSz(BigInteger.valueOf(size)); + b.setSpace(BigInteger.valueOf(space)); + b.setColor(rgbColor); + } + + public void setInsideVBorder(XWPFBorderType type, int size, int space, String rgbColor) { + CTTblPr tblPr = getTrPr(); + CTTblBorders ctb = tblPr.isSetTblBorders() ? tblPr.getTblBorders() : tblPr.addNewTblBorders(); + CTBorder b = ctb.isSetInsideV() ? ctb.getInsideV() : ctb.addNewInsideV(); + b.setVal(xwpfBorderTypeMap.get(type)); + b.setSz(BigInteger.valueOf(size)); + b.setSpace(BigInteger.valueOf(space)); + b.setColor(rgbColor); + } + + public int getCellMarginTop() { + int margin = 0; + CTTblPr tblPr = getTrPr(); + CTTblCellMar tcm = tblPr.getTblCellMar(); + if (tcm != null) { + CTTblWidth tw = tcm.getTop(); + if (tw != null) { + margin = tw.getW().intValue(); + } + } + return margin; + } + + public int getCellMarginLeft() { + int margin = 0; + CTTblPr tblPr = getTrPr(); + CTTblCellMar tcm = tblPr.getTblCellMar(); + if (tcm != null) { + CTTblWidth tw = tcm.getLeft(); + if (tw != null) { + margin = tw.getW().intValue(); + } + } + return margin; + } + + public int getCellMarginBottom() { + int margin = 0; + CTTblPr tblPr = getTrPr(); + CTTblCellMar tcm = tblPr.getTblCellMar(); + if (tcm != null) { + CTTblWidth tw = tcm.getBottom(); + if (tw != null) { + margin = tw.getW().intValue(); + } + } + return margin; + } + + public int getCellMarginRight() { + int margin = 0; + CTTblPr tblPr = getTrPr(); + CTTblCellMar tcm = tblPr.getTblCellMar(); + if (tcm != null) { + CTTblWidth tw = tcm.getRight(); + if (tw != null) { + margin = tw.getW().intValue(); + } + } + return margin; + } + + public void setCellMargins(int top, int left, int bottom, int right) { + CTTblPr tblPr = getTrPr(); + CTTblCellMar tcm = tblPr.isSetTblCellMar() ? tblPr.getTblCellMar() : tblPr.addNewTblCellMar(); + + CTTblWidth tw = tcm.isSetLeft() ? tcm.getLeft() : tcm.addNewLeft(); + tw.setType(STTblWidth.DXA); + tw.setW(BigInteger.valueOf(left)); + + tw = tcm.isSetTop() ? tcm.getTop() : tcm.addNewTop(); + tw.setType(STTblWidth.DXA); + tw.setW(BigInteger.valueOf(top)); + + tw = tcm.isSetBottom() ? tcm.getBottom() : tcm.addNewBottom(); + tw.setType(STTblWidth.DXA); + tw.setW(BigInteger.valueOf(bottom)); + + tw = tcm.isSetRight() ? tcm.getRight() : tcm.addNewRight(); + tw.setType(STTblWidth.DXA); + tw.setW(BigInteger.valueOf(right)); } /** @@ -269,7 +575,9 @@ public class XWPFTable implements IBodyElement{ */ public boolean removeRow(int pos) throws IndexOutOfBoundsException { if (pos >= 0 && pos < tableRows.size()) { + if (ctTbl.sizeOfTrArray() > 0) { ctTbl.removeTr(pos); + } tableRows.remove(pos); return true; } diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTable.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTable.java index a8eaf1966c..fd9db3b6b7 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTable.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTable.java @@ -22,12 +22,19 @@ import java.util.List; import junit.framework.TestCase; import org.apache.poi.xwpf.XWPFTestDataSamples; +import org.apache.poi.xwpf.usermodel.XWPFTable.XWPFBorderType; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblBorders; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblCellMar; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder; /** * Tests for XWPF Run @@ -132,11 +139,95 @@ public class TestXWPFTable extends TestCase { assertEquals(20, row.getHeight()); } + public void testSetGetMargins() { + // instantiate the following class so it'll get picked up by + // the XmlBean process and added to the jar file. it's required + // for the following XWPFTable methods. + CTTblCellMar ctm = CTTblCellMar.Factory.newInstance(); + assertNotNull(ctm); + // create a table + XWPFDocument doc = new XWPFDocument(); + CTTbl ctTable = CTTbl.Factory.newInstance(); + XWPFTable table = new XWPFTable(ctTable, doc); + // set margins + table.setCellMargins(50, 50, 250, 450); + // get margin components + int t = table.getCellMarginTop(); + assertEquals(50, t); + int l = table.getCellMarginLeft(); + assertEquals(50, l); + int b = table.getCellMarginBottom(); + assertEquals(250, b); + int r = table.getCellMarginRight(); + assertEquals(450, r); + } + + public void testSetGetHBorders() { + // instantiate the following classes so they'll get picked up by + // the XmlBean process and added to the jar file. they are required + // for the following XWPFTable methods. + CTTblBorders cttb = CTTblBorders.Factory.newInstance(); + assertNotNull(cttb); + STBorder stb = STBorder.Factory.newInstance(); + assertNotNull(stb); + // create a table + XWPFDocument doc = new XWPFDocument(); + CTTbl ctTable = CTTbl.Factory.newInstance(); + XWPFTable table = new XWPFTable(ctTable, doc); + // set inside horizontal border + table.setInsideHBorder(XWPFBorderType.SINGLE, 4, 0, "FF0000"); + // get inside horizontal border components + int s = table.getInsideHBorderSize(); + assertEquals(4, s); + int sp = table.getInsideHBorderSpace(); + assertEquals(0, sp); + String clr = table.getInsideHBorderColor(); + assertEquals("FF0000", clr); + XWPFBorderType bt = table.getInsideHBorderType(); + assertEquals(XWPFBorderType.SINGLE, bt); + } + + public void testSetGetVBorders() { + // create a table + XWPFDocument doc = new XWPFDocument(); + CTTbl ctTable = CTTbl.Factory.newInstance(); + XWPFTable table = new XWPFTable(ctTable, doc); + // set inside vertical border + table.setInsideVBorder(XWPFBorderType.DOUBLE, 4, 0, "00FF00"); + // get inside vertical border components + XWPFBorderType bt = table.getInsideVBorderType(); + assertEquals(XWPFBorderType.DOUBLE, bt); + int sz = table.getInsideVBorderSize(); + assertEquals(4, sz); + int sp = table.getInsideVBorderSpace(); + assertEquals(0, sp); + String clr = table.getInsideVBorderColor(); + assertEquals("00FF00", clr); + } + + public void testSetGetRowBandSize() { + XWPFDocument doc = new XWPFDocument(); + CTTbl ctTable = CTTbl.Factory.newInstance(); + XWPFTable table = new XWPFTable(ctTable, doc); + table.setRowBandSize(12); + int sz = table.getRowBandSize(); + assertEquals(12, sz); + } + + public void testSetGetColBandSize() { + XWPFDocument doc = new XWPFDocument(); + CTTbl ctTable = CTTbl.Factory.newInstance(); + XWPFTable table = new XWPFTable(ctTable, doc); + table.setColBandSize(16); + int sz = table.getColBandSize(); + assertEquals(16, sz); + } + public void testCreateTable() throws Exception { // open an empty document XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("sample.docx"); - // create a table with 5 rows and 7 coloumns + // create a table with 5 rows and 7 columns int noRows = 5; int noCols = 7; XWPFTable table = doc.createTable(noRows,noCols);