--- /dev/null
+/* ====================================================================
+ 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;
+ }
+}
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;
@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,
}
/**
- * @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();
}
/**
- * @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);
}
/**
}
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);
+ }
+ }
+ }
}
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;
/**
* @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);
* @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));
}
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;
}
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();
+ }
}
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) {
}
}
}
+
+ @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();
+ }
}