All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.moon.poi.excel.table.HeadUtil Maven / Gradle / Ivy

package com.moon.poi.excel.table;

import com.moon.core.util.Table;
import com.moon.core.util.TableImpl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static com.moon.poi.excel.table.HeadCell.getTitleOfNull;

/**
 * @author moonsky
 */
final class HeadUtil {

    /**
     * 计算表头最大行数
     *
     * @param columns {@link ParserUtil#mapAttrs(Class, Map, Function)}
     *
     * @return 行数
     */
    static int maxHeaderRowNum(TableCol[] columns) {
        int maxTitleRowCount = 0;
        for (TableCol column : columns) {
            maxTitleRowCount = Math.max(column.getHeaderRowsCount(), maxTitleRowCount);
        }
        return maxTitleRowCount;
    }

    static int groupDepth(TableCol[] cols) {
        int depth = 0;
        for (int i = 0; i < cols.length; i++) {
            TableCol col = cols[i];
            depth = Math.max(col.getDepth(), depth);
        }
        return depth;
    }

    /**
     * 计算表头,结果呈一个矩阵,可能包含相邻位置值相同的情况
     *
     * @param columns     {@link ParserUtil#mapAttrs(Class, Map, Function)}
     * @param maxRowCount {@link #maxHeaderRowNum(TableCol[])}
     *
     * @return 表头矩阵
     *
     * @see TableRenderer
     */
    static List[] collectTableHead(TableCol[] columns, int maxRowCount) {
        List[] tableHead = new List[maxRowCount];
        for (int i = 0; i < maxRowCount; i++) {
            List titleRow = new ArrayList<>();
            for (TableCol column : columns) {
                column.appendTitlesAtRowIdx(titleRow, i);
            }
            tableHead[i] = titleRow;
        }
        return tableHead;
    }

    static Integer[] collectColumnsWidth(TableCol[] columns) {
        List widthList = new ArrayList<>();
        for (TableCol column : columns) {
            column.appendColumnWidth(widthList);
        }
        int size = widthList.size();
        Integer[] widthArr = new Integer[size];
        for (int i = 0; i < size; i++) {
            Integer width = widthList.get(i);
            widthArr[i] = width == null || width < 0 ? null : width;
        }
        return widthArr;
    }

    static List[] collectHeaderCells(List[] collected) {
        Table table = collectRegionAddresses(collected);
        List[] headerCells = new List[table.sizeOfRows()];
        for (int i = 0; i < headerCells.length; i++) {
            List row = new ArrayList<>();
            Map cols = table.get(i);
            cols.forEach((idx, cell) -> row.add(cell));
            headerCells[i] = row;
        }
        return headerCells;
    }

    /**
     * 计算合并的单元格信息,返回值中每个{@link TableCell}的信息至少合并两个单元格
     *
     * @param tableHead {@link #collectTableHead(TableCol[], int)}
     *
     * @return 计算后的合并单元格信息
     *
     * @see TableRenderer
     */
    private static Table collectRegionAddresses(List[] tableHead) {
        int maxLength = tableHead.length;
        Table table = TableImpl.newLinkedHashTable();
        for (int rowIdx = 0; rowIdx < maxLength; rowIdx++) {
            List rowTitles = tableHead[rowIdx];

            TableHeaderCell previousCell = null, headerCell;
            for (int colIdx = 0; colIdx < rowTitles.size(); colIdx++) {
                HeadCell thisCell = rowTitles.get(colIdx);
                String thisTitle = getTitleOfNull(thisCell);
                headerCell = new TableHeaderCell(thisCell, rowIdx, colIdx);
                table.put(rowIdx, colIdx, headerCell);
                if (previousCell == null) {
                    previousCell = headerCell;
                } else if (!previousCell.mergeColsIfTitleEquals(thisTitle)) {
                    mergeRowsIfLikeCell(table, previousCell);
                    previousCell = headerCell;
                }
            }
            if (previousCell != null) {
                mergeRowsIfLikeCell(table, previousCell);
            }
        }
        return table;
    }

    private static void mergeRowsIfLikeCell(
        Table table, TableHeaderCell cell
    ) {
        int colIdx = cell.getColIdx();
        int maxRowNum = cell.getRowIdx(0) + 1;
        for (int rowIdx = 0; rowIdx < maxRowNum; rowIdx++) {
            TableHeaderCell prevRowCell = table.get(rowIdx, colIdx);
            if (prevRowCell.mergeRowsIfLikeCell(cell)) {
                break;
            }
        }
    }

    private final static class TableHeaderCell extends HeaderCell {

        private final boolean fillSkipped;
        private final String title;
        private final short height;
        private final int rowIdx;
        private final int colIdx;
        private int rowspan;
        private int colspan;

        TableHeaderCell(HeadCell targetCell, int rowIdx, int colIdx) {
            this.title = HeadCell.getTitleOfNull(targetCell);
            this.fillSkipped = targetCell.isOffsetFilled();
            this.height = targetCell.getHeight();
            this.rowIdx = rowIdx;
            this.colIdx = colIdx;
            this.rowspan = 1;
            this.colspan = 1;
        }

        boolean isTitleEquals(String otherTitle) {
            if (title != null && otherTitle != null) {
                return title.equals(otherTitle);
            }
            return false;
        }

        /**
         * 如果两个单元格相似(标题一致),则合并
         *
         * @param thisTitle 期望标题
         *
         * @return 是否合并完成
         */
        boolean mergeColsIfTitleEquals(String thisTitle) {
            boolean equals = isTitleEquals(thisTitle);
            if (equals) {
                this.colspan++;
            }
            return equals;
        }

        /**
         * 如果两个单元格“相似”(标题一致,合并列一致),则合并
         *
         * @param that 目标单元格
         *
         * @return 是否合并完成
         */
        boolean mergeRowsIfLikeCell(TableCell that) {
            boolean equals = this != that

                && this.colspan == that.getColspan()

                && isTitleEquals(that.getValue());
            if (equals) {
                this.rowspan++;
            }
            return equals;
        }

        @Override
        public int getColIdx() { return colIdx; }

        @Override
        public String getValue() { return title; }

        @Override
        public int getRowIdx(int rowIdxOffset) { return rowIdx + rowIdxOffset; }

        @Override
        public int getRowspan() { return rowspan; }

        @Override
        public int getColspan() { return colspan; }

        @Override
        public short getHeight() { return height; }

        @Override
        boolean isOffsetCell() { return getValue() == null; }

        @Override
        boolean isFillSkipped() { return fillSkipped; }
    }
}






© 2015 - 2025 Weber Informatics LLC | Privacy Policy