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

com.vaadin.flow.component.spreadsheet.charts.converter.xssfreader.ChartStylesReader Maven / Gradle / Ivy

/**
 * Copyright 2000-2024 Vaadin Ltd.
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See {@literal } for the full
 * license.
 */
package com.vaadin.flow.component.spreadsheet.charts.converter.xssfreader;

import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.apache.poi.xssf.model.ThemesTable;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTScaling;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTTitle;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBaseStyles;
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument;

import com.vaadin.flow.component.spreadsheet.Spreadsheet;
import com.vaadin.flow.component.spreadsheet.charts.converter.chartdata.ChartData.AxisProperties;
import com.vaadin.flow.component.spreadsheet.charts.converter.chartdata.ChartData.BackgroundProperties;
import com.vaadin.flow.component.spreadsheet.charts.converter.chartdata.ChartData.BorderStyle;
import com.vaadin.flow.component.spreadsheet.charts.converter.chartdata.ChartData.ColorProperties;
import com.vaadin.flow.component.spreadsheet.charts.converter.chartdata.ChartData.TextProperties;
import com.vaadin.flow.component.spreadsheet.charts.converter.chartdata.ChartData.TitleProperties;

class ChartStylesReader {

    private static final double DEFAULT_BORDER_WIDTH = 0.75;

    private static final double FONT_SIZE_FACTOR = 100.0;

    // in excel it is a boolean option
    private static final int EXCEL_BORDER_RADIUS = 8;

    private static final double EMU_PER_PT = 12700.0;

    private final Spreadsheet spreadsheet;

    private XSSFChart xssfChart;

    private CTBaseStyles themeElements;

    private Map colorMap;

    private static Logger logger = Logger
            .getLogger(ChartStylesReader.class.getName());

    public ChartStylesReader(Spreadsheet spreadsheet, XSSFChart xssfChart) {
        this.spreadsheet = spreadsheet;
        this.xssfChart = xssfChart;
    }

    public BackgroundProperties getBackgroundProperties() {
        CTShapeProperties spPr = xssfChart.getCTChartSpace().getSpPr();

        if (spPr == null)
            return null;

        BackgroundProperties backgroundProperties = new BackgroundProperties();

        if (spPr.isSetNoFill())
            backgroundProperties.color = new ColorProperties(
                    new int[] { 0xFF, 0xFF, 0xFF }, 0);
        else if (spPr.isSetSolidFill())
            backgroundProperties.color = ColorUtils
                    .createColorPropertiesFromFill(spPr.getSolidFill(),
                            getColorMap());
        else if (spPr.isSetGradFill()) {
            backgroundProperties.gradient = ColorUtils.createGradientProperties(
                    spPr.getGradFill(), getColorMap());
        } else {
            boolean onlyBorderIsSet = (spPr.getDomNode().getChildNodes()
                    .getLength() == 1) && spPr.isSetLn();

            if (!onlyBorderIsSet)
                logger.warning("Unsupported fill for shape " + spPr);
        }

        return backgroundProperties;
    }

    public TitleProperties getTitleProperties() {
        TitleProperties result = new TitleProperties();

        try {
            CTTitle ctTitle = xssfChart.getCTChart().getTitle();

            CTTextCharacterProperties textProp;

            if (ctTitle.isSetTx()) {
                textProp = ctTitle.getTx().getRich().getPList().get(0).getPPr()
                        .getDefRPr();
            } else {
                textProp = ctTitle.getTxPr().getPList().get(0).getPPr()
                        .getDefRPr();
            }

            result.textProperties = createFontProperties(textProp);

            result.isFloating = ctTitle.getOverlay().getVal();
        } catch (NullPointerException e) {
            // NOP
        }

        return result;
    }

    public TextProperties getLegendTextProperties() {
        try {
            CTTextCharacterProperties defRPr = xssfChart.getCTChart()
                    .getLegend().getTxPr().getPArray(0).getPPr().getDefRPr();

            return createFontProperties(defRPr);
        } catch (NullPointerException e) {
            return null;
        }
    }

    public LinkedHashMap getYAxisProperties() {
        LinkedHashMap result = new LinkedHashMap();

        List valAxList = xssfChart.getCTChart().getPlotArea()
                .getValAxList();

        for (CTValAx valAx : valAxList) {
            result.put(valAx.getAxId().getVal(), getAxisProperties(valAx));
        }

        return result;
    }

    public AxisProperties getXAxisProperties() {
        List catAxList = xssfChart.getCTChart().getPlotArea()
                .getCatAxList();

        if (catAxList.size() > 0)
            return getAxisProperties(catAxList.get(0));
        else
            return null;
    }

    public BorderStyle getBorderStyle() {
        try {
            BorderStyle result = new BorderStyle();

            CTLineProperties borderLineProp = xssfChart.getCTChartSpace()
                    .getSpPr().getLn();

            if (borderLineProp.isSetNoFill())
                return result;

            if (xssfChart.getCTChartSpace().getRoundedCorners().getVal())
                result.radius = EXCEL_BORDER_RADIUS;

            if (borderLineProp.isSetW())
                result.width = borderLineProp.getW() / EMU_PER_PT;
            else
                result.width = DEFAULT_BORDER_WIDTH;

            result.color = ColorUtils.createColorPropertiesFromFill(
                    borderLineProp.getSolidFill(), getColorMap());

            return result;
        } catch (NullPointerException e) {
            // it seems that excel default is to have a border
            return new BorderStyle() {
                {
                    width = DEFAULT_BORDER_WIDTH;
                }
            };
        }
    }

    /**
     * Allows for overriding to wrap in additional property detection/conversion
     * NOTE: POI needs a meta-API for the generated OOXML CT* classes, so shared
     * properties like these can come from a common interface
     *
     * @return axis properties
     */
    protected AxisProperties getAxisProperties(CTValAx yAx) {
        AxisProperties axisProperties = new AxisProperties();

        readAxisTitle(yAx.getTitle(), axisProperties);

        CTScaling scaling = yAx.getScaling();
        if (scaling != null && scaling.isSetMin()) {
            axisProperties.minVal = Double.valueOf(scaling.getMin().getVal());
        }
        if (scaling != null && scaling.isSetMax()) {
            axisProperties.maxVal = Double.valueOf(scaling.getMax().getVal());
        }

        return axisProperties;
    }

    /**
     * Allows for overriding to wrap in additional property detection/conversion
     * NOTE: POI needs a meta-API for the generated OOXML CT* classes, so shared
     * properties like these can come from a common interface
     *
     * @param xAx
     * @return axis properties
     */
    protected AxisProperties getAxisProperties(CTCatAx xAx) {
        AxisProperties axisProperties = new AxisProperties();

        readAxisTitle(xAx.getTitle(), axisProperties);

        CTScaling scaling = xAx.getScaling();
        if (scaling != null && scaling.isSetMin()) {
            axisProperties.minVal = Double.valueOf(scaling.getMin().getVal());
        }
        if (scaling != null && scaling.isSetMax()) {
            axisProperties.maxVal = Double.valueOf(scaling.getMax().getVal());
        }

        return axisProperties;
    }

    private void readAxisTitle(CTTitle title, AxisProperties axisProperties) {
        try {
            CTTextParagraph p = title.getTx().getRich().getPArray(0);

            axisProperties.title = "";

            for (CTRegularTextRun r : p.getRList())
                axisProperties.title += r.getT();

            axisProperties.textProperties = createFontProperties(
                    p.getPPr().getDefRPr());

            if (axisProperties.textProperties == null) {
                axisProperties.textProperties = new TextProperties();
                // default in Excel
                axisProperties.textProperties.bold = true;
            }
        } catch (NullPointerException e) {
            // NOP
        }
    }

    private CTBaseStyles getThemeElements() {
        if (themeElements == null) {
            ThemesTable theme = ((XSSFWorkbook) spreadsheet.getWorkbook())
                    .getTheme();
            if (theme == null) {
                return null;
            }
            ThemeDocument themeDocument;
            try {
                themeDocument = ThemeDocument.Factory
                        .parse(theme.getPackagePart().getInputStream());
            } catch (XmlException e) {
                return null;
            } catch (IOException e) {
                return null;
            }

            themeElements = themeDocument.getTheme().getThemeElements();
        }

        return themeElements;
    }

    private String getFontFamilyConsideringTheme(
            CTTextCharacterProperties pPr) {
        try {
            String fontString = pPr.getLatin().getTypeface();

            if (fontString.startsWith("+mj"))
                return getMajorFont();
            else if (fontString.startsWith("+mn"))
                return getMinorFont();
            else
                return fontString;
        } catch (NullPointerException e) {
            return null;
        }
    }

    private String getMinorFont() {
        if (getThemeElements() == null) {
            return "";
        }
        try {
            return getThemeElements().getFontScheme().getMinorFont().getLatin()
                    .getTypeface();
        } catch (NullPointerException e) {
            return "";
        }
    }

    private String getMajorFont() {
        if (getThemeElements() == null) {
            return "";
        }
        try {
            return getThemeElements().getFontScheme().getMajorFont().getLatin()
                    .getTypeface();
        } catch (NullPointerException e) {
            return "";
        }
    }

    private TextProperties createFontProperties(CTTextCharacterProperties pPr) {
        try {
            TextProperties result = new TextProperties();

            result.fontFamily = getFontFamilyConsideringTheme(pPr);
            result.size = pPr.getSz() / FONT_SIZE_FACTOR;
            result.bold = pPr.getB();
            result.italics = pPr.getI();

            result.color = ColorUtils.createColorPropertiesFromFill(
                    pPr.getSolidFill(), getColorMap());

            return result;
        } catch (NullPointerException e) {
            return null;
        }
    }

    private Map getColorMap() {
        if (colorMap == null) {
            if (getThemeElements() == null) {
                return new HashMap<>();
            }
            colorMap = ColorUtils
                    .createColorMap(getThemeElements().getClrScheme());
        }
        return colorMap;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy