From 9e33ff2c79ab0393a0dcbb794bf83db19fae5cb4 Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Thu, 30 Oct 2014 14:50:01 +0800 Subject: [PATCH] Fix Issue #59 :Multiply rows and columns can be passed to Chart::addSeries() now --- examples/xlsx/chart/main.cpp | 41 +++++++---- src/xlsx/xlsxchart.cpp | 132 ++++++++++++++++++++++++++++------- src/xlsx/xlsxchart_p.h | 7 +- 3 files changed, 139 insertions(+), 41 deletions(-) diff --git a/examples/xlsx/chart/main.cpp b/examples/xlsx/chart/main.cpp index bae6ee0..b105d28 100644 --- a/examples/xlsx/chart/main.cpp +++ b/examples/xlsx/chart/main.cpp @@ -9,50 +9,63 @@ int main() { //![0] Document xlsx; - for (int i=1; i<10; ++i) - xlsx.write(i, 1, i*i); + for (int i=1; i<10; ++i) { + xlsx.write(i, 1, i*i*i); //A1:A9 + xlsx.write(i, 2, i*i); //B1:B9 + xlsx.write(i, 3, i*i-1); //C1:C9 + } //![0] //![1] Chart *pieChart = xlsx.insertChart(3, 3, QSize(300, 300)); pieChart->setChartType(Chart::CT_Pie); pieChart->addSeries(CellRange("A1:A9")); + pieChart->addSeries(CellRange("B1:B9")); + pieChart->addSeries(CellRange("C1:C9")); - Chart *pie3DChart = xlsx.insertChart(3, 7, QSize(300, 300)); + Chart *pie3DChart = xlsx.insertChart(3, 9, QSize(300, 300)); pie3DChart->setChartType(Chart::CT_Pie3D); - pie3DChart->addSeries(CellRange("A1:A9")); + pie3DChart->addSeries(CellRange("A1:C9")); Chart *barChart = xlsx.insertChart(23, 3, QSize(300, 300)); barChart->setChartType(Chart::CT_Bar); - barChart->addSeries(CellRange("A1:A9")); + barChart->addSeries(CellRange("A1:C9")); - Chart *bar3DChart = xlsx.insertChart(23, 7, QSize(300, 300)); + Chart *bar3DChart = xlsx.insertChart(23, 9, QSize(300, 300)); bar3DChart->setChartType(Chart::CT_Bar3D); - bar3DChart->addSeries(CellRange("A1:A9")); + bar3DChart->addSeries(CellRange("A1:C9")); Chart *lineChart = xlsx.insertChart(43, 3, QSize(300, 300)); lineChart->setChartType(Chart::CT_Line); - lineChart->addSeries(CellRange("A1:A9")); + lineChart->addSeries(CellRange("A1:C9")); - Chart *line3DChart = xlsx.insertChart(43, 7, QSize(300, 300)); + Chart *line3DChart = xlsx.insertChart(43, 9, QSize(300, 300)); line3DChart->setChartType(Chart::CT_Line3D); - line3DChart->addSeries(CellRange("A1:A9")); + line3DChart->addSeries(CellRange("A1:C9")); Chart *areaChart = xlsx.insertChart(63, 3, QSize(300, 300)); areaChart->setChartType(Chart::CT_Area); - areaChart->addSeries(CellRange("A1:A9")); + areaChart->addSeries(CellRange("A1:C9")); - Chart *area3DChart = xlsx.insertChart(63, 7, QSize(300, 300)); + Chart *area3DChart = xlsx.insertChart(63, 9, QSize(300, 300)); area3DChart->setChartType(Chart::CT_Area3D); - area3DChart->addSeries(CellRange("A1:A9")); + area3DChart->addSeries(CellRange("A1:C9")); Chart *scatterChart = xlsx.insertChart(83, 3, QSize(300, 300)); scatterChart->setChartType(Chart::CT_Scatter); + //Will generate three lines. scatterChart->addSeries(CellRange("A1:A9")); + scatterChart->addSeries(CellRange("B1:B9")); + scatterChart->addSeries(CellRange("C1:C9")); + + Chart *scatterChart_2 = xlsx.insertChart(83, 9, QSize(300, 300)); + scatterChart_2->setChartType(Chart::CT_Scatter); + //Will generate two lines. + scatterChart_2->addSeries(CellRange("A1:C9")); Chart *doughnutChart = xlsx.insertChart(103, 3, QSize(300, 300)); doughnutChart->setChartType(Chart::CT_Doughnut); - doughnutChart->addSeries(CellRange("A1:A9")); + doughnutChart->addSeries(CellRange("A1:C9")); //![1] //![2] diff --git a/src/xlsx/xlsxchart.cpp b/src/xlsx/xlsxchart.cpp index c618f37..f801572 100644 --- a/src/xlsx/xlsxchart.cpp +++ b/src/xlsx/xlsxchart.cpp @@ -96,20 +96,55 @@ Chart::~Chart() void Chart::addSeries(const CellRange &range, AbstractSheet *sheet) { 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 serRef = sheet ? sheet->sheetName() : d->sheet->sheetName(); + QString sheetName = sheet ? sheet->sheetName() : d->sheet->sheetName(); + + if (range.columnCount() == 1 || range.rowCount() == 1) { + QSharedPointer series = QSharedPointer(new XlsxSeries); + series->numberDataSource_numRef = sheetName + QLatin1String("!") + range.toString(true, true); + d->seriesList.append(series); + } else if (range.columnCount() < range.rowCount()) { + //Column based series + int firstDataColumn = range.firstColumn(); + QString axDataSouruce_numRef; + if (d->chartType == CT_Scatter || d->chartType == CT_Bubble) { + firstDataColumn += 1; + CellRange subRange(range.firstRow(), range.firstColumn(), range.lastRow(), range.firstColumn()); + axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); + } - serRef += QLatin1String("!"); - serRef += range.toString(true, true); + for (int col=firstDataColumn; col<=range.lastColumn(); ++col) { + CellRange subRange(range.firstRow(), col, range.lastRow(), col); + QSharedPointer series = QSharedPointer(new XlsxSeries); + series->axDataSource_numRef = axDataSouruce_numRef; + series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); + d->seriesList.append(series); + } - XlsxSeries *series = new XlsxSeries; - series->numRef = serRef; + } else { + //Row based series + int firstDataRow = range.firstRow(); + QString axDataSouruce_numRef; + if (d->chartType == CT_Scatter || d->chartType == CT_Bubble) { + firstDataRow += 1; + CellRange subRange(range.firstRow(), range.firstColumn(), range.firstRow(), range.lastColumn()); + axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); + } - d->seriesList.append(QSharedPointer(series)); + for (int row=firstDataRow; row<=range.lastRow(); ++row) { + CellRange subRange(row, range.firstColumn(), row, range.lastColumn()); + QSharedPointer series = QSharedPointer(new XlsxSeries); + series->axDataSource_numRef = axDataSouruce_numRef; + series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); + d->seriesList.append(series); + } + } } /*! @@ -253,23 +288,57 @@ bool ChartPrivate::loadXmlSer(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("ser")); - while (!reader.atEnd()) { - reader.readNextStartElement(); - if (reader.tokenType() == QXmlStreamReader::StartElement) { - if (reader.name() == QLatin1String("f")) { - XlsxSeries *series = new XlsxSeries; - series->numRef = reader.readElementText(); - seriesList.append(QSharedPointer(series)); + QSharedPointer series = QSharedPointer(new XlsxSeries); + seriesList.append(series); + + while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == QLatin1String("ser"))) { + if (reader.readNextStartElement()) { + QStringRef name = reader.name(); + 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 (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(); + } } - } else if (reader.tokenType() == QXmlStreamReader::EndElement - && reader.name() == QLatin1String("ser")) { - break; } } 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(); +} + void ChartPrivate::saveXmlChart(QXmlStreamWriter &writer) const { writer.writeStartElement(QStringLiteral("c:chart")); @@ -459,14 +528,29 @@ void ChartPrivate::saveXmlSer(QXmlStreamWriter &writer, XlsxSeries *ser, int id) writer.writeAttribute(QStringLiteral("val"), QString::number(id)); writer.writeEmptyElement(QStringLiteral("c:order")); writer.writeAttribute(QStringLiteral("val"), QString::number(id)); - if (chartType == Chart::CT_Scatter) - writer.writeStartElement(QStringLiteral("c:yVal")); - else - writer.writeStartElement(QStringLiteral("c:val")); - writer.writeStartElement(QStringLiteral("c:numRef")); - writer.writeTextElement(QStringLiteral("c:f"), ser->numRef); - writer.writeEndElement();//c:numRef - writer.writeEndElement();//c:val + + if (!ser->axDataSource_numRef.isEmpty()) { + if (chartType == Chart::CT_Scatter || chartType == Chart::CT_Bubble) + 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 + } + + if (!ser->numberDataSource_numRef.isEmpty()) { + if (chartType == Chart::CT_Scatter || chartType == Chart::CT_Bubble) + 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 } diff --git a/src/xlsx/xlsxchart_p.h b/src/xlsx/xlsxchart_p.h index c87c182..4fcd0fb 100644 --- a/src/xlsx/xlsxchart_p.h +++ b/src/xlsx/xlsxchart_p.h @@ -50,9 +50,9 @@ namespace QXlsx { class XlsxSeries { public: - - QString numRef;// For scatterChart, means y values - QString numRef_x; + //At present, we care about number cell ranges only! + QString numberDataSource_numRef; //yval, val + QString axDataSource_numRef; //xval, cat }; class XlsxAxis @@ -99,6 +99,7 @@ public: bool loadXmlPlotArea(QXmlStreamReader &reader); bool loadXmlXxxChart(QXmlStreamReader &reader); bool loadXmlSer(QXmlStreamReader &reader); + QString loadXmlNumRef(QXmlStreamReader &reader); bool loadXmlAxis(QXmlStreamReader &reader); void saveXmlChart(QXmlStreamWriter &writer) const;