Java tutorial
/** * Copyright (C) 2011-2015 The XDocReport Team <xdocreport@googlegroups.com> * * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package fr.opensagres.poi.xwpf.converter.core.utils; import static fr.opensagres.poi.xwpf.converter.core.utils.DxaUtil.dxa2points; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFTableRow; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShortHexNumber; 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.CTTblGrid; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTrPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth; import org.w3c.dom.Attr; import org.w3c.dom.Node; import fr.opensagres.poi.xwpf.converter.core.Color; import fr.opensagres.poi.xwpf.converter.core.TableCellBorder; import fr.opensagres.poi.xwpf.converter.core.TableWidth; public class XWPFTableUtil { private static final String MAIN_NAMESPACE = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; // Hexa Bitmask for tblLook. public static final int DEFAULT_TBLLOOK = 0x0000; public static final int APPLY_FIRST_ROW_CONDITIONNAL_FORMATTING = 0x0020; // Apply first row conditional formatting public static final int APPLY_LAST_ROW_CONDITIONNAL_FORMATTING = 0x0040; // Apply last row conditional formatting public static final int APPLY_FIRST_COLUMN_CONDITIONNAL_FORMATTING = 0x0080; // Apply first column conditional // formatting public static final int APPLY_LAST_COLUMN_CONDITIONNAL_FORMATTING = 0x0100; // Apply last column conditional // formatting public static final int DO_NOT_APPLY_ROW_BANDING_CONDITIONNAL_FORMATTING = 0x0200; // Do not apply row banding // conditional formatting public static final int DO_NOT_APPLY_COLUMN_BANDING_CONDITIONNAL_FORMATTING = 0x0400; // Do not apply column banding // conditional formatting public static float[] computeColWidths(CTTbl table) { CTTblGrid grid = table.getTblGrid(); List<CTTblGridCol> cols = getGridColList(grid); int nbColumns = cols.size(); float[] colWidths = new float[nbColumns]; float colWidth = -1; int nbColumnsToIgnoreBefore = 0; for (int i = nbColumnsToIgnoreBefore; i < colWidths.length; i++) { CTTblGridCol tblGridCol = cols.get(i); colWidth = tblGridCol.getW().floatValue(); colWidths[i] = dxa2points(colWidth); } return colWidths; } /** * Compute column widths of the XWPF table. * * @param table * @return */ public static float[] computeColWidths(XWPFTable table) { XWPFTableRow firstRow = getFirstRow(table); float[] colWidths; // Get first row to know if there is cell which have gridSpan to compute // columns number. int nbCols = getNumberOfColumns(firstRow); // Compare nbCols computed with number of grid colList CTTblGrid grid = table.getCTTbl().getTblGrid(); List<CTTblGridCol> cols = getGridColList(grid); if (nbCols > cols.size()) { Collection<Float> maxColWidths = null; Collection<Float> currentColWidths = null; // nbCols computed is not equals to number of grid colList // columns width must be computed by looping for each row/cells List<XWPFTableRow> rows = table.getRows(); for (XWPFTableRow row : rows) { currentColWidths = computeColWidths(row); if (maxColWidths == null) { maxColWidths = currentColWidths; } else { if (currentColWidths.size() > maxColWidths.size()) { maxColWidths = currentColWidths; } } } colWidths = new float[maxColWidths.size()]; int i = 0; for (Float colWidth : maxColWidths) { colWidths[i++] = colWidth; } return colWidths; } else { // If w:gridAfter is defined, ignore the last columns defined on the gridColumn int nbColumnsToIgnoreBefore = getNbColumnsToIgnore(firstRow, true); int nbColumnsToIgnoreAfter = getNbColumnsToIgnore(firstRow, false); int nbColumns = cols.size() - nbColumnsToIgnoreBefore - nbColumnsToIgnoreAfter; // nbCols computed is equals to number of grid colList // columns width can be computed by using the grid colList colWidths = new float[nbColumns]; float colWidth = -1; for (int i = nbColumnsToIgnoreBefore; i < colWidths.length; i++) { CTTblGridCol tblGridCol = cols.get(i); colWidth = tblGridCol.getW().floatValue(); colWidths[i] = dxa2points(colWidth); } } return colWidths; } /** * <w:gridCol list should be filtered to ignore negative value. * <p> * Ex : <w:gridCol w:w="-54" /> should be ignored. See https://code.google.com/p/xdocreport/issues/detail?id=315 * </p> * * @param grid * @return */ private static List<CTTblGridCol> getGridColList(CTTblGrid grid) { List<CTTblGridCol> newCols = new ArrayList<CTTblGridCol>(); List<CTTblGridCol> cols = grid.getGridColList(); for (CTTblGridCol col : cols) { if (col.getW().floatValue() >= 0) { newCols.add(col); } } return newCols; } private static int getNbColumnsToIgnore(XWPFTableRow row, boolean before) { CTTrPr trPr = row.getCtRow().getTrPr(); if (trPr == null) { return 0; } List<CTDecimalNumber> gridBeforeAfters = before ? trPr.getGridBeforeList() : trPr.getGridAfterList(); if (gridBeforeAfters == null || gridBeforeAfters.size() < 1) { return 0; } int nbColumns = 0; BigInteger val = null; for (CTDecimalNumber gridBeforeAfter : gridBeforeAfters) { val = gridBeforeAfter.getVal(); if (val != null) { nbColumns += val.intValue(); } } return nbColumns; } /** * Returns number of column if the XWPF table by using the declared cell (which can declare gridSpan) from the first * row. * * @param table * @return */ public static int getNumberOfColumns(XWPFTableRow row) { if (row == null) { return 0; } // Get first row to know if there is cell which have gridSpan to compute // columns number. int nbCols = 0; List<XWPFTableCell> tableCellsOffFirstRow = row.getTableCells(); for (XWPFTableCell tableCellOffFirstRow : tableCellsOffFirstRow) { CTDecimalNumber gridSpan = getGridSpan(tableCellOffFirstRow); if (gridSpan != null) { nbCols += gridSpan.getVal().intValue(); } else { nbCols += 1; } } return nbCols; } public static XWPFTableRow getFirstRow(XWPFTable table) { int numberOfRows = table.getNumberOfRows(); if (numberOfRows > 0) { return table.getRow(0); } return null; } public static CTDecimalNumber getGridSpan(XWPFTableCell cell) { if (cell.getCTTc().getTcPr() != null) return cell.getCTTc().getTcPr().getGridSpan(); return null; } public static CTTblWidth getWidth(XWPFTableCell cell) { return cell.getCTTc().getTcPr().getTcW(); } private static Collection<Float> computeColWidths(XWPFTableRow row) { List<Float> colWidths = new ArrayList<Float>(); List<XWPFTableCell> cells = row.getTableCells(); for (XWPFTableCell cell : cells) { // Width CTTblWidth width = getWidth(cell); if (width != null) { int nb = 1; CTDecimalNumber gridSpan = getGridSpan(cell); TableWidth tableCellWidth = getTableWidth(cell); if (gridSpan != null) { nb = gridSpan.getVal().intValue(); } for (int i = 0; i < nb; i++) { colWidths.add(tableCellWidth.width / nb); } } } return colWidths; } /** * Returns table width of teh XWPF table. * * @param table * @return */ public static TableWidth getTableWidth(XWPFTable table) { float width = 0; boolean percentUnit = false; CTTblPr tblPr = table.getCTTbl().getTblPr(); if (tblPr.isSetTblW()) { CTTblWidth tblWidth = tblPr.getTblW(); return getTableWidth(tblWidth); } return new TableWidth(width, percentUnit); } public static TableWidth getTableWidth(XWPFTableCell cell) { float width = 0; boolean percentUnit = false; CTTcPr tblPr = cell.getCTTc().getTcPr(); if (tblPr.isSetTcW()) { CTTblWidth tblWidth = tblPr.getTcW(); return getTableWidth(tblWidth); } return new TableWidth(width, percentUnit); } public static TableWidth getTableWidth(CTTblWidth tblWidth) { if (tblWidth == null) { return null; } Float width = getTblWidthW(tblWidth); if (width == null) { return null; } boolean percentUnit = (STTblWidth.INT_PCT == tblWidth.getType().intValue()); if (percentUnit) { width = width / 100f; } else { width = dxa2points(width); } return new TableWidth(width, percentUnit); } /** * Returns the float value of <w:tblW w:w="9288.0" w:type="dxa" /> * * @param tblWidth * @return */ public static Float getTblWidthW(CTTblWidth tblWidth) { try { return tblWidth.getW().floatValue(); } catch (Throwable e) { // Sometimes w:w is a float value.Ex : <w:tblW w:w="9288.0" w:type="dxa" /> // see https://code.google.com/p/xdocreport/issues/detail?id=315 Attr attr = (Attr) tblWidth.getDomNode().getAttributes() .getNamedItemNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w"); if (attr != null) { return Float.valueOf(attr.getValue()); } } return null; } public static CTTblPr getTblPr(XWPFTable table) { CTTbl tbl = table.getCTTbl(); if (tbl != null) { return tbl.getTblPr(); } return null; } public static CTTblBorders getTblBorders(XWPFTable table) { CTTblPr tblPr = getTblPr(table); if (tblPr != null) { return tblPr.getTblBorders(); } return null; } public static CTTblCellMar getTblCellMar(XWPFTable table) { CTTblPr tblPr = getTblPr(table); if (tblPr != null) { return tblPr.getTblCellMar(); } return null; } public static TableCellBorder getTableCellBorder(CTBorder border, boolean fromTableCell) { if (border != null) { boolean noBorder = (STBorder.NONE == border.getVal() || STBorder.NIL == border.getVal()); if (noBorder) { return new TableCellBorder(!noBorder, fromTableCell); } Float borderSize = null; BigInteger size = border.getSz(); if (size != null) { // http://officeopenxml.com/WPtableBorders.php // if w:sz="4" => 1/4 points borderSize = size.floatValue() / 8f; } Color borderColor = ColorHelper.getBorderColor(border); return new TableCellBorder(borderSize, borderColor, fromTableCell); } return null; } public static Color getBorderColor(CTBorder border) { if (border == null) { return null; } // border.getColor returns object???, use attribute w:color to get // the color. Node colorAttr = border.getDomNode().getAttributes().getNamedItemNS(MAIN_NAMESPACE, "color"); if (colorAttr != null) { Object val = border.getVal(); return ColorHelper.getColor(((Attr) colorAttr).getValue(), val, false); } return null; } public static CTShortHexNumber getTblLook(XWPFTable table) { CTTblPr tblPr = getTblPr(table); if (tblPr != null) { return tblPr.getTblLook(); } return null; } public static int getTblLookVal(XWPFTable table) { int tblLook = DEFAULT_TBLLOOK; CTShortHexNumber hexNumber = getTblLook(table); if (hexNumber != null && !hexNumber.isNil()) { // CTShortHexNumber#getVal() returns byte[] and not byte, use attr value ??? Attr attr = (Attr) hexNumber.getDomNode().getAttributes().getNamedItemNS(MAIN_NAMESPACE, "val"); if (attr != null) { String value = attr.getValue(); try { tblLook = Integer.parseInt(value, 16); } catch (Throwable e) { e.printStackTrace(); } } } return tblLook; } public static boolean canApplyFirstRow(int tblLookVal) { int mask = APPLY_FIRST_ROW_CONDITIONNAL_FORMATTING; return (tblLookVal & mask) == mask; } public static boolean canApplyLastRow(int tblLookVal) { int mask = APPLY_LAST_ROW_CONDITIONNAL_FORMATTING; return (tblLookVal & mask) == mask; } public static boolean canApplyFirstCol(int tblLookVal) { int mask = APPLY_FIRST_COLUMN_CONDITIONNAL_FORMATTING; return (tblLookVal & mask) == mask; } public static boolean canApplyLastCol(int tblLookVal) { int mask = APPLY_LAST_COLUMN_CONDITIONNAL_FORMATTING; return (tblLookVal & mask) == mask; } }