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

org.ddr.poi.html.util.NumberingContext Maven / Gradle / Ivy

/*
 * Copyright 2016 - 2021 Draco, https://github.com/draco1023
 *
 * Licensed 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.ddr.poi.html.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFAbstractNum;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFNumbering;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLvl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHint;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STLevelSuffix;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMultiLevelType;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * 列表上下文
 *
 * @author Draco
 * @since 2021-02-19
 */
public class NumberingContext {
    /**
     * 每级缩进
     */
    private static final int INDENT = 360;
    private static final int HANGING = 360;
    private final XWPFDocument document;
    private int indent = INDENT;
    private int hanging = HANGING;
    private STLevelSuffix.Enum spacing;
    private int nextAbstractNumberId;
    private int nextNumberingLevel;

    private List listStyles;
    private TreeMap numberIdMap = new TreeMap<>(Collections.reverseOrder());
    private List numberingParagraphs;

    public NumberingContext(XWPFDocument document) {
        this.document = document;
    }

    /**
     * 开始新的列表
     *
     * @param listStyle  列表样式
     */
    public void startLevel(ListStyle listStyle) {
        int level = nextNumberingLevel++;
        if (level == 0) {
            numberingParagraphs = new ArrayList<>(8);
            listStyles = new ArrayList<>(4);
        }
        listStyles.add(listStyle);
    }

    /**
     * 结束当前列表
     */
    public void endLevel() {
        nextNumberingLevel--;

        String key = getFormatKey();
        BigInteger numberId = getNumberId(key);

        BigInteger currentLevel = BigInteger.valueOf(nextNumberingLevel);
        for (int i = numberingParagraphs.size() - 1; i >= 0; i--) {
            XWPFParagraph paragraph = numberingParagraphs.get(i);
            if (currentLevel.equals(paragraph.getNumIlvl())) {
                paragraph.setNumID(numberId);
                numberingParagraphs.remove(i);
            } else {
                break;
            }
        }
        if (!listStyles.isEmpty()) {
            listStyles.remove(listStyles.size() - 1);
        }

        if (nextNumberingLevel == 0) {
            numberingParagraphs = null;
            listStyles = null;
        }
    }

    /**
     * 新增段落
     *
     * @param paragraph 段落
     */
    public void add(XWPFParagraph paragraph) {
        if (numberingParagraphs == null) {
            // startLevel method not called, fallback as 
or

return; } paragraph.setNumILvl(BigInteger.valueOf(nextNumberingLevel - 1)); numberingParagraphs.add(paragraph); } /** * 获取列表ID * * @param key Key * @return 列表ID */ private BigInteger getNumberId(String key) { BigInteger numberId = null; for (Map.Entry entry : numberIdMap.entrySet()) { if (entry.getKey().startsWith(key)) { numberId = entry.getValue(); break; } } if (numberId == null) { XWPFNumbering numbering = document.createNumbering(); while (true) { BigInteger abstractNumberId = BigInteger.valueOf(nextAbstractNumberId++); XWPFAbstractNum abstractNum = numbering.getAbstractNum(abstractNumberId); if (abstractNum == null) { CTAbstractNum ctAbstractNum = CTAbstractNum.Factory.newInstance(); ctAbstractNum.setAbstractNumId(abstractNumberId); ctAbstractNum.addNewMultiLevelType().setVal(STMultiLevelType.HYBRID_MULTILEVEL); for (int i = 0; i < listStyles.size(); i++) { ListStyle listStyle = listStyles.get(i); ListStyleType listStyleType = listStyle.getNumberFormat(); CTLvl cTLvl = ctAbstractNum.addNewLvl(); CTInd ind = cTLvl.addNewPPr().addNewInd(); long left = indent * i + listStyle.getLeft(); long right = listStyle.getRight(); for (int j = 0; j < i; j++) { ListStyle previous = listStyles.get(j); left += previous.getLeft(); right += previous.getRight(); } ind.setLeft(BigInteger.valueOf(left)); ind.setRight(BigInteger.valueOf(right)); if (listStyle.isHanging()) { ind.setHanging(BigInteger.valueOf(hanging)); } cTLvl.addNewNumFmt().setVal(listStyleType.getFormat()); cTLvl.addNewLvlText().setVal(getLevelText(listStyleType, i)); cTLvl.addNewStart().setVal(BigInteger.ONE); cTLvl.setIlvl(BigInteger.valueOf(i)); cTLvl.addNewLvlJc().setVal(STJc.LEFT); if (StringUtils.isNotBlank(listStyleType.getFont())) { CTFonts ctFonts = cTLvl.addNewRPr().addNewRFonts(); ctFonts.setAscii(listStyleType.getFont()); ctFonts.setHAnsi(listStyleType.getFont()); ctFonts.setHint(STHint.DEFAULT); } if (spacing != null) { cTLvl.addNewSuff().setVal(spacing); } } numbering.addAbstractNum(new XWPFAbstractNum(ctAbstractNum, numbering)); numberId = numbering.addNum(abstractNumberId); numberIdMap.put(key, numberId); break; } } } return numberId; } private String getLevelText(ListStyleType listStyleType, int i) { if (listStyleType.getText() == null) { return ""; } if (listStyleType.getText().length() == 0) { return getOrderedLevelText(i); } return listStyleType.getText(); } /** * 获取有序列表项的序号格式 * * @param i 索引,从0开始 * @return 序号格式 */ private String getOrderedLevelText(int i) { return "%" + (i + 1) + "."; } private String getFormatKey() { StringBuilder sb = new StringBuilder(); for (ListStyle listStyle : listStyles) { sb.append(listStyle.getNumberFormat().getName()).append(StringUtils.SPACE); } return sb.toString(); } public void setIndent(int indent) { if (indent >= 0) { this.indent = indent; } } public void setHanging(int hanging) { if (hanging >= 0) { this.hanging = hanging; } } public void setSpacing(STLevelSuffix.Enum spacing) { this.spacing = spacing; } public boolean contains(XWPFParagraph paragraph) { return numberingParagraphs != null && numberingParagraphs.contains(paragraph); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy