mirror of https://github.com/apache/poi.git
[github-122] XWPF: Set table and table cell widths to percentage, twips, or auto. This closes #122
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1838449 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
278ed0fc32
commit
1a3032f253
|
@ -0,0 +1,54 @@
|
|||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
package org.apache.poi.xwpf.usermodel;
|
||||
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth.Enum;
|
||||
|
||||
/**
|
||||
* The width types for tables and table cells. Table width can be specified as "auto" (AUTO),
|
||||
* an absolute value in 20ths of a point (DXA), or as a percentage (PCT).
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public enum TableWidthType {
|
||||
AUTO(STTblWidth.AUTO), /* Width is determined by content. */
|
||||
DXA(STTblWidth.DXA), /* Width is an integer number of 20ths of a point (twips) */
|
||||
NIL(STTblWidth.NIL), /* No width value set */
|
||||
PCT(STTblWidth.PCT); /* Width is a percentage, e.g. "33.3%" or 50 times percentage value, rounded to an integer, */
|
||||
/* e.g. 2500 for 50% */
|
||||
|
||||
private Enum type = STTblWidth.NIL;
|
||||
|
||||
TableWidthType(STTblWidth.Enum type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
protected STTblWidth.Enum getSTWidthType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying STTblWidth enum value.
|
||||
*
|
||||
* @return STTblWidth.Enum value
|
||||
*/
|
||||
@Internal
|
||||
public STTblWidth.Enum getStWidthType() {
|
||||
return this.type;
|
||||
}
|
||||
}
|
|
@ -18,13 +18,12 @@ package org.apache.poi.xwpf.usermodel;
|
|||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.poi.ooxml.POIXMLDocumentPart;
|
||||
import org.apache.poi.util.Internal;
|
||||
|
@ -54,6 +53,11 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
|
|||
@SuppressWarnings("WeakerAccess")
|
||||
public class XWPFTable implements IBodyElement, ISDTContents {
|
||||
|
||||
public static final String REGEX_PERCENTAGE = "[0-9]+(\\.[0-9]+)?%";
|
||||
public static final String DEFAULT_PERCENTAGE_WIDTH = "100%";
|
||||
static final String NS_OOXML_WP_MAIN = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
||||
public static final String REGEX_WIDTH_VALUE = "auto|[0-9]+|" + REGEX_PERCENTAGE;
|
||||
|
||||
// Create a map from this XWPF-level enum to the STBorder.Enum values
|
||||
public enum XWPFBorderType {
|
||||
NIL, NONE, SINGLE, THICK, DOUBLE, DOTTED, DASHED, DOT_DASH, DOT_DOT_DASH, TRIPLE,
|
||||
|
@ -282,7 +286,10 @@ public class XWPFTable implements IBodyElement, ISDTContents {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return width value
|
||||
* Get the width value as an integer.
|
||||
* <p>If the width type is AUTO, DXA, or NIL, the value is 20ths of a point. If
|
||||
* the width type is PCT, the value is the percentage times 50 (e.g., 2500 for 50%).</p>
|
||||
* @return width value as an integer
|
||||
*/
|
||||
public int getWidth() {
|
||||
CTTblPr tblPr = getTblPr();
|
||||
|
@ -290,12 +297,14 @@ public class XWPFTable implements IBodyElement, ISDTContents {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param width
|
||||
* Set the width in 20ths of a point (twips).
|
||||
* @param width Width value (20ths of a point)
|
||||
*/
|
||||
public void setWidth(int width) {
|
||||
CTTblPr tblPr = getTblPr();
|
||||
CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();
|
||||
tblWidth.setW(new BigInteger(Integer.toString(width)));
|
||||
tblWidth.setType(STTblWidth.DXA);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1125,4 +1134,168 @@ public class XWPFTable implements IBodyElement, ISDTContents {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table width as a decimal value.
|
||||
* <p>If the width type is DXA or AUTO, then the value will always have
|
||||
* a fractional part of zero (because these values are really integers).
|
||||
* If the with type is percentage, then value may have a non-zero fractional
|
||||
* part.
|
||||
*
|
||||
* @return Width value as a double-precision decimal.
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public double getWidthDecimal() {
|
||||
return getWidthDecimal(getTblPr().getTblW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width as a decimal value.
|
||||
* <p>This method is also used by table cells.
|
||||
* @param ctWidth Width value to evaluate.
|
||||
* @return Width value as a decimal
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected static double getWidthDecimal(CTTblWidth ctWidth) {
|
||||
double result = 0.0;
|
||||
STTblWidth.Enum typeValue = ctWidth.getType();
|
||||
if (typeValue == STTblWidth.DXA
|
||||
|| typeValue == STTblWidth.AUTO
|
||||
|| typeValue == STTblWidth.NIL) {
|
||||
result = 0.0 + ctWidth.getW().intValue();
|
||||
} else if (typeValue == STTblWidth.PCT) {
|
||||
// Percentage values are stored as integers that are 50 times
|
||||
// percentage.
|
||||
result = ctWidth.getW().intValue() / 50.0;
|
||||
} else {
|
||||
// Should never get here
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width type for the table, as an {@link STTblWidth.Enum} value.
|
||||
* A table width can be specified as an absolute measurement (an integer
|
||||
* number of twips), a percentage, or the value "AUTO".
|
||||
*
|
||||
* @return The width type.
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public TableWidthType getWidthType() {
|
||||
return getWidthType(getTblPr().getTblW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width type from the width value
|
||||
* @param ctWidth CTTblWidth to evalute
|
||||
* @return The table width type
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected static TableWidthType getWidthType(CTTblWidth ctWidth) {
|
||||
STTblWidth.Enum typeValue = ctWidth.getType();
|
||||
if (typeValue == null) {
|
||||
typeValue = STTblWidth.NIL;
|
||||
ctWidth.setType(typeValue);
|
||||
}
|
||||
switch (typeValue.intValue()) {
|
||||
case STTblWidth.INT_NIL:
|
||||
return TableWidthType.NIL;
|
||||
case STTblWidth.INT_AUTO:
|
||||
return TableWidthType.AUTO;
|
||||
case STTblWidth.INT_DXA:
|
||||
return TableWidthType.DXA;
|
||||
case STTblWidth.INT_PCT:
|
||||
return TableWidthType.PCT;
|
||||
default:
|
||||
// Should never get here
|
||||
return TableWidthType.AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width to the value "auto", an integer value (20ths of a point), or a percentage ("nn.nn%").
|
||||
*
|
||||
* @param widthValue String matching one of "auto", [0-9]+, or [0-9]+(\.[0-9]+)%.
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public void setWidth(String widthValue) {
|
||||
setWidthValue(widthValue, getTblPr().getTblW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width value from a string
|
||||
* @param widthValue The width value string
|
||||
* @param ctWidth CTTblWidth to set the value on.
|
||||
*/
|
||||
protected static void setWidthValue(String widthValue, CTTblWidth ctWidth) {
|
||||
if (!widthValue.matches(REGEX_WIDTH_VALUE)) {
|
||||
throw new RuntimeException("Table width value \"" + widthValue + "\" "
|
||||
+ "must match regular expression \"" + REGEX_WIDTH_VALUE + "\".");
|
||||
}
|
||||
if (widthValue.matches("auto")) {
|
||||
ctWidth.setType(STTblWidth.AUTO);
|
||||
ctWidth.setW(BigInteger.ZERO);
|
||||
} else if (widthValue.matches(REGEX_PERCENTAGE)) {
|
||||
setWidthPercentage(ctWidth, widthValue);
|
||||
} else {
|
||||
// Must be an integer
|
||||
ctWidth.setW(new BigInteger(widthValue));
|
||||
ctWidth.setType(STTblWidth.DXA);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying table width value to a percentage value.
|
||||
* @param ctWidth The CTTblWidth to set the value on
|
||||
* @param widthValue String width value in form "33.3%" or an integer that is 50 times desired percentage value (e.g,
|
||||
* 2500 for 50%)
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected static void setWidthPercentage(CTTblWidth ctWidth, String widthValue) {
|
||||
ctWidth.setType(STTblWidth.PCT);
|
||||
if (widthValue.matches(REGEX_PERCENTAGE)) {
|
||||
String numberPart = widthValue.substring(0, widthValue.length() - 1);
|
||||
double percentage = Double.parseDouble(numberPart) * 50;
|
||||
long intValue = Math.round(percentage);
|
||||
ctWidth.setW(BigInteger.valueOf(intValue));
|
||||
} else if (widthValue.matches("[0-9]+")) {
|
||||
ctWidth.setW(new BigInteger(widthValue));
|
||||
} else {
|
||||
throw new RuntimeException("setWidthPercentage(): Width value must be a percentage (\"33.3%\" or an integer, was \"" + widthValue + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width value type for the table.
|
||||
* <p>If the width type is changed from the current type and the currently-set value
|
||||
* is not consistent with the new width type, the value is reset to the default value
|
||||
* for the specified width type.</p>
|
||||
*
|
||||
* @param widthType Width type
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public void setWidthType(TableWidthType widthType) {
|
||||
setWidthType(widthType, getTblPr().getTblW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width type if different from current width type
|
||||
* @param widthType The new width type
|
||||
* @param ctWidth CTTblWidth to set the type on
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected static void setWidthType(TableWidthType widthType, CTTblWidth ctWidth) {
|
||||
TableWidthType currentType = getWidthType(ctWidth);
|
||||
if (!currentType.equals(widthType)) {
|
||||
STTblWidth.Enum stWidthType = widthType.getSTWidthType();
|
||||
ctWidth.setType(stWidthType);
|
||||
switch (stWidthType.intValue()) {
|
||||
case STTblWidth.INT_PCT:
|
||||
setWidthPercentage(ctWidth, DEFAULT_PERCENTAGE_WIDTH);
|
||||
break;
|
||||
default:
|
||||
ctWidth.setW(BigInteger.ZERO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,10 +32,12 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtBlock;
|
|||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtRun;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVerticalJc;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STShd;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
|
||||
|
||||
/**
|
||||
|
@ -216,7 +218,7 @@ public class XWPFTableCell implements IBody, ICell {
|
|||
* @param rgbStr - the desired cell color, in the hex form "RRGGBB".
|
||||
*/
|
||||
public void setColor(String rgbStr) {
|
||||
CTTcPr tcpr = ctTc.isSetTcPr() ? ctTc.getTcPr() : ctTc.addNewTcPr();
|
||||
CTTcPr tcpr = getTcPr();
|
||||
CTShd ctshd = tcpr.isSetShd() ? tcpr.getShd() : tcpr.addNewShd();
|
||||
ctshd.setColor("auto");
|
||||
ctshd.setVal(STShd.CLEAR);
|
||||
|
@ -247,7 +249,7 @@ public class XWPFTableCell implements IBody, ICell {
|
|||
* @param vAlign - the desired alignment enum value
|
||||
*/
|
||||
public void setVerticalAlignment(XWPFVertAlign vAlign) {
|
||||
CTTcPr tcpr = ctTc.isSetTcPr() ? ctTc.getTcPr() : ctTc.addNewTcPr();
|
||||
CTTcPr tcpr = getTcPr();
|
||||
CTVerticalJc va = tcpr.addNewVAlign();
|
||||
va.setVal(alignMap.get(vAlign));
|
||||
}
|
||||
|
@ -407,7 +409,7 @@ public class XWPFTableCell implements IBody, ICell {
|
|||
public void insertTable(int pos, XWPFTable table) {
|
||||
bodyElements.add(pos, table);
|
||||
int i = 0;
|
||||
for (CTTbl tbl : ctTc.getTblArray()) {
|
||||
for (CTTbl tbl : ctTc.getTblList()) {
|
||||
if (tbl == table.getCTTbl()) {
|
||||
break;
|
||||
}
|
||||
|
@ -510,4 +512,71 @@ public class XWPFTableCell implements IBody, ICell {
|
|||
public enum XWPFVertAlign {
|
||||
TOP, CENTER, BOTH, BOTTOM
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table width as a decimal value.
|
||||
* <p>If the width type is DXA or AUTO, then the value will always have
|
||||
* a fractional part of zero (because these values are really integers).
|
||||
* If the with type is percentage, then value may have a non-zero fractional
|
||||
* part.
|
||||
*
|
||||
* @return Width value as a double-precision decimal.
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public double getWidthDecimal() {
|
||||
return XWPFTable.getWidthDecimal(getTcWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width type for the table, as an {@link STTblWidth.Enum} value.
|
||||
* A table width can be specified as an absolute measurement (an integer
|
||||
* number of twips), a percentage, or the value "AUTO".
|
||||
*
|
||||
* @return The width type.
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public TableWidthType getWidthType() {
|
||||
return XWPFTable.getWidthType(getTcWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width to the value "auto", an integer value (20ths of a point), or a percentage ("nn.nn%").
|
||||
*
|
||||
* @param widthValue String matching one of "auto", [0-9]+, or [0-9]+(\.[0-9]+)%.
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public void setWidth(String widthValue) {
|
||||
XWPFTable.setWidthValue(widthValue, getTcWidth());
|
||||
}
|
||||
|
||||
private CTTblWidth getTcWidth() {
|
||||
CTTcPr tcPr = getTcPr();
|
||||
return tcPr.isSetTcW() ? tcPr.getTcW() : tcPr.addNewTcW();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cell properties for the cell.
|
||||
* @return The cell properties
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected CTTcPr getTcPr() {
|
||||
return ctTc.isSetTcPr() ? ctTc.getTcPr() : ctTc.addNewTcPr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width value type for the table.
|
||||
* <p>If the width type is changed from the current type and the currently-set value
|
||||
* is not consistent with the new width type, the value is reset to the default value
|
||||
* for the specified width type.</p>
|
||||
*
|
||||
* @param widthType Width type
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public void setWidthType(TableWidthType widthType) {
|
||||
XWPFTable.setWidthType(widthType, getTcWidth());
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return getTcWidth().getW().intValue();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,15 +146,63 @@ public class TestXWPFTable {
|
|||
public void testSetGetWidth() {
|
||||
XWPFDocument doc = new XWPFDocument();
|
||||
|
||||
CTTbl table = CTTbl.Factory.newInstance();
|
||||
table.addNewTblPr().addNewTblW().setW(new BigInteger("1000"));
|
||||
|
||||
XWPFTable xtab = new XWPFTable(table, doc);
|
||||
XWPFTable xtab = doc.createTable();
|
||||
|
||||
assertEquals(0, xtab.getWidth());
|
||||
assertEquals(TableWidthType.AUTO, xtab.getWidthType());
|
||||
|
||||
xtab.setWidth(1000);
|
||||
assertEquals(TableWidthType.DXA, xtab.getWidthType());
|
||||
assertEquals(1000, xtab.getWidth());
|
||||
|
||||
xtab.setWidth("auto");
|
||||
assertEquals(TableWidthType.AUTO, xtab.getWidthType());
|
||||
assertEquals(0, xtab.getWidth());
|
||||
assertEquals(0.0, xtab.getWidthDecimal(), 0.01);
|
||||
|
||||
xtab.setWidth("999");
|
||||
assertEquals(TableWidthType.DXA, xtab.getWidthType());
|
||||
assertEquals(999, xtab.getWidth());
|
||||
|
||||
xtab.setWidth("50.5%");
|
||||
assertEquals(TableWidthType.PCT, xtab.getWidthType());
|
||||
assertEquals(50.5, xtab.getWidthDecimal(), 0.01);
|
||||
|
||||
// Test effect of setting width type to a new value
|
||||
|
||||
// From PCT to NIL:
|
||||
xtab.setWidthType(TableWidthType.NIL);
|
||||
assertEquals(TableWidthType.NIL, xtab.getWidthType());
|
||||
assertEquals(0, xtab.getWidth());
|
||||
|
||||
xtab.setWidth("999"); // Sets type to DXA
|
||||
assertEquals(TableWidthType.DXA, xtab.getWidthType());
|
||||
|
||||
// From DXA to AUTO:
|
||||
xtab.setWidthType(TableWidthType.AUTO);
|
||||
assertEquals(TableWidthType.AUTO, xtab.getWidthType());
|
||||
assertEquals(0, xtab.getWidth());
|
||||
|
||||
xtab.setWidthType(TableWidthType.PCT);
|
||||
assertEquals(TableWidthType.PCT, xtab.getWidthType());
|
||||
|
||||
// From PCT to DXA:
|
||||
xtab.setWidth("33.3%");
|
||||
xtab.setWidthType(TableWidthType.DXA);
|
||||
assertEquals(TableWidthType.DXA, xtab.getWidthType());
|
||||
assertEquals(0, xtab.getWidth());
|
||||
|
||||
// From DXA to DXA: (value should be unchanged)
|
||||
xtab.setWidth("999");
|
||||
xtab.setWidthType(TableWidthType.DXA);
|
||||
assertEquals(TableWidthType.DXA, xtab.getWidthType());
|
||||
assertEquals(999, xtab.getWidth());
|
||||
|
||||
// From DXA to PCT:
|
||||
xtab.setWidthType(TableWidthType.PCT);
|
||||
assertEquals(TableWidthType.PCT, xtab.getWidthType());
|
||||
assertEquals(100.0, xtab.getWidthDecimal(), 0.0);
|
||||
|
||||
xtab.setWidth(100);
|
||||
assertEquals(100, table.getTblPr().getTblW().getW().intValue());
|
||||
try {
|
||||
doc.close();
|
||||
} catch (IOException e) {
|
||||
|
|
|
@ -133,4 +133,18 @@ public class TestXWPFTableCell {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCellGetSetWidth() throws Exception {
|
||||
XWPFDocument doc = new XWPFDocument();
|
||||
XWPFTable table = doc.createTable();
|
||||
XWPFTableRow tr = table.createRow();
|
||||
XWPFTableCell cell = tr.addNewTableCell();
|
||||
|
||||
cell.setWidth("50%");
|
||||
assertEquals(TableWidthType.PCT, cell.getWidthType());
|
||||
assertEquals(50.0, cell.getWidthDecimal(), 0.0);
|
||||
assertEquals(2500, cell.getWidth());
|
||||
doc.close();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue