git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1838449 13f79535-47bb-0310-9956-ffa450edef68tags/REL_4_0_0_FINAL
@@ -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(); | |||
} | |||
} |