fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.java Source code

Java tutorial

Introduction

Here is the source code for fr.opensagres.poi.xwpf.converter.core.utils.XWPFTableUtil.java

Source

/**
 * 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;
    }

}