File indexing completed on 2025-03-16 03:35:10
0001 // xlsxchart.cpp 0002 0003 #include <QtGlobal> 0004 #include <QString> 0005 #include <QIODevice> 0006 #include <QXmlStreamReader> 0007 #include <QXmlStreamWriter> 0008 #include <QDebug> 0009 0010 #include "xlsxchart_p.h" 0011 #include "xlsxworksheet.h" 0012 #include "xlsxcellrange.h" 0013 #include "xlsxutility_p.h" 0014 0015 QT_BEGIN_NAMESPACE_XLSX 0016 0017 ChartPrivate::ChartPrivate(Chart *q, Chart::CreateFlag flag) 0018 : AbstractOOXmlFilePrivate(q, flag), chartType(static_cast<Chart::ChartType>(0)) 0019 { 0020 0021 } 0022 0023 ChartPrivate::~ChartPrivate() 0024 { 0025 } 0026 0027 0028 0029 /*! 0030 * \internal 0031 */ 0032 Chart::Chart(AbstractSheet *parent, CreateFlag flag) 0033 : AbstractOOXmlFile(new ChartPrivate(this, flag)) 0034 { 0035 Q_D(Chart); 0036 0037 d_func()->sheet = parent; 0038 0039 // d->legendPos = Chart::ChartAxisPos::None; 0040 d->legendPos = Chart::None; 0041 d->legendOverlay = false; 0042 d->majorGridlinesEnabled = false; 0043 d->minorGridlinesEnabled = false; 0044 } 0045 0046 /*! 0047 * Destroys the chart. 0048 */ 0049 Chart::~Chart() 0050 { 0051 } 0052 0053 /*! 0054 * Add the data series which is in the range \a range of the \a sheet. 0055 */ 0056 void Chart::addSeries(const CellRange &range, AbstractSheet *sheet, bool headerH, bool headerV, bool swapHeaders) 0057 { 0058 Q_D(Chart); 0059 0060 if (!range.isValid()) 0061 return; 0062 if (sheet && sheet->sheetType() != AbstractSheet::ST_WorkSheet) 0063 return; 0064 if (!sheet && d->sheet->sheetType() != AbstractSheet::ST_WorkSheet) 0065 return; 0066 0067 QString sheetName = sheet ? sheet->sheetName() : d->sheet->sheetName(); 0068 //In case sheetName contains space or ' 0069 sheetName = escapeSheetName(sheetName); 0070 0071 if (range.columnCount() == 1 || range.rowCount() == 1) 0072 { 0073 auto series = std::make_shared<XlsxSeries>(); 0074 series->numberDataSource_numRef = sheetName + QLatin1String("!") + range.toString(true, true); 0075 d->seriesList.append(series); 0076 } 0077 else if ((range.columnCount() < range.rowCount()) || swapHeaders ) 0078 { 0079 //Column based series 0080 int firstDataRow = range.firstRow(); 0081 int firstDataColumn = range.firstColumn(); 0082 0083 QString axDataSouruce_numRef; 0084 if (d->chartType == CT_ScatterChart || d->chartType == CT_BubbleChart) 0085 { 0086 firstDataColumn += 1; 0087 CellRange subRange(range.firstRow(), range.firstColumn(), range.lastRow(), range.firstColumn()); 0088 axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); 0089 } 0090 0091 if( headerH ) 0092 { 0093 firstDataRow += 1; 0094 } 0095 if( headerV ) 0096 { 0097 firstDataColumn += 1; 0098 } 0099 0100 for (int col=firstDataColumn; col<=range.lastColumn(); ++col) 0101 { 0102 CellRange subRange(firstDataRow, col, range.lastRow(), col); 0103 auto series = std::make_shared<XlsxSeries>(); 0104 series->axDataSource_numRef = axDataSouruce_numRef; 0105 series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); 0106 0107 if( headerH ) 0108 { 0109 CellRange subRange(range.firstRow(), col, range.firstRow(), col); 0110 series->headerH_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); 0111 } 0112 else 0113 { 0114 series->headerH_numRef = QString(); 0115 } 0116 if( headerV ) 0117 { 0118 CellRange subRange(firstDataRow, range.firstColumn(), range.lastRow(), range.firstColumn()); 0119 series->headerV_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); 0120 } 0121 else 0122 { 0123 series->headerV_numRef = QString(); 0124 } 0125 series->swapHeader = swapHeaders; 0126 0127 d->seriesList.append(series); 0128 } 0129 0130 } 0131 else 0132 { 0133 //Row based series 0134 int firstDataRow = range.firstRow(); 0135 int firstDataColumn = range.firstColumn(); 0136 0137 QString axDataSouruce_numRef; 0138 if (d->chartType == CT_ScatterChart || d->chartType == CT_BubbleChart) 0139 { 0140 firstDataRow += 1; 0141 CellRange subRange(range.firstRow(), range.firstColumn(), range.firstRow(), range.lastColumn()); 0142 axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); 0143 } 0144 0145 if( headerH ) 0146 { 0147 firstDataRow += 1; 0148 } 0149 if( headerV ) 0150 { 0151 firstDataColumn += 1; 0152 } 0153 0154 for (int row=firstDataRow; row<=range.lastRow(); ++row) 0155 { 0156 CellRange subRange(row, firstDataColumn, row, range.lastColumn()); 0157 auto series = std::make_shared<XlsxSeries>(); 0158 series->axDataSource_numRef = axDataSouruce_numRef; 0159 series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); 0160 0161 if( headerH ) 0162 { 0163 CellRange subRange(range.firstRow(), firstDataColumn, range.firstRow(), range.lastColumn()); 0164 series->headerH_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); 0165 } 0166 else 0167 { 0168 series->headerH_numRef = QString(); 0169 } 0170 0171 if( headerV ) 0172 { 0173 CellRange subRange(row, range.firstColumn(), row, range.firstColumn()); 0174 series->headerV_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true); 0175 } 0176 else 0177 { 0178 series->headerV_numRef = QString(); 0179 } 0180 series->swapHeader = swapHeaders; 0181 0182 d->seriesList.append(series); 0183 } 0184 } 0185 } 0186 0187 /*! 0188 * Set the type of the chart to \a type 0189 */ 0190 void Chart::setChartType(ChartType type) 0191 { 0192 Q_D(Chart); 0193 0194 d->chartType = type; 0195 } 0196 0197 /*! 0198 * \internal 0199 * 0200 */ 0201 void Chart::setChartStyle(int id) 0202 { 0203 Q_UNUSED(id) 0204 //!Todo 0205 } 0206 0207 void Chart::setAxisTitle(Chart::ChartAxisPos pos, QString axisTitle) 0208 { 0209 Q_D(Chart); 0210 0211 if ( axisTitle.isEmpty() ) 0212 return; 0213 0214 // dev24 : fixed for old compiler 0215 if ( pos == Chart::Left ) 0216 { 0217 d->axisNames[ XlsxAxis::Left ] = axisTitle; 0218 } 0219 else if ( pos == Chart::Top ) 0220 { 0221 d->axisNames[ XlsxAxis::Top ] = axisTitle; 0222 } 0223 else if ( pos == Chart::Right ) 0224 { 0225 d->axisNames[ XlsxAxis::Right ] = axisTitle; 0226 } 0227 else if ( pos == Chart::Bottom ) 0228 { 0229 d->axisNames[ XlsxAxis::Bottom ] = axisTitle; 0230 } 0231 0232 } 0233 0234 // dev25 0235 void Chart::setChartTitle(QString strchartTitle) 0236 { 0237 Q_D(Chart); 0238 0239 d->chartTitle = strchartTitle; 0240 } 0241 0242 0243 void Chart::setChartLegend(Chart::ChartAxisPos legendPos, bool overlay) 0244 { 0245 Q_D(Chart); 0246 0247 d->legendPos = legendPos; 0248 d->legendOverlay = overlay; 0249 } 0250 0251 0252 void Chart::setGridlinesEnable(bool majorGridlinesEnable, bool minorGridlinesEnable) 0253 { 0254 Q_D(Chart); 0255 0256 d->majorGridlinesEnabled = majorGridlinesEnable; 0257 d->minorGridlinesEnabled = minorGridlinesEnable; 0258 } 0259 0260 0261 /*! 0262 * \internal 0263 */ 0264 void Chart::saveToXmlFile(QIODevice *device) const 0265 { 0266 Q_D(const Chart); 0267 0268 /* 0269 <chartSpace> 0270 <chart> 0271 <view3D> 0272 <perspective val="30"/> 0273 </view3D> 0274 <plotArea> 0275 <layout/> 0276 <barChart> 0277 ... 0278 </barChart> 0279 <catAx/> 0280 <valAx/> 0281 </plotArea> 0282 <legend> 0283 ... 0284 </legend> 0285 </chart> 0286 <printSettings> 0287 </printSettings> 0288 </chartSpace> 0289 */ 0290 0291 QXmlStreamWriter writer(device); 0292 0293 writer.writeStartDocument(QStringLiteral("1.0"), true); 0294 0295 // L.4.13.2.2 Chart 0296 // 0297 // chartSpace is the root node, which contains an element defining the chart, 0298 // and an element defining the print settings for the chart. 0299 0300 writer.writeStartElement(QStringLiteral("c:chartSpace")); 0301 0302 writer.writeAttribute(QStringLiteral("xmlns:c"), 0303 QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart")); 0304 writer.writeAttribute(QStringLiteral("xmlns:a"), 0305 QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main")); 0306 writer.writeAttribute(QStringLiteral("xmlns:r"), 0307 QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships")); 0308 0309 /* 0310 * chart is the root element for the chart. If the chart is a 3D chart, 0311 * then a view3D element is contained, which specifies the 3D view. 0312 * It then has a plot area, which defines a layout and contains an element 0313 * that corresponds to, and defines, the type of chart. 0314 */ 0315 0316 d->saveXmlChart(writer); 0317 0318 writer.writeEndElement();// c:chartSpace 0319 writer.writeEndDocument(); 0320 } 0321 0322 /*! 0323 * \internal 0324 */ 0325 bool Chart::loadFromXmlFile(QIODevice *device) 0326 { 0327 Q_D(Chart); 0328 0329 QXmlStreamReader reader(device); 0330 while (!reader.atEnd()) 0331 { 0332 reader.readNextStartElement(); 0333 if (reader.tokenType() == QXmlStreamReader::StartElement) 0334 { 0335 if (reader.name() == QLatin1String("chart")) 0336 { 0337 if (!d->loadXmlChart(reader)) 0338 { 0339 return false; 0340 } 0341 } 0342 } 0343 } 0344 0345 return true; 0346 } 0347 0348 0349 bool ChartPrivate::loadXmlChart(QXmlStreamReader &reader) 0350 { 0351 Q_ASSERT(reader.name() == QLatin1String("chart")); 0352 0353 // qDebug() << "-------------- loadXmlChart"; 0354 0355 while (!reader.atEnd()) 0356 { 0357 reader.readNextStartElement(); 0358 0359 // qDebug() << "-------------1- " << reader.name(); 0360 0361 if (reader.tokenType() == QXmlStreamReader::StartElement) 0362 { 0363 0364 if (reader.name() == QLatin1String("plotArea")) 0365 { 0366 if (!loadXmlPlotArea(reader)) 0367 { 0368 return false; 0369 } 0370 } 0371 else if (reader.name() == QLatin1String("title")) 0372 { 0373 //!Todo 0374 0375 if ( loadXmlChartTitle(reader) ) 0376 { 0377 } 0378 0379 } 0380 // else if (reader.name() == QLatin1String("legend")) 0381 // { 0382 // loadXmlChartLegend(reader); 0383 // qDebug() << "-------------- loadXmlChartLegend"; 0384 // } 0385 } 0386 else if (reader.tokenType() == QXmlStreamReader::EndElement && 0387 reader.name() == QLatin1String("chart") ) 0388 { 0389 break; 0390 } 0391 } 0392 return true; 0393 } 0394 0395 // TO DEBUG: loop is not work, when i looping second element. 0396 /* 0397 dchrt_CT_PlotArea = 0398 element layout { dchrt_CT_Layout }?, 0399 (element areaChart { dchrt_CT_AreaChart } 0400 | element area3DChart { dchrt_ CT_Area3DChart } 0401 | element lineChart { dchrt_CT_LineChart } 0402 | element line3DChart { dchrt_CT_Line3DChart } 0403 | element stockChart { dchrt_CT_StockChart } 0404 | element radarChart { dchrt_CT_RadarChart } 0405 | element scatterChart { dchrt_CT_ScatterChart } 0406 | element pieChart { dchrt_CT_PieChart } 0407 | element pie3DChart { dchrt_CT_Pie3DChart } 0408 | element doughnutChart { dchrt_CT_DoughnutChart } 0409 | element barChart { dchrt_CT_BarChart } 0410 | element bar3DChart { dchrt_CT_Bar3DChart } 0411 | element ofPieChart { dchrt_CT_OfPieChart } 0412 | element surfaceChart { dchrt_CT_SurfaceChart } 0413 | element surface3DChart { dchrt_CT_Surface3DChart } 0414 | element bubbleChart { dchrt_CT_BubbleChart })+, 0415 (element valAx { dchrt_CT_ValAx } 0416 | element catAx { dchrt_CT_CatAx } 0417 | element dateAx { dchrt_CT_DateAx } 0418 | element serAx { dchrt_CT_SerAx })*, 0419 element dTable { dchrt_CT_DTable }?, 0420 element spPr { a_CT_ShapeProperties }?, 0421 element extLst { dchrt_CT_ExtensionList }? 0422 */ 0423 bool ChartPrivate::loadXmlPlotArea(QXmlStreamReader &reader) 0424 { 0425 Q_ASSERT(reader.name() == QLatin1String("plotArea")); 0426 0427 // TO DEBUG: 0428 0429 reader.readNext(); 0430 0431 while (!reader.atEnd()) 0432 { 0433 // qDebug() << "-------------2- " << reader.name(); 0434 0435 if (reader.isStartElement()) 0436 { 0437 if (!loadXmlPlotAreaElement(reader)) 0438 { 0439 qDebug() << "[debug] failed to load plotarea element."; 0440 return false; 0441 } 0442 else if (reader.name() == QLatin1String("legend")) // Why here? 0443 { 0444 loadXmlChartLegend(reader); 0445 // qDebug() << "-------------- loadXmlChartLegend"; 0446 } 0447 0448 reader.readNext(); 0449 } 0450 else 0451 { 0452 reader.readNext(); 0453 } 0454 } 0455 0456 return true; 0457 } 0458 0459 bool ChartPrivate::loadXmlPlotAreaElement(QXmlStreamReader &reader) 0460 { 0461 if (reader.name() == QLatin1String("layout")) 0462 { 0463 //!ToDo extract attributes 0464 layout = readSubTree(reader); 0465 } 0466 else if (reader.name().endsWith(QLatin1String("Chart"))) 0467 { 0468 // for pieChart, barChart, ... (choose one) 0469 if ( !loadXmlXxxChart(reader) ) 0470 { 0471 qDebug() << "[debug] failed to load chart"; 0472 return false; 0473 } 0474 } 0475 else if (reader.name() == QLatin1String("catAx")) // choose one : catAx, dateAx, serAx, valAx 0476 { 0477 // qDebug() << "loadXmlAxisCatAx()"; 0478 loadXmlAxisCatAx(reader); 0479 } 0480 else if (reader.name() == QLatin1String("dateAx")) // choose one : catAx, dateAx, serAx, valAx 0481 { 0482 // qDebug() << "loadXmlAxisDateAx()"; 0483 loadXmlAxisDateAx(reader); 0484 } 0485 else if (reader.name() == QLatin1String("serAx")) // choose one : catAx, dateAx, serAx, valAx 0486 { 0487 // qDebug() << "loadXmlAxisSerAx()"; 0488 loadXmlAxisSerAx(reader); 0489 } 0490 else if (reader.name() == QLatin1String("valAx")) // choose one : catAx, dateAx, serAx, valAx 0491 { 0492 // qDebug() << "loadXmlAxisValAx()"; 0493 loadXmlAxisValAx(reader); 0494 } 0495 else if (reader.name() == QLatin1String("dTable")) 0496 { 0497 //!ToDo 0498 // dTable "CT_DTable" 0499 // reader.skipCurrentElement(); 0500 } 0501 else if (reader.name() == QLatin1String("spPr")) 0502 { 0503 //!ToDo 0504 // spPr "a:CT_ShapeProperties" 0505 // reader.skipCurrentElement(); 0506 } 0507 else if (reader.name() == QLatin1String("extLst")) 0508 { 0509 //!ToDo 0510 // extLst "CT_ExtensionList" 0511 // reader.skipCurrentElement(); 0512 } 0513 0514 return true; 0515 } 0516 0517 bool ChartPrivate::loadXmlXxxChart(QXmlStreamReader &reader) 0518 { 0519 const auto& name = reader.name(); 0520 0521 if (name == QLatin1String("areaChart")) 0522 { 0523 chartType = Chart::CT_AreaChart; 0524 } 0525 else if (name == QLatin1String("area3DChart")) 0526 { 0527 chartType = Chart::CT_Area3DChart; 0528 } 0529 else if (name == QLatin1String("lineChart")) 0530 { 0531 chartType = Chart::CT_LineChart; 0532 } 0533 else if (name == QLatin1String("line3DChart")) 0534 { 0535 chartType = Chart::CT_Line3DChart; 0536 } 0537 else if (name == QLatin1String("stockChart")) 0538 { 0539 chartType = Chart::CT_StockChart; 0540 } 0541 else if (name == QLatin1String("radarChart")) 0542 { 0543 chartType = Chart::CT_RadarChart; 0544 } 0545 else if (name == QLatin1String("scatterChart")) 0546 { 0547 chartType = Chart::CT_ScatterChart; 0548 } 0549 else if (name == QLatin1String("pieChart")) 0550 { 0551 chartType = Chart::CT_PieChart; 0552 } 0553 else if (name == QLatin1String("pie3DChart")) 0554 { 0555 chartType = Chart::CT_Pie3DChart; 0556 } 0557 else if (name == QLatin1String("doughnutChart")) 0558 { 0559 chartType = Chart::CT_DoughnutChart; 0560 } 0561 else if (name == QLatin1String("barChart")) 0562 { 0563 chartType = Chart::CT_BarChart; 0564 } 0565 else if (name == QLatin1String("bar3DChart")) 0566 { 0567 chartType = Chart::CT_Bar3DChart; 0568 } 0569 else if (name == QLatin1String("ofPieChart")) 0570 { 0571 chartType = Chart::CT_OfPieChart; 0572 } 0573 else if (name == QLatin1String("surfaceChart")) 0574 { 0575 chartType = Chart::CT_SurfaceChart; 0576 } 0577 else if (name == QLatin1String("surface3DChart")) 0578 { 0579 chartType = Chart::CT_Surface3DChart; 0580 } 0581 else if (name == QLatin1String("bubbleChart")) 0582 { 0583 chartType = Chart::CT_BubbleChart; 0584 } 0585 else 0586 { 0587 qDebug() << "[undefined chart type] " << name; 0588 chartType = Chart::CT_NoStatementChart; 0589 return false; 0590 } 0591 0592 while( !reader.atEnd() ) 0593 { 0594 reader.readNextStartElement(); 0595 if (reader.tokenType() == QXmlStreamReader::StartElement) 0596 { 0597 // dev57 0598 0599 if ( reader.name() == QLatin1String("ser") ) 0600 { 0601 loadXmlSer(reader); 0602 } 0603 else if (reader.name() == QLatin1String("varyColors")) 0604 { 0605 } 0606 else if (reader.name() == QLatin1String("barDir")) 0607 { 0608 } 0609 else if (reader.name() == QLatin1String("axId")) 0610 { 0611 // 0612 0613 } 0614 else if (reader.name() == QLatin1String("scatterStyle")) 0615 { 0616 } 0617 else if (reader.name() == QLatin1String("holeSize")) 0618 { 0619 } 0620 else 0621 { 0622 } 0623 0624 } 0625 else if ( reader.tokenType() == QXmlStreamReader::EndElement && 0626 reader.name() == name ) 0627 { 0628 break; 0629 } 0630 } 0631 0632 return true; 0633 } 0634 0635 bool ChartPrivate::loadXmlSer(QXmlStreamReader &reader) 0636 { 0637 Q_ASSERT(reader.name() == QLatin1String("ser")); 0638 0639 auto series = std::make_shared<XlsxSeries>(); 0640 seriesList.append(series); 0641 0642 while ( !reader.atEnd() && 0643 !(reader.tokenType() == QXmlStreamReader::EndElement && 0644 reader.name() == QLatin1String("ser")) ) 0645 { 0646 if (reader.readNextStartElement()) 0647 { 0648 //TODO beide Header noch auswerten RTR 2019.11 0649 const auto& name = reader.name(); 0650 if ( name == QLatin1String("tx") ) 0651 { 0652 while ( !reader.atEnd() && 0653 !(reader.tokenType() == QXmlStreamReader::EndElement && 0654 reader.name() == name)) 0655 { 0656 if (reader.readNextStartElement()) 0657 { 0658 if (reader.name() == QLatin1String("strRef")) 0659 series->headerV_numRef = loadXmlStrRef(reader); 0660 } 0661 } 0662 } 0663 else if ( name == QLatin1String("cat") || 0664 name == QLatin1String("xVal") ) 0665 { 0666 while ( !reader.atEnd() && 0667 !(reader.tokenType() == QXmlStreamReader::EndElement && 0668 reader.name() == name)) 0669 { 0670 if (reader.readNextStartElement()) 0671 { 0672 if (reader.name() == QLatin1String("numRef")) 0673 series->axDataSource_numRef = loadXmlNumRef(reader); 0674 else 0675 if (reader.name() == QLatin1String("strRef")) 0676 series->headerH_numRef = loadXmlStrRef(reader); 0677 } 0678 } 0679 } 0680 else if (name == QLatin1String("val") || name == QLatin1String("yVal")) 0681 { 0682 while ( !reader.atEnd() && 0683 !(reader.tokenType() == QXmlStreamReader::EndElement && 0684 reader.name() == name)) 0685 { 0686 if (reader.readNextStartElement()) 0687 { 0688 if (reader.name() == QLatin1String("numRef")) 0689 series->numberDataSource_numRef = loadXmlNumRef(reader); 0690 } 0691 } 0692 } 0693 else if (name == QLatin1String("extLst")) 0694 { 0695 while ( !reader.atEnd() && 0696 !(reader.tokenType() == QXmlStreamReader::EndElement && 0697 reader.name() == name)) 0698 { 0699 reader.readNextStartElement(); 0700 } 0701 } 0702 } 0703 } 0704 0705 return true; 0706 } 0707 0708 0709 QString ChartPrivate::loadXmlNumRef(QXmlStreamReader &reader) 0710 { 0711 Q_ASSERT(reader.name() == QLatin1String("numRef")); 0712 0713 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0714 && reader.name() == QLatin1String("numRef"))) 0715 { 0716 if (reader.readNextStartElement()) 0717 { 0718 if (reader.name() == QLatin1String("f")) 0719 return reader.readElementText(); 0720 } 0721 } 0722 0723 return QString(); 0724 } 0725 0726 0727 QString ChartPrivate::loadXmlStrRef(QXmlStreamReader &reader) 0728 { 0729 Q_ASSERT(reader.name() == QLatin1String("strRef")); 0730 0731 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0732 && reader.name() == QLatin1String("strRef"))) 0733 { 0734 if (reader.readNextStartElement()) 0735 { 0736 if (reader.name() == QLatin1String("f")) 0737 return reader.readElementText(); 0738 } 0739 } 0740 0741 return QString(); 0742 } 0743 0744 0745 void ChartPrivate::saveXmlChart(QXmlStreamWriter &writer) const 0746 { 0747 //---------------------------------------------------- 0748 // c:chart 0749 writer.writeStartElement(QStringLiteral("c:chart")); 0750 0751 //---------------------------------------------------- 0752 // c:title 0753 0754 saveXmlChartTitle(writer); // write 'chart title' 0755 0756 //---------------------------------------------------- 0757 // c:plotArea 0758 0759 writer.writeStartElement(QStringLiteral("c:plotArea")); 0760 0761 // a little workaround for Start- and EndElement with starting ">" and ending without ">" 0762 writer.device()->write("><c:layout>"); //layout 0763 writer.device()->write(layout.toUtf8()); 0764 writer.device()->write("</c:layout"); //layout 0765 0766 // dev35 0767 switch (chartType) 0768 { 0769 case Chart::CT_AreaChart: saveXmlAreaChart(writer); break; 0770 case Chart::CT_Area3DChart: saveXmlAreaChart(writer); break; 0771 case Chart::CT_LineChart: saveXmlLineChart(writer); break; 0772 case Chart::CT_Line3DChart: saveXmlLineChart(writer); break; 0773 case Chart::CT_StockChart: break; 0774 case Chart::CT_RadarChart: break; 0775 case Chart::CT_ScatterChart: saveXmlScatterChart(writer); break; 0776 case Chart::CT_PieChart: saveXmlPieChart(writer); break; 0777 case Chart::CT_Pie3DChart: saveXmlPieChart(writer); break; 0778 case Chart::CT_DoughnutChart: saveXmlDoughnutChart(writer); break; 0779 case Chart::CT_BarChart: saveXmlBarChart(writer); break; 0780 case Chart::CT_Bar3DChart: saveXmlBarChart(writer); break; 0781 case Chart::CT_OfPieChart: break; 0782 case Chart::CT_SurfaceChart: break; 0783 case Chart::CT_Surface3DChart: break; 0784 case Chart::CT_BubbleChart: break; 0785 default: break; 0786 } 0787 0788 saveXmlAxis(writer); // c:catAx, c:valAx, c:serAx, c:dateAx (choose one) 0789 0790 //!TODO: write element 0791 // c:dTable CT_DTable 0792 // c:spPr CT_ShapeProperties 0793 // c:extLst CT_ExtensionList 0794 0795 writer.writeEndElement(); // c:plotArea 0796 0797 // c:legend 0798 saveXmlChartLegend(writer); // c:legend 0799 0800 writer.writeEndElement(); // c:chart 0801 } 0802 0803 bool ChartPrivate::loadXmlChartTitle(QXmlStreamReader &reader) 0804 { 0805 //!TODO : load chart title 0806 0807 Q_ASSERT(reader.name() == QLatin1String("title")); 0808 0809 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0810 && reader.name() == QLatin1String("title"))) 0811 { 0812 if (reader.readNextStartElement()) 0813 { 0814 if (reader.name() == QLatin1String("tx")) // c:tx 0815 return loadXmlChartTitleTx(reader); 0816 } 0817 } 0818 0819 return false; 0820 } 0821 0822 bool ChartPrivate::loadXmlChartTitleTx(QXmlStreamReader &reader) 0823 { 0824 Q_ASSERT(reader.name() == QLatin1String("tx")); 0825 0826 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0827 && reader.name() == QLatin1String("tx"))) 0828 { 0829 if (reader.readNextStartElement()) 0830 { 0831 if (reader.name() == QLatin1String("rich")) // c:rich 0832 return loadXmlChartTitleTxRich(reader); 0833 } 0834 } 0835 0836 return false; 0837 } 0838 0839 bool ChartPrivate::loadXmlChartTitleTxRich(QXmlStreamReader &reader) 0840 { 0841 Q_ASSERT(reader.name() == QLatin1String("rich")); 0842 0843 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0844 && reader.name() == QLatin1String("rich"))) 0845 { 0846 if (reader.readNextStartElement()) 0847 { 0848 if (reader.name() == QLatin1String("p")) // a:p 0849 return loadXmlChartTitleTxRichP(reader); 0850 } 0851 } 0852 0853 return false; 0854 } 0855 0856 bool ChartPrivate::loadXmlChartTitleTxRichP(QXmlStreamReader &reader) 0857 { 0858 Q_ASSERT(reader.name() == QLatin1String("p")); 0859 0860 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0861 && reader.name() == QLatin1String("p"))) 0862 { 0863 if (reader.readNextStartElement()) 0864 { 0865 if (reader.name() == QLatin1String("r")) // a:r 0866 return loadXmlChartTitleTxRichP_R(reader); 0867 } 0868 } 0869 0870 return false; 0871 } 0872 0873 bool ChartPrivate::loadXmlChartTitleTxRichP_R(QXmlStreamReader &reader) 0874 { 0875 Q_ASSERT(reader.name() == QLatin1String("r")); 0876 0877 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0878 && reader.name() == QLatin1String("r"))) 0879 { 0880 if (reader.readNextStartElement()) 0881 { 0882 if (reader.name() == QLatin1String("t")) // a:t 0883 { 0884 QString textValue = reader.readElementText(); 0885 this->chartTitle = textValue; 0886 return true; 0887 } 0888 } 0889 } 0890 0891 return false; 0892 } 0893 0894 0895 // write 'chart title' 0896 void ChartPrivate::saveXmlChartTitle(QXmlStreamWriter &writer) const 0897 { 0898 if ( chartTitle.isEmpty() ) 0899 return; 0900 0901 writer.writeStartElement(QStringLiteral("c:title")); 0902 /* 0903 <xsd:complexType name="CT_Title"> 0904 <xsd:sequence> 0905 <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/> 0906 <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> 0907 <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 0908 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> 0909 <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> 0910 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 0911 </xsd:sequence> 0912 </xsd:complexType> 0913 */ 0914 0915 writer.writeStartElement(QStringLiteral("c:tx")); 0916 /* 0917 <xsd:complexType name="CT_Tx"> 0918 <xsd:sequence> 0919 <xsd:choice minOccurs="1" maxOccurs="1"> 0920 <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/> 0921 <xsd:element name="rich" type="a:CT_TextBody" minOccurs="1" maxOccurs="1"/> 0922 </xsd:choice> 0923 </xsd:sequence> 0924 </xsd:complexType> 0925 */ 0926 0927 writer.writeStartElement(QStringLiteral("c:rich")); 0928 /* 0929 <xsd:complexType name="CT_TextBody"> 0930 <xsd:sequence> 0931 <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs=" 1" maxOccurs="1"/> 0932 <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/> 0933 <xsd:element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/> 0934 </xsd:sequence> 0935 </xsd:complexType> 0936 */ 0937 0938 writer.writeEmptyElement(QStringLiteral("a:bodyPr")); // <a:bodyPr/> 0939 /* 0940 <xsd:complexType name="CT_TextBodyProperties"> 0941 <xsd:sequence> 0942 <xsd:element name="prstTxWarp" type="CT_PresetTextShape" minOccurs="0" maxOccurs="1"/> 0943 <xsd:group ref="EG_TextAutofit" minOccurs="0" maxOccurs="1"/> 0944 <xsd:element name="scene3d" type="CT_Scene3D" minOccurs="0" maxOccurs="1"/> 0945 <xsd:group ref="EG_Text3D" minOccurs="0" maxOccurs="1"/> 0946 <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> 0947 </xsd:sequence> 0948 <xsd:attribute name="rot" type="ST_Angle" use="optional"/> 0949 <xsd:attribute name="spcFirstLastPara" type="xsd:boolean" use="optional"/> 0950 <xsd:attribute name="vertOverflow" type="ST_TextVertOverflowType" use="optional"/> 0951 <xsd:attribute name="horzOverflow" type="ST_TextHorzOverflowType" use="optional"/> 0952 <xsd:attribute name="vert" type="ST_TextVerticalType" use="optional"/> 0953 <xsd:attribute name="wrap" type="ST_TextWrappingType" use="optional"/> 0954 <xsd:attribute name="lIns" type="ST_Coordinate32" use="optional"/> 0955 <xsd:attribute name="tIns" type="ST_Coordinate32" use="optional"/> 0956 <xsd:attribute name="rIns" type="ST_Coordinate32" use="optional"/> 0957 <xsd:attribute name="bIns" type="ST_Coordinate32" use="optional"/> 0958 <xsd:attribute name="numCol" type="ST_TextColumnCount" use="optional"/> 0959 <xsd:attribute name="spcCol" type="ST_PositiveCoordinate32" use="optional"/> 0960 <xsd:attribute name="rtlCol" type="xsd:boolean" use="optional"/> 0961 <xsd:attribute name="fromWordArt" type="xsd:boolean" use="optional"/> 0962 <xsd:attribute name="anchor" type="ST_TextAnchoringType" use="optional"/> 0963 <xsd:attribute name="anchorCtr" type="xsd:boolean" use="optional"/> 0964 <xsd:attribute name="forceAA" type="xsd:boolean" use="optional"/> 0965 <xsd:attribute name="upright" type="xsd:boolean" use="optional" default="false"/> 0966 <xsd:attribute name="compatLnSpc" type="xsd:boolean" use="optional"/> 0967 </xsd:complexType> 0968 */ 0969 0970 writer.writeEmptyElement(QStringLiteral("a:lstStyle")); // <a:lstStyle/> 0971 0972 writer.writeStartElement(QStringLiteral("a:p")); 0973 /* 0974 <xsd:complexType name="CT_TextParagraph"> 0975 <xsd:sequence> 0976 <xsd:element name="pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/> 0977 <xsd:group ref="EG_TextRun" minOccurs="0" maxOccurs="unbounded"/> 0978 <xsd:element name="endParaRPr" type="CT_TextCharacterProperties" minOccurs="0" 0979 maxOccurs="1"/> 0980 </xsd:sequence> 0981 </xsd:complexType> 0982 */ 0983 0984 // <a:pPr lvl="0"> 0985 writer.writeStartElement(QStringLiteral("a:pPr")); 0986 0987 writer.writeAttribute(QStringLiteral("lvl"), QStringLiteral("0")); 0988 0989 // <a:defRPr b="0"/> 0990 writer.writeStartElement(QStringLiteral("a:defRPr")); 0991 0992 writer.writeAttribute(QStringLiteral("b"), QStringLiteral("0")); 0993 0994 writer.writeEndElement(); // a:defRPr 0995 0996 writer.writeEndElement(); // a:pPr 0997 0998 /* 0999 <xsd:group name="EG_TextRun"> 1000 <xsd:choice> 1001 <xsd:element name="r" type="CT_RegularTextRun"/> 1002 <xsd:element name="br" type="CT_TextLineBreak"/> 1003 <xsd:element name="fld" type="CT_TextField"/> 1004 </xsd:choice> 1005 </xsd:group> 1006 */ 1007 1008 writer.writeStartElement(QStringLiteral("a:r")); 1009 /* 1010 <xsd:complexType name="CT_RegularTextRun"> 1011 <xsd:sequence> 1012 <xsd:element name="rPr" type="CT_TextCharacterProperties" minOccurs="0" maxOccurs="1"/> 1013 <xsd:element name="t" type="xsd:string" minOccurs="1" maxOccurs="1"/> 1014 </xsd:sequence> 1015 </xsd:complexType> 1016 */ 1017 1018 // <a:t>chart name</a:t> 1019 writer.writeTextElement(QStringLiteral("a:t"), chartTitle); 1020 1021 writer.writeEndElement(); // a:r 1022 1023 writer.writeEndElement(); // a:p 1024 1025 writer.writeEndElement(); // c:rich 1026 1027 writer.writeEndElement(); // c:tx 1028 1029 // <c:overlay val="0"/> 1030 writer.writeStartElement(QStringLiteral("c:overlay")); 1031 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0")); 1032 writer.writeEndElement(); // c:overlay 1033 1034 writer.writeEndElement(); // c:title 1035 } 1036 // }} 1037 1038 1039 // write 'chart legend' 1040 void ChartPrivate::saveXmlChartLegend(QXmlStreamWriter &writer) const 1041 { 1042 if ( legendPos == Chart::None ) 1043 return; 1044 1045 // <c:legend> 1046 // <c:legendPos val="r"/> 1047 // <c:overlay val="0"/> 1048 // </c:legend> 1049 1050 writer.writeStartElement(QStringLiteral("c:legend")); 1051 1052 writer.writeStartElement(QStringLiteral("c:legendPos")); 1053 1054 QString pos; 1055 switch( legendPos ) 1056 { 1057 //case Chart::ChartAxisPos::Right: 1058 case Chart::Right : 1059 pos = QStringLiteral("r"); 1060 break; 1061 1062 // case Chart::ChartAxisPos::Left: 1063 case Chart::Left : 1064 pos = QStringLiteral("l"); 1065 break; 1066 1067 // case Chart::ChartAxisPos::Top: 1068 case Chart::Top : 1069 pos = QStringLiteral("t"); 1070 break; 1071 1072 // case Chart::ChartAxisPos::Bottom: 1073 case Chart::Bottom : 1074 pos = QStringLiteral("b"); 1075 break; 1076 1077 default: 1078 pos = QStringLiteral("r"); 1079 break; 1080 } 1081 1082 writer.writeAttribute(QStringLiteral("val"), pos); 1083 1084 writer.writeEndElement(); // c:legendPos 1085 1086 writer.writeStartElement(QStringLiteral("c:overlay")); 1087 1088 if( legendOverlay ) 1089 { 1090 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1")); 1091 } 1092 else 1093 { 1094 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0")); 1095 } 1096 1097 writer.writeEndElement(); // c:overlay 1098 1099 writer.writeEndElement(); // c:legend 1100 } 1101 1102 1103 void ChartPrivate::saveXmlPieChart(QXmlStreamWriter &writer) const 1104 { 1105 QString name = chartType == Chart::CT_PieChart ? QStringLiteral("c:pieChart") : QStringLiteral("c:pie3DChart"); 1106 1107 writer.writeStartElement(name); 1108 1109 //Do the same behavior as Excel, Pie prefer varyColors 1110 writer.writeEmptyElement(QStringLiteral("c:varyColors")); 1111 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1")); 1112 1113 for (int i=0; i<seriesList.size(); ++i) 1114 saveXmlSer(writer, seriesList[i].get(), i); 1115 1116 writer.writeEndElement(); //pieChart, pie3DChart 1117 } 1118 1119 void ChartPrivate::saveXmlBarChart(QXmlStreamWriter &writer) const 1120 { 1121 QString name = chartType == Chart::CT_BarChart ? QStringLiteral("c:barChart") : QStringLiteral("c:bar3DChart"); 1122 1123 writer.writeStartElement(name); 1124 1125 writer.writeEmptyElement(QStringLiteral("c:barDir")); 1126 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("col")); 1127 1128 for ( int i = 0 ; i < seriesList.size() ; ++i ) 1129 { 1130 saveXmlSer(writer, seriesList[i].get(), i); 1131 } 1132 1133 if ( axisList.isEmpty() ) 1134 { 1135 const_cast<ChartPrivate*>(this)->axisList.append( 1136 std::make_shared<XlsxAxis>( XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1, axisNames[XlsxAxis::Bottom] )); 1137 1138 const_cast<ChartPrivate*>(this)->axisList.append( 1139 std::make_shared<XlsxAxis>( XlsxAxis::T_Val, XlsxAxis::Left, 1, 0, axisNames[XlsxAxis::Left] )); 1140 } 1141 1142 1143 // Note: Bar3D have 2~3 axes 1144 // int axisListSize = axisList.size(); 1145 // [dev62] 1146 // Q_ASSERT( axisListSize == 2 || 1147 // ( axisListSize == 3 && chartType == Chart::CT_Bar3DChart ) ); 1148 1149 for ( int i = 0 ; i < axisList.size() ; ++i ) 1150 { 1151 writer.writeEmptyElement(QStringLiteral("c:axId")); 1152 writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId)); 1153 } 1154 1155 writer.writeEndElement(); //barChart, bar3DChart 1156 } 1157 1158 void ChartPrivate::saveXmlLineChart(QXmlStreamWriter &writer) const 1159 { 1160 QString name = chartType==Chart::CT_LineChart ? QStringLiteral("c:lineChart") : QStringLiteral("c:line3DChart"); 1161 1162 writer.writeStartElement(name); 1163 1164 // writer.writeEmptyElement(QStringLiteral("grouping")); // dev22 1165 1166 for (int i=0; i<seriesList.size(); ++i) 1167 saveXmlSer(writer, seriesList[i].get(), i); 1168 1169 if (axisList.isEmpty()) 1170 { 1171 const_cast<ChartPrivate*>(this)->axisList.append(std::make_shared<XlsxAxis>(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1, axisNames[XlsxAxis::Bottom] )); 1172 const_cast<ChartPrivate*>(this)->axisList.append(std::make_shared<XlsxAxis>(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0, axisNames[XlsxAxis::Left] )); 1173 if (chartType==Chart::CT_Line3DChart) 1174 const_cast<ChartPrivate*>(this)->axisList.append(std::make_shared<XlsxAxis>(XlsxAxis::T_Ser, XlsxAxis::Bottom, 2, 0)); 1175 } 1176 1177 Q_ASSERT((axisList.size()==2||chartType==Chart::CT_LineChart)|| (axisList.size()==3 && chartType==Chart::CT_Line3DChart)); 1178 1179 for (int i=0; i<axisList.size(); ++i) 1180 { 1181 writer.writeEmptyElement(QStringLiteral("c:axId")); 1182 writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId)); 1183 } 1184 1185 writer.writeEndElement(); //lineChart, line3DChart 1186 } 1187 1188 void ChartPrivate::saveXmlScatterChart(QXmlStreamWriter &writer) const 1189 { 1190 const QString name = QStringLiteral("c:scatterChart"); 1191 1192 writer.writeStartElement(name); 1193 1194 writer.writeEmptyElement(QStringLiteral("c:scatterStyle")); 1195 1196 for (int i=0; i<seriesList.size(); ++i) 1197 saveXmlSer(writer, seriesList[i].get(), i); 1198 1199 if (axisList.isEmpty()) 1200 { 1201 const_cast<ChartPrivate*>(this)->axisList.append( 1202 std::make_shared<XlsxAxis>(XlsxAxis::T_Val, XlsxAxis::Bottom, 0, 1, axisNames[XlsxAxis::Bottom] )); 1203 const_cast<ChartPrivate*>(this)->axisList.append( 1204 std::make_shared<XlsxAxis>(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0, axisNames[XlsxAxis::Left] )); 1205 } 1206 1207 int axisListSize = axisList.size(); 1208 Q_ASSERT(axisListSize == 2); 1209 1210 for (int i=0; i<axisList.size(); ++i) 1211 { 1212 writer.writeEmptyElement(QStringLiteral("c:axId")); 1213 writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId)); 1214 } 1215 1216 writer.writeEndElement(); //c:scatterChart 1217 } 1218 1219 void ChartPrivate::saveXmlAreaChart(QXmlStreamWriter &writer) const 1220 { 1221 QString name = chartType==Chart::CT_AreaChart ? QStringLiteral("c:areaChart") : QStringLiteral("c:area3DChart"); 1222 1223 writer.writeStartElement(name); 1224 1225 // writer.writeEmptyElement(QStringLiteral("grouping")); // dev22 1226 1227 for (int i=0; i<seriesList.size(); ++i) 1228 saveXmlSer(writer, seriesList[i].get(), i); 1229 1230 if (axisList.isEmpty()) 1231 { 1232 const_cast<ChartPrivate*>(this)->axisList.append(std::make_shared<XlsxAxis>(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1)); 1233 const_cast<ChartPrivate*>(this)->axisList.append(std::make_shared<XlsxAxis>(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)); 1234 } 1235 1236 //Note: Area3D have 2~3 axes 1237 Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Area3DChart)); 1238 1239 for (int i=0; i<axisList.size(); ++i) 1240 { 1241 writer.writeEmptyElement(QStringLiteral("c:axId")); 1242 writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId)); 1243 } 1244 1245 writer.writeEndElement(); //lineChart, line3DChart 1246 } 1247 1248 void ChartPrivate::saveXmlDoughnutChart(QXmlStreamWriter &writer) const 1249 { 1250 QString name = QStringLiteral("c:doughnutChart"); 1251 1252 writer.writeStartElement(name); 1253 1254 writer.writeEmptyElement(QStringLiteral("c:varyColors")); 1255 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1")); 1256 1257 for (int i=0; i<seriesList.size(); ++i) 1258 saveXmlSer(writer, seriesList[i].get(), i); 1259 1260 writer.writeStartElement(QStringLiteral("c:holeSize")); 1261 writer.writeAttribute(QStringLiteral("val"), QString::number(50)); 1262 1263 writer.writeEndElement(); 1264 } 1265 1266 void ChartPrivate::saveXmlSer(QXmlStreamWriter &writer, XlsxSeries *ser, int id) const 1267 { 1268 1269 writer.writeStartElement(QStringLiteral("c:ser")); 1270 writer.writeEmptyElement(QStringLiteral("c:idx")); 1271 writer.writeAttribute(QStringLiteral("val"), QString::number(id)); 1272 writer.writeEmptyElement(QStringLiteral("c:order")); 1273 writer.writeAttribute(QStringLiteral("val"), QString::number(id)); 1274 1275 QString header1; 1276 QString header2; 1277 if( ser->swapHeader ) 1278 { 1279 header1 = ser->headerH_numRef; 1280 header2 = ser->headerV_numRef; 1281 } 1282 else 1283 { 1284 header1 = ser->headerV_numRef; 1285 header2 = ser->headerH_numRef; 1286 } 1287 1288 if( !header1.isEmpty() ) 1289 { 1290 writer.writeStartElement(QStringLiteral("c:tx")); 1291 writer.writeStartElement(QStringLiteral("c:strRef")); 1292 writer.writeTextElement(QStringLiteral("c:f"), header1); 1293 writer.writeEndElement(); 1294 writer.writeEndElement(); 1295 } 1296 if( !header2.isEmpty() ) 1297 { 1298 writer.writeStartElement(QStringLiteral("c:cat")); 1299 writer.writeStartElement(QStringLiteral("c:strRef")); 1300 writer.writeTextElement(QStringLiteral("c:f"), header2); 1301 writer.writeEndElement(); 1302 writer.writeEndElement(); 1303 } 1304 1305 #if 0 1306 if (!ser->axDataSource_numRef.isEmpty()) 1307 { 1308 if (chartType == Chart::CT_ScatterChart || chartType == Chart::CT_BubbleChart) 1309 { 1310 writer.writeStartElement(QStringLiteral("c:xVal")); 1311 } 1312 else 1313 { 1314 writer.writeStartElement(QStringLiteral("c:cat")); 1315 } 1316 1317 writer.writeStartElement(QStringLiteral("c:numRef")); 1318 writer.writeTextElement(QStringLiteral("c:f"), ser->axDataSource_numRef); 1319 writer.writeEndElement();//c:numRef 1320 writer.writeEndElement();//c:cat or c:xVal 1321 } 1322 #endif 1323 1324 if (!ser->numberDataSource_numRef.isEmpty()) 1325 { 1326 if (chartType == Chart::CT_ScatterChart || chartType == Chart::CT_BubbleChart) 1327 writer.writeStartElement(QStringLiteral("c:yVal")); 1328 else 1329 writer.writeStartElement(QStringLiteral("c:val")); 1330 writer.writeStartElement(QStringLiteral("c:numRef")); 1331 writer.writeTextElement(QStringLiteral("c:f"), ser->numberDataSource_numRef); 1332 writer.writeEndElement();//c:numRef 1333 writer.writeEndElement();//c:val or c:yVal 1334 } 1335 1336 writer.writeEndElement();//c:ser 1337 } 1338 1339 bool ChartPrivate::loadXmlAxisCatAx(QXmlStreamReader &reader) 1340 { 1341 1342 auto axis = std::make_shared<XlsxAxis>(); 1343 axis->type = XlsxAxis::T_Cat; 1344 axisList.append(axis); 1345 1346 // load EG_AxShared 1347 if ( ! loadXmlAxisEG_AxShared( reader, axis.get() ) ) 1348 { 1349 qDebug() << "failed to load EG_AxShared"; 1350 return false; 1351 } 1352 1353 //!TODO: load element 1354 // auto 1355 // lblAlgn 1356 // lblOffset 1357 // tickLblSkip 1358 // tickMarkSkip 1359 // noMultiLvlLbl 1360 // extLst 1361 1362 return true; 1363 } 1364 1365 bool ChartPrivate::loadXmlAxisDateAx(QXmlStreamReader &reader) 1366 { 1367 1368 auto axis = std::make_shared<XlsxAxis>(); 1369 axis->type = XlsxAxis::T_Date; 1370 axisList.append(axis); 1371 1372 // load EG_AxShared 1373 if ( ! loadXmlAxisEG_AxShared( reader, axis.get() ) ) 1374 { 1375 qDebug() << "failed to load EG_AxShared"; 1376 return false; 1377 } 1378 1379 //!TODO: load element 1380 // auto 1381 // lblOffset 1382 // baseTimeUnit 1383 // majorUnit 1384 // majorTimeUnit 1385 // minorUnit 1386 // minorTimeUnit 1387 // extLst 1388 1389 return true; 1390 } 1391 1392 bool ChartPrivate::loadXmlAxisSerAx(QXmlStreamReader &reader) 1393 { 1394 1395 auto axis = std::make_shared<XlsxAxis>(); 1396 axis->type = XlsxAxis::T_Ser; 1397 axisList.append(axis); 1398 1399 // load EG_AxShared 1400 if ( ! loadXmlAxisEG_AxShared( reader, axis.get() ) ) 1401 { 1402 qDebug() << "failed to load EG_AxShared"; 1403 return false; 1404 } 1405 1406 //!TODO: load element 1407 // tickLblSkip 1408 // tickMarkSkip 1409 // extLst 1410 1411 return true; 1412 } 1413 1414 bool ChartPrivate::loadXmlAxisValAx(QXmlStreamReader &reader) 1415 { 1416 Q_ASSERT(reader.name() == QLatin1String("valAx")); 1417 1418 auto axis = std::make_shared<XlsxAxis>(); 1419 axis->type = XlsxAxis::T_Val; 1420 axisList.append(axis); 1421 1422 if ( ! loadXmlAxisEG_AxShared( reader, axis.get() ) ) 1423 { 1424 qDebug() << "failed to load EG_AxShared"; 1425 return false; 1426 } 1427 1428 //!TODO: load element 1429 // crossBetween 1430 // majorUnit 1431 // minorUnit 1432 // dispUnits 1433 // extLst 1434 1435 return true; 1436 } 1437 1438 /* 1439 <xsd:group name="EG_AxShared"> 1440 <xsd:sequence> 1441 <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*)(M) 1442 <xsd:element name="scaling" type="CT_Scaling" minOccurs="1" maxOccurs="1"/> (*)(M) 1443 <xsd:element name="delete" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 1444 <xsd:element name="axPos" type="CT_AxPos" minOccurs="1" maxOccurs="1"/> (*)(M) 1445 <xsd:element name="majorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> 1446 <xsd:element name="minorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> 1447 <xsd:element name="title" type="CT_Title" minOccurs="0" maxOccurs="1"/> (*) 1448 <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="1"/> 1449 <xsd:element name="majorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/> 1450 <xsd:element name="minorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/> 1451 <xsd:element name="tickLblPos" type="CT_TickLblPos" minOccurs="0" maxOccurs="1"/> 1452 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> 1453 <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> 1454 <xsd:element name="crossAx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*)(M) 1455 <xsd:choice minOccurs="0" maxOccurs="1"> 1456 <xsd:element name="crosses" type="CT_Crosses" minOccurs="1" maxOccurs="1"/> 1457 <xsd:element name="crossesAt" type="CT_Double" minOccurs="1" maxOccurs="1"/> 1458 </xsd:choice> 1459 </xsd:sequence> 1460 </xsd:group> 1461 */ 1462 bool ChartPrivate::loadXmlAxisEG_AxShared(QXmlStreamReader &reader, XlsxAxis* axis) 1463 { 1464 Q_ASSERT( nullptr != axis ); 1465 Q_ASSERT( reader.name().endsWith(QLatin1String("Ax")) ); 1466 QString name = reader.name().toString(); // 1467 1468 while ( !reader.atEnd() ) 1469 { 1470 reader.readNextStartElement(); 1471 if ( reader.tokenType() == QXmlStreamReader::StartElement ) 1472 { 1473 // qDebug() << "[debug]" << QTime::currentTime() << reader.name().toString(); 1474 1475 if ( reader.name() == QLatin1String("axId") ) // mandatory element 1476 { 1477 // dev57 1478 uint axId = reader.attributes().value(QStringLiteral("val")).toUInt(); // for Qt5.1 1479 axis->axisId = axId; 1480 } 1481 else if ( reader.name() == QLatin1String("scaling") ) 1482 { 1483 // mandatory element 1484 1485 loadXmlAxisEG_AxShared_Scaling(reader, axis); 1486 } 1487 else if ( reader.name() == QLatin1String("delete") ) 1488 { 1489 //!TODO 1490 } 1491 else if ( reader.name() == QLatin1String("axPos") ) 1492 { 1493 // mandatory element 1494 1495 QString axPosVal = reader.attributes().value(QLatin1String("val")).toString(); 1496 1497 if ( axPosVal == QLatin1String("l") ) { axis->axisPos = XlsxAxis::Left; } 1498 else if ( axPosVal == QLatin1String("r") ) { axis->axisPos = XlsxAxis::Right; } 1499 else if ( axPosVal == QLatin1String("t") ) { axis->axisPos = XlsxAxis::Top; } 1500 else if ( axPosVal == QLatin1String("b") ) { axis->axisPos = XlsxAxis::Bottom; } 1501 } 1502 else if ( reader.name() == QLatin1String("majorGridlines") ) 1503 { 1504 //!TODO anything else? 1505 majorGridlinesEnabled = true; 1506 } 1507 else if ( reader.name() == QLatin1String("minorGridlines") ) 1508 { 1509 //!TODO anything else? 1510 minorGridlinesEnabled = true; 1511 } 1512 else if ( reader.name() == QLatin1String("title") ) 1513 { 1514 // title 1515 if ( !loadXmlAxisEG_AxShared_Title(reader, axis) ) 1516 { 1517 qDebug() << "failed to load EG_AxShared title."; 1518 Q_ASSERT(false); 1519 return false; 1520 } 1521 } 1522 else if ( reader.name() == QLatin1String("numFmt") ) 1523 { 1524 //!TODO 1525 } 1526 else if ( reader.name() == QLatin1String("majorTickMark") ) 1527 { 1528 //!TODO 1529 } 1530 else if ( reader.name() == QLatin1String("minorTickMark") ) 1531 { 1532 //!TODO 1533 } 1534 else if ( reader.name() == QLatin1String("tickLblPos") ) 1535 { 1536 //!TODO 1537 } 1538 else if ( reader.name() == QLatin1String("spPr") ) 1539 { 1540 //!TODO 1541 } 1542 else if ( reader.name() == QLatin1String("txPr") ) 1543 { 1544 //!TODO 1545 } 1546 else if ( reader.name() == QLatin1String("crossAx") ) // mandatory element 1547 { 1548 // dev57 1549 uint crossAx = reader.attributes().value(QLatin1String("val")).toUInt(); // for Qt5.1 1550 axis->crossAx = crossAx; 1551 } 1552 else if ( reader.name() == QLatin1String("crosses") ) 1553 { 1554 //!TODO 1555 } 1556 else if ( reader.name() == QLatin1String("crossesAt") ) 1557 { 1558 //!TODO 1559 } 1560 1561 // reader.readNext(); 1562 } 1563 else if ( reader.tokenType() == QXmlStreamReader::EndElement && 1564 reader.name().toString() == name ) 1565 { 1566 break; 1567 } 1568 } 1569 1570 return true; 1571 } 1572 1573 bool ChartPrivate::loadXmlAxisEG_AxShared_Scaling(QXmlStreamReader &reader, XlsxAxis* axis) 1574 { 1575 Q_UNUSED(axis); 1576 Q_ASSERT(reader.name() == QLatin1String("scaling")); 1577 1578 while ( !reader.atEnd() ) 1579 { 1580 reader.readNextStartElement(); 1581 if ( reader.tokenType() == QXmlStreamReader::StartElement ) 1582 { 1583 if ( reader.name() == QLatin1String("orientation") ) 1584 { 1585 } 1586 else 1587 { 1588 } 1589 } 1590 else if ( reader.tokenType() == QXmlStreamReader::EndElement && 1591 reader.name() == QLatin1String("scaling") ) 1592 { 1593 break; 1594 } 1595 } 1596 1597 return true; 1598 } 1599 1600 /* 1601 <xsd:complexType name="CT_Title"> 1602 <xsd:sequence> 1603 <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/> 1604 <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> 1605 <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 1606 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> 1607 <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> 1608 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 1609 </xsd:sequence> 1610 </xsd:complexType> 1611 1612 <xsd:complexType name="CT_Tx"> 1613 <xsd:sequence> 1614 <xsd:choice minOccurs="1" maxOccurs="1"> 1615 <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/> 1616 <xsd:element name="rich" type="a:CT_TextBody" minOccurs="1" maxOccurs="1"/> 1617 </xsd:choice> 1618 </xsd:sequence> 1619 </xsd:complexType> 1620 1621 <xsd:complexType name="CT_StrRef"> 1622 <xsd:sequence> 1623 <xsd:element name="f" type="xsd:string" minOccurs="1" maxOccurs="1"/> 1624 <xsd:element name="strCache" type="CT_StrData" minOccurs="0" maxOccurs="1"/> 1625 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 1626 </xsd:sequence> 1627 </xsd:complexType> 1628 1629 <xsd:complexType name="CT_TextBody"> 1630 <xsd:sequence> 1631 <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/> 1632 <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/> 1633 <xsd:element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/> 1634 </xsd:sequence> 1635 </xsd:complexType> 1636 */ 1637 bool ChartPrivate::loadXmlAxisEG_AxShared_Title(QXmlStreamReader &reader, XlsxAxis* axis) 1638 { 1639 Q_ASSERT(reader.name() == QLatin1String("title")); 1640 1641 while ( !reader.atEnd() ) 1642 { 1643 reader.readNextStartElement(); 1644 if ( reader.tokenType() == QXmlStreamReader::StartElement ) 1645 { 1646 if ( reader.name() == QLatin1String("tx") ) 1647 { 1648 loadXmlAxisEG_AxShared_Title_Tx(reader, axis); 1649 } 1650 else if ( reader.name() == QLatin1String("overlay") ) 1651 { 1652 //!TODO: load overlay 1653 loadXmlAxisEG_AxShared_Title_Overlay(reader, axis); 1654 } 1655 else 1656 { 1657 } 1658 } 1659 else if ( reader.tokenType() == QXmlStreamReader::EndElement && 1660 reader.name() == QLatin1String("title") ) 1661 { 1662 break; 1663 } 1664 } 1665 1666 return true; 1667 } 1668 1669 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Overlay(QXmlStreamReader &reader, XlsxAxis* axis) 1670 { 1671 Q_UNUSED(axis); 1672 Q_ASSERT(reader.name() == QLatin1String("overlay")); 1673 1674 while ( !reader.atEnd() ) 1675 { 1676 reader.readNextStartElement(); 1677 if ( reader.tokenType() == QXmlStreamReader::StartElement ) 1678 { 1679 } 1680 else if ( reader.tokenType() == QXmlStreamReader::EndElement && 1681 reader.name() == QLatin1String("overlay") ) 1682 { 1683 break; 1684 } 1685 } 1686 1687 return true; 1688 } 1689 1690 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx(QXmlStreamReader &reader, XlsxAxis* axis) 1691 { 1692 Q_ASSERT(reader.name() == QLatin1String("tx")); 1693 1694 while ( !reader.atEnd() ) 1695 { 1696 reader.readNextStartElement(); 1697 if ( reader.tokenType() == QXmlStreamReader::StartElement ) 1698 { 1699 if ( reader.name() == QLatin1String("rich") ) 1700 { 1701 loadXmlAxisEG_AxShared_Title_Tx_Rich(reader, axis); 1702 } 1703 else 1704 { 1705 } 1706 } 1707 else if ( reader.tokenType() == QXmlStreamReader::EndElement && 1708 reader.name() == QLatin1String("tx") ) 1709 { 1710 break; 1711 } 1712 } 1713 1714 return true; 1715 } 1716 1717 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich(QXmlStreamReader &reader, XlsxAxis* axis) 1718 { 1719 Q_ASSERT(reader.name() == QLatin1String("rich")); 1720 1721 while ( !reader.atEnd() ) 1722 { 1723 reader.readNextStartElement(); 1724 if ( reader.tokenType() == QXmlStreamReader::StartElement ) 1725 { 1726 if ( reader.name() == QLatin1String("p") ) 1727 { 1728 loadXmlAxisEG_AxShared_Title_Tx_Rich_P(reader, axis); 1729 } 1730 else 1731 { 1732 } 1733 } 1734 else if ( reader.tokenType() == QXmlStreamReader::EndElement && 1735 reader.name() == QLatin1String("rich") ) 1736 { 1737 break; 1738 } 1739 } 1740 1741 return true; 1742 } 1743 1744 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich_P(QXmlStreamReader &reader, XlsxAxis* axis) 1745 { 1746 Q_ASSERT(reader.name() == QLatin1String("p")); 1747 1748 while ( !reader.atEnd() ) 1749 { 1750 reader.readNextStartElement(); 1751 if ( reader.tokenType() == QXmlStreamReader::StartElement ) 1752 { 1753 if ( reader.name() == QLatin1String("r") ) 1754 { 1755 loadXmlAxisEG_AxShared_Title_Tx_Rich_P_R(reader, axis); 1756 } 1757 else if ( reader.name() == QLatin1String("pPr") ) 1758 { 1759 loadXmlAxisEG_AxShared_Title_Tx_Rich_P_pPr(reader, axis); 1760 } 1761 else 1762 { 1763 1764 } 1765 } 1766 else if ( reader.tokenType() == QXmlStreamReader::EndElement && 1767 reader.name() == QLatin1String("p") ) 1768 { 1769 break; 1770 } 1771 } 1772 1773 return true; 1774 } 1775 1776 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich_P_pPr(QXmlStreamReader &reader, XlsxAxis* axis) 1777 { 1778 Q_UNUSED(axis); 1779 Q_ASSERT(reader.name() == QLatin1String("pPr")); 1780 1781 while ( !reader.atEnd() ) 1782 { 1783 reader.readNextStartElement(); 1784 if ( reader.tokenType() == QXmlStreamReader::StartElement ) 1785 { 1786 if ( reader.name() == QLatin1String("defRPr") ) 1787 { 1788 reader.readElementText(); 1789 } 1790 else 1791 { 1792 } 1793 } 1794 else if ( reader.tokenType() == QXmlStreamReader::EndElement && 1795 reader.name() == QLatin1String("pPr") ) 1796 { 1797 break; 1798 } 1799 } 1800 1801 return true; 1802 } 1803 1804 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich_P_R(QXmlStreamReader &reader, XlsxAxis* axis) 1805 { 1806 Q_ASSERT(reader.name() == QLatin1String("r")); 1807 1808 while ( !reader.atEnd() ) 1809 { 1810 reader.readNextStartElement(); 1811 if ( reader.tokenType() == QXmlStreamReader::StartElement ) 1812 { 1813 if ( reader.name() == QLatin1String("t") ) 1814 { 1815 QString strAxisName = reader.readElementText(); 1816 XlsxAxis::AxisPos axisPos = axis->axisPos; 1817 axis->axisNames[ axisPos ] = strAxisName; 1818 } 1819 else 1820 { 1821 } 1822 } 1823 else if ( reader.tokenType() == QXmlStreamReader::EndElement && 1824 reader.name() == QLatin1String("r") ) 1825 { 1826 break; 1827 } 1828 } 1829 1830 return true; 1831 } 1832 1833 /* 1834 <xsd:complexType name="CT_PlotArea"> 1835 <xsd:sequence> 1836 <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> 1837 <xsd:choice minOccurs="1" maxOccurs="unbounded"> 1838 <xsd:element name="areaChart" type="CT_AreaChart" minOccurs="1" maxOccurs="1"/> 1839 <xsd:element name="area3DChart" type="CT_Area3DChart" minOccurs="1" maxOccurs="1"/> 1840 <xsd:element name="lineChart" type="CT_LineChart" minOccurs="1" maxOccurs="1"/> 1841 <xsd:element name="line3DChart" type="CT_Line3DChart" minOccurs="1" maxOccurs="1"/> 1842 <xsd:element name="stockChart" type="CT_StockChart" minOccurs="1" maxOccurs="1"/> 1843 <xsd:element name="radarChart" type="CT_RadarChart" minOccurs="1" maxOccurs="1"/> 1844 <xsd:element name="scatterChart" type="CT_ScatterChart" minOccurs="1" maxOccurs="1"/> 1845 <xsd:element name="pieChart" type="CT_PieChart" minOccurs="1" maxOccurs="1"/> 1846 <xsd:element name="pie3DChart" type="CT_Pie3DChart" minOccurs="1" maxOccurs="1"/> 1847 <xsd:element name="doughnutChart" type="CT_DoughnutChart" minOccurs="1" maxOccurs="1"/> 1848 <xsd:element name="barChart" type="CT_BarChart" minOccurs="1" maxOccurs="1"/> 1849 <xsd:element name="bar3DChart" type="CT_Bar3DChart" minOccurs="1" maxOccurs="1"/> 1850 <xsd:element name="ofPieChart" type="CT_OfPieChart" minOccurs="1" maxOccurs="1"/> 1851 <xsd:element name="surfaceChart" type="CT_SurfaceChart" minOccurs="1" maxOccurs="1"/> 1852 <xsd:element name="surface3DChart" type="CT_Surface3DChart" minOccurs="1" maxOccurs="1"/> 1853 <xsd:element name="bubbleChart" type="CT_BubbleChart" minOccurs="1" maxOccurs="1"/> 1854 </xsd:choice> 1855 <xsd:choice minOccurs="0" maxOccurs="unbounded"> 1856 <xsd:element name="valAx" type="CT_ValAx" minOccurs="1" maxOccurs="1"/> 1857 <xsd:element name="catAx" type="CT_CatAx" minOccurs="1" maxOccurs="1"/> 1858 <xsd:element name="dateAx" type="CT_DateAx" minOccurs="1" maxOccurs="1"/> 1859 <xsd:element name="serAx" type="CT_SerAx" minOccurs="1" maxOccurs="1"/> 1860 </xsd:choice> 1861 <xsd:element name="dTable" type="CT_DTable" minOccurs="0" maxOccurs="1"/> 1862 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> 1863 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 1864 </xsd:sequence> 1865 </xsd:complexType> 1866 */ 1867 1868 /* 1869 <xsd:complexType name="CT_CatAx"> 1870 <xsd:sequence> 1871 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> 1872 <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 1873 <xsd:element name="lblAlgn" type="CT_LblAlgn" minOccurs="0" maxOccurs="1"/> 1874 <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/> 1875 <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> 1876 <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> 1877 <xsd:element name="noMultiLvlLbl" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 1878 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 1879 </xsd:sequence> 1880 </xsd:complexType> 1881 <!-----------------------------------------------------------------------------> 1882 <xsd:complexType name="CT_DateAx"> 1883 <xsd:sequence> 1884 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> 1885 <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 1886 <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/> 1887 <xsd:element name="baseTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> 1888 <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> 1889 <xsd:element name="majorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> 1890 <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> 1891 <xsd:element name="minorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> 1892 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 1893 </xsd:sequence> 1894 </xsd:complexType> 1895 <!-----------------------------------------------------------------------------> 1896 <xsd:complexType name="CT_SerAx"> 1897 <xsd:sequence> 1898 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> 1899 <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> 1900 <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> 1901 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 1902 </xsd:sequence> 1903 </xsd:complexType> 1904 <!-----------------------------------------------------------------------------> 1905 <xsd:complexType name="CT_ValAx"> 1906 <xsd:sequence> 1907 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> 1908 <xsd:element name="crossBetween" type="CT_CrossBetween" minOccurs="0" maxOccurs="1"/> 1909 <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> 1910 <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> 1911 <xsd:element name="dispUnits" type="CT_DispUnits" minOccurs="0" maxOccurs="1"/> 1912 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 1913 </xsd:sequence> 1914 </xsd:complexType> 1915 */ 1916 1917 void ChartPrivate::saveXmlAxis(QXmlStreamWriter &writer) const 1918 { 1919 for ( int i = 0 ; i < axisList.size() ; ++i ) 1920 { 1921 XlsxAxis* axis = axisList[i].get(); 1922 if ( nullptr == axis ) 1923 continue; 1924 1925 if ( axis->type == XlsxAxis::T_Cat ) { saveXmlAxisCatAx( writer, axis ); } 1926 if ( axis->type == XlsxAxis::T_Val ) { saveXmlAxisValAx( writer, axis ); } 1927 if ( axis->type == XlsxAxis::T_Ser ) { saveXmlAxisSerAx( writer, axis ); } 1928 if ( axis->type == XlsxAxis::T_Date ) { saveXmlAxisDateAx( writer, axis ); } 1929 } 1930 1931 } 1932 1933 void ChartPrivate::saveXmlAxisCatAx(QXmlStreamWriter &writer, XlsxAxis* axis) const 1934 { 1935 /* 1936 <xsd:complexType name="CT_CatAx"> 1937 <xsd:sequence> 1938 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> 1939 <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 1940 <xsd:element name="lblAlgn" type="CT_LblAlgn" minOccurs="0" maxOccurs="1"/> 1941 <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/> 1942 <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> 1943 <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> 1944 <xsd:element name="noMultiLvlLbl" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 1945 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 1946 </xsd:sequence> 1947 </xsd:complexType> 1948 */ 1949 1950 writer.writeStartElement(QStringLiteral("c:catAx")); 1951 1952 saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared 1953 1954 //!TODO: write element 1955 // auto 1956 // lblAlgn 1957 // lblOffset 1958 // tickLblSkip 1959 // tickMarkSkip 1960 // noMultiLvlLbl 1961 // extLst 1962 1963 writer.writeEndElement(); // c:catAx 1964 } 1965 1966 void ChartPrivate::saveXmlAxisDateAx(QXmlStreamWriter &writer, XlsxAxis* axis) const 1967 { 1968 /* 1969 <xsd:complexType name="CT_DateAx"> 1970 <xsd:sequence> 1971 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> 1972 <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 1973 <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/> 1974 <xsd:element name="baseTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> 1975 <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> 1976 <xsd:element name="majorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> 1977 <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> 1978 <xsd:element name="minorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/> 1979 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 1980 </xsd:sequence> 1981 </xsd:complexType> 1982 */ 1983 1984 writer.writeStartElement(QStringLiteral("c:dateAx")); 1985 1986 saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared 1987 1988 //!TODO: write element 1989 // auto 1990 // lblOffset 1991 // baseTimeUnit 1992 // majorUnit 1993 // majorTimeUnit 1994 // minorUnit 1995 // minorTimeUnit 1996 // extLst 1997 1998 writer.writeEndElement(); // c:dateAx 1999 } 2000 2001 void ChartPrivate::saveXmlAxisSerAx(QXmlStreamWriter &writer, XlsxAxis* axis) const 2002 { 2003 /* 2004 <xsd:complexType name="CT_SerAx"> 2005 <xsd:sequence> 2006 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> 2007 <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> 2008 <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/> 2009 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 2010 </xsd:sequence> 2011 </xsd:complexType> 2012 */ 2013 2014 writer.writeStartElement(QStringLiteral("c:serAx")); 2015 2016 saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared 2017 2018 //!TODO: write element 2019 // tickLblSkip 2020 // tickMarkSkip 2021 // extLst 2022 2023 writer.writeEndElement(); // c:serAx 2024 } 2025 2026 void ChartPrivate::saveXmlAxisValAx(QXmlStreamWriter &writer, XlsxAxis* axis) const 2027 { 2028 /* 2029 <xsd:complexType name="CT_ValAx"> 2030 <xsd:sequence> 2031 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/> 2032 <xsd:element name="crossBetween" type="CT_CrossBetween" minOccurs="0" maxOccurs="1"/> 2033 <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> 2034 <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/> 2035 <xsd:element name="dispUnits" type="CT_DispUnits" minOccurs="0" maxOccurs="1"/> 2036 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 2037 </xsd:sequence> 2038 </xsd:complexType> 2039 */ 2040 2041 writer.writeStartElement(QStringLiteral("c:valAx")); 2042 2043 saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared 2044 2045 //!TODO: write element 2046 // crossBetween 2047 // majorUnit 2048 // minorUnit 2049 // dispUnits 2050 // extLst 2051 2052 writer.writeEndElement(); // c:valAx 2053 } 2054 2055 void ChartPrivate::saveXmlAxisEG_AxShared(QXmlStreamWriter &writer, XlsxAxis* axis) const 2056 { 2057 /* 2058 <xsd:group name="EG_AxShared"> 2059 <xsd:sequence> 2060 <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*) 2061 <xsd:element name="scaling" type="CT_Scaling" minOccurs="1" maxOccurs="1"/> (*) 2062 <xsd:element name="delete" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 2063 <xsd:element name="axPos" type="CT_AxPos" minOccurs="1" maxOccurs="1"/> (*) 2064 <xsd:element name="majorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> 2065 <xsd:element name="minorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/> 2066 <xsd:element name="title" type="CT_Title" minOccurs="0" maxOccurs="1"/> (***********************) 2067 <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="1"/> 2068 <xsd:element name="majorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/> 2069 <xsd:element name="minorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/> 2070 <xsd:element name="tickLblPos" type="CT_TickLblPos" minOccurs="0" maxOccurs="1"/> 2071 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> 2072 <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> 2073 <xsd:element name="crossAx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*) 2074 <xsd:choice minOccurs="0" maxOccurs="1"> 2075 <xsd:element name="crosses" type="CT_Crosses" minOccurs="1" maxOccurs="1"/> 2076 <xsd:element name="crossesAt" type="CT_Double" minOccurs="1" maxOccurs="1"/> 2077 </xsd:choice> 2078 </xsd:sequence> 2079 </xsd:group> 2080 */ 2081 2082 writer.writeEmptyElement(QStringLiteral("c:axId")); // 21.2.2.9. axId (Axis ID) (mandatory value) 2083 writer.writeAttribute(QStringLiteral("val"), QString::number(axis->axisId)); 2084 2085 writer.writeStartElement(QStringLiteral("c:scaling")); // CT_Scaling (mandatory value) 2086 writer.writeEmptyElement(QStringLiteral("c:orientation")); // CT_Orientation 2087 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("minMax")); // ST_Orientation 2088 writer.writeEndElement(); // c:scaling 2089 2090 writer.writeEmptyElement(QStringLiteral("c:axPos")); // axPos CT_AxPos (mandatory value) 2091 QString pos = GetAxisPosString( axis->axisPos ); 2092 if ( !pos.isEmpty() ) 2093 { 2094 writer.writeAttribute(QStringLiteral("val"), pos); // ST_AxPos 2095 } 2096 2097 if( majorGridlinesEnabled ) 2098 { 2099 writer.writeEmptyElement(QStringLiteral("c:majorGridlines")); 2100 } 2101 if( minorGridlinesEnabled ) 2102 { 2103 writer.writeEmptyElement(QStringLiteral("c:minorGridlines")); 2104 } 2105 2106 saveXmlAxisEG_AxShared_Title(writer, axis); // "c:title" CT_Title 2107 2108 writer.writeEmptyElement(QStringLiteral("c:crossAx")); // crossAx (mandatory value) 2109 writer.writeAttribute(QStringLiteral("val"), QString::number(axis->crossAx)); 2110 2111 } 2112 2113 void ChartPrivate::saveXmlAxisEG_AxShared_Title(QXmlStreamWriter &writer, XlsxAxis* axis) const 2114 { 2115 // CT_Title 2116 2117 /* 2118 <xsd:complexType name="CT_Title"> 2119 <xsd:sequence> 2120 <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/> 2121 <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/> 2122 <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/> 2123 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/> 2124 <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/> 2125 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 2126 </xsd:sequence> 2127 </xsd:complexType> 2128 */ 2129 /* 2130 <xsd:complexType name="CT_Tx"> 2131 <xsd:sequence> 2132 <xsd:choice minOccurs="1" maxOccurs="1"> 2133 <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/> 2134 <xsd:element name="rich" type="a:CT_TextBody" minOccurs="1" maxOccurs="1"/> 2135 </xsd:choice> 2136 </xsd:sequence> 2137 </xsd:complexType> 2138 */ 2139 /* 2140 <xsd:complexType name="CT_StrRef"> 2141 <xsd:sequence> 2142 <xsd:element name="f" type="xsd:string" minOccurs="1" maxOccurs="1"/> 2143 <xsd:element name="strCache" type="CT_StrData" minOccurs="0" maxOccurs="1"/> 2144 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/> 2145 </xsd:sequence> 2146 </xsd:complexType> 2147 */ 2148 /* 2149 <xsd:complexType name="CT_TextBody"> 2150 <xsd:sequence> 2151 <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/> 2152 <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/> 2153 <xsd:element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/> 2154 </xsd:sequence> 2155 </xsd:complexType> 2156 */ 2157 2158 writer.writeStartElement(QStringLiteral("c:title")); 2159 2160 // CT_Tx {{ 2161 writer.writeStartElement(QStringLiteral("c:tx")); 2162 2163 writer.writeStartElement(QStringLiteral("c:rich")); // CT_TextBody 2164 2165 writer.writeEmptyElement(QStringLiteral("a:bodyPr")); // CT_TextBodyProperties 2166 2167 writer.writeEmptyElement(QStringLiteral("a:lstStyle")); // CT_TextListStyle 2168 2169 writer.writeStartElement(QStringLiteral("a:p")); 2170 2171 writer.writeStartElement(QStringLiteral("a:pPr")); 2172 writer.writeAttribute(QStringLiteral("lvl"), QString::number(0)); 2173 2174 writer.writeStartElement(QStringLiteral("a:defRPr")); 2175 writer.writeAttribute(QStringLiteral("b"), QString::number(0)); 2176 writer.writeEndElement(); // a:defRPr 2177 writer.writeEndElement(); // a:pPr 2178 2179 writer.writeStartElement(QStringLiteral("a:r")); 2180 QString strAxisName = GetAxisName(axis); 2181 writer.writeTextElement( QStringLiteral("a:t"), strAxisName ); 2182 writer.writeEndElement(); // a:r 2183 2184 writer.writeEndElement(); // a:p 2185 2186 writer.writeEndElement(); // c:rich 2187 2188 writer.writeEndElement(); // c:tx 2189 // CT_Tx }} 2190 2191 writer.writeStartElement(QStringLiteral("c:overlay")); 2192 writer.writeAttribute(QStringLiteral("val"), QString::number(0)); // CT_Boolean 2193 writer.writeEndElement(); // c:overlay 2194 2195 writer.writeEndElement(); // c:title 2196 2197 } 2198 2199 QString ChartPrivate::GetAxisPosString( XlsxAxis::AxisPos axisPos ) const 2200 { 2201 QString pos; 2202 switch ( axisPos ) 2203 { 2204 case XlsxAxis::Top : pos = QStringLiteral("t"); break; 2205 case XlsxAxis::Bottom : pos = QStringLiteral("b"); break; 2206 case XlsxAxis::Left : pos = QStringLiteral("l"); break; 2207 case XlsxAxis::Right : pos = QStringLiteral("r"); break; 2208 default: break; // ?? 2209 } 2210 2211 return pos; 2212 } 2213 2214 QString ChartPrivate::GetAxisName(XlsxAxis* axis) const 2215 { 2216 QString strAxisName; 2217 if ( nullptr == axis ) 2218 return strAxisName; 2219 2220 QString pos = GetAxisPosString( axis->axisPos ); // l, t, r, b 2221 if ( pos.isEmpty() ) 2222 return strAxisName; 2223 2224 strAxisName = axis->axisNames[ axis->axisPos ]; 2225 return strAxisName; 2226 } 2227 2228 2229 /// 2230 /// \brief ChartPrivate::readSubTree 2231 /// \param reader 2232 /// \return 2233 /// 2234 QString ChartPrivate::readSubTree(QXmlStreamReader &reader) 2235 { 2236 QString treeString; 2237 QString prefix; 2238 const auto& treeName = reader.name(); 2239 2240 while (!reader.atEnd()) 2241 { 2242 reader.readNextStartElement(); 2243 if (reader.tokenType() == QXmlStreamReader::StartElement) 2244 { 2245 prefix = reader.prefix().toString(); 2246 2247 treeString += QLatin1String("<") + reader.qualifiedName().toString(); 2248 2249 const QXmlStreamAttributes attributes = reader.attributes(); 2250 for (const QXmlStreamAttribute &attr : attributes) { 2251 treeString += QLatin1String(" ") + attr.name().toString() + QLatin1String("=\"") + attr.value().toString() + QLatin1String("\""); 2252 } 2253 treeString += QStringLiteral(">"); 2254 } 2255 else if (reader.tokenType() == QXmlStreamReader::EndElement ) 2256 { 2257 if( reader.name() == treeName) 2258 { 2259 break; 2260 } 2261 treeString += QLatin1String("</") + reader.qualifiedName().toString() + QLatin1String(">"); 2262 } 2263 } 2264 2265 return treeString; 2266 } 2267 2268 2269 /// 2270 /// \brief ChartPrivate::loadXmlChartLegend 2271 /// \param reader 2272 /// \return 2273 /// 2274 bool ChartPrivate::loadXmlChartLegend(QXmlStreamReader &reader) 2275 { 2276 2277 Q_ASSERT(reader.name() == QLatin1String("legend")); 2278 2279 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 2280 && reader.name() == QLatin1String("legend"))) 2281 { 2282 if (reader.readNextStartElement()) 2283 { 2284 if (reader.name() == QLatin1String("legendPos")) // c:legendPos 2285 { 2286 QString pos = reader.attributes().value(QLatin1String("val")).toString(); 2287 if( pos.compare(QLatin1String("r"), Qt::CaseInsensitive) == 0) 2288 { 2289 // legendPos = Chart::ChartAxisPos::Right; 2290 legendPos = Chart::Right; 2291 } 2292 else 2293 if( pos.compare(QLatin1String("l"), Qt::CaseInsensitive) == 0) 2294 { 2295 // legendPos = Chart::ChartAxisPos::Left; 2296 legendPos = Chart::Left; 2297 } 2298 else 2299 if( pos.compare(QLatin1String("t"), Qt::CaseInsensitive) == 0) 2300 { 2301 // legendPos = Chart::ChartAxisPos::Top; 2302 legendPos = Chart::Top; 2303 } 2304 else 2305 if( pos.compare(QLatin1String("b"), Qt::CaseInsensitive) == 0) 2306 { 2307 // legendPos = Chart::ChartAxisPos::Bottom; 2308 legendPos = Chart::Bottom; 2309 } 2310 else 2311 { 2312 // legendPos = Chart::ChartAxisPos::None; 2313 legendPos = Chart::None; 2314 } 2315 } 2316 else 2317 if (reader.name() == QLatin1String("overlay")) // c:legendPos 2318 { 2319 QString pos = reader.attributes().value(QLatin1String("val")).toString(); 2320 if( pos.compare(QLatin1String("1"), Qt::CaseInsensitive) == 0 ) 2321 { 2322 legendOverlay = true; 2323 } 2324 else 2325 { 2326 legendOverlay = false; 2327 } 2328 } 2329 } 2330 } 2331 2332 return false; 2333 } 2334 2335 QT_END_NAMESPACE_XLSX