// xlsxchart.cpp #include <QtGlobal> #include <QString> #include <QIODevice> #include <QXmlStreamReader> #include <QXmlStreamWriter> #include <QDebug> #include "xlsxchart_p.h" #include "xlsxworksheet.h" #include "xlsxcellrange.h" #include "xlsxutility_p.h" QT_BEGIN_NAMESPACE_XLSX ChartPrivate::ChartPrivate(Chart *q, Chart::CreateFlag flag) : AbstractOOXmlFilePrivate(q, flag), chartType(static_cast<Chart::ChartType>(0)) { } ChartPrivate::~ChartPrivate() { } /*! * \internal */ Chart::Chart(AbstractSheet *parent, CreateFlag flag) : AbstractOOXmlFile(new ChartPrivate(this, flag)) { Q_D(Chart); d_func()->sheet = parent; // d->legendPos = Chart::ChartAxisPos::None; d->legendPos = Chart::None; d->legendOverlay = false; d->majorGridlinesEnabled = false; d->minorGridlinesEnabled = false; } /*! * Destroys the chart. */ Chart::~Chart() { } /*! * Add the data series which is in the range \a range of the \a sheet. */ void Chart::addSeries(const CellRange &range, AbstractSheet *sheet, bool headerH, bool headerV, bool swapHeaders) { Q_D(Chart); if (!range.isValid()) return; if (sheet && sheet->sheetType() != AbstractSheet::ST_WorkSheet) return; if (!sheet && d->sheet->sheetType() != AbstractSheet::ST_WorkSheet) return; QString sheetName = sheet ? sheet->sheetName() : d->sheet->sheetName(); //In case sheetName contains space or ' sheetName = escapeSheetName(sheetName); if (range.columnCount() == 1 || range.rowCount() == 1) { auto series = std::make_shared<XlsxSeries>(); series->numberDataSource_numRef = sheetName + QLatin1String("!") + range.toString(true, true); d->seriesList.append(series); } else if ((range.columnCount() < range.rowCount()) || swapHeaders ) { //Column based series int firstDataRow = range.firstRow(); int firstDataColumn = range.firstColumn(); QString axDataSouruce_numRef; if (d->chartType == CT_ScatterChart || d->chartType == CT_BubbleChart) { firstDataColumn += 1; CellRange subRange(range.firstRow(), range.firstColumn(), range.lastRow(), range.firstColumn()); axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); } if( headerH ) { firstDataRow += 1; } if( headerV ) { firstDataColumn += 1; } for (int col=firstDataColumn; col<=range.lastColumn(); ++col) { CellRange subRange(firstDataRow, col, range.lastRow(), col); auto series = std::make_shared<XlsxSeries>(); series->axDataSource_numRef = axDataSouruce_numRef; series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); if( headerH ) { CellRange subRange(range.firstRow(), col, range.firstRow(), col); series->headerH_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); } else { series->headerH_numRef = QString(); } if( headerV ) { CellRange subRange(firstDataRow, range.firstColumn(), range.lastRow(), range.firstColumn()); series->headerV_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); } else { series->headerV_numRef = QString(); } series->swapHeader = swapHeaders; d->seriesList.append(series); } } else { //Row based series int firstDataRow = range.firstRow(); int firstDataColumn = range.firstColumn(); QString axDataSouruce_numRef; if (d->chartType == CT_ScatterChart || d->chartType == CT_BubbleChart) { firstDataRow += 1; CellRange subRange(range.firstRow(), range.firstColumn(), range.firstRow(), range.lastColumn()); axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); } if( headerH ) { firstDataRow += 1; } if( headerV ) { firstDataColumn += 1; } for (int row=firstDataRow; row<=range.lastRow(); ++row) { CellRange subRange(row, firstDataColumn, row, range.lastColumn()); auto series = std::make_shared<XlsxSeries>(); series->axDataSource_numRef = axDataSouruce_numRef; series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); if( headerH ) { CellRange subRange(range.firstRow(), firstDataColumn, range.firstRow(), range.lastColumn()); series->headerH_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); } else { series->headerH_numRef = QString(); } if( headerV ) { CellRange subRange(row, range.firstColumn(), row, range.firstColumn()); series->headerV_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); } else { series->headerV_numRef = QString(); } series->swapHeader = swapHeaders; d->seriesList.append(series); } } } /*! * Set the type of the chart to \a type */ void Chart::setChartType(ChartType type) { Q_D(Chart); d->chartType = type; } /*! * \internal * */ void Chart::setChartStyle(int id) { Q_UNUSED(id) //!Todo } void Chart::setAxisTitle(Chart::ChartAxisPos pos, QString axisTitle) { Q_D(Chart); if ( axisTitle.isEmpty() ) return; // dev24 : fixed for old compiler if ( pos == Chart::Left ) { d->axisNames[ XlsxAxis::Left ] = axisTitle; } else if ( pos == Chart::Top ) { d->axisNames[ XlsxAxis::Top ] = axisTitle; } else if ( pos == Chart::Right ) { d->axisNames[ XlsxAxis::Right ] = axisTitle; } else if ( pos == Chart::Bottom ) { d->axisNames[ XlsxAxis::Bottom ] = axisTitle; } } // dev25 void Chart::setChartTitle(QString strchartTitle) { Q_D(Chart); d->chartTitle = strchartTitle; } void Chart::setChartLegend(Chart::ChartAxisPos legendPos, bool overlay) { Q_D(Chart); d->legendPos = legendPos; d->legendOverlay = overlay; } void Chart::setGridlinesEnable(bool majorGridlinesEnable, bool minorGridlinesEnable) { Q_D(Chart); d->majorGridlinesEnabled = majorGridlinesEnable; d->minorGridlinesEnabled = minorGridlinesEnable; } /*! * \internal */ void Chart::saveToXmlFile(QIODevice *device) const { Q_D(const Chart); /* <chartSpace> <chart> <view3D> <perspective val="30"/> </view3D> <plotArea> <layout/> <barChart> ... </barChart> <catAx/> <valAx/> </plotArea> <legend> ... </legend> </chart> <printSettings> </printSettings> </chartSpace> */ QXmlStreamWriter writer(device); writer.writeStartDocument(QStringLiteral("1.0"), true); // L.4.13.2.2 Chart // // chartSpace is the root node, which contains an element defining the chart, // and an element defining the print settings for the chart. writer.writeStartElement(QStringLiteral("c:chartSpace")); writer.writeAttribute(QStringLiteral("xmlns:c"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart")); writer.writeAttribute(QStringLiteral("xmlns:a"), QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main")); writer.writeAttribute(QStringLiteral("xmlns:r"), QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships")); /* * chart is the root element for the chart. If the chart is a 3D chart, * then a view3D element is contained, which specifies the 3D view. * It then has a plot area, which defines a layout and contains an element * that corresponds to, and defines, the type of chart. */ d->saveXmlChart(writer); writer.writeEndElement();// c:chartSpace writer.writeEndDocument(); } /*! * \internal */ bool Chart::loadFromXmlFile(QIODevice *device) { Q_D(Chart); QXmlStreamReader reader(device); while (!reader.atEnd()) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("chart")) { if (!d->loadXmlChart(reader)) { return false; } } } } return true; } bool ChartPrivate::loadXmlChart(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("chart")); // qDebug() << "-------------- loadXmlChart"; while (!reader.atEnd()) { reader.readNextStartElement(); // qDebug() << "-------------1- " << reader.name(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("plotArea")) { if (!loadXmlPlotArea(reader)) { return false; } } else if (reader.name() == QLatin1String("title")) { //!Todo if ( loadXmlChartTitle(reader) ) { } } // else if (reader.name() == QLatin1String("legend")) // { // loadXmlChartLegend(reader); // qDebug() << "-------------- loadXmlChartLegend"; // } } else if (reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("chart") ) { break; } } return true; } // TO DEBUG: loop is not work, when i looping second element. /* dchrt_CT_PlotArea = element layout { dchrt_CT_Layout }?, (element areaChart { dchrt_CT_AreaChart } | element area3DChart { dchrt_ CT_Area3DChart } | element lineChart { dchrt_CT_LineChart } | element line3DChart { dchrt_CT_Line3DChart } | element stockChart { dchrt_CT_StockChart } | element radarChart { dchrt_CT_RadarChart } | element scatterChart { dchrt_CT_ScatterChart } | element pieChart { dchrt_CT_PieChart } | element pie3DChart { dchrt_CT_Pie3DChart } | element doughnutChart { dchrt_CT_DoughnutChart } | element barChart { dchrt_CT_BarChart } | element bar3DChart { dchrt_CT_Bar3DChart } | element ofPieChart { dchrt_CT_OfPieChart } | element surfaceChart { dchrt_CT_SurfaceChart } | element surface3DChart { dchrt_CT_Surface3DChart } | element bubbleChart { dchrt_CT_BubbleChart })+, (element valAx { dchrt_CT_ValAx } | element catAx { dchrt_CT_CatAx } | element dateAx { dchrt_CT_DateAx } | element serAx { dchrt_CT_SerAx })*, element dTable { dchrt_CT_DTable }?, element spPr { a_CT_ShapeProperties }?, element extLst { dchrt_CT_ExtensionList }? */ bool ChartPrivate::loadXmlPlotArea(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("plotArea")); // TO DEBUG: reader.readNext(); while (!reader.atEnd()) { // qDebug() << "-------------2- " << reader.name(); if (reader.isStartElement()) { if (!loadXmlPlotAreaElement(reader)) { qDebug() << "[debug] failed to load plotarea element."; return false; } else if (reader.name() == QLatin1String("legend")) // Why here? { loadXmlChartLegend(reader); // qDebug() << "-------------- loadXmlChartLegend"; } reader.readNext(); } else { reader.readNext(); } } return true; } bool ChartPrivate::loadXmlPlotAreaElement(QXmlStreamReader &reader) { if (reader.name() == QLatin1String("layout")) { //!ToDo extract attributes layout = readSubTree(reader); } else if (reader.name().endsWith(QLatin1String("Chart"))) { // for pieChart, barChart, ... (choose one) if ( !loadXmlXxxChart(reader) ) { qDebug() << "[debug] failed to load chart"; return false; } } else if (reader.name() == QLatin1String("catAx")) // choose one : catAx, dateAx, serAx, valAx { // qDebug() << "loadXmlAxisCatAx()"; loadXmlAxisCatAx(reader); } else if (reader.name() == QLatin1String("dateAx")) // choose one : catAx, dateAx, serAx, valAx { // qDebug() << "loadXmlAxisDateAx()"; loadXmlAxisDateAx(reader); } else if (reader.name() == QLatin1String("serAx")) // choose one : catAx, dateAx, serAx, valAx { // qDebug() << "loadXmlAxisSerAx()"; loadXmlAxisSerAx(reader); } else if (reader.name() == QLatin1String("valAx")) // choose one : catAx, dateAx, serAx, valAx { // qDebug() << "loadXmlAxisValAx()"; loadXmlAxisValAx(reader); } else if (reader.name() == QLatin1String("dTable")) { //!ToDo // dTable "CT_DTable" // reader.skipCurrentElement(); } else if (reader.name() == QLatin1String("spPr")) { //!ToDo // spPr "a:CT_ShapeProperties" // reader.skipCurrentElement(); } else if (reader.name() == QLatin1String("extLst")) { //!ToDo // extLst "CT_ExtensionList" // reader.skipCurrentElement(); } return true; } bool ChartPrivate::loadXmlXxxChart(QXmlStreamReader &reader) { const auto& name = reader.name(); if (name == QLatin1String("areaChart")) { chartType = Chart::CT_AreaChart; } else if (name == QLatin1String("area3DChart")) { chartType = Chart::CT_Area3DChart; } else if (name == QLatin1String("lineChart")) { chartType = Chart::CT_LineChart; } else if (name == QLatin1String("line3DChart")) { chartType = Chart::CT_Line3DChart; } else if (name == QLatin1String("stockChart")) { chartType = Chart::CT_StockChart; } else if (name == QLatin1String("radarChart")) { chartType = Chart::CT_RadarChart; } else if (name == QLatin1String("scatterChart")) { chartType = Chart::CT_ScatterChart; } else if (name == QLatin1String("pieChart")) { chartType = Chart::CT_PieChart; } else if (name == QLatin1String("pie3DChart")) { chartType = Chart::CT_Pie3DChart; } else if (name == QLatin1String("doughnutChart")) { chartType = Chart::CT_DoughnutChart; } else if (name == QLatin1String("barChart")) { chartType = Chart::CT_BarChart; } else if (name == QLatin1String("bar3DChart")) { chartType = Chart::CT_Bar3DChart; } else if (name == QLatin1String("ofPieChart")) { chartType = Chart::CT_OfPieChart; } else if (name == QLatin1String("surfaceChart")) { chartType = Chart::CT_SurfaceChart; } else if (name == QLatin1String("surface3DChart")) { chartType = Chart::CT_Surface3DChart; } else if (name == QLatin1String("bubbleChart")) { chartType = Chart::CT_BubbleChart; } else { qDebug() << "[undefined chart type] " << name; chartType = Chart::CT_NoStatementChart; return false; } while( !reader.atEnd() ) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { // dev57 if ( reader.name() == QLatin1String("ser") ) { loadXmlSer(reader); } else if (reader.name() == QLatin1String("varyColors")) { } else if (reader.name() == QLatin1String("barDir")) { } else if (reader.name() == QLatin1String("axId")) { // } else if (reader.name() == QLatin1String("scatterStyle")) { } else if (reader.name() == QLatin1String("holeSize")) { } else { } } else if ( reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == name ) { break; } } return true; } bool ChartPrivate::loadXmlSer(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("ser")); auto series = std::make_shared<XlsxSeries>(); seriesList.append(series); while ( !reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("ser")) ) { if (reader.readNextStartElement()) { //TODO beide Header noch auswerten RTR 2019.11 const auto& name = reader.name(); if ( name == QLatin1String("tx") ) { while ( !reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == name)) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("strRef")) series->headerV_numRef = loadXmlStrRef(reader); } } } else if ( name == QLatin1String("cat") || name == QLatin1String("xVal") ) { while ( !reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == name)) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("numRef")) series->axDataSource_numRef = loadXmlNumRef(reader); else if (reader.name() == QLatin1String("strRef")) series->headerH_numRef = loadXmlStrRef(reader); } } } else if (name == QLatin1String("val") || name == QLatin1String("yVal")) { while ( !reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == name)) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("numRef")) series->numberDataSource_numRef = loadXmlNumRef(reader); } } } else if (name == QLatin1String("extLst")) { while ( !reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == name)) { reader.readNextStartElement(); } } } } return true; } QString ChartPrivate::loadXmlNumRef(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("numRef")); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("numRef"))) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("f")) return reader.readElementText(); } } return QString(); } QString ChartPrivate::loadXmlStrRef(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("strRef")); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("strRef"))) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("f")) return reader.readElementText(); } } return QString(); } void ChartPrivate::saveXmlChart(QXmlStreamWriter &writer) const { //---------------------------------------------------- // c:chart writer.writeStartElement(QStringLiteral("c:chart")); //---------------------------------------------------- // c:title saveXmlChartTitle(writer); // write 'chart title' //---------------------------------------------------- // c:plotArea writer.writeStartElement(QStringLiteral("c:plotArea")); // a little workaround for Start- and EndElement with starting ">" and ending without ">" writer.device()->write("><c:layout>"); //layout writer.device()->write(layout.toUtf8()); writer.device()->write("</c:layout"); //layout // dev35 switch (chartType) { case Chart::CT_AreaChart: saveXmlAreaChart(writer); break; case Chart::CT_Area3DChart: saveXmlAreaChart(writer); break; case Chart::CT_LineChart: saveXmlLineChart(writer); break; case Chart::CT_Line3DChart: saveXmlLineChart(writer); break; case Chart::CT_StockChart: break; case Chart::CT_RadarChart: break; case Chart::CT_ScatterChart: saveXmlScatterChart(writer); break; case Chart::CT_PieChart: saveXmlPieChart(writer); break; case Chart::CT_Pie3DChart: saveXmlPieChart(writer); break; case Chart::CT_DoughnutChart: saveXmlDoughnutChart(writer); break; case Chart::CT_BarChart: saveXmlBarChart(writer); break; case Chart::CT_Bar3DChart: saveXmlBarChart(writer); break; case Chart::CT_OfPieChart: break; case Chart::CT_SurfaceChart: break; case Chart::CT_Surface3DChart: break; case Chart::CT_BubbleChart: break; default: break; } saveXmlAxis(writer); // c:catAx, c:valAx, c:serAx, c:dateAx (choose one) //!TODO: write element // c:dTable CT_DTable // c:spPr CT_ShapeProperties // c:extLst CT_ExtensionList writer.writeEndElement(); // c:plotArea // c:legend saveXmlChartLegend(writer); // c:legend writer.writeEndElement(); // c:chart } bool ChartPrivate::loadXmlChartTitle(QXmlStreamReader &reader) { //!TODO : load chart title Q_ASSERT(reader.name() == QLatin1String("title")); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("title"))) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("tx")) // c:tx return loadXmlChartTitleTx(reader); } } return false; } bool ChartPrivate::loadXmlChartTitleTx(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("tx")); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("tx"))) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("rich")) // c:rich return loadXmlChartTitleTxRich(reader); } } return false; } bool ChartPrivate::loadXmlChartTitleTxRich(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("rich")); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("rich"))) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("p")) // a:p return loadXmlChartTitleTxRichP(reader); } } return false; } bool ChartPrivate::loadXmlChartTitleTxRichP(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("p")); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("p"))) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("r")) // a:r return loadXmlChartTitleTxRichP_R(reader); } } return false; } bool ChartPrivate::loadXmlChartTitleTxRichP_R(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("r")); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("r"))) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("t")) // a:t { QString textValue = reader.readElementText(); this->chartTitle = textValue; return true; } } } return false; } // write 'chart title' void ChartPrivate::saveXmlChartTitle(QXmlStreamWriter &writer) const { if ( chartTitle.isEmpty() ) return; writer.writeStartElement(QStringLiteral("c:title")); /* <xsd:complexType name="CT_Title"> <xsd:sequence> <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/> <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ writer.writeStartElement(QStringLiteral("c:tx")); /* <xsd:complexType name="CT_Tx"> <xsd:sequence> <xsd:choice minOccurs="1" maxOccurs="1"> <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/> <xsd:element name="rich" type="a:CT_TextBody" minOccurs="1" maxOccurs="1"/> </xsd:choice> </xsd:sequence> </xsd:complexType> */ writer.writeStartElement(QStringLiteral("c:rich")); /* <xsd:complexType name="CT_TextBody"> <xsd:sequence> <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs=" 1" maxOccurs="1"/> <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/> <xsd:element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> */ writer.writeEmptyElement(QStringLiteral("a:bodyPr")); // <a:bodyPr/> /* <xsd:complexType name="CT_TextBodyProperties"> <xsd:sequence> <xsd:element name="prstTxWarp" type="CT_PresetTextShape" minOccurs="0" maxOccurs="1"/> <xsd:group ref="EG_TextAutofit" minOccurs="0" maxOccurs="1"/> <xsd:element name="scene3d" type="CT_Scene3D" minOccurs="0" maxOccurs="1"/> <xsd:group ref="EG_Text3D" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> <xsd:attribute name="rot" type="ST_Angle" use="optional"/> <xsd:attribute name="spcFirstLastPara" type="xsd:boolean" use="optional"/> <xsd:attribute name="vertOverflow" type="ST_TextVertOverflowType" use="optional"/> <xsd:attribute name="horzOverflow" type="ST_TextHorzOverflowType" use="optional"/> <xsd:attribute name="vert" type="ST_TextVerticalType" use="optional"/> <xsd:attribute name="wrap" type="ST_TextWrappingType" use="optional"/> <xsd:attribute name="lIns" type="ST_Coordinate32" use="optional"/> <xsd:attribute name="tIns" type="ST_Coordinate32" use="optional"/> <xsd:attribute name="rIns" type="ST_Coordinate32" use="optional"/> <xsd:attribute name="bIns" type="ST_Coordinate32" use="optional"/> <xsd:attribute name="numCol" type="ST_TextColumnCount" use="optional"/> <xsd:attribute name="spcCol" type="ST_PositiveCoordinate32" use="optional"/> <xsd:attribute name="rtlCol" type="xsd:boolean" use="optional"/> <xsd:attribute name="fromWordArt" type="xsd:boolean" use="optional"/> <xsd:attribute name="anchor" type="ST_TextAnchoringType" use="optional"/> <xsd:attribute name="anchorCtr" type="xsd:boolean" use="optional"/> <xsd:attribute name="forceAA" type="xsd:boolean" use="optional"/> <xsd:attribute name="upright" type="xsd:boolean" use="optional" default="false"/> <xsd:attribute name="compatLnSpc" type="xsd:boolean" use="optional"/> </xsd:complexType> */ writer.writeEmptyElement(QStringLiteral("a:lstStyle")); // <a:lstStyle/> writer.writeStartElement(QStringLiteral("a:p")); /* <xsd:complexType name="CT_TextParagraph"> <xsd:sequence> <xsd:element name="pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> <xsd:group ref="EG_TextRun" minOccurs="0" maxOccurs="unbounded"/> <xsd:element name="endParaRPr" type="CT_TextCharacterProperties" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ // <a:pPr lvl="0"> writer.writeStartElement(QStringLiteral("a:pPr")); writer.writeAttribute(QStringLiteral("lvl"), QStringLiteral("0")); // <a:defRPr b="0"/> writer.writeStartElement(QStringLiteral("a:defRPr")); writer.writeAttribute(QStringLiteral("b"), QStringLiteral("0")); writer.writeEndElement(); // a:defRPr writer.writeEndElement(); // a:pPr /* <xsd:group name="EG_TextRun"> <xsd:choice> <xsd:element name="r" type="CT_RegularTextRun"/> <xsd:element name="br" type="CT_TextLineBreak"/> <xsd:element name="fld" type="CT_TextField"/> </xsd:choice> </xsd:group> */ writer.writeStartElement(QStringLiteral("a:r")); /* <xsd:complexType name="CT_RegularTextRun"> <xsd:sequence> <xsd:element name="rPr" type="CT_TextCharacterProperties" minOccurs="0" maxOccurs="1"/> <xsd:element name="t" type="xsd:string" minOccurs="1" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ // <a:t>chart name</a:t> writer.writeTextElement(QStringLiteral("a:t"), chartTitle); writer.writeEndElement(); // a:r writer.writeEndElement(); // a:p writer.writeEndElement(); // c:rich writer.writeEndElement(); // c:tx // <c:overlay val="0"/> writer.writeStartElement(QStringLiteral("c:overlay")); writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0")); writer.writeEndElement(); // c:overlay writer.writeEndElement(); // c:title } // }} // write 'chart legend' void ChartPrivate::saveXmlChartLegend(QXmlStreamWriter &writer) const { if ( legendPos == Chart::None ) return; // <c:legend> // <c:legendPos val="r"/> // <c:overlay val="0"/> // </c:legend> writer.writeStartElement(QStringLiteral("c:legend")); writer.writeStartElement(QStringLiteral("c:legendPos")); QString pos; switch( legendPos ) { //case Chart::ChartAxisPos::Right: case Chart::Right : pos = QStringLiteral("r"); break; // case Chart::ChartAxisPos::Left: case Chart::Left : pos = QStringLiteral("l"); break; // case Chart::ChartAxisPos::Top: case Chart::Top : pos = QStringLiteral("t"); break; // case Chart::ChartAxisPos::Bottom: case Chart::Bottom : pos = QStringLiteral("b"); break; default: pos = QStringLiteral("r"); break; } writer.writeAttribute(QStringLiteral("val"), pos); writer.writeEndElement(); // c:legendPos writer.writeStartElement(QStringLiteral("c:overlay")); if( legendOverlay ) { writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1")); } else { writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0")); } writer.writeEndElement(); // c:overlay writer.writeEndElement(); // c:legend } void ChartPrivate::saveXmlPieChart(QXmlStreamWriter &writer) const { QString name = chartType == Chart::CT_PieChart ? QStringLiteral("c:pieChart") : QStringLiteral("c:pie3DChart"); writer.writeStartElement(name); //Do the same behavior as Excel, Pie prefer varyColors writer.writeEmptyElement(QStringLiteral("c:varyColors")); writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1")); for (int i=0; i<seriesList.size(); ++i) saveXmlSer(writer, seriesList[i].get(), i); writer.writeEndElement(); //pieChart, pie3DChart } void ChartPrivate::saveXmlBarChart(QXmlStreamWriter &writer) const { QString name = chartType == Chart::CT_BarChart ? QStringLiteral("c:barChart") : QStringLiteral("c:bar3DChart"); writer.writeStartElement(name); writer.writeEmptyElement(QStringLiteral("c:barDir")); writer.writeAttribute(QStringLiteral("val"), QStringLiteral("col")); for ( int i = 0 ; i < seriesList.size() ; ++i ) { saveXmlSer(writer, seriesList[i].get(), i); } if ( axisList.isEmpty() ) { const_cast<ChartPrivate*>(this)->axisList.append( std::make_shared<XlsxAxis>( XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1, axisNames[XlsxAxis::Bottom] )); const_cast<ChartPrivate*>(this)->axisList.append( std::make_shared<XlsxAxis>( XlsxAxis::T_Val, XlsxAxis::Left, 1, 0, axisNames[XlsxAxis::Left] )); } // Note: Bar3D have 2~3 axes // int axisListSize = axisList.size(); // [dev62] // Q_ASSERT( axisListSize == 2 || // ( axisListSize == 3 && chartType == Chart::CT_Bar3DChart ) ); for ( int i = 0 ; i < axisList.size() ; ++i ) { writer.writeEmptyElement(QStringLiteral("c:axId")); writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId)); } writer.writeEndElement(); //barChart, bar3DChart } void ChartPrivate::saveXmlLineChart(QXmlStreamWriter &writer) const { QString name = chartType==Chart::CT_LineChart ? QStringLiteral("c:lineChart") : QStringLiteral("c:line3DChart"); writer.writeStartElement(name); // writer.writeEmptyElement(QStringLiteral("grouping")); // dev22 for (int i=0; i<seriesList.size(); ++i) saveXmlSer(writer, seriesList[i].get(), i); if (axisList.isEmpty()) { const_cast<ChartPrivate*>(this)->axisList.append(std::make_shared<XlsxAxis>(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1, axisNames[XlsxAxis::Bottom] )); const_cast<ChartPrivate*>(this)->axisList.append(std::make_shared<XlsxAxis>(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0, axisNames[XlsxAxis::Left] )); if (chartType==Chart::CT_Line3DChart) const_cast<ChartPrivate*>(this)->axisList.append(std::make_shared<XlsxAxis>(XlsxAxis::T_Ser, XlsxAxis::Bottom, 2, 0)); } Q_ASSERT((axisList.size()==2||chartType==Chart::CT_LineChart)|| (axisList.size()==3 && chartType==Chart::CT_Line3DChart)); for (int i=0; i<axisList.size(); ++i) { writer.writeEmptyElement(QStringLiteral("c:axId")); writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId)); } writer.writeEndElement(); //lineChart, line3DChart } void ChartPrivate::saveXmlScatterChart(QXmlStreamWriter &writer) const { const QString name = QStringLiteral("c:scatterChart"); writer.writeStartElement(name); writer.writeEmptyElement(QStringLiteral("c:scatterStyle")); for (int i=0; i<seriesList.size(); ++i) saveXmlSer(writer, seriesList[i].get(), i); if (axisList.isEmpty()) { const_cast<ChartPrivate*>(this)->axisList.append( std::make_shared<XlsxAxis>(XlsxAxis::T_Val, XlsxAxis::Bottom, 0, 1, axisNames[XlsxAxis::Bottom] )); const_cast<ChartPrivate*>(this)->axisList.append( std::make_shared<XlsxAxis>(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0, axisNames[XlsxAxis::Left] )); } int axisListSize = axisList.size(); Q_ASSERT(axisListSize == 2); for (int i=0; i<axisList.size(); ++i) { writer.writeEmptyElement(QStringLiteral("c:axId")); writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId)); } writer.writeEndElement(); //c:scatterChart } void ChartPrivate::saveXmlAreaChart(QXmlStreamWriter &writer) const { QString name = chartType==Chart::CT_AreaChart ? QStringLiteral("c:areaChart") : QStringLiteral("c:area3DChart"); writer.writeStartElement(name); // writer.writeEmptyElement(QStringLiteral("grouping")); // dev22 for (int i=0; i<seriesList.size(); ++i) saveXmlSer(writer, seriesList[i].get(), i); if (axisList.isEmpty()) { const_cast<ChartPrivate*>(this)->axisList.append(std::make_shared<XlsxAxis>(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1)); const_cast<ChartPrivate*>(this)->axisList.append(std::make_shared<XlsxAxis>(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)); } //Note: Area3D have 2~3 axes Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Area3DChart)); for (int i=0; i<axisList.size(); ++i) { writer.writeEmptyElement(QStringLiteral("c:axId")); writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId)); } writer.writeEndElement(); //lineChart, line3DChart } void ChartPrivate::saveXmlDoughnutChart(QXmlStreamWriter &writer) const { QString name = QStringLiteral("c:doughnutChart"); writer.writeStartElement(name); writer.writeEmptyElement(QStringLiteral("c:varyColors")); writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1")); for (int i=0; i<seriesList.size(); ++i) saveXmlSer(writer, seriesList[i].get(), i); writer.writeStartElement(QStringLiteral("c:holeSize")); writer.writeAttribute(QStringLiteral("val"), QString::number(50)); writer.writeEndElement(); } void ChartPrivate::saveXmlSer(QXmlStreamWriter &writer, XlsxSeries *ser, int id) const { writer.writeStartElement(QStringLiteral("c:ser")); writer.writeEmptyElement(QStringLiteral("c:idx")); writer.writeAttribute(QStringLiteral("val"), QString::number(id)); writer.writeEmptyElement(QStringLiteral("c:order")); writer.writeAttribute(QStringLiteral("val"), QString::number(id)); QString header1; QString header2; if( ser->swapHeader ) { header1 = ser->headerH_numRef; header2 = ser->headerV_numRef; } else { header1 = ser->headerV_numRef; header2 = ser->headerH_numRef; } if( !header1.isEmpty() ) { writer.writeStartElement(QStringLiteral("c:tx")); writer.writeStartElement(QStringLiteral("c:strRef")); writer.writeTextElement(QStringLiteral("c:f"), header1); writer.writeEndElement(); writer.writeEndElement(); } if( !header2.isEmpty() ) { writer.writeStartElement(QStringLiteral("c:cat")); writer.writeStartElement(QStringLiteral("c:strRef")); writer.writeTextElement(QStringLiteral("c:f"), header2); writer.writeEndElement(); writer.writeEndElement(); } #if 0 if (!ser->axDataSource_numRef.isEmpty()) { if (chartType == Chart::CT_ScatterChart || chartType == Chart::CT_BubbleChart) { writer.writeStartElement(QStringLiteral("c:xVal")); } else { writer.writeStartElement(QStringLiteral("c:cat")); } writer.writeStartElement(QStringLiteral("c:numRef")); writer.writeTextElement(QStringLiteral("c:f"), ser->axDataSource_numRef); writer.writeEndElement();//c:numRef writer.writeEndElement();//c:cat or c:xVal } #endif if (!ser->numberDataSource_numRef.isEmpty()) { if (chartType == Chart::CT_ScatterChart || chartType == Chart::CT_BubbleChart) writer.writeStartElement(QStringLiteral("c:yVal")); else writer.writeStartElement(QStringLiteral("c:val")); writer.writeStartElement(QStringLiteral("c:numRef")); writer.writeTextElement(QStringLiteral("c:f"), ser->numberDataSource_numRef); writer.writeEndElement();//c:numRef writer.writeEndElement();//c:val or c:yVal } writer.writeEndElement();//c:ser } bool ChartPrivate::loadXmlAxisCatAx(QXmlStreamReader &reader) { auto axis = std::make_shared<XlsxAxis>(); axis->type = XlsxAxis::T_Cat; axisList.append(axis); // load EG_AxShared if ( ! loadXmlAxisEG_AxShared( reader, axis.get() ) ) { qDebug() << "failed to load EG_AxShared"; return false; } //!TODO: load element // auto // lblAlgn // lblOffset // tickLblSkip // tickMarkSkip // noMultiLvlLbl // extLst return true; } bool ChartPrivate::loadXmlAxisDateAx(QXmlStreamReader &reader) { auto axis = std::make_shared<XlsxAxis>(); axis->type = XlsxAxis::T_Date; axisList.append(axis); // load EG_AxShared if ( ! loadXmlAxisEG_AxShared( reader, axis.get() ) ) { qDebug() << "failed to load EG_AxShared"; return false; } //!TODO: load element // auto // lblOffset // baseTimeUnit // majorUnit // majorTimeUnit // minorUnit // minorTimeUnit // extLst return true; } bool ChartPrivate::loadXmlAxisSerAx(QXmlStreamReader &reader) { auto axis = std::make_shared<XlsxAxis>(); axis->type = XlsxAxis::T_Ser; axisList.append(axis); // load EG_AxShared if ( ! loadXmlAxisEG_AxShared( reader, axis.get() ) ) { qDebug() << "failed to load EG_AxShared"; return false; } //!TODO: load element // tickLblSkip // tickMarkSkip // extLst return true; } bool ChartPrivate::loadXmlAxisValAx(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("valAx")); auto axis = std::make_shared<XlsxAxis>(); axis->type = XlsxAxis::T_Val; axisList.append(axis); if ( ! loadXmlAxisEG_AxShared( reader, axis.get() ) ) { qDebug() << "failed to load EG_AxShared"; return false; } //!TODO: load element // crossBetween // majorUnit // minorUnit // dispUnits // extLst return true; } /* <xsd:group name="EG_AxShared"> <xsd:sequence> <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*)(M) <xsd:element name="scaling" type="CT_Scaling" minOccurs="1" maxOccurs="1"/> (*)(M) <xsd:element name="delete" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="axPos" type="CT_AxPos" minOccurs="1" maxOccurs="1"/> (*)(M) <xsd:element name="majorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> <xsd:element name="minorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> <xsd:element name="title" type="CT_Title" minOccurs="0" maxOccurs="1"/> (*) <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="1"/> <xsd:element name="majorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/> <xsd:element name="minorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/> <xsd:element name="tickLblPos" type="CT_TickLblPos" minOccurs="0" maxOccurs="1"/> <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> <xsd:element name="crossAx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*)(M) <xsd:choice minOccurs="0" maxOccurs="1"> <xsd:element name="crosses" type="CT_Crosses" minOccurs="1" maxOccurs="1"/> <xsd:element name="crossesAt" type="CT_Double" minOccurs="1" maxOccurs="1"/> </xsd:choice> </xsd:sequence> </xsd:group> */ bool ChartPrivate::loadXmlAxisEG_AxShared(QXmlStreamReader &reader, XlsxAxis* axis) { Q_ASSERT( NULL != axis ); Q_ASSERT( reader.name().endsWith(QLatin1String("Ax")) ); QString name = reader.name().toString(); // while ( !reader.atEnd() ) { reader.readNextStartElement(); if ( reader.tokenType() == QXmlStreamReader::StartElement ) { // qDebug() << "[debug]" << QTime::currentTime() << reader.name().toString(); if ( reader.name() == QLatin1String("axId") ) // mandatory element { // dev57 uint axId = reader.attributes().value(QStringLiteral("val")).toUInt(); // for Qt5.1 axis->axisId = axId; } else if ( reader.name() == QLatin1String("scaling") ) { // mandatory element loadXmlAxisEG_AxShared_Scaling(reader, axis); } else if ( reader.name() == QLatin1String("delete") ) { //!TODO } else if ( reader.name() == QLatin1String("axPos") ) { // mandatory element QString axPosVal = reader.attributes().value(QLatin1String("val")).toString(); if ( axPosVal == QLatin1String("l") ) { axis->axisPos = XlsxAxis::Left; } else if ( axPosVal == QLatin1String("r") ) { axis->axisPos = XlsxAxis::Right; } else if ( axPosVal == QLatin1String("t") ) { axis->axisPos = XlsxAxis::Top; } else if ( axPosVal == QLatin1String("b") ) { axis->axisPos = XlsxAxis::Bottom; } } else if ( reader.name() == QLatin1String("majorGridlines") ) { //!TODO anything else? majorGridlinesEnabled = true; } else if ( reader.name() == QLatin1String("minorGridlines") ) { //!TODO anything else? minorGridlinesEnabled = true; } else if ( reader.name() == QLatin1String("title") ) { // title if ( !loadXmlAxisEG_AxShared_Title(reader, axis) ) { qDebug() << "failed to load EG_AxShared title."; Q_ASSERT(false); return false; } } else if ( reader.name() == QLatin1String("numFmt") ) { //!TODO } else if ( reader.name() == QLatin1String("majorTickMark") ) { //!TODO } else if ( reader.name() == QLatin1String("minorTickMark") ) { //!TODO } else if ( reader.name() == QLatin1String("tickLblPos") ) { //!TODO } else if ( reader.name() == QLatin1String("spPr") ) { //!TODO } else if ( reader.name() == QLatin1String("txPr") ) { //!TODO } else if ( reader.name() == QLatin1String("crossAx") ) // mandatory element { // dev57 uint crossAx = reader.attributes().value(QLatin1String("val")).toUInt(); // for Qt5.1 axis->crossAx = crossAx; } else if ( reader.name() == QLatin1String("crosses") ) { //!TODO } else if ( reader.name() == QLatin1String("crossesAt") ) { //!TODO } // reader.readNext(); } else if ( reader.tokenType() == QXmlStreamReader::EndElement && reader.name().toString() == name ) { break; } } return true; } bool ChartPrivate::loadXmlAxisEG_AxShared_Scaling(QXmlStreamReader &reader, XlsxAxis* axis) { Q_UNUSED(axis); Q_ASSERT(reader.name() == QLatin1String("scaling")); while ( !reader.atEnd() ) { reader.readNextStartElement(); if ( reader.tokenType() == QXmlStreamReader::StartElement ) { if ( reader.name() == QLatin1String("orientation") ) { } else { } } else if ( reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("scaling") ) { break; } } return true; } /* <xsd:complexType name="CT_Title"> <xsd:sequence> <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/> <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="CT_Tx"> <xsd:sequence> <xsd:choice minOccurs="1" maxOccurs="1"> <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/> <xsd:element name="rich" type="a:CT_TextBody" minOccurs="1" maxOccurs="1"/> </xsd:choice> </xsd:sequence> </xsd:complexType> <xsd:complexType name="CT_StrRef"> <xsd:sequence> <xsd:element name="f" type="xsd:string" minOccurs="1" maxOccurs="1"/> <xsd:element name="strCache" type="CT_StrData" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="CT_TextBody"> <xsd:sequence> <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/> <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/> <xsd:element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> */ bool ChartPrivate::loadXmlAxisEG_AxShared_Title(QXmlStreamReader &reader, XlsxAxis* axis) { Q_ASSERT(reader.name() == QLatin1String("title")); while ( !reader.atEnd() ) { reader.readNextStartElement(); if ( reader.tokenType() == QXmlStreamReader::StartElement ) { if ( reader.name() == QLatin1String("tx") ) { loadXmlAxisEG_AxShared_Title_Tx(reader, axis); } else if ( reader.name() == QLatin1String("overlay") ) { //!TODO: load overlay loadXmlAxisEG_AxShared_Title_Overlay(reader, axis); } else { } } else if ( reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("title") ) { break; } } return true; } bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Overlay(QXmlStreamReader &reader, XlsxAxis* axis) { Q_UNUSED(axis); Q_ASSERT(reader.name() == QLatin1String("overlay")); while ( !reader.atEnd() ) { reader.readNextStartElement(); if ( reader.tokenType() == QXmlStreamReader::StartElement ) { } else if ( reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("overlay") ) { break; } } return true; } bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx(QXmlStreamReader &reader, XlsxAxis* axis) { Q_ASSERT(reader.name() == QLatin1String("tx")); while ( !reader.atEnd() ) { reader.readNextStartElement(); if ( reader.tokenType() == QXmlStreamReader::StartElement ) { if ( reader.name() == QLatin1String("rich") ) { loadXmlAxisEG_AxShared_Title_Tx_Rich(reader, axis); } else { } } else if ( reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("tx") ) { break; } } return true; } bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich(QXmlStreamReader &reader, XlsxAxis* axis) { Q_ASSERT(reader.name() == QLatin1String("rich")); while ( !reader.atEnd() ) { reader.readNextStartElement(); if ( reader.tokenType() == QXmlStreamReader::StartElement ) { if ( reader.name() == QLatin1String("p") ) { loadXmlAxisEG_AxShared_Title_Tx_Rich_P(reader, axis); } else { } } else if ( reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("rich") ) { break; } } return true; } bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich_P(QXmlStreamReader &reader, XlsxAxis* axis) { Q_ASSERT(reader.name() == QLatin1String("p")); while ( !reader.atEnd() ) { reader.readNextStartElement(); if ( reader.tokenType() == QXmlStreamReader::StartElement ) { if ( reader.name() == QLatin1String("r") ) { loadXmlAxisEG_AxShared_Title_Tx_Rich_P_R(reader, axis); } else if ( reader.name() == QLatin1String("pPr") ) { loadXmlAxisEG_AxShared_Title_Tx_Rich_P_pPr(reader, axis); } else { } } else if ( reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("p") ) { break; } } return true; } bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich_P_pPr(QXmlStreamReader &reader, XlsxAxis* axis) { Q_UNUSED(axis); Q_ASSERT(reader.name() == QLatin1String("pPr")); while ( !reader.atEnd() ) { reader.readNextStartElement(); if ( reader.tokenType() == QXmlStreamReader::StartElement ) { if ( reader.name() == QLatin1String("defRPr") ) { reader.readElementText(); } else { } } else if ( reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("pPr") ) { break; } } return true; } bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich_P_R(QXmlStreamReader &reader, XlsxAxis* axis) { Q_ASSERT(reader.name() == QLatin1String("r")); while ( !reader.atEnd() ) { reader.readNextStartElement(); if ( reader.tokenType() == QXmlStreamReader::StartElement ) { if ( reader.name() == QLatin1String("t") ) { QString strAxisName = reader.readElementText(); XlsxAxis::AxisPos axisPos = axis->axisPos; axis->axisNames[ axisPos ] = strAxisName; } else { } } else if ( reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("r") ) { break; } } return true; } /* <xsd:complexType name="CT_PlotArea"> <xsd:sequence> <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> <xsd:choice minOccurs="1" maxOccurs="unbounded"> <xsd:element name="areaChart" type="CT_AreaChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="area3DChart" type="CT_Area3DChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="lineChart" type="CT_LineChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="line3DChart" type="CT_Line3DChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="stockChart" type="CT_StockChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="radarChart" type="CT_RadarChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="scatterChart" type="CT_ScatterChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="pieChart" type="CT_PieChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="pie3DChart" type="CT_Pie3DChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="doughnutChart" type="CT_DoughnutChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="barChart" type="CT_BarChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="bar3DChart" type="CT_Bar3DChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="ofPieChart" type="CT_OfPieChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="surfaceChart" type="CT_SurfaceChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="surface3DChart" type="CT_Surface3DChart" minOccurs="1" maxOccurs="1"/> <xsd:element name="bubbleChart" type="CT_BubbleChart" minOccurs="1" maxOccurs="1"/> </xsd:choice> <xsd:choice minOccurs="0" maxOccurs="unbounded"> <xsd:element name="valAx" type="CT_ValAx" minOccurs="1" maxOccurs="1"/> <xsd:element name="catAx" type="CT_CatAx" minOccurs="1" maxOccurs="1"/> <xsd:element name="dateAx" type="CT_DateAx" minOccurs="1" maxOccurs="1"/> <xsd:element name="serAx" type="CT_SerAx" minOccurs="1" maxOccurs="1"/> </xsd:choice> <xsd:element name="dTable" type="CT_DTable" minOccurs="0" maxOccurs="1"/> <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ /* <xsd:complexType name="CT_CatAx"> <xsd:sequence> <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="lblAlgn" type="CT_LblAlgn" minOccurs="0" maxOccurs="1"/> <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/> <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> <xsd:element name="noMultiLvlLbl" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> <!-----------------------------------------------------------------------------> <xsd:complexType name="CT_DateAx"> <xsd:sequence> <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/> <xsd:element name="baseTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="majorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="minorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> <!-----------------------------------------------------------------------------> <xsd:complexType name="CT_SerAx"> <xsd:sequence> <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> <!-----------------------------------------------------------------------------> <xsd:complexType name="CT_ValAx"> <xsd:sequence> <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> <xsd:element name="crossBetween" type="CT_CrossBetween" minOccurs="0" maxOccurs="1"/> <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="dispUnits" type="CT_DispUnits" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ void ChartPrivate::saveXmlAxis(QXmlStreamWriter &writer) const { for ( int i = 0 ; i < axisList.size() ; ++i ) { XlsxAxis* axis = axisList[i].get(); if ( nullptr == axis ) continue; if ( axis->type == XlsxAxis::T_Cat ) { saveXmlAxisCatAx( writer, axis ); } if ( axis->type == XlsxAxis::T_Val ) { saveXmlAxisValAx( writer, axis ); } if ( axis->type == XlsxAxis::T_Ser ) { saveXmlAxisSerAx( writer, axis ); } if ( axis->type == XlsxAxis::T_Date ) { saveXmlAxisDateAx( writer, axis ); } } } void ChartPrivate::saveXmlAxisCatAx(QXmlStreamWriter &writer, XlsxAxis* axis) const { /* <xsd:complexType name="CT_CatAx"> <xsd:sequence> <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="lblAlgn" type="CT_LblAlgn" minOccurs="0" maxOccurs="1"/> <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/> <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> <xsd:element name="noMultiLvlLbl" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ writer.writeStartElement(QStringLiteral("c:catAx")); saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared //!TODO: write element // auto // lblAlgn // lblOffset // tickLblSkip // tickMarkSkip // noMultiLvlLbl // extLst writer.writeEndElement(); // c:catAx } void ChartPrivate::saveXmlAxisDateAx(QXmlStreamWriter &writer, XlsxAxis* axis) const { /* <xsd:complexType name="CT_DateAx"> <xsd:sequence> <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/> <xsd:element name="baseTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="majorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="minorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ writer.writeStartElement(QStringLiteral("c:dateAx")); saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared //!TODO: write element // auto // lblOffset // baseTimeUnit // majorUnit // majorTimeUnit // minorUnit // minorTimeUnit // extLst writer.writeEndElement(); // c:dateAx } void ChartPrivate::saveXmlAxisSerAx(QXmlStreamWriter &writer, XlsxAxis* axis) const { /* <xsd:complexType name="CT_SerAx"> <xsd:sequence> <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ writer.writeStartElement(QStringLiteral("c:serAx")); saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared //!TODO: write element // tickLblSkip // tickMarkSkip // extLst writer.writeEndElement(); // c:serAx } void ChartPrivate::saveXmlAxisValAx(QXmlStreamWriter &writer, XlsxAxis* axis) const { /* <xsd:complexType name="CT_ValAx"> <xsd:sequence> <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> <xsd:element name="crossBetween" type="CT_CrossBetween" minOccurs="0" maxOccurs="1"/> <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> <xsd:element name="dispUnits" type="CT_DispUnits" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ writer.writeStartElement(QStringLiteral("c:valAx")); saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared //!TODO: write element // crossBetween // majorUnit // minorUnit // dispUnits // extLst writer.writeEndElement(); // c:valAx } void ChartPrivate::saveXmlAxisEG_AxShared(QXmlStreamWriter &writer, XlsxAxis* axis) const { /* <xsd:group name="EG_AxShared"> <xsd:sequence> <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*) <xsd:element name="scaling" type="CT_Scaling" minOccurs="1" maxOccurs="1"/> (*) <xsd:element name="delete" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="axPos" type="CT_AxPos" minOccurs="1" maxOccurs="1"/> (*) <xsd:element name="majorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> <xsd:element name="minorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> <xsd:element name="title" type="CT_Title" minOccurs="0" maxOccurs="1"/> (***********************) <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="1"/> <xsd:element name="majorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/> <xsd:element name="minorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/> <xsd:element name="tickLblPos" type="CT_TickLblPos" minOccurs="0" maxOccurs="1"/> <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> <xsd:element name="crossAx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*) <xsd:choice minOccurs="0" maxOccurs="1"> <xsd:element name="crosses" type="CT_Crosses" minOccurs="1" maxOccurs="1"/> <xsd:element name="crossesAt" type="CT_Double" minOccurs="1" maxOccurs="1"/> </xsd:choice> </xsd:sequence> </xsd:group> */ writer.writeEmptyElement(QStringLiteral("c:axId")); // 21.2.2.9. axId (Axis ID) (mandatory value) writer.writeAttribute(QStringLiteral("val"), QString::number(axis->axisId)); writer.writeStartElement(QStringLiteral("c:scaling")); // CT_Scaling (mandatory value) writer.writeEmptyElement(QStringLiteral("c:orientation")); // CT_Orientation writer.writeAttribute(QStringLiteral("val"), QStringLiteral("minMax")); // ST_Orientation writer.writeEndElement(); // c:scaling writer.writeEmptyElement(QStringLiteral("c:axPos")); // axPos CT_AxPos (mandatory value) QString pos = GetAxisPosString( axis->axisPos ); if ( !pos.isEmpty() ) { writer.writeAttribute(QStringLiteral("val"), pos); // ST_AxPos } if( majorGridlinesEnabled ) { writer.writeEmptyElement(QStringLiteral("c:majorGridlines")); } if( minorGridlinesEnabled ) { writer.writeEmptyElement(QStringLiteral("c:minorGridlines")); } saveXmlAxisEG_AxShared_Title(writer, axis); // "c:title" CT_Title writer.writeEmptyElement(QStringLiteral("c:crossAx")); // crossAx (mandatory value) writer.writeAttribute(QStringLiteral("val"), QString::number(axis->crossAx)); } void ChartPrivate::saveXmlAxisEG_AxShared_Title(QXmlStreamWriter &writer, XlsxAxis* axis) const { // CT_Title /* <xsd:complexType name="CT_Title"> <xsd:sequence> <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/> <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ /* <xsd:complexType name="CT_Tx"> <xsd:sequence> <xsd:choice minOccurs="1" maxOccurs="1"> <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/> <xsd:element name="rich" type="a:CT_TextBody" minOccurs="1" maxOccurs="1"/> </xsd:choice> </xsd:sequence> </xsd:complexType> */ /* <xsd:complexType name="CT_StrRef"> <xsd:sequence> <xsd:element name="f" type="xsd:string" minOccurs="1" maxOccurs="1"/> <xsd:element name="strCache" type="CT_StrData" minOccurs="0" maxOccurs="1"/> <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> */ /* <xsd:complexType name="CT_TextBody"> <xsd:sequence> <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/> <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/> <xsd:element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> */ writer.writeStartElement(QStringLiteral("c:title")); // CT_Tx {{ writer.writeStartElement(QStringLiteral("c:tx")); writer.writeStartElement(QStringLiteral("c:rich")); // CT_TextBody writer.writeEmptyElement(QStringLiteral("a:bodyPr")); // CT_TextBodyProperties writer.writeEmptyElement(QStringLiteral("a:lstStyle")); // CT_TextListStyle writer.writeStartElement(QStringLiteral("a:p")); writer.writeStartElement(QStringLiteral("a:pPr")); writer.writeAttribute(QStringLiteral("lvl"), QString::number(0)); writer.writeStartElement(QStringLiteral("a:defRPr")); writer.writeAttribute(QStringLiteral("b"), QString::number(0)); writer.writeEndElement(); // a:defRPr writer.writeEndElement(); // a:pPr writer.writeStartElement(QStringLiteral("a:r")); QString strAxisName = GetAxisName(axis); writer.writeTextElement( QStringLiteral("a:t"), strAxisName ); writer.writeEndElement(); // a:r writer.writeEndElement(); // a:p writer.writeEndElement(); // c:rich writer.writeEndElement(); // c:tx // CT_Tx }} writer.writeStartElement(QStringLiteral("c:overlay")); writer.writeAttribute(QStringLiteral("val"), QString::number(0)); // CT_Boolean writer.writeEndElement(); // c:overlay writer.writeEndElement(); // c:title } QString ChartPrivate::GetAxisPosString( XlsxAxis::AxisPos axisPos ) const { QString pos; switch ( axisPos ) { case XlsxAxis::Top : pos = QStringLiteral("t"); break; case XlsxAxis::Bottom : pos = QStringLiteral("b"); break; case XlsxAxis::Left : pos = QStringLiteral("l"); break; case XlsxAxis::Right : pos = QStringLiteral("r"); break; default: break; // ?? } return pos; } QString ChartPrivate::GetAxisName(XlsxAxis* axis) const { QString strAxisName; if ( NULL == axis ) return strAxisName; QString pos = GetAxisPosString( axis->axisPos ); // l, t, r, b if ( pos.isEmpty() ) return strAxisName; strAxisName = axis->axisNames[ axis->axisPos ]; return strAxisName; } /// /// \brief ChartPrivate::readSubTree /// \param reader /// \return /// QString ChartPrivate::readSubTree(QXmlStreamReader &reader) { QString treeString; QString prefix; const auto& treeName = reader.name(); while (!reader.atEnd()) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { prefix = reader.prefix().toString(); treeString += QLatin1String("<") + reader.qualifiedName().toString(); const QXmlStreamAttributes attributes = reader.attributes(); for (const QXmlStreamAttribute &attr : attributes) { treeString += QLatin1String(" ") + attr.name().toString() + QLatin1String("=\"") + attr.value().toString() + QLatin1String("\""); } treeString += QStringLiteral(">"); } else if (reader.tokenType() == QXmlStreamReader::EndElement ) { if( reader.name() == treeName) { break; } treeString += QLatin1String("</") + reader.qualifiedName().toString() + QLatin1String(">"); } } return treeString; } /// /// \brief ChartPrivate::loadXmlChartLegend /// \param reader /// \return /// bool ChartPrivate::loadXmlChartLegend(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("legend")); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("legend"))) { if (reader.readNextStartElement()) { if (reader.name() == QLatin1String("legendPos")) // c:legendPos { QString pos = reader.attributes().value(QLatin1String("val")).toString(); if( pos.compare(QLatin1String("r"), Qt::CaseInsensitive) == 0) { // legendPos = Chart::ChartAxisPos::Right; legendPos = Chart::Right; } else if( pos.compare(QLatin1String("l"), Qt::CaseInsensitive) == 0) { // legendPos = Chart::ChartAxisPos::Left; legendPos = Chart::Left; } else if( pos.compare(QLatin1String("t"), Qt::CaseInsensitive) == 0) { // legendPos = Chart::ChartAxisPos::Top; legendPos = Chart::Top; } else if( pos.compare(QLatin1String("b"), Qt::CaseInsensitive) == 0) { // legendPos = Chart::ChartAxisPos::Bottom; legendPos = Chart::Bottom; } else { // legendPos = Chart::ChartAxisPos::None; legendPos = Chart::None; } } else if (reader.name() == QLatin1String("overlay")) // c:legendPos { QString pos = reader.attributes().value(QLatin1String("val")).toString(); if( pos.compare(QLatin1String("1"), Qt::CaseInsensitive) == 0 ) { legendOverlay = true; } else { legendOverlay = false; } } } } return false; } QT_END_NAMESPACE_XLSX