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

com.moon.poi.excel.WorkbookProxy Maven / Gradle / Ivy

package com.moon.poi.excel;

import com.moon.core.lang.StringUtil;
import com.moon.core.lang.ref.FinalAccessor;
import com.moon.core.util.CollectUtil;
import com.moon.core.util.Table;
import com.moon.core.util.TableImpl;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.IntConsumer;

/**
 * @author moonsky
 */
public final class WorkbookProxy {

    private final static boolean DEFAULT_APPEND_DATA = true;

    private final static Object PLACEHOLDER = new byte[0];

    private final FinalAccessor mergedOnCell = FinalAccessor.of();

    private final Map> sheetMap = new HashMap<>();

    private final WorkbookType type;
    private final Workbook workbook;

    private ProxyStyleModel proxyStyleModel;
    private ProxyCommentModel proxyCommentModel;

    private Table table;
    private Sheet sheet;
    private int indexOfRow;

    private Row row;
    private int indexOfCell;

    private Map rowFilled;
    private Cell cell;

    // 图片管理器
    private Table> pictureManagerTable;

    WorkbookProxy(Workbook workbook) {
        this.workbook = workbook;
        if (WorkbookType.XLSX.test(workbook)) {
            type = WorkbookType.XLSX;
        } else if (WorkbookType.XLS.test(workbook)) {
            type = WorkbookType.XLS;
        } else if (WorkbookType.SUPER.test(workbook)) {
            type = WorkbookType.SUPER;
        } else {
            type = null;
        }
    }

    Workbook getWorkbook() { return workbook; }

    public Table> getPictureManagerTable() {
        return pictureManagerTable;
    }

    public Table> ensurePictureManagerTable() {
        return pictureManagerTable == null ? (pictureManagerTable = new TableImpl<>()) : pictureManagerTable;
    }

    private Table getTable(Sheet sheet) {
        Table t = this.table;
        if (t == null) {
            t = sheetMap.get(sheet);
            if (t == null) {
                t = new TableImpl();
                sheetMap.put(sheet, t);
            }
            this.table = t;
        }
        return t;
    }

    private static Map getRowFilled(Table table, int rowIdx) {
        Map rowFilled = table.get(rowIdx);
        if (rowFilled == null) {
            rowFilled = new HashMap<>();
            table.put(rowIdx, rowFilled);
        }
        return rowFilled;
    }

    private Map getRowFilled() {
        Map rowFilled = this.rowFilled;
        if (rowFilled == null) {
            int rowIdx = this.indexOfRow;
            Table table = getTable(sheet);
            rowFilled = table.get(rowIdx);
            if (rowFilled == null) {
                rowFilled = new HashMap<>();
                table.put(rowIdx, rowFilled);
            }
            this.rowFilled = rowFilled;
        }
        return rowFilled;
    }

    /*
     * style
     */

    private static void useProxyModel(ProxyModel proxyModel, Object from) {
        if (proxyModel != null) {
            proxyModel.use(from);
        }
    }

    private ProxyCommentModel getCommentProxy() { return proxyCommentModel; }

    private ProxyStyleModel getStyleProxy() { return this.proxyStyleModel; }

    private ProxyCommentModel ensureCommentProxy() {
        ProxyCommentModel proxy = this.getCommentProxy();
        if (proxy == null) {
            proxy = new ProxyCommentModel();
            this.proxyCommentModel = proxy;
        }
        return proxy;
    }

    private ProxyStyleModel ensureStyleProxy() {
        ProxyStyleModel proxy = this.getStyleProxy();
        if (proxy == null) {
            proxy = new ProxyStyleModel();
            this.proxyStyleModel = proxy;
        }
        return proxy;
    }

    void definitionBuilder(ProxyStyleBuilder builder) { ensureStyleProxy().addBuilder(builder); }

    void addSetter(ProxyStyleSetter setter, String classname) { ensureStyleProxy().addSetter(classname, setter); }

    ProxyStyleBuilder findBuilder(ProxyStyleSetter setter) {
        ProxyStyleModel styleModel = ensureStyleProxy();
        Object classname = styleModel.find(setter);
        return styleModel.find(classname);
    }

    void definitionBuilder(ProxyCommentBuilder builder) { ensureCommentProxy().addBuilder(builder); }

    void addSetter(ProxyCommentSetter setter, String unique) { ensureCommentProxy().addSetter(unique, setter); }

    void removeSetter(ProxyCommentSetter setter) { ensureCommentProxy().removeSetter(setter); }

    void applyProxiedModel() {
        useProxyModel(getStyleProxy(), workbook);
        useProxyModel(getCommentProxy(), null);
    }

    /*
     workbook
     */

    Comment createComment(String content) {
        Comment comment = createComment();
        comment.setString(createRichText(content));
        return comment;
    }

    Comment createComment() {
        Drawing drawing = getSheet().createDrawingPatriarch();
        return drawing.createCellComment(getWorkbookType().newAnchor());
    }

    RichTextString createRichText(String content) { return getWorkbookType().newRichText(content); }

    WorkbookType getWorkbookType() { return type; }

    ClientAnchor getAnchor() {
        FinalAccessor region = this.mergedOnCell;
        if (region.isAbsent()) {
            Cell cell = getCell();
            int rowIdx = cell.getRowIndex();
            int colIdx = cell.getColumnIndex();
            return getWorkbookType().newAnchor(0, 0, 0, 0, colIdx, rowIdx, colIdx + 1, rowIdx + 1);
        } else {
            CellRangeAddress address = region.get();
            int col1 = address.getFirstColumn();
            int col2 = address.getLastColumn();
            int row1 = address.getFirstRow();
            int row2 = address.getLastRow();
            return getWorkbookType().newAnchor(0, 0, 0, 0, col1, row1, col2 + 1, row2 + 1);
        }
    }

    /*
     sheet
     */

    Sheet setSheet(Sheet sheet, int startOfRowIndex) {
        this.indexOfRow = startOfRowIndex;
        this.table = null;
        this.sheet = sheet;
        return sheet;
    }

    Sheet setSheet(Sheet sheet, boolean appendRow) {
        return setSheet(sheet, appendRow ? sheet.getLastRowNum() : 0);
    }

    Sheet getSheet() { return sheet; }

    Sheet useSheet(String sheetName, boolean appendRow) {
        if (StringUtil.isEmpty(sheetName)) {
            return setSheet(workbook.createSheet(), false);
        }
        Sheet sheet = workbook.getSheet(sheetName);
        if (sheet == null) {
            return setSheet(workbook.createSheet(sheetName), appendRow);
        } else {
            return setSheet(sheet, appendRow);
        }
    }

    Sheet useSheet(int index, boolean appendRow) {
        if (index < workbook.getNumberOfSheets()) {
            return setSheet(workbook.getSheetAt(index), appendRow);
        } else {
            return setSheet(workbook.createSheet(), appendRow);
        }
    }

    Sheet useSheet(String sheetName) { return useSheet(sheetName, DEFAULT_APPEND_DATA); }

    /*
     row
     */

    int nextIndexOfRow() { return indexOfRow++; }

    int nextIndexOfRow(int offset) {
        int index = indexOfRow + offset;
        this.indexOfRow = index + 1;
        return index;
    }

    Row setRow(Row row, int index) {
        this.indexOfCell = index;
        this.rowFilled = null;
        return this.row = row;
    }

    Row setRow(Row row, boolean appendCell) {
        int index = appendCell ? row.getLastCellNum() : 0;
        return setRow(row, Math.max(index, 0));
    }

    Row getRow() { return row; }

    int getIndexOfRow() { return indexOfRow; }

    private Row createRow(int index, boolean appendCell) { return setRow(sheet.createRow(index), appendCell); }

    Row useOrCreateRow(int index, boolean appendCell) {
        Row row = sheet.getRow(index);
        if (row == null) {
            row = sheet.createRow(index);
        }
        return purelyUseRow(row, index, appendCell);
    }

    Row purelyUseRow(Row row, int index, boolean appendCell) {
        // 保持 indexOfRow 指向下一行
        this.indexOfRow = index + 1;
        return setRow(row, appendCell);
    }

    Row nextRow(boolean appendCell) { return createRow(nextIndexOfRow(), appendCell); }

    Row nextRow(int offset, boolean appendCell) { return createRow(nextIndexOfRow(offset), appendCell); }

    Row nextRow() { return nextRow(DEFAULT_APPEND_DATA); }

    Row nextRow(int offset) { return nextRow(offset, DEFAULT_APPEND_DATA); }

    /*
     cell
     */

    int getColumnWidth() {
        return sheet.getColumnWidth(getCell().getColumnIndex());
    }

    void setColumnWidth(Sheet sheet, int index, int width) {
        sheet.setColumnWidth(index, width);
        Table> table = getPictureManagerTable();
        if (table != null) {
            List consumers = table.get(sheet, index);
            if (consumers != null) {
                for (IntConsumer consumer : consumers) {
                    consumer.accept(width);
                }
            }
        }
    }

    boolean isAllowAutoWidth(Sheet sheet, int index) {
        Table> table = getPictureManagerTable();
        return table == null || CollectUtil.isEmpty(table.get(sheet, index));
    }

    IntConsumer getIndexedColumnRunner(BufferedImage image) {
        final Row row = this.getRow();
        final double w = image.getWidth(), h = image.getHeight();
        final double scale = h / w, compatibleScale = scale / 3;
        // System.out.println("Width: " + w + ", Height: " + h + ", Scale: " + scale);
        return width -> {
            // System.out.println(row.getHeight());
            // System.out.println(width + "\t\t" + (width * scale) + "\t\t" + ((short) (width * scale)));
            row.setHeight((short) (width * compatibleScale));
        };
    }

    final void writeImageOnCell(BufferedImage image) {
        IntConsumer consumer = getIndexedColumnRunner(image);
        final int width = getColumnWidth();
        try {
            Sheet sheet = getSheet();
            Drawing drawing = sheet.createDrawingPatriarch();
            ByteArrayOutputStream byteArr = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", byteArr);
            ClientAnchor anchor = getAnchor();
            byte[] bytes = byteArr.toByteArray();
            int picture = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);
            drawing.createPicture(anchor, picture);

            // 执行器
            Table table = ensurePictureManagerTable();
            int columnIndex = getCell().getColumnIndex();
            List list = (List) table.get(sheet, columnIndex);
            if (list == null) {
                list = new ArrayList();
                table.put(sheet, columnIndex, list);
            }
            list.add(consumer);
        } catch (Throwable t) {
            throw new IllegalStateException(t);
        } finally {
            consumer.accept(width);
        }
    }

    int nextIndexOfCell(int offset, int rowspan, int colspan) {
        int cIdx = this.indexOfCell;
        Map rowFilled = getRowFilled();
        for (; rowFilled.get(cIdx) != null; cIdx++) { }
        int nCellIdx = cIdx + offset;
        int eCellIdx = nCellIdx + colspan;
        Object placeholder = PLACEHOLDER;
        for (int i = nCellIdx; i < eCellIdx; i++) {
            rowFilled.put(i, placeholder);
        }
        int rowIdx = this.indexOfRow;
        if (rowspan > 1) {
            int nRowIdx = rowIdx + 1;
            int eRowIdx = nRowIdx + (rowspan - 1);
            Table table = getTable(sheet);
            for (int i = nRowIdx; i < eRowIdx; i++) {
                Map idxRowFilled = getRowFilled(table, i);
                for (int j = nCellIdx; j < eCellIdx; j++) {
                    idxRowFilled.put(j, placeholder);
                }
            }
        }
        CellRangeAddress region = null;
        if (rowspan > 1 || colspan > 1) {
            int fr = rowIdx - 1;
            int lr = fr + rowspan - 1;
            region = new CellRangeAddress(fr, lr, nCellIdx, eCellIdx - 1);
            sheet.addMergedRegion(region);
        }
        mergedOnCell.replaceOf(region);
        this.indexOfCell = eCellIdx;
        return nCellIdx;
    }

    Cell setCell(Cell cell) { return this.cell = cell; }

    Cell getCell() { return cell; }

    CellRangeAddress getRegion() { return mergedOnCell.get(); }

    private Cell createCell(int index) { return setCell(row.createCell(index)); }

    private void fillIndex(Integer index) {
        getRowFilled().put(index, PLACEHOLDER);
    }

    Cell setCellAndFill(Cell cell, int index) {
        fillIndex(index);
        return setCell(cell);
    }

    Cell createCellAndFill(int index) {
        fillIndex(index);
        return createCell(index);
    }

    Cell useOrCreateCell(int index, boolean alwaysCreateCell) {
        if (alwaysCreateCell) {
            return createCellAndFill(index);
        } else {
            Cell cell = row.getCell(index);
            return cell == null ? createCellAndFill(index) : setCellAndFill(cell, index);
        }
    }

    Cell useOrCreateCell(int index) {
        return useOrCreateCell(index, false);
    }

    Cell nextCell(int offset, int rowspan, int colspan) {
        return createCell(nextIndexOfCell(offset, rowspan, colspan));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy