diff --git a/QXlsx/header/xlsxchart.h b/QXlsx/header/xlsxchart.h index 686ef2f..3656861 100644 --- a/QXlsx/header/xlsxchart.h +++ b/QXlsx/header/xlsxchart.h @@ -40,6 +40,8 @@ class Worksheet; class ChartPrivate; class CellRange; class DrawingAnchor; +// class XlsxAxis; +// enum XlsxAxisPos : short; class Chart : public AbstractOOXmlFile { @@ -65,11 +67,20 @@ public: CT_Bubble }; + enum ChartAxisPos + { + Left, + Right, + Top, + Bottom + }; + ~Chart(); void addSeries(const CellRange &range, AbstractSheet *sheet=0); void setChartType(ChartType type); void setChartStyle(int id); + void setAxisTitle(Chart::ChartAxisPos pos, QString axisTitle); void saveToXmlFile(QIODevice *device) const; bool loadFromXmlFile(QIODevice *device); diff --git a/QXlsx/header/xlsxchart_p.h b/QXlsx/header/xlsxchart_p.h index 4fcd0fb..df57fdb 100644 --- a/QXlsx/header/xlsxchart_p.h +++ b/QXlsx/header/xlsxchart_p.h @@ -40,7 +40,13 @@ #include "xlsxabstractooxmlfile_p.h" #include "xlsxchart.h" +#include +#include +#include #include +#include +#include +#include class QXmlStreamReader; class QXmlStreamWriter; @@ -51,8 +57,8 @@ class XlsxSeries { public: //At present, we care about number cell ranges only! - QString numberDataSource_numRef; //yval, val - QString axDataSource_numRef; //xval, cat + QString numberDataSource_numRef; // yval, val + QString axDataSource_numRef; // xval, cat }; class XlsxAxis @@ -66,8 +72,9 @@ public: T_Ser }; - enum Pos + enum AxisPos { + None = -1, Left, Right, Top, @@ -76,15 +83,23 @@ public: XlsxAxis(){} - XlsxAxis(Type t, Pos p, int id, int crossId) + XlsxAxis(Type t, XlsxAxis::AxisPos p, int id, int crossId, QString axisTitle = QString("")) :type(t), axisPos(p), axisId(id), crossAx(crossId) { + if ( !axisTitle.isEmpty() ) + { + axisNames[ p ] = axisTitle; + } } Type type; - Pos axisPos; //l,r,b,t + XlsxAxis::AxisPos axisPos; // l(left),r(right),b(bottom),t(top) int axisId; int crossAx; + + // dev22 {{ + QMap< XlsxAxis::AxisPos, QString > axisNames; + // }} }; class ChartPrivate : public AbstractOOXmlFilePrivate @@ -114,8 +129,10 @@ public: Chart::ChartType chartType; - QList > seriesList; - QList > axisList; + QList< QSharedPointer > seriesList; + QList< QSharedPointer > axisList; + + QMap< XlsxAxis::AxisPos, QString > axisNames; // dev22 AbstractSheet *sheet; }; diff --git a/QXlsx/source/xlsxchart.cpp b/QXlsx/source/xlsxchart.cpp index 6fc0c1b..1e48851 100644 --- a/QXlsx/source/xlsxchart.cpp +++ b/QXlsx/source/xlsxchart.cpp @@ -11,11 +11,12 @@ #include #include #include +#include QT_BEGIN_NAMESPACE_XLSX ChartPrivate::ChartPrivate(Chart *q, Chart::CreateFlag flag) - :AbstractOOXmlFilePrivate(q, flag), chartType(static_cast(0)) + : AbstractOOXmlFilePrivate(q, flag), chartType(static_cast(0)) { } @@ -57,7 +58,7 @@ ChartPrivate::~ChartPrivate() * \internal */ Chart::Chart(AbstractSheet *parent, CreateFlag flag) - :AbstractOOXmlFile(new ChartPrivate(this, flag)) + : AbstractOOXmlFile(new ChartPrivate(this, flag)) { d_func()->sheet = parent; } @@ -86,21 +87,26 @@ void Chart::addSeries(const CellRange &range, AbstractSheet *sheet) //In case sheetName contains space or ' sheetName = escapeSheetName(sheetName); - if (range.columnCount() == 1 || range.rowCount() == 1) { + 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()) { + } + 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) { + 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); } - for (int col=firstDataColumn; col<=range.lastColumn(); ++col) { + 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; @@ -108,17 +114,21 @@ void Chart::addSeries(const CellRange &range, AbstractSheet *sheet) d->seriesList.append(series); } - } else { + } + else + { //Row based series int firstDataRow = range.firstRow(); QString axDataSouruce_numRef; - if (d->chartType == CT_Scatter || d->chartType == CT_Bubble) { + 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); } - for (int row=firstDataRow; row<=range.lastRow(); ++row) { + 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; @@ -147,6 +157,25 @@ void Chart::setChartStyle(int id) //!Todo } +void Chart::setAxisTitle(Chart::ChartAxisPos pos, QString axisTitle) +{ + Q_D(Chart); + + if ( axisTitle.isEmpty() ) + return; + + if ( pos == Chart::ChartAxisPos::Left ) d->axisNames[ XlsxAxis::AxisPos::Left ] = axisTitle; + else if ( pos == Chart::ChartAxisPos::Top ) d->axisNames[ XlsxAxis::AxisPos::Top ] = axisTitle; + else if ( pos == Chart::ChartAxisPos::Right ) d->axisNames[ XlsxAxis::AxisPos::Right ] = axisTitle; + else if ( pos == Chart::ChartAxisPos::Bottom ) d->axisNames[ XlsxAxis::AxisPos::Bottom ] = axisTitle; + else + { + // ?? + } + +} + + /*! * \internal */ @@ -192,17 +221,24 @@ bool ChartPrivate::loadXmlChart(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("chart")); - while (!reader.atEnd()) { + while (!reader.atEnd()) + { reader.readNextStartElement(); - if (reader.tokenType() == QXmlStreamReader::StartElement) { - if (reader.name() == QLatin1String("plotArea")) { + if (reader.tokenType() == QXmlStreamReader::StartElement) + { + if (reader.name() == QLatin1String("plotArea")) + { if (!loadXmlPlotArea(reader)) return false; - } else if (reader.name() == QLatin1String("legend")) { + } + else if (reader.name() == QLatin1String("legend")) + { //!Todo } - } else if (reader.tokenType() == QXmlStreamReader::EndElement && - reader.name() == QLatin1String("chart")) { + } + else if (reader.tokenType() == QXmlStreamReader::EndElement && + reader.name() == QLatin1String("chart") ) + { break; } } @@ -323,8 +359,11 @@ QString ChartPrivate::loadXmlNumRef(QXmlStreamReader &reader) void ChartPrivate::saveXmlChart(QXmlStreamWriter &writer) const { writer.writeStartElement(QStringLiteral("c:chart")); + writer.writeStartElement(QStringLiteral("c:plotArea")); - switch (chartType) { + + switch (chartType) + { case Chart::CT_Pie: case Chart::CT_Pie3D: saveXmlPieChart(writer); @@ -350,12 +389,12 @@ void ChartPrivate::saveXmlChart(QXmlStreamWriter &writer) const default: break; } + saveXmlAxes(writer); - writer.writeEndElement(); //plotArea -// saveXmlLegend(writer); + writer.writeEndElement(); // c:plotArea - writer.writeEndElement(); //chart + writer.writeEndElement(); // c:chart } void ChartPrivate::saveXmlPieChart(QXmlStreamWriter &writer) const @@ -376,26 +415,30 @@ void ChartPrivate::saveXmlPieChart(QXmlStreamWriter &writer) const void ChartPrivate::saveXmlBarChart(QXmlStreamWriter &writer) const { - QString name = chartType==Chart::CT_Bar ? QStringLiteral("c:barChart") : QStringLiteral("c:bar3DChart"); + QString name = chartType == Chart::CT_Bar ? 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(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1))); - const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0))); + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::AxisPos::Bottom, 0, 1, axisNames[XlsxAxis::AxisPos::Bottom] ))); + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::AxisPos::Left, 1, 0, axisNames[XlsxAxis::AxisPos::Left] ))); } //Note: Bar3D have 2~3 axes Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Bar3D)); - for (int i=0; iaxisId)); } @@ -414,11 +457,12 @@ void ChartPrivate::saveXmlLineChart(QXmlStreamWriter &writer) const for (int i=0; i(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1))); - const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0))); + if (axisList.isEmpty()) + { + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::AxisPos::Bottom, 0, 1, axisNames[XlsxAxis::AxisPos::Bottom] ))); + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::AxisPos::Left, 1, 0, axisNames[XlsxAxis::AxisPos::Left] ))); if (chartType==Chart::CT_Line3D) - const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Ser, XlsxAxis::Bottom, 2, 0))); + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Ser, XlsxAxis::AxisPos::Bottom, 2, 0))); } Q_ASSERT((axisList.size()==2||chartType==Chart::CT_Line)|| (axisList.size()==3 && chartType==Chart::CT_Line3D)); @@ -442,14 +486,16 @@ void ChartPrivate::saveXmlScatterChart(QXmlStreamWriter &writer) const for (int i=0; i(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Bottom, 0, 1))); - const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0))); + if (axisList.isEmpty()) + { + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::AxisPos::Bottom, 0, 1, axisNames[XlsxAxis::AxisPos::Bottom] ))); + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::AxisPos::Left, 1, 0, axisNames[XlsxAxis::AxisPos::Left] ))); } Q_ASSERT(axisList.size()==2); - for (int i=0; iaxisId)); } @@ -468,15 +514,17 @@ void ChartPrivate::saveXmlAreaChart(QXmlStreamWriter &writer) const for (int i=0; i(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1))); - const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0))); + if (axisList.isEmpty()) + { + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::AxisPos::Bottom, 0, 1))); + const_cast(this)->axisList.append(QSharedPointer(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::AxisPos::Left, 1, 0))); } //Note: Area3D have 2~3 axes Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Area3D)); - for (int i=0; iaxisId)); } @@ -542,37 +590,57 @@ bool ChartPrivate::loadXmlAxis(QXmlStreamReader &reader) XlsxAxis *axis = new XlsxAxis; if (name == QLatin1String("valAx")) + { axis->type = XlsxAxis::T_Val; + } else if (name == QLatin1String("catAx")) + { axis->type = XlsxAxis::T_Cat; + } else if (name == QLatin1String("serAx")) + { axis->type = XlsxAxis::T_Ser; + } else + { axis->type = XlsxAxis::T_Date; + } axisList.append(QSharedPointer(axis)); - while (!reader.atEnd()) { + // TODO: load axis title : name == QLatin1String("valAx") + while ( !reader.atEnd() ) + { reader.readNextStartElement(); - if (reader.tokenType() == QXmlStreamReader::StartElement) { - if (reader.name() == QLatin1String("axPos")) { + if ( reader.tokenType() == QXmlStreamReader::StartElement ) + { + if ( reader.name() == QLatin1String("axPos") ) + { QXmlStreamAttributes attrs = reader.attributes(); QStringRef pos = attrs.value(QLatin1String("val")); - if (pos==QLatin1String("l")) - axis->axisPos = XlsxAxis::Left; - else if (pos==QLatin1String("r")) - axis->axisPos = XlsxAxis::Right; - else if (pos==QLatin1String("b")) - axis->axisPos = XlsxAxis::Bottom; + if ( pos == QLatin1String("l") ) + axis->axisPos = XlsxAxis::AxisPos::Left; + else if ( pos == QLatin1String("r") ) + axis->axisPos = XlsxAxis::AxisPos::Right; + else if ( pos == QLatin1String("b") ) + axis->axisPos = XlsxAxis::AxisPos::Bottom; + else if ( pos == QLatin1String("t") ) + axis->axisPos = XlsxAxis::AxisPos::Top; else - axis->axisPos = XlsxAxis::Top; - } else if (reader.name() == QLatin1String("axId")) { + axis->axisPos = XlsxAxis::AxisPos::None; + } + else if ( reader.name() == QLatin1String("axId") ) + { axis->axisId = reader.attributes().value(QLatin1String("val")).toString().toInt(); - } else if (reader.name() == QLatin1String("crossAx")) { + } + else if ( reader.name() == QLatin1String("crossAx") ) + { axis->crossAx = reader.attributes().value(QLatin1String("val")).toString().toInt(); } - } else if (reader.tokenType() == QXmlStreamReader::EndElement - && reader.name() == name) { + } + else if ( reader.tokenType() == QXmlStreamReader::EndElement + && reader.name() == name ) + { break; } } @@ -582,27 +650,80 @@ bool ChartPrivate::loadXmlAxis(QXmlStreamReader &reader) void ChartPrivate::saveXmlAxes(QXmlStreamWriter &writer) const { - for (int i=0; itype) { - case XlsxAxis::T_Cat: name = QStringLiteral("c:catAx"); break; - case XlsxAxis::T_Val: name = QStringLiteral("c:valAx"); break; - case XlsxAxis::T_Ser: name = QStringLiteral("c:serAx"); break; - case XlsxAxis::T_Date: name = QStringLiteral("c:dateAx"); break; - default: break; + switch (axis->type) + { + case XlsxAxis::T_Cat: name = QStringLiteral("c:catAx"); break; + case XlsxAxis::T_Val: name = QStringLiteral("c:valAx"); break; + case XlsxAxis::T_Ser: name = QStringLiteral("c:serAx"); break; + case XlsxAxis::T_Date: name = QStringLiteral("c:dateAx"); break; + default: break; } QString pos; - switch (axis->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; + switch (axis->axisPos) + { + case XlsxAxis::AxisPos::Top: pos = QStringLiteral("t"); break; + case XlsxAxis::AxisPos::Bottom: pos = QStringLiteral("b"); break; + case XlsxAxis::AxisPos::Left: pos = QStringLiteral("l"); break; + case XlsxAxis::AxisPos::Right: pos = QStringLiteral("r"); break; + default: break; // ?? } writer.writeStartElement(name); + + // dev22 {{ + + QString strAxisName; + strAxisName.clear(); + if ( pos == "t" || + pos == "b" || + pos == "l" || + pos == "r" ) + { + strAxisName = axis->axisNames[ axis->axisPos ]; + } + + if ( name == "c:valAx" && + false == strAxisName.isEmpty() ) + { + writer.writeStartElement("c:title"); + writer.writeStartElement("c:tx"); + + writer.writeStartElement("c:rich"); + writer.writeEmptyElement(QStringLiteral("a:bodyPr")); + writer.writeEmptyElement(QStringLiteral("a:lstStyle")); + + writer.writeStartElement("a:p"); + + writer.writeStartElement("a:pPr"); + writer.writeAttribute(QStringLiteral("lvl"), QString::number(0)); + writer.writeStartElement("a:defRPr"); + writer.writeAttribute(QStringLiteral("b"), QString::number(0)); + writer.writeEndElement(); // a:defRPr + writer.writeEndElement(); // a:pPr + + writer.writeStartElement("a:r"); + writer.writeTextElement(QStringLiteral("a:t"), strAxisName ); + writer.writeEndElement(); // a:r + + writer.writeEndElement(); // a:p + + writer.writeEndElement(); // c:rich + writer.writeEndElement(); // c:tx + + writer.writeStartElement("c:overlay"); + writer.writeAttribute(QStringLiteral("val"), QString::number(0)); + writer.writeEndElement(); // c:overlay + + writer.writeEndElement(); // c:title + } + // }} dev22 + writer.writeEmptyElement(QStringLiteral("c:axId")); writer.writeAttribute(QStringLiteral("val"), QString::number(axis->axisId)); diff --git a/chartsquestions/sat_calc.cpp b/chartsquestions/sat_calc.cpp index 10d5f95..1af703f 100644 --- a/chartsquestions/sat_calc.cpp +++ b/chartsquestions/sat_calc.cpp @@ -143,9 +143,13 @@ void sat_calc::generate_report() } chrom_data_array += ":B" + QString::number(output_line_count - 1); + Chart * Crom = output.insertChart( 3, 5, QSize(600, 500) ); Crom->setChartType( Chart::CT_Scatter ); Crom->addSeries( CellRange(chrom_data_array) ); + Crom->setAxisTitle( Chart::ChartAxisPos::Left, QString("left title") ); // dev22 + Crom->setAxisTitle( Chart::ChartAxisPos::Bottom, QString("bottom title") ); // dev22 + qDebug() << "[debug] chrom_data_array : " << chrom_data_array; output.saveAs(report_file);