1 // xlsxchart.cpp
2
3 #include <QtGlobal>
4 #include <QString>
5 #include <QIODevice>
6 #include <QXmlStreamReader>
7 #include <QXmlStreamWriter>
8 #include <QDebug>
9
10 #include "xlsxchart_p.h"
11 #include "xlsxworksheet.h"
12 #include "xlsxcellrange.h"
13 #include "xlsxutility_p.h"
14
15 QT_BEGIN_NAMESPACE_XLSX
16
ChartPrivate(Chart * q,Chart::CreateFlag flag)17 ChartPrivate::ChartPrivate(Chart *q, Chart::CreateFlag flag)
18 : AbstractOOXmlFilePrivate(q, flag), chartType(static_cast<Chart::ChartType>(0))
19 {
20
21 }
22
~ChartPrivate()23 ChartPrivate::~ChartPrivate()
24 {
25 }
26
27
28
29 /*!
30 * \internal
31 */
Chart(AbstractSheet * parent,CreateFlag flag)32 Chart::Chart(AbstractSheet *parent, CreateFlag flag)
33 : AbstractOOXmlFile(new ChartPrivate(this, flag))
34 {
35 Q_D(Chart);
36
37 d_func()->sheet = parent;
38
39 // d->legendPos = Chart::ChartAxisPos::None;
40 d->legendPos = Chart::None;
41 d->legendOverlay = false;
42 d->majorGridlinesEnabled = false;
43 d->minorGridlinesEnabled = false;
44 }
45
46 /*!
47 * Destroys the chart.
48 */
~Chart()49 Chart::~Chart()
50 {
51 }
52
53 /*!
54 * Add the data series which is in the range \a range of the \a sheet.
55 */
addSeries(const CellRange & range,AbstractSheet * sheet,bool headerH,bool headerV,bool swapHeaders)56 void Chart::addSeries(const CellRange &range, AbstractSheet *sheet, bool headerH, bool headerV, bool swapHeaders)
57 {
58 Q_D(Chart);
59
60 if (!range.isValid())
61 return;
62 if (sheet && sheet->sheetType() != AbstractSheet::ST_WorkSheet)
63 return;
64 if (!sheet && d->sheet->sheetType() != AbstractSheet::ST_WorkSheet)
65 return;
66
67 QString sheetName = sheet ? sheet->sheetName() : d->sheet->sheetName();
68 //In case sheetName contains space or '
69 sheetName = escapeSheetName(sheetName);
70
71 if (range.columnCount() == 1 || range.rowCount() == 1)
72 {
73 QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
74 series->numberDataSource_numRef = sheetName + QLatin1String("!") + range.toString(true, true);
75 d->seriesList.append(series);
76 }
77 else if ((range.columnCount() < range.rowCount()) || swapHeaders )
78 {
79 //Column based series
80 int firstDataRow = range.firstRow();
81 int firstDataColumn = range.firstColumn();
82
83 QString axDataSouruce_numRef;
84 if (d->chartType == CT_ScatterChart || d->chartType == CT_BubbleChart)
85 {
86 firstDataColumn += 1;
87 CellRange subRange(range.firstRow(), range.firstColumn(), range.lastRow(), range.firstColumn());
88 axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
89 }
90
91 if( headerH )
92 {
93 firstDataRow += 1;
94 }
95 if( headerV )
96 {
97 firstDataColumn += 1;
98 }
99
100 for (int col=firstDataColumn; col<=range.lastColumn(); ++col)
101 {
102 CellRange subRange(firstDataRow, col, range.lastRow(), col);
103 QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
104 series->axDataSource_numRef = axDataSouruce_numRef;
105 series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
106
107 if( headerH )
108 {
109 CellRange subRange(range.firstRow(), col, range.firstRow(), col);
110 series->headerH_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
111 }
112 else
113 {
114 series->headerH_numRef = QString();
115 }
116 if( headerV )
117 {
118 CellRange subRange(firstDataRow, range.firstColumn(), range.lastRow(), range.firstColumn());
119 series->headerV_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
120 }
121 else
122 {
123 series->headerV_numRef = QString();
124 }
125 series->swapHeader = swapHeaders;
126
127 d->seriesList.append(series);
128 }
129
130 }
131 else
132 {
133 //Row based series
134 int firstDataRow = range.firstRow();
135 int firstDataColumn = range.firstColumn();
136
137 QString axDataSouruce_numRef;
138 if (d->chartType == CT_ScatterChart || d->chartType == CT_BubbleChart)
139 {
140 firstDataRow += 1;
141 CellRange subRange(range.firstRow(), range.firstColumn(), range.firstRow(), range.lastColumn());
142 axDataSouruce_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
143 }
144
145 if( headerH )
146 {
147 firstDataRow += 1;
148 }
149 if( headerV )
150 {
151 firstDataColumn += 1;
152 }
153
154 for (int row=firstDataRow; row<=range.lastRow(); ++row)
155 {
156 CellRange subRange(row, firstDataColumn, row, range.lastColumn());
157 QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
158 series->axDataSource_numRef = axDataSouruce_numRef;
159 series->numberDataSource_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
160
161 if( headerH )
162 {
163 CellRange subRange(range.firstRow(), firstDataColumn, range.firstRow(), range.lastColumn());
164 series->headerH_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
165 }
166 else
167 {
168 series->headerH_numRef = QString();
169 }
170
171 if( headerV )
172 {
173 CellRange subRange(row, range.firstColumn(), row, range.firstColumn());
174 series->headerV_numRef = sheetName + QLatin1String("!") + subRange.toString(true, true);
175 }
176 else
177 {
178 series->headerV_numRef = QString();
179 }
180 series->swapHeader = swapHeaders;
181
182 d->seriesList.append(series);
183 }
184 }
185 }
186
187 /*!
188 * Set the type of the chart to \a type
189 */
setChartType(ChartType type)190 void Chart::setChartType(ChartType type)
191 {
192 Q_D(Chart);
193
194 d->chartType = type;
195 }
196
197 /*!
198 * \internal
199 *
200 */
setChartStyle(int id)201 void Chart::setChartStyle(int id)
202 {
203 Q_UNUSED(id)
204 //!Todo
205 }
206
setAxisTitle(Chart::ChartAxisPos pos,QString axisTitle)207 void Chart::setAxisTitle(Chart::ChartAxisPos pos, QString axisTitle)
208 {
209 Q_D(Chart);
210
211 if ( axisTitle.isEmpty() )
212 return;
213
214 // dev24 : fixed for old compiler
215 if ( pos == Chart::Left )
216 {
217 d->axisNames[ XlsxAxis::Left ] = axisTitle;
218 }
219 else if ( pos == Chart::Top )
220 {
221 d->axisNames[ XlsxAxis::Top ] = axisTitle;
222 }
223 else if ( pos == Chart::Right )
224 {
225 d->axisNames[ XlsxAxis::Right ] = axisTitle;
226 }
227 else if ( pos == Chart::Bottom )
228 {
229 d->axisNames[ XlsxAxis::Bottom ] = axisTitle;
230 }
231
232 }
233
234 // dev25
setChartTitle(QString strchartTitle)235 void Chart::setChartTitle(QString strchartTitle)
236 {
237 Q_D(Chart);
238
239 d->chartTitle = strchartTitle;
240 }
241
242
setChartLegend(Chart::ChartAxisPos legendPos,bool overlay)243 void Chart::setChartLegend(Chart::ChartAxisPos legendPos, bool overlay)
244 {
245 Q_D(Chart);
246
247 d->legendPos = legendPos;
248 d->legendOverlay = overlay;
249 }
250
251
setGridlinesEnable(bool majorGridlinesEnable,bool minorGridlinesEnable)252 void Chart::setGridlinesEnable(bool majorGridlinesEnable, bool minorGridlinesEnable)
253 {
254 Q_D(Chart);
255
256 d->majorGridlinesEnabled = majorGridlinesEnable;
257 d->minorGridlinesEnabled = minorGridlinesEnable;
258 }
259
260
261 /*!
262 * \internal
263 */
saveToXmlFile(QIODevice * device) const264 void Chart::saveToXmlFile(QIODevice *device) const
265 {
266 Q_D(const Chart);
267
268 /*
269 <chartSpace>
270 <chart>
271 <view3D>
272 <perspective val="30"/>
273 </view3D>
274 <plotArea>
275 <layout/>
276 <barChart>
277 ...
278 </barChart>
279 <catAx/>
280 <valAx/>
281 </plotArea>
282 <legend>
283 ...
284 </legend>
285 </chart>
286 <printSettings>
287 </printSettings>
288 </chartSpace>
289 */
290
291 QXmlStreamWriter writer(device);
292
293 writer.writeStartDocument(QStringLiteral("1.0"), true);
294
295 // L.4.13.2.2 Chart
296 //
297 // chartSpace is the root node, which contains an element defining the chart,
298 // and an element defining the print settings for the chart.
299
300 writer.writeStartElement(QStringLiteral("c:chartSpace"));
301
302 writer.writeAttribute(QStringLiteral("xmlns:c"),
303 QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/chart"));
304 writer.writeAttribute(QStringLiteral("xmlns:a"),
305 QStringLiteral("http://schemas.openxmlformats.org/drawingml/2006/main"));
306 writer.writeAttribute(QStringLiteral("xmlns:r"),
307 QStringLiteral("http://schemas.openxmlformats.org/officeDocument/2006/relationships"));
308
309 /*
310 * chart is the root element for the chart. If the chart is a 3D chart,
311 * then a view3D element is contained, which specifies the 3D view.
312 * It then has a plot area, which defines a layout and contains an element
313 * that corresponds to, and defines, the type of chart.
314 */
315
316 d->saveXmlChart(writer);
317
318 writer.writeEndElement();// c:chartSpace
319 writer.writeEndDocument();
320 }
321
322 /*!
323 * \internal
324 */
loadFromXmlFile(QIODevice * device)325 bool Chart::loadFromXmlFile(QIODevice *device)
326 {
327 Q_D(Chart);
328
329 QXmlStreamReader reader(device);
330 while (!reader.atEnd())
331 {
332 reader.readNextStartElement();
333 if (reader.tokenType() == QXmlStreamReader::StartElement)
334 {
335 if (reader.name() == QLatin1String("chart"))
336 {
337 if (!d->loadXmlChart(reader))
338 {
339 return false;
340 }
341 }
342 }
343 }
344
345 return true;
346 }
347
348
loadXmlChart(QXmlStreamReader & reader)349 bool ChartPrivate::loadXmlChart(QXmlStreamReader &reader)
350 {
351 Q_ASSERT(reader.name() == QLatin1String("chart"));
352
353 // qDebug() << "-------------- loadXmlChart";
354
355 while (!reader.atEnd())
356 {
357 reader.readNextStartElement();
358
359 // qDebug() << "-------------1- " << reader.name();
360
361 if (reader.tokenType() == QXmlStreamReader::StartElement)
362 {
363
364 if (reader.name() == QLatin1String("plotArea"))
365 {
366 if (!loadXmlPlotArea(reader))
367 {
368 return false;
369 }
370 }
371 else if (reader.name() == QLatin1String("title"))
372 {
373 //!Todo
374
375 if ( loadXmlChartTitle(reader) )
376 {
377 }
378
379 }
380 // else if (reader.name() == QLatin1String("legend"))
381 // {
382 // loadXmlChartLegend(reader);
383 // qDebug() << "-------------- loadXmlChartLegend";
384 // }
385 }
386 else if (reader.tokenType() == QXmlStreamReader::EndElement &&
387 reader.name() == QLatin1String("chart") )
388 {
389 break;
390 }
391 }
392 return true;
393 }
394
395 // TO DEBUG: loop is not work, when i looping second element.
396 /*
397 dchrt_CT_PlotArea =
398 element layout { dchrt_CT_Layout }?,
399 (element areaChart { dchrt_CT_AreaChart }
400 | element area3DChart { dchrt_ CT_Area3DChart }
401 | element lineChart { dchrt_CT_LineChart }
402 | element line3DChart { dchrt_CT_Line3DChart }
403 | element stockChart { dchrt_CT_StockChart }
404 | element radarChart { dchrt_CT_RadarChart }
405 | element scatterChart { dchrt_CT_ScatterChart }
406 | element pieChart { dchrt_CT_PieChart }
407 | element pie3DChart { dchrt_CT_Pie3DChart }
408 | element doughnutChart { dchrt_CT_DoughnutChart }
409 | element barChart { dchrt_CT_BarChart }
410 | element bar3DChart { dchrt_CT_Bar3DChart }
411 | element ofPieChart { dchrt_CT_OfPieChart }
412 | element surfaceChart { dchrt_CT_SurfaceChart }
413 | element surface3DChart { dchrt_CT_Surface3DChart }
414 | element bubbleChart { dchrt_CT_BubbleChart })+,
415 (element valAx { dchrt_CT_ValAx }
416 | element catAx { dchrt_CT_CatAx }
417 | element dateAx { dchrt_CT_DateAx }
418 | element serAx { dchrt_CT_SerAx })*,
419 element dTable { dchrt_CT_DTable }?,
420 element spPr { a_CT_ShapeProperties }?,
421 element extLst { dchrt_CT_ExtensionList }?
422 */
loadXmlPlotArea(QXmlStreamReader & reader)423 bool ChartPrivate::loadXmlPlotArea(QXmlStreamReader &reader)
424 {
425 Q_ASSERT(reader.name() == QLatin1String("plotArea"));
426
427 // TO DEBUG:
428
429 reader.readNext();
430
431 while (!reader.atEnd())
432 {
433 // qDebug() << "-------------2- " << reader.name();
434
435 if (reader.isStartElement())
436 {
437 if (!loadXmlPlotAreaElement(reader))
438 {
439 qDebug() << "[debug] failed to load plotarea element.";
440 return false;
441 }
442 else if (reader.name() == QLatin1String("legend")) // Why here?
443 {
444 loadXmlChartLegend(reader);
445 // qDebug() << "-------------- loadXmlChartLegend";
446 }
447
448 reader.readNext();
449 }
450 else
451 {
452 reader.readNext();
453 }
454 }
455
456 return true;
457 }
458
loadXmlPlotAreaElement(QXmlStreamReader & reader)459 bool ChartPrivate::loadXmlPlotAreaElement(QXmlStreamReader &reader)
460 {
461 if (reader.name() == QLatin1String("layout"))
462 {
463 //!ToDo extract attributes
464 layout = readSubTree(reader);
465 }
466 else if (reader.name().endsWith(QLatin1String("Chart")))
467 {
468 // for pieChart, barChart, ... (choose one)
469 if ( !loadXmlXxxChart(reader) )
470 {
471 qDebug() << "[debug] failed to load chart";
472 return false;
473 }
474 }
475 else if (reader.name() == QLatin1String("catAx")) // choose one : catAx, dateAx, serAx, valAx
476 {
477 // qDebug() << "loadXmlAxisCatAx()";
478 loadXmlAxisCatAx(reader);
479 }
480 else if (reader.name() == QLatin1String("dateAx")) // choose one : catAx, dateAx, serAx, valAx
481 {
482 // qDebug() << "loadXmlAxisDateAx()";
483 loadXmlAxisDateAx(reader);
484 }
485 else if (reader.name() == QLatin1String("serAx")) // choose one : catAx, dateAx, serAx, valAx
486 {
487 // qDebug() << "loadXmlAxisSerAx()";
488 loadXmlAxisSerAx(reader);
489 }
490 else if (reader.name() == QLatin1String("valAx")) // choose one : catAx, dateAx, serAx, valAx
491 {
492 // qDebug() << "loadXmlAxisValAx()";
493 loadXmlAxisValAx(reader);
494 }
495 else if (reader.name() == QLatin1String("dTable"))
496 {
497 //!ToDo
498 // dTable "CT_DTable"
499 // reader.skipCurrentElement();
500 }
501 else if (reader.name() == QLatin1String("spPr"))
502 {
503 //!ToDo
504 // spPr "a:CT_ShapeProperties"
505 // reader.skipCurrentElement();
506 }
507 else if (reader.name() == QLatin1String("extLst"))
508 {
509 //!ToDo
510 // extLst "CT_ExtensionList"
511 // reader.skipCurrentElement();
512 }
513
514 return true;
515 }
516
loadXmlXxxChart(QXmlStreamReader & reader)517 bool ChartPrivate::loadXmlXxxChart(QXmlStreamReader &reader)
518 {
519 const auto& name = reader.name();
520
521 if (name == QLatin1String("areaChart"))
522 {
523 chartType = Chart::CT_AreaChart;
524 }
525 else if (name == QLatin1String("area3DChart"))
526 {
527 chartType = Chart::CT_Area3DChart;
528 }
529 else if (name == QLatin1String("lineChart"))
530 {
531 chartType = Chart::CT_LineChart;
532 }
533 else if (name == QLatin1String("line3DChart"))
534 {
535 chartType = Chart::CT_Line3DChart;
536 }
537 else if (name == QLatin1String("stockChart"))
538 {
539 chartType = Chart::CT_StockChart;
540 }
541 else if (name == QLatin1String("radarChart"))
542 {
543 chartType = Chart::CT_RadarChart;
544 }
545 else if (name == QLatin1String("scatterChart"))
546 {
547 chartType = Chart::CT_ScatterChart;
548 }
549 else if (name == QLatin1String("pieChart"))
550 {
551 chartType = Chart::CT_PieChart;
552 }
553 else if (name == QLatin1String("pie3DChart"))
554 {
555 chartType = Chart::CT_Pie3DChart;
556 }
557 else if (name == QLatin1String("doughnutChart"))
558 {
559 chartType = Chart::CT_DoughnutChart;
560 }
561 else if (name == QLatin1String("barChart"))
562 {
563 chartType = Chart::CT_BarChart;
564 }
565 else if (name == QLatin1String("bar3DChart"))
566 {
567 chartType = Chart::CT_Bar3DChart;
568 }
569 else if (name == QLatin1String("ofPieChart"))
570 {
571 chartType = Chart::CT_OfPieChart;
572 }
573 else if (name == QLatin1String("surfaceChart"))
574 {
575 chartType = Chart::CT_SurfaceChart;
576 }
577 else if (name == QLatin1String("surface3DChart"))
578 {
579 chartType = Chart::CT_Surface3DChart;
580 }
581 else if (name == QLatin1String("bubbleChart"))
582 {
583 chartType = Chart::CT_BubbleChart;
584 }
585 else
586 {
587 qDebug() << "[undefined chart type] " << name;
588 chartType = Chart::CT_NoStatementChart;
589 return false;
590 }
591
592 while( !reader.atEnd() )
593 {
594 reader.readNextStartElement();
595 if (reader.tokenType() == QXmlStreamReader::StartElement)
596 {
597 // dev57
598
599 if ( reader.name() == QLatin1String("ser") )
600 {
601 loadXmlSer(reader);
602 }
603 else if (reader.name() == QLatin1String("varyColors"))
604 {
605 }
606 else if (reader.name() == QLatin1String("barDir"))
607 {
608 }
609 else if (reader.name() == QLatin1String("axId"))
610 {
611 //
612
613 }
614 else if (reader.name() == QLatin1String("scatterStyle"))
615 {
616 }
617 else if (reader.name() == QLatin1String("holeSize"))
618 {
619 }
620 else
621 {
622 }
623
624 }
625 else if ( reader.tokenType() == QXmlStreamReader::EndElement &&
626 reader.name() == name )
627 {
628 break;
629 }
630 }
631
632 return true;
633 }
634
loadXmlSer(QXmlStreamReader & reader)635 bool ChartPrivate::loadXmlSer(QXmlStreamReader &reader)
636 {
637 Q_ASSERT(reader.name() == QLatin1String("ser"));
638
639 QSharedPointer<XlsxSeries> series = QSharedPointer<XlsxSeries>(new XlsxSeries);
640 seriesList.append(series);
641
642 while ( !reader.atEnd() &&
643 !(reader.tokenType() == QXmlStreamReader::EndElement &&
644 reader.name() == QLatin1String("ser")) )
645 {
646 if (reader.readNextStartElement())
647 {
648 //TODO beide Header noch auswerten RTR 2019.11
649 const auto& name = reader.name();
650 if ( name == QLatin1String("tx") )
651 {
652 while ( !reader.atEnd() &&
653 !(reader.tokenType() == QXmlStreamReader::EndElement &&
654 reader.name() == name))
655 {
656 if (reader.readNextStartElement())
657 {
658 if (reader.name() == QLatin1String("strRef"))
659 series->headerV_numRef = loadXmlStrRef(reader);
660 }
661 }
662 }
663 else if ( name == QLatin1String("cat") ||
664 name == QLatin1String("xVal") )
665 {
666 while ( !reader.atEnd() &&
667 !(reader.tokenType() == QXmlStreamReader::EndElement &&
668 reader.name() == name))
669 {
670 if (reader.readNextStartElement())
671 {
672 if (reader.name() == QLatin1String("numRef"))
673 series->axDataSource_numRef = loadXmlNumRef(reader);
674 else
675 if (reader.name() == QLatin1String("strRef"))
676 series->headerH_numRef = loadXmlStrRef(reader);
677 }
678 }
679 }
680 else if (name == QLatin1String("val") || name == QLatin1String("yVal"))
681 {
682 while ( !reader.atEnd() &&
683 !(reader.tokenType() == QXmlStreamReader::EndElement &&
684 reader.name() == name))
685 {
686 if (reader.readNextStartElement())
687 {
688 if (reader.name() == QLatin1String("numRef"))
689 series->numberDataSource_numRef = loadXmlNumRef(reader);
690 }
691 }
692 }
693 else if (name == QLatin1String("extLst"))
694 {
695 while ( !reader.atEnd() &&
696 !(reader.tokenType() == QXmlStreamReader::EndElement &&
697 reader.name() == name))
698 {
699 reader.readNextStartElement();
700 }
701 }
702 }
703 }
704
705 return true;
706 }
707
708
loadXmlNumRef(QXmlStreamReader & reader)709 QString ChartPrivate::loadXmlNumRef(QXmlStreamReader &reader)
710 {
711 Q_ASSERT(reader.name() == QLatin1String("numRef"));
712
713 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
714 && reader.name() == QLatin1String("numRef")))
715 {
716 if (reader.readNextStartElement())
717 {
718 if (reader.name() == QLatin1String("f"))
719 return reader.readElementText();
720 }
721 }
722
723 return QString();
724 }
725
726
loadXmlStrRef(QXmlStreamReader & reader)727 QString ChartPrivate::loadXmlStrRef(QXmlStreamReader &reader)
728 {
729 Q_ASSERT(reader.name() == QLatin1String("strRef"));
730
731 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
732 && reader.name() == QLatin1String("strRef")))
733 {
734 if (reader.readNextStartElement())
735 {
736 if (reader.name() == QLatin1String("f"))
737 return reader.readElementText();
738 }
739 }
740
741 return QString();
742 }
743
744
saveXmlChart(QXmlStreamWriter & writer) const745 void ChartPrivate::saveXmlChart(QXmlStreamWriter &writer) const
746 {
747 //----------------------------------------------------
748 // c:chart
749 writer.writeStartElement(QStringLiteral("c:chart"));
750
751 //----------------------------------------------------
752 // c:title
753
754 saveXmlChartTitle(writer); // write 'chart title'
755
756 //----------------------------------------------------
757 // c:plotArea
758
759 writer.writeStartElement(QStringLiteral("c:plotArea"));
760
761 // a little workaround for Start- and EndElement with starting ">" and ending without ">"
762 writer.device()->write("><c:layout>"); //layout
763 writer.device()->write(layout.toUtf8());
764 writer.device()->write("</c:layout"); //layout
765
766 // dev35
767 switch (chartType)
768 {
769 case Chart::CT_AreaChart: saveXmlAreaChart(writer); break;
770 case Chart::CT_Area3DChart: saveXmlAreaChart(writer); break;
771 case Chart::CT_LineChart: saveXmlLineChart(writer); break;
772 case Chart::CT_Line3DChart: saveXmlLineChart(writer); break;
773 case Chart::CT_StockChart: break;
774 case Chart::CT_RadarChart: break;
775 case Chart::CT_ScatterChart: saveXmlScatterChart(writer); break;
776 case Chart::CT_PieChart: saveXmlPieChart(writer); break;
777 case Chart::CT_Pie3DChart: saveXmlPieChart(writer); break;
778 case Chart::CT_DoughnutChart: saveXmlDoughnutChart(writer); break;
779 case Chart::CT_BarChart: saveXmlBarChart(writer); break;
780 case Chart::CT_Bar3DChart: saveXmlBarChart(writer); break;
781 case Chart::CT_OfPieChart: break;
782 case Chart::CT_SurfaceChart: break;
783 case Chart::CT_Surface3DChart: break;
784 case Chart::CT_BubbleChart: break;
785 default: break;
786 }
787
788 saveXmlAxis(writer); // c:catAx, c:valAx, c:serAx, c:dateAx (choose one)
789
790 //!TODO: write element
791 // c:dTable CT_DTable
792 // c:spPr CT_ShapeProperties
793 // c:extLst CT_ExtensionList
794
795 writer.writeEndElement(); // c:plotArea
796
797 // c:legend
798 saveXmlChartLegend(writer); // c:legend
799
800 writer.writeEndElement(); // c:chart
801 }
802
loadXmlChartTitle(QXmlStreamReader & reader)803 bool ChartPrivate::loadXmlChartTitle(QXmlStreamReader &reader)
804 {
805 //!TODO : load chart title
806
807 Q_ASSERT(reader.name() == QLatin1String("title"));
808
809 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
810 && reader.name() == QLatin1String("title")))
811 {
812 if (reader.readNextStartElement())
813 {
814 if (reader.name() == QLatin1String("tx")) // c:tx
815 return loadXmlChartTitleTx(reader);
816 }
817 }
818
819 return false;
820 }
821
loadXmlChartTitleTx(QXmlStreamReader & reader)822 bool ChartPrivate::loadXmlChartTitleTx(QXmlStreamReader &reader)
823 {
824 Q_ASSERT(reader.name() == QLatin1String("tx"));
825
826 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
827 && reader.name() == QLatin1String("tx")))
828 {
829 if (reader.readNextStartElement())
830 {
831 if (reader.name() == QLatin1String("rich")) // c:rich
832 return loadXmlChartTitleTxRich(reader);
833 }
834 }
835
836 return false;
837 }
838
loadXmlChartTitleTxRich(QXmlStreamReader & reader)839 bool ChartPrivate::loadXmlChartTitleTxRich(QXmlStreamReader &reader)
840 {
841 Q_ASSERT(reader.name() == QLatin1String("rich"));
842
843 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
844 && reader.name() == QLatin1String("rich")))
845 {
846 if (reader.readNextStartElement())
847 {
848 if (reader.name() == QLatin1String("p")) // a:p
849 return loadXmlChartTitleTxRichP(reader);
850 }
851 }
852
853 return false;
854 }
855
loadXmlChartTitleTxRichP(QXmlStreamReader & reader)856 bool ChartPrivate::loadXmlChartTitleTxRichP(QXmlStreamReader &reader)
857 {
858 Q_ASSERT(reader.name() == QLatin1String("p"));
859
860 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
861 && reader.name() == QLatin1String("p")))
862 {
863 if (reader.readNextStartElement())
864 {
865 if (reader.name() == QLatin1String("r")) // a:r
866 return loadXmlChartTitleTxRichP_R(reader);
867 }
868 }
869
870 return false;
871 }
872
loadXmlChartTitleTxRichP_R(QXmlStreamReader & reader)873 bool ChartPrivate::loadXmlChartTitleTxRichP_R(QXmlStreamReader &reader)
874 {
875 Q_ASSERT(reader.name() == QLatin1String("r"));
876
877 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
878 && reader.name() == QLatin1String("r")))
879 {
880 if (reader.readNextStartElement())
881 {
882 if (reader.name() == QLatin1String("t")) // a:t
883 {
884 QString textValue = reader.readElementText();
885 this->chartTitle = textValue;
886 return true;
887 }
888 }
889 }
890
891 return false;
892 }
893
894
895 // write 'chart title'
saveXmlChartTitle(QXmlStreamWriter & writer) const896 void ChartPrivate::saveXmlChartTitle(QXmlStreamWriter &writer) const
897 {
898 if ( chartTitle.isEmpty() )
899 return;
900
901 writer.writeStartElement(QStringLiteral("c:title"));
902 /*
903 <xsd:complexType name="CT_Title">
904 <xsd:sequence>
905 <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/>
906 <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/>
907 <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
908 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/>
909 <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
910 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
911 </xsd:sequence>
912 </xsd:complexType>
913 */
914
915 writer.writeStartElement(QStringLiteral("c:tx"));
916 /*
917 <xsd:complexType name="CT_Tx">
918 <xsd:sequence>
919 <xsd:choice minOccurs="1" maxOccurs="1">
920 <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/>
921 <xsd:element name="rich" type="a:CT_TextBody" minOccurs="1" maxOccurs="1"/>
922 </xsd:choice>
923 </xsd:sequence>
924 </xsd:complexType>
925 */
926
927 writer.writeStartElement(QStringLiteral("c:rich"));
928 /*
929 <xsd:complexType name="CT_TextBody">
930 <xsd:sequence>
931 <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs=" 1" maxOccurs="1"/>
932 <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/>
933 <xsd:element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/>
934 </xsd:sequence>
935 </xsd:complexType>
936 */
937
938 writer.writeEmptyElement(QStringLiteral("a:bodyPr")); // <a:bodyPr/>
939 /*
940 <xsd:complexType name="CT_TextBodyProperties">
941 <xsd:sequence>
942 <xsd:element name="prstTxWarp" type="CT_PresetTextShape" minOccurs="0" maxOccurs="1"/>
943 <xsd:group ref="EG_TextAutofit" minOccurs="0" maxOccurs="1"/>
944 <xsd:element name="scene3d" type="CT_Scene3D" minOccurs="0" maxOccurs="1"/>
945 <xsd:group ref="EG_Text3D" minOccurs="0" maxOccurs="1"/>
946 <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
947 </xsd:sequence>
948 <xsd:attribute name="rot" type="ST_Angle" use="optional"/>
949 <xsd:attribute name="spcFirstLastPara" type="xsd:boolean" use="optional"/>
950 <xsd:attribute name="vertOverflow" type="ST_TextVertOverflowType" use="optional"/>
951 <xsd:attribute name="horzOverflow" type="ST_TextHorzOverflowType" use="optional"/>
952 <xsd:attribute name="vert" type="ST_TextVerticalType" use="optional"/>
953 <xsd:attribute name="wrap" type="ST_TextWrappingType" use="optional"/>
954 <xsd:attribute name="lIns" type="ST_Coordinate32" use="optional"/>
955 <xsd:attribute name="tIns" type="ST_Coordinate32" use="optional"/>
956 <xsd:attribute name="rIns" type="ST_Coordinate32" use="optional"/>
957 <xsd:attribute name="bIns" type="ST_Coordinate32" use="optional"/>
958 <xsd:attribute name="numCol" type="ST_TextColumnCount" use="optional"/>
959 <xsd:attribute name="spcCol" type="ST_PositiveCoordinate32" use="optional"/>
960 <xsd:attribute name="rtlCol" type="xsd:boolean" use="optional"/>
961 <xsd:attribute name="fromWordArt" type="xsd:boolean" use="optional"/>
962 <xsd:attribute name="anchor" type="ST_TextAnchoringType" use="optional"/>
963 <xsd:attribute name="anchorCtr" type="xsd:boolean" use="optional"/>
964 <xsd:attribute name="forceAA" type="xsd:boolean" use="optional"/>
965 <xsd:attribute name="upright" type="xsd:boolean" use="optional" default="false"/>
966 <xsd:attribute name="compatLnSpc" type="xsd:boolean" use="optional"/>
967 </xsd:complexType>
968 */
969
970 writer.writeEmptyElement(QStringLiteral("a:lstStyle")); // <a:lstStyle/>
971
972 writer.writeStartElement(QStringLiteral("a:p"));
973 /*
974 <xsd:complexType name="CT_TextParagraph">
975 <xsd:sequence>
976 <xsd:element name="pPr" type="CT_TextParagraphProperties" minOccurs="0" maxOccurs="1"/>
977 <xsd:group ref="EG_TextRun" minOccurs="0" maxOccurs="unbounded"/>
978 <xsd:element name="endParaRPr" type="CT_TextCharacterProperties" minOccurs="0"
979 maxOccurs="1"/>
980 </xsd:sequence>
981 </xsd:complexType>
982 */
983
984 // <a:pPr lvl="0">
985 writer.writeStartElement(QStringLiteral("a:pPr"));
986
987 writer.writeAttribute(QStringLiteral("lvl"), QStringLiteral("0"));
988
989 // <a:defRPr b="0"/>
990 writer.writeStartElement(QStringLiteral("a:defRPr"));
991
992 writer.writeAttribute(QStringLiteral("b"), QStringLiteral("0"));
993
994 writer.writeEndElement(); // a:defRPr
995
996 writer.writeEndElement(); // a:pPr
997
998 /*
999 <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'
saveXmlChartLegend(QXmlStreamWriter & writer) const1040 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
saveXmlPieChart(QXmlStreamWriter & writer) const1103 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].data(), i);
1115
1116 writer.writeEndElement(); //pieChart, pie3DChart
1117 }
1118
saveXmlBarChart(QXmlStreamWriter & writer) const1119 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].data(), i);
1131 }
1132
1133 if ( axisList.isEmpty() )
1134 {
1135 const_cast<ChartPrivate*>(this)->axisList.append(
1136 QSharedPointer<XlsxAxis>(
1137 new XlsxAxis( XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1, axisNames[XlsxAxis::Bottom] )));
1138
1139 const_cast<ChartPrivate*>(this)->axisList.append(
1140 QSharedPointer<XlsxAxis>(
1141 new XlsxAxis( XlsxAxis::T_Val, XlsxAxis::Left, 1, 0, axisNames[XlsxAxis::Left] )));
1142 }
1143
1144
1145 // Note: Bar3D have 2~3 axes
1146 // int axisListSize = axisList.size();
1147 // [dev62]
1148 // Q_ASSERT( axisListSize == 2 ||
1149 // ( axisListSize == 3 && chartType == Chart::CT_Bar3DChart ) );
1150
1151 for ( int i = 0 ; i < axisList.size() ; ++i )
1152 {
1153 writer.writeEmptyElement(QStringLiteral("c:axId"));
1154 writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
1155 }
1156
1157 writer.writeEndElement(); //barChart, bar3DChart
1158 }
1159
saveXmlLineChart(QXmlStreamWriter & writer) const1160 void ChartPrivate::saveXmlLineChart(QXmlStreamWriter &writer) const
1161 {
1162 QString name = chartType==Chart::CT_LineChart ? QStringLiteral("c:lineChart") : QStringLiteral("c:line3DChart");
1163
1164 writer.writeStartElement(name);
1165
1166 // writer.writeEmptyElement(QStringLiteral("grouping")); // dev22
1167
1168 for (int i=0; i<seriesList.size(); ++i)
1169 saveXmlSer(writer, seriesList[i].data(), i);
1170
1171 if (axisList.isEmpty())
1172 {
1173 const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1, axisNames[XlsxAxis::Bottom] )));
1174 const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0, axisNames[XlsxAxis::Left] )));
1175 if (chartType==Chart::CT_Line3DChart)
1176 const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Ser, XlsxAxis::Bottom, 2, 0)));
1177 }
1178
1179 Q_ASSERT((axisList.size()==2||chartType==Chart::CT_LineChart)|| (axisList.size()==3 && chartType==Chart::CT_Line3DChart));
1180
1181 for (int i=0; i<axisList.size(); ++i)
1182 {
1183 writer.writeEmptyElement(QStringLiteral("c:axId"));
1184 writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
1185 }
1186
1187 writer.writeEndElement(); //lineChart, line3DChart
1188 }
1189
saveXmlScatterChart(QXmlStreamWriter & writer) const1190 void ChartPrivate::saveXmlScatterChart(QXmlStreamWriter &writer) const
1191 {
1192 const QString name = QStringLiteral("c:scatterChart");
1193
1194 writer.writeStartElement(name);
1195
1196 writer.writeEmptyElement(QStringLiteral("c:scatterStyle"));
1197
1198 for (int i=0; i<seriesList.size(); ++i)
1199 saveXmlSer(writer, seriesList[i].data(), i);
1200
1201 if (axisList.isEmpty())
1202 {
1203 const_cast<ChartPrivate*>(this)->axisList.append(
1204 QSharedPointer<XlsxAxis>(
1205 new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Bottom, 0, 1, axisNames[XlsxAxis::Bottom] )));
1206 const_cast<ChartPrivate*>(this)->axisList.append(
1207 QSharedPointer<XlsxAxis>(
1208 new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0, axisNames[XlsxAxis::Left] )));
1209 }
1210
1211 int axisListSize = axisList.size();
1212 Q_ASSERT(axisListSize == 2);
1213
1214 for (int i=0; i<axisList.size(); ++i)
1215 {
1216 writer.writeEmptyElement(QStringLiteral("c:axId"));
1217 writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
1218 }
1219
1220 writer.writeEndElement(); //c:scatterChart
1221 }
1222
saveXmlAreaChart(QXmlStreamWriter & writer) const1223 void ChartPrivate::saveXmlAreaChart(QXmlStreamWriter &writer) const
1224 {
1225 QString name = chartType==Chart::CT_AreaChart ? QStringLiteral("c:areaChart") : QStringLiteral("c:area3DChart");
1226
1227 writer.writeStartElement(name);
1228
1229 // writer.writeEmptyElement(QStringLiteral("grouping")); // dev22
1230
1231 for (int i=0; i<seriesList.size(); ++i)
1232 saveXmlSer(writer, seriesList[i].data(), i);
1233
1234 if (axisList.isEmpty())
1235 {
1236 const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Cat, XlsxAxis::Bottom, 0, 1)));
1237 const_cast<ChartPrivate*>(this)->axisList.append(QSharedPointer<XlsxAxis>(new XlsxAxis(XlsxAxis::T_Val, XlsxAxis::Left, 1, 0)));
1238 }
1239
1240 //Note: Area3D have 2~3 axes
1241 Q_ASSERT(axisList.size()==2 || (axisList.size()==3 && chartType==Chart::CT_Area3DChart));
1242
1243 for (int i=0; i<axisList.size(); ++i)
1244 {
1245 writer.writeEmptyElement(QStringLiteral("c:axId"));
1246 writer.writeAttribute(QStringLiteral("val"), QString::number(axisList[i]->axisId));
1247 }
1248
1249 writer.writeEndElement(); //lineChart, line3DChart
1250 }
1251
saveXmlDoughnutChart(QXmlStreamWriter & writer) const1252 void ChartPrivate::saveXmlDoughnutChart(QXmlStreamWriter &writer) const
1253 {
1254 QString name = QStringLiteral("c:doughnutChart");
1255
1256 writer.writeStartElement(name);
1257
1258 writer.writeEmptyElement(QStringLiteral("c:varyColors"));
1259 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("1"));
1260
1261 for (int i=0; i<seriesList.size(); ++i)
1262 saveXmlSer(writer, seriesList[i].data(), i);
1263
1264 writer.writeStartElement(QStringLiteral("c:holeSize"));
1265 writer.writeAttribute(QStringLiteral("val"), QString::number(50));
1266
1267 writer.writeEndElement();
1268 }
1269
saveXmlSer(QXmlStreamWriter & writer,XlsxSeries * ser,int id) const1270 void ChartPrivate::saveXmlSer(QXmlStreamWriter &writer, XlsxSeries *ser, int id) const
1271 {
1272
1273 writer.writeStartElement(QStringLiteral("c:ser"));
1274 writer.writeEmptyElement(QStringLiteral("c:idx"));
1275 writer.writeAttribute(QStringLiteral("val"), QString::number(id));
1276 writer.writeEmptyElement(QStringLiteral("c:order"));
1277 writer.writeAttribute(QStringLiteral("val"), QString::number(id));
1278
1279 QString header1;
1280 QString header2;
1281 if( ser->swapHeader )
1282 {
1283 header1 = ser->headerH_numRef;
1284 header2 = ser->headerV_numRef;
1285 }
1286 else
1287 {
1288 header1 = ser->headerV_numRef;
1289 header2 = ser->headerH_numRef;
1290 }
1291
1292 if( !header1.isEmpty() )
1293 {
1294 writer.writeStartElement(QStringLiteral("c:tx"));
1295 writer.writeStartElement(QStringLiteral("c:strRef"));
1296 writer.writeTextElement(QStringLiteral("c:f"), header1);
1297 writer.writeEndElement();
1298 writer.writeEndElement();
1299 }
1300 if( !header2.isEmpty() )
1301 {
1302 writer.writeStartElement(QStringLiteral("c:cat"));
1303 writer.writeStartElement(QStringLiteral("c:strRef"));
1304 writer.writeTextElement(QStringLiteral("c:f"), header2);
1305 writer.writeEndElement();
1306 writer.writeEndElement();
1307 }
1308
1309 #if 0
1310 if (!ser->axDataSource_numRef.isEmpty())
1311 {
1312 if (chartType == Chart::CT_ScatterChart || chartType == Chart::CT_BubbleChart)
1313 {
1314 writer.writeStartElement(QStringLiteral("c:xVal"));
1315 }
1316 else
1317 {
1318 writer.writeStartElement(QStringLiteral("c:cat"));
1319 }
1320
1321 writer.writeStartElement(QStringLiteral("c:numRef"));
1322 writer.writeTextElement(QStringLiteral("c:f"), ser->axDataSource_numRef);
1323 writer.writeEndElement();//c:numRef
1324 writer.writeEndElement();//c:cat or c:xVal
1325 }
1326 #endif
1327
1328 if (!ser->numberDataSource_numRef.isEmpty())
1329 {
1330 if (chartType == Chart::CT_ScatterChart || chartType == Chart::CT_BubbleChart)
1331 writer.writeStartElement(QStringLiteral("c:yVal"));
1332 else
1333 writer.writeStartElement(QStringLiteral("c:val"));
1334 writer.writeStartElement(QStringLiteral("c:numRef"));
1335 writer.writeTextElement(QStringLiteral("c:f"), ser->numberDataSource_numRef);
1336 writer.writeEndElement();//c:numRef
1337 writer.writeEndElement();//c:val or c:yVal
1338 }
1339
1340 writer.writeEndElement();//c:ser
1341 }
1342
loadXmlAxisCatAx(QXmlStreamReader & reader)1343 bool ChartPrivate::loadXmlAxisCatAx(QXmlStreamReader &reader)
1344 {
1345
1346 XlsxAxis* axis = new XlsxAxis();
1347 axis->type = XlsxAxis::T_Cat;
1348 axisList.append( QSharedPointer<XlsxAxis>(axis) );
1349
1350 // load EG_AxShared
1351 if ( ! loadXmlAxisEG_AxShared( reader, axis ) )
1352 {
1353 qDebug() << "failed to load EG_AxShared";
1354 return false;
1355 }
1356
1357 //!TODO: load element
1358 // auto
1359 // lblAlgn
1360 // lblOffset
1361 // tickLblSkip
1362 // tickMarkSkip
1363 // noMultiLvlLbl
1364 // extLst
1365
1366 return true;
1367 }
1368
loadXmlAxisDateAx(QXmlStreamReader & reader)1369 bool ChartPrivate::loadXmlAxisDateAx(QXmlStreamReader &reader)
1370 {
1371
1372 XlsxAxis* axis = new XlsxAxis();
1373 axis->type = XlsxAxis::T_Date;
1374 axisList.append( QSharedPointer<XlsxAxis>(axis) );
1375
1376 // load EG_AxShared
1377 if ( ! loadXmlAxisEG_AxShared( reader, axis ) )
1378 {
1379 qDebug() << "failed to load EG_AxShared";
1380 return false;
1381 }
1382
1383 //!TODO: load element
1384 // auto
1385 // lblOffset
1386 // baseTimeUnit
1387 // majorUnit
1388 // majorTimeUnit
1389 // minorUnit
1390 // minorTimeUnit
1391 // extLst
1392
1393 return true;
1394 }
1395
loadXmlAxisSerAx(QXmlStreamReader & reader)1396 bool ChartPrivate::loadXmlAxisSerAx(QXmlStreamReader &reader)
1397 {
1398
1399 XlsxAxis* axis = new XlsxAxis();
1400 axis->type = XlsxAxis::T_Ser;
1401 axisList.append( QSharedPointer<XlsxAxis>(axis) );
1402
1403 // load EG_AxShared
1404 if ( ! loadXmlAxisEG_AxShared( reader, axis ) )
1405 {
1406 qDebug() << "failed to load EG_AxShared";
1407 return false;
1408 }
1409
1410 //!TODO: load element
1411 // tickLblSkip
1412 // tickMarkSkip
1413 // extLst
1414
1415 return true;
1416 }
1417
loadXmlAxisValAx(QXmlStreamReader & reader)1418 bool ChartPrivate::loadXmlAxisValAx(QXmlStreamReader &reader)
1419 {
1420 Q_ASSERT(reader.name() == QLatin1String("valAx"));
1421
1422 XlsxAxis* axis = new XlsxAxis();
1423 axis->type = XlsxAxis::T_Val;
1424 axisList.append( QSharedPointer<XlsxAxis>(axis) );
1425
1426 if ( ! loadXmlAxisEG_AxShared( reader, axis ) )
1427 {
1428 qDebug() << "failed to load EG_AxShared";
1429 return false;
1430 }
1431
1432 //!TODO: load element
1433 // crossBetween
1434 // majorUnit
1435 // minorUnit
1436 // dispUnits
1437 // extLst
1438
1439 return true;
1440 }
1441
1442 /*
1443 <xsd:group name="EG_AxShared">
1444 <xsd:sequence>
1445 <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*)(M)
1446 <xsd:element name="scaling" type="CT_Scaling" minOccurs="1" maxOccurs="1"/> (*)(M)
1447 <xsd:element name="delete" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
1448 <xsd:element name="axPos" type="CT_AxPos" minOccurs="1" maxOccurs="1"/> (*)(M)
1449 <xsd:element name="majorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/>
1450 <xsd:element name="minorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/>
1451 <xsd:element name="title" type="CT_Title" minOccurs="0" maxOccurs="1"/> (*)
1452 <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="1"/>
1453 <xsd:element name="majorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/>
1454 <xsd:element name="minorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/>
1455 <xsd:element name="tickLblPos" type="CT_TickLblPos" minOccurs="0" maxOccurs="1"/>
1456 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/>
1457 <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
1458 <xsd:element name="crossAx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*)(M)
1459 <xsd:choice minOccurs="0" maxOccurs="1">
1460 <xsd:element name="crosses" type="CT_Crosses" minOccurs="1" maxOccurs="1"/>
1461 <xsd:element name="crossesAt" type="CT_Double" minOccurs="1" maxOccurs="1"/>
1462 </xsd:choice>
1463 </xsd:sequence>
1464 </xsd:group>
1465 */
loadXmlAxisEG_AxShared(QXmlStreamReader & reader,XlsxAxis * axis)1466 bool ChartPrivate::loadXmlAxisEG_AxShared(QXmlStreamReader &reader, XlsxAxis* axis)
1467 {
1468 Q_ASSERT( NULL != axis );
1469 Q_ASSERT( reader.name().endsWith(QLatin1String("Ax")) );
1470 QString name = reader.name().toString(); //
1471
1472 while ( !reader.atEnd() )
1473 {
1474 reader.readNextStartElement();
1475 if ( reader.tokenType() == QXmlStreamReader::StartElement )
1476 {
1477 // qDebug() << "[debug]" << QTime::currentTime() << reader.name().toString();
1478
1479 if ( reader.name() == QLatin1String("axId") ) // mandatory element
1480 {
1481 // dev57
1482 uint axId = reader.attributes().value(QStringLiteral("val")).toString().toUInt(); // for Qt5.1
1483 axis->axisId = axId;
1484 }
1485 else if ( reader.name() == QLatin1String("scaling") )
1486 {
1487 // mandatory element
1488
1489 loadXmlAxisEG_AxShared_Scaling(reader, axis);
1490 }
1491 else if ( reader.name() == QLatin1String("delete") )
1492 {
1493 //!TODO
1494 }
1495 else if ( reader.name() == QLatin1String("axPos") )
1496 {
1497 // mandatory element
1498
1499 QString axPosVal = reader.attributes().value(QLatin1String("val")).toString();
1500
1501 if ( axPosVal == QLatin1String("l") ) { axis->axisPos = XlsxAxis::Left; }
1502 else if ( axPosVal == QLatin1String("r") ) { axis->axisPos = XlsxAxis::Right; }
1503 else if ( axPosVal == QLatin1String("t") ) { axis->axisPos = XlsxAxis::Top; }
1504 else if ( axPosVal == QLatin1String("b") ) { axis->axisPos = XlsxAxis::Bottom; }
1505 }
1506 else if ( reader.name() == QLatin1String("majorGridlines") )
1507 {
1508 //!TODO anything else?
1509 majorGridlinesEnabled = true;
1510 }
1511 else if ( reader.name() == QLatin1String("minorGridlines") )
1512 {
1513 //!TODO anything else?
1514 minorGridlinesEnabled = true;
1515 }
1516 else if ( reader.name() == QLatin1String("title") )
1517 {
1518 // title
1519 if ( !loadXmlAxisEG_AxShared_Title(reader, axis) )
1520 {
1521 qDebug() << "failed to load EG_AxShared title.";
1522 Q_ASSERT(false);
1523 return false;
1524 }
1525 }
1526 else if ( reader.name() == QLatin1String("numFmt") )
1527 {
1528 //!TODO
1529 }
1530 else if ( reader.name() == QLatin1String("majorTickMark") )
1531 {
1532 //!TODO
1533 }
1534 else if ( reader.name() == QLatin1String("minorTickMark") )
1535 {
1536 //!TODO
1537 }
1538 else if ( reader.name() == QLatin1String("tickLblPos") )
1539 {
1540 //!TODO
1541 }
1542 else if ( reader.name() == QLatin1String("spPr") )
1543 {
1544 //!TODO
1545 }
1546 else if ( reader.name() == QLatin1String("txPr") )
1547 {
1548 //!TODO
1549 }
1550 else if ( reader.name() == QLatin1String("crossAx") ) // mandatory element
1551 {
1552 // dev57
1553 uint crossAx = reader.attributes().value(QLatin1String("val")).toString().toUInt(); // for Qt5.1
1554 axis->crossAx = crossAx;
1555 }
1556 else if ( reader.name() == QLatin1String("crosses") )
1557 {
1558 //!TODO
1559 }
1560 else if ( reader.name() == QLatin1String("crossesAt") )
1561 {
1562 //!TODO
1563 }
1564
1565 // reader.readNext();
1566 }
1567 else if ( reader.tokenType() == QXmlStreamReader::EndElement &&
1568 reader.name().toString() == name )
1569 {
1570 break;
1571 }
1572 }
1573
1574 return true;
1575 }
1576
loadXmlAxisEG_AxShared_Scaling(QXmlStreamReader & reader,XlsxAxis * axis)1577 bool ChartPrivate::loadXmlAxisEG_AxShared_Scaling(QXmlStreamReader &reader, XlsxAxis* axis)
1578 {
1579 Q_UNUSED(axis);
1580 Q_ASSERT(reader.name() == QLatin1String("scaling"));
1581
1582 while ( !reader.atEnd() )
1583 {
1584 reader.readNextStartElement();
1585 if ( reader.tokenType() == QXmlStreamReader::StartElement )
1586 {
1587 if ( reader.name() == QLatin1String("orientation") )
1588 {
1589 }
1590 else
1591 {
1592 }
1593 }
1594 else if ( reader.tokenType() == QXmlStreamReader::EndElement &&
1595 reader.name() == QLatin1String("scaling") )
1596 {
1597 break;
1598 }
1599 }
1600
1601 return true;
1602 }
1603
1604 /*
1605 <xsd:complexType name="CT_Title">
1606 <xsd:sequence>
1607 <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/>
1608 <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/>
1609 <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
1610 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/>
1611 <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
1612 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
1613 </xsd:sequence>
1614 </xsd:complexType>
1615
1616 <xsd:complexType name="CT_Tx">
1617 <xsd:sequence>
1618 <xsd:choice minOccurs="1" maxOccurs="1">
1619 <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/>
1620 <xsd:element name="rich" type="a:CT_TextBody" minOccurs="1" maxOccurs="1"/>
1621 </xsd:choice>
1622 </xsd:sequence>
1623 </xsd:complexType>
1624
1625 <xsd:complexType name="CT_StrRef">
1626 <xsd:sequence>
1627 <xsd:element name="f" type="xsd:string" minOccurs="1" maxOccurs="1"/>
1628 <xsd:element name="strCache" type="CT_StrData" minOccurs="0" maxOccurs="1"/>
1629 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
1630 </xsd:sequence>
1631 </xsd:complexType>
1632
1633 <xsd:complexType name="CT_TextBody">
1634 <xsd:sequence>
1635 <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/>
1636 <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/>
1637 <xsd:element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/>
1638 </xsd:sequence>
1639 </xsd:complexType>
1640 */
loadXmlAxisEG_AxShared_Title(QXmlStreamReader & reader,XlsxAxis * axis)1641 bool ChartPrivate::loadXmlAxisEG_AxShared_Title(QXmlStreamReader &reader, XlsxAxis* axis)
1642 {
1643 Q_ASSERT(reader.name() == QLatin1String("title"));
1644
1645 while ( !reader.atEnd() )
1646 {
1647 reader.readNextStartElement();
1648 if ( reader.tokenType() == QXmlStreamReader::StartElement )
1649 {
1650 if ( reader.name() == QLatin1String("tx") )
1651 {
1652 loadXmlAxisEG_AxShared_Title_Tx(reader, axis);
1653 }
1654 else if ( reader.name() == QLatin1String("overlay") )
1655 {
1656 //!TODO: load overlay
1657 loadXmlAxisEG_AxShared_Title_Overlay(reader, axis);
1658 }
1659 else
1660 {
1661 }
1662 }
1663 else if ( reader.tokenType() == QXmlStreamReader::EndElement &&
1664 reader.name() == QLatin1String("title") )
1665 {
1666 break;
1667 }
1668 }
1669
1670 return true;
1671 }
1672
loadXmlAxisEG_AxShared_Title_Overlay(QXmlStreamReader & reader,XlsxAxis * axis)1673 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Overlay(QXmlStreamReader &reader, XlsxAxis* axis)
1674 {
1675 Q_UNUSED(axis);
1676 Q_ASSERT(reader.name() == QLatin1String("overlay"));
1677
1678 while ( !reader.atEnd() )
1679 {
1680 reader.readNextStartElement();
1681 if ( reader.tokenType() == QXmlStreamReader::StartElement )
1682 {
1683 }
1684 else if ( reader.tokenType() == QXmlStreamReader::EndElement &&
1685 reader.name() == QLatin1String("overlay") )
1686 {
1687 break;
1688 }
1689 }
1690
1691 return true;
1692 }
1693
loadXmlAxisEG_AxShared_Title_Tx(QXmlStreamReader & reader,XlsxAxis * axis)1694 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx(QXmlStreamReader &reader, XlsxAxis* axis)
1695 {
1696 Q_ASSERT(reader.name() == QLatin1String("tx"));
1697
1698 while ( !reader.atEnd() )
1699 {
1700 reader.readNextStartElement();
1701 if ( reader.tokenType() == QXmlStreamReader::StartElement )
1702 {
1703 if ( reader.name() == QLatin1String("rich") )
1704 {
1705 loadXmlAxisEG_AxShared_Title_Tx_Rich(reader, axis);
1706 }
1707 else
1708 {
1709 }
1710 }
1711 else if ( reader.tokenType() == QXmlStreamReader::EndElement &&
1712 reader.name() == QLatin1String("tx") )
1713 {
1714 break;
1715 }
1716 }
1717
1718 return true;
1719 }
1720
loadXmlAxisEG_AxShared_Title_Tx_Rich(QXmlStreamReader & reader,XlsxAxis * axis)1721 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich(QXmlStreamReader &reader, XlsxAxis* axis)
1722 {
1723 Q_ASSERT(reader.name() == QLatin1String("rich"));
1724
1725 while ( !reader.atEnd() )
1726 {
1727 reader.readNextStartElement();
1728 if ( reader.tokenType() == QXmlStreamReader::StartElement )
1729 {
1730 if ( reader.name() == QLatin1String("p") )
1731 {
1732 loadXmlAxisEG_AxShared_Title_Tx_Rich_P(reader, axis);
1733 }
1734 else
1735 {
1736 }
1737 }
1738 else if ( reader.tokenType() == QXmlStreamReader::EndElement &&
1739 reader.name() == QLatin1String("rich") )
1740 {
1741 break;
1742 }
1743 }
1744
1745 return true;
1746 }
1747
loadXmlAxisEG_AxShared_Title_Tx_Rich_P(QXmlStreamReader & reader,XlsxAxis * axis)1748 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich_P(QXmlStreamReader &reader, XlsxAxis* axis)
1749 {
1750 Q_ASSERT(reader.name() == QLatin1String("p"));
1751
1752 while ( !reader.atEnd() )
1753 {
1754 reader.readNextStartElement();
1755 if ( reader.tokenType() == QXmlStreamReader::StartElement )
1756 {
1757 if ( reader.name() == QLatin1String("r") )
1758 {
1759 loadXmlAxisEG_AxShared_Title_Tx_Rich_P_R(reader, axis);
1760 }
1761 else if ( reader.name() == QLatin1String("pPr") )
1762 {
1763 loadXmlAxisEG_AxShared_Title_Tx_Rich_P_pPr(reader, axis);
1764 }
1765 else
1766 {
1767
1768 }
1769 }
1770 else if ( reader.tokenType() == QXmlStreamReader::EndElement &&
1771 reader.name() == QLatin1String("p") )
1772 {
1773 break;
1774 }
1775 }
1776
1777 return true;
1778 }
1779
loadXmlAxisEG_AxShared_Title_Tx_Rich_P_pPr(QXmlStreamReader & reader,XlsxAxis * axis)1780 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich_P_pPr(QXmlStreamReader &reader, XlsxAxis* axis)
1781 {
1782 Q_UNUSED(axis);
1783 Q_ASSERT(reader.name() == QLatin1String("pPr"));
1784
1785 while ( !reader.atEnd() )
1786 {
1787 reader.readNextStartElement();
1788 if ( reader.tokenType() == QXmlStreamReader::StartElement )
1789 {
1790 if ( reader.name() == QLatin1String("defRPr") )
1791 {
1792 reader.readElementText();
1793 }
1794 else
1795 {
1796 }
1797 }
1798 else if ( reader.tokenType() == QXmlStreamReader::EndElement &&
1799 reader.name() == QLatin1String("pPr") )
1800 {
1801 break;
1802 }
1803 }
1804
1805 return true;
1806 }
1807
loadXmlAxisEG_AxShared_Title_Tx_Rich_P_R(QXmlStreamReader & reader,XlsxAxis * axis)1808 bool ChartPrivate::loadXmlAxisEG_AxShared_Title_Tx_Rich_P_R(QXmlStreamReader &reader, XlsxAxis* axis)
1809 {
1810 Q_ASSERT(reader.name() == QLatin1String("r"));
1811
1812 while ( !reader.atEnd() )
1813 {
1814 reader.readNextStartElement();
1815 if ( reader.tokenType() == QXmlStreamReader::StartElement )
1816 {
1817 if ( reader.name() == QLatin1String("t") )
1818 {
1819 QString strAxisName = reader.readElementText();
1820 XlsxAxis::AxisPos axisPos = axis->axisPos;
1821 axis->axisNames[ axisPos ] = strAxisName;
1822 }
1823 else
1824 {
1825 }
1826 }
1827 else if ( reader.tokenType() == QXmlStreamReader::EndElement &&
1828 reader.name() == QLatin1String("r") )
1829 {
1830 break;
1831 }
1832 }
1833
1834 return true;
1835 }
1836
1837 /*
1838 <xsd:complexType name="CT_PlotArea">
1839 <xsd:sequence>
1840 <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/>
1841 <xsd:choice minOccurs="1" maxOccurs="unbounded">
1842 <xsd:element name="areaChart" type="CT_AreaChart" minOccurs="1" maxOccurs="1"/>
1843 <xsd:element name="area3DChart" type="CT_Area3DChart" minOccurs="1" maxOccurs="1"/>
1844 <xsd:element name="lineChart" type="CT_LineChart" minOccurs="1" maxOccurs="1"/>
1845 <xsd:element name="line3DChart" type="CT_Line3DChart" minOccurs="1" maxOccurs="1"/>
1846 <xsd:element name="stockChart" type="CT_StockChart" minOccurs="1" maxOccurs="1"/>
1847 <xsd:element name="radarChart" type="CT_RadarChart" minOccurs="1" maxOccurs="1"/>
1848 <xsd:element name="scatterChart" type="CT_ScatterChart" minOccurs="1" maxOccurs="1"/>
1849 <xsd:element name="pieChart" type="CT_PieChart" minOccurs="1" maxOccurs="1"/>
1850 <xsd:element name="pie3DChart" type="CT_Pie3DChart" minOccurs="1" maxOccurs="1"/>
1851 <xsd:element name="doughnutChart" type="CT_DoughnutChart" minOccurs="1" maxOccurs="1"/>
1852 <xsd:element name="barChart" type="CT_BarChart" minOccurs="1" maxOccurs="1"/>
1853 <xsd:element name="bar3DChart" type="CT_Bar3DChart" minOccurs="1" maxOccurs="1"/>
1854 <xsd:element name="ofPieChart" type="CT_OfPieChart" minOccurs="1" maxOccurs="1"/>
1855 <xsd:element name="surfaceChart" type="CT_SurfaceChart" minOccurs="1" maxOccurs="1"/>
1856 <xsd:element name="surface3DChart" type="CT_Surface3DChart" minOccurs="1" maxOccurs="1"/>
1857 <xsd:element name="bubbleChart" type="CT_BubbleChart" minOccurs="1" maxOccurs="1"/>
1858 </xsd:choice>
1859 <xsd:choice minOccurs="0" maxOccurs="unbounded">
1860 <xsd:element name="valAx" type="CT_ValAx" minOccurs="1" maxOccurs="1"/>
1861 <xsd:element name="catAx" type="CT_CatAx" minOccurs="1" maxOccurs="1"/>
1862 <xsd:element name="dateAx" type="CT_DateAx" minOccurs="1" maxOccurs="1"/>
1863 <xsd:element name="serAx" type="CT_SerAx" minOccurs="1" maxOccurs="1"/>
1864 </xsd:choice>
1865 <xsd:element name="dTable" type="CT_DTable" minOccurs="0" maxOccurs="1"/>
1866 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/>
1867 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
1868 </xsd:sequence>
1869 </xsd:complexType>
1870 */
1871
1872 /*
1873 <xsd:complexType name="CT_CatAx">
1874 <xsd:sequence>
1875 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/>
1876 <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
1877 <xsd:element name="lblAlgn" type="CT_LblAlgn" minOccurs="0" maxOccurs="1"/>
1878 <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/>
1879 <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/>
1880 <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/>
1881 <xsd:element name="noMultiLvlLbl" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
1882 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
1883 </xsd:sequence>
1884 </xsd:complexType>
1885 <!----------------------------------------------------------------------------->
1886 <xsd:complexType name="CT_DateAx">
1887 <xsd:sequence>
1888 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/>
1889 <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
1890 <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/>
1891 <xsd:element name="baseTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/>
1892 <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/>
1893 <xsd:element name="majorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/>
1894 <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/>
1895 <xsd:element name="minorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/>
1896 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
1897 </xsd:sequence>
1898 </xsd:complexType>
1899 <!----------------------------------------------------------------------------->
1900 <xsd:complexType name="CT_SerAx">
1901 <xsd:sequence>
1902 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/>
1903 <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/>
1904 <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/>
1905 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
1906 </xsd:sequence>
1907 </xsd:complexType>
1908 <!----------------------------------------------------------------------------->
1909 <xsd:complexType name="CT_ValAx">
1910 <xsd:sequence>
1911 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/>
1912 <xsd:element name="crossBetween" type="CT_CrossBetween" minOccurs="0" maxOccurs="1"/>
1913 <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/>
1914 <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/>
1915 <xsd:element name="dispUnits" type="CT_DispUnits" minOccurs="0" maxOccurs="1"/>
1916 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
1917 </xsd:sequence>
1918 </xsd:complexType>
1919 */
1920
saveXmlAxis(QXmlStreamWriter & writer) const1921 void ChartPrivate::saveXmlAxis(QXmlStreamWriter &writer) const
1922 {
1923 for ( int i = 0 ; i < axisList.size() ; ++i )
1924 {
1925 XlsxAxis* axis = axisList[i].data();
1926 if ( NULL == axis )
1927 continue;
1928
1929 if ( axis->type == XlsxAxis::T_Cat ) { saveXmlAxisCatAx( writer, axis ); }
1930 if ( axis->type == XlsxAxis::T_Val ) { saveXmlAxisValAx( writer, axis ); }
1931 if ( axis->type == XlsxAxis::T_Ser ) { saveXmlAxisSerAx( writer, axis ); }
1932 if ( axis->type == XlsxAxis::T_Date ) { saveXmlAxisDateAx( writer, axis ); }
1933 }
1934
1935 }
1936
saveXmlAxisCatAx(QXmlStreamWriter & writer,XlsxAxis * axis) const1937 void ChartPrivate::saveXmlAxisCatAx(QXmlStreamWriter &writer, XlsxAxis* axis) const
1938 {
1939 /*
1940 <xsd:complexType name="CT_CatAx">
1941 <xsd:sequence>
1942 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/>
1943 <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
1944 <xsd:element name="lblAlgn" type="CT_LblAlgn" minOccurs="0" maxOccurs="1"/>
1945 <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/>
1946 <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/>
1947 <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/>
1948 <xsd:element name="noMultiLvlLbl" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
1949 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
1950 </xsd:sequence>
1951 </xsd:complexType>
1952 */
1953
1954 writer.writeStartElement(QStringLiteral("c:catAx"));
1955
1956 saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared
1957
1958 //!TODO: write element
1959 // auto
1960 // lblAlgn
1961 // lblOffset
1962 // tickLblSkip
1963 // tickMarkSkip
1964 // noMultiLvlLbl
1965 // extLst
1966
1967 writer.writeEndElement(); // c:catAx
1968 }
1969
saveXmlAxisDateAx(QXmlStreamWriter & writer,XlsxAxis * axis) const1970 void ChartPrivate::saveXmlAxisDateAx(QXmlStreamWriter &writer, XlsxAxis* axis) const
1971 {
1972 /*
1973 <xsd:complexType name="CT_DateAx">
1974 <xsd:sequence>
1975 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/>
1976 <xsd:element name="auto" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
1977 <xsd:element name="lblOffset" type="CT_LblOffset" minOccurs="0" maxOccurs="1"/>
1978 <xsd:element name="baseTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/>
1979 <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/>
1980 <xsd:element name="majorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/>
1981 <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/>
1982 <xsd:element name="minorTimeUnit" type="CT_TimeUnit" minOccurs="0" maxOccurs="1"/>
1983 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
1984 </xsd:sequence>
1985 </xsd:complexType>
1986 */
1987
1988 writer.writeStartElement(QStringLiteral("c:dateAx"));
1989
1990 saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared
1991
1992 //!TODO: write element
1993 // auto
1994 // lblOffset
1995 // baseTimeUnit
1996 // majorUnit
1997 // majorTimeUnit
1998 // minorUnit
1999 // minorTimeUnit
2000 // extLst
2001
2002 writer.writeEndElement(); // c:dateAx
2003 }
2004
saveXmlAxisSerAx(QXmlStreamWriter & writer,XlsxAxis * axis) const2005 void ChartPrivate::saveXmlAxisSerAx(QXmlStreamWriter &writer, XlsxAxis* axis) const
2006 {
2007 /*
2008 <xsd:complexType name="CT_SerAx">
2009 <xsd:sequence>
2010 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/>
2011 <xsd:element name="tickLblSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/>
2012 <xsd:element name="tickMarkSkip" type="CT_Skip" minOccurs="0" maxOccurs="1"/>
2013 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
2014 </xsd:sequence>
2015 </xsd:complexType>
2016 */
2017
2018 writer.writeStartElement(QStringLiteral("c:serAx"));
2019
2020 saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared
2021
2022 //!TODO: write element
2023 // tickLblSkip
2024 // tickMarkSkip
2025 // extLst
2026
2027 writer.writeEndElement(); // c:serAx
2028 }
2029
saveXmlAxisValAx(QXmlStreamWriter & writer,XlsxAxis * axis) const2030 void ChartPrivate::saveXmlAxisValAx(QXmlStreamWriter &writer, XlsxAxis* axis) const
2031 {
2032 /*
2033 <xsd:complexType name="CT_ValAx">
2034 <xsd:sequence>
2035 <xsd:group ref="EG_AxShared" minOccurs="1" maxOccurs="1"/>
2036 <xsd:element name="crossBetween" type="CT_CrossBetween" minOccurs="0" maxOccurs="1"/>
2037 <xsd:element name="majorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/>
2038 <xsd:element name="minorUnit" type="CT_AxisUnit" minOccurs="0" maxOccurs="1"/>
2039 <xsd:element name="dispUnits" type="CT_DispUnits" minOccurs="0" maxOccurs="1"/>
2040 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
2041 </xsd:sequence>
2042 </xsd:complexType>
2043 */
2044
2045 writer.writeStartElement(QStringLiteral("c:valAx"));
2046
2047 saveXmlAxisEG_AxShared(writer, axis); // EG_AxShared
2048
2049 //!TODO: write element
2050 // crossBetween
2051 // majorUnit
2052 // minorUnit
2053 // dispUnits
2054 // extLst
2055
2056 writer.writeEndElement(); // c:valAx
2057 }
2058
saveXmlAxisEG_AxShared(QXmlStreamWriter & writer,XlsxAxis * axis) const2059 void ChartPrivate::saveXmlAxisEG_AxShared(QXmlStreamWriter &writer, XlsxAxis* axis) const
2060 {
2061 /*
2062 <xsd:group name="EG_AxShared">
2063 <xsd:sequence>
2064 <xsd:element name="axId" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*)
2065 <xsd:element name="scaling" type="CT_Scaling" minOccurs="1" maxOccurs="1"/> (*)
2066 <xsd:element name="delete" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
2067 <xsd:element name="axPos" type="CT_AxPos" minOccurs="1" maxOccurs="1"/> (*)
2068 <xsd:element name="majorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/>
2069 <xsd:element name="minorGridlines" type="CT_ChartLines" minOccurs="0" maxOccurs="1"/>
2070 <xsd:element name="title" type="CT_Title" minOccurs="0" maxOccurs="1"/> (***********************)
2071 <xsd:element name="numFmt" type="CT_NumFmt" minOccurs="0" maxOccurs="1"/>
2072 <xsd:element name="majorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/>
2073 <xsd:element name="minorTickMark" type="CT_TickMark" minOccurs="0" maxOccurs="1"/>
2074 <xsd:element name="tickLblPos" type="CT_TickLblPos" minOccurs="0" maxOccurs="1"/>
2075 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/>
2076 <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
2077 <xsd:element name="crossAx" type="CT_UnsignedInt" minOccurs="1" maxOccurs="1"/> (*)
2078 <xsd:choice minOccurs="0" maxOccurs="1">
2079 <xsd:element name="crosses" type="CT_Crosses" minOccurs="1" maxOccurs="1"/>
2080 <xsd:element name="crossesAt" type="CT_Double" minOccurs="1" maxOccurs="1"/>
2081 </xsd:choice>
2082 </xsd:sequence>
2083 </xsd:group>
2084 */
2085
2086 writer.writeEmptyElement(QStringLiteral("c:axId")); // 21.2.2.9. axId (Axis ID) (mandatory value)
2087 writer.writeAttribute(QStringLiteral("val"), QString::number(axis->axisId));
2088
2089 writer.writeStartElement(QStringLiteral("c:scaling")); // CT_Scaling (mandatory value)
2090 writer.writeEmptyElement(QStringLiteral("c:orientation")); // CT_Orientation
2091 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("minMax")); // ST_Orientation
2092 writer.writeEndElement(); // c:scaling
2093
2094 writer.writeEmptyElement(QStringLiteral("c:axPos")); // axPos CT_AxPos (mandatory value)
2095 QString pos = GetAxisPosString( axis->axisPos );
2096 if ( !pos.isEmpty() )
2097 {
2098 writer.writeAttribute(QStringLiteral("val"), pos); // ST_AxPos
2099 }
2100
2101 if( majorGridlinesEnabled )
2102 {
2103 writer.writeEmptyElement(QStringLiteral("c:majorGridlines"));
2104 }
2105 if( minorGridlinesEnabled )
2106 {
2107 writer.writeEmptyElement(QStringLiteral("c:minorGridlines"));
2108 }
2109
2110 saveXmlAxisEG_AxShared_Title(writer, axis); // "c:title" CT_Title
2111
2112 writer.writeEmptyElement(QStringLiteral("c:crossAx")); // crossAx (mandatory value)
2113 writer.writeAttribute(QStringLiteral("val"), QString::number(axis->crossAx));
2114
2115 }
2116
saveXmlAxisEG_AxShared_Title(QXmlStreamWriter & writer,XlsxAxis * axis) const2117 void ChartPrivate::saveXmlAxisEG_AxShared_Title(QXmlStreamWriter &writer, XlsxAxis* axis) const
2118 {
2119 // CT_Title
2120
2121 /*
2122 <xsd:complexType name="CT_Title">
2123 <xsd:sequence>
2124 <xsd:element name="tx" type="CT_Tx" minOccurs="0" maxOccurs="1"/>
2125 <xsd:element name="layout" type="CT_Layout" minOccurs="0" maxOccurs="1"/>
2126 <xsd:element name="overlay" type="CT_Boolean" minOccurs="0" maxOccurs="1"/>
2127 <xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/>
2128 <xsd:element name="txPr" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
2129 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
2130 </xsd:sequence>
2131 </xsd:complexType>
2132 */
2133 /*
2134 <xsd:complexType name="CT_Tx">
2135 <xsd:sequence>
2136 <xsd:choice minOccurs="1" maxOccurs="1">
2137 <xsd:element name="strRef" type="CT_StrRef" minOccurs="1" maxOccurs="1"/>
2138 <xsd:element name="rich" type="a:CT_TextBody" minOccurs="1" maxOccurs="1"/>
2139 </xsd:choice>
2140 </xsd:sequence>
2141 </xsd:complexType>
2142 */
2143 /*
2144 <xsd:complexType name="CT_StrRef">
2145 <xsd:sequence>
2146 <xsd:element name="f" type="xsd:string" minOccurs="1" maxOccurs="1"/>
2147 <xsd:element name="strCache" type="CT_StrData" minOccurs="0" maxOccurs="1"/>
2148 <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
2149 </xsd:sequence>
2150 </xsd:complexType>
2151 */
2152 /*
2153 <xsd:complexType name="CT_TextBody">
2154 <xsd:sequence>
2155 <xsd:element name="bodyPr" type="CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/>
2156 <xsd:element name="lstStyle" type="CT_TextListStyle" minOccurs="0" maxOccurs="1"/>
2157 <xsd:element name="p" type="CT_TextParagraph" minOccurs="1" maxOccurs="unbounded"/>
2158 </xsd:sequence>
2159 </xsd:complexType>
2160 */
2161
2162 writer.writeStartElement(QStringLiteral("c:title"));
2163
2164 // CT_Tx {{
2165 writer.writeStartElement(QStringLiteral("c:tx"));
2166
2167 writer.writeStartElement(QStringLiteral("c:rich")); // CT_TextBody
2168
2169 writer.writeEmptyElement(QStringLiteral("a:bodyPr")); // CT_TextBodyProperties
2170
2171 writer.writeEmptyElement(QStringLiteral("a:lstStyle")); // CT_TextListStyle
2172
2173 writer.writeStartElement(QStringLiteral("a:p"));
2174
2175 writer.writeStartElement(QStringLiteral("a:pPr"));
2176 writer.writeAttribute(QStringLiteral("lvl"), QString::number(0));
2177
2178 writer.writeStartElement(QStringLiteral("a:defRPr"));
2179 writer.writeAttribute(QStringLiteral("b"), QString::number(0));
2180 writer.writeEndElement(); // a:defRPr
2181 writer.writeEndElement(); // a:pPr
2182
2183 writer.writeStartElement(QStringLiteral("a:r"));
2184 QString strAxisName = GetAxisName(axis);
2185 writer.writeTextElement( QStringLiteral("a:t"), strAxisName );
2186 writer.writeEndElement(); // a:r
2187
2188 writer.writeEndElement(); // a:p
2189
2190 writer.writeEndElement(); // c:rich
2191
2192 writer.writeEndElement(); // c:tx
2193 // CT_Tx }}
2194
2195 writer.writeStartElement(QStringLiteral("c:overlay"));
2196 writer.writeAttribute(QStringLiteral("val"), QString::number(0)); // CT_Boolean
2197 writer.writeEndElement(); // c:overlay
2198
2199 writer.writeEndElement(); // c:title
2200
2201 }
2202
GetAxisPosString(XlsxAxis::AxisPos axisPos) const2203 QString ChartPrivate::GetAxisPosString( XlsxAxis::AxisPos axisPos ) const
2204 {
2205 QString pos;
2206 switch ( axisPos )
2207 {
2208 case XlsxAxis::Top : pos = QStringLiteral("t"); break;
2209 case XlsxAxis::Bottom : pos = QStringLiteral("b"); break;
2210 case XlsxAxis::Left : pos = QStringLiteral("l"); break;
2211 case XlsxAxis::Right : pos = QStringLiteral("r"); break;
2212 default: break; // ??
2213 }
2214
2215 return pos;
2216 }
2217
GetAxisName(XlsxAxis * axis) const2218 QString ChartPrivate::GetAxisName(XlsxAxis* axis) const
2219 {
2220 QString strAxisName;
2221 if ( NULL == axis )
2222 return strAxisName;
2223
2224 QString pos = GetAxisPosString( axis->axisPos ); // l, t, r, b
2225 if ( pos.isEmpty() )
2226 return strAxisName;
2227
2228 strAxisName = axis->axisNames[ axis->axisPos ];
2229 return strAxisName;
2230 }
2231
2232
2233 ///
2234 /// \brief ChartPrivate::readSubTree
2235 /// \param reader
2236 /// \return
2237 ///
readSubTree(QXmlStreamReader & reader)2238 QString ChartPrivate::readSubTree(QXmlStreamReader &reader)
2239 {
2240 QString treeString;
2241 QString prefix;
2242 const auto& treeName = reader.name();
2243
2244 while (!reader.atEnd())
2245 {
2246 reader.readNextStartElement();
2247 if (reader.tokenType() == QXmlStreamReader::StartElement)
2248 {
2249 prefix = reader.prefix().toString();
2250
2251 treeString += QLatin1String("<") + reader.qualifiedName().toString();
2252
2253 const QXmlStreamAttributes attributes = reader.attributes();
2254 for (const QXmlStreamAttribute &attr : attributes) {
2255 treeString += QLatin1String(" ") + attr.name().toString() + QLatin1String("=\"") + attr.value().toString() + QLatin1String("\"");
2256 }
2257 treeString += QStringLiteral(">");
2258 }
2259 else if (reader.tokenType() == QXmlStreamReader::EndElement )
2260 {
2261 if( reader.name() == treeName)
2262 {
2263 break;
2264 }
2265 treeString += QLatin1String("</") + reader.qualifiedName().toString() + QLatin1String(">");
2266 }
2267 }
2268
2269 return treeString;
2270 }
2271
2272
2273 ///
2274 /// \brief ChartPrivate::loadXmlChartLegend
2275 /// \param reader
2276 /// \return
2277 ///
loadXmlChartLegend(QXmlStreamReader & reader)2278 bool ChartPrivate::loadXmlChartLegend(QXmlStreamReader &reader)
2279 {
2280
2281 Q_ASSERT(reader.name() == QLatin1String("legend"));
2282
2283 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
2284 && reader.name() == QLatin1String("legend")))
2285 {
2286 if (reader.readNextStartElement())
2287 {
2288 if (reader.name() == QLatin1String("legendPos")) // c:legendPos
2289 {
2290 QString pos = reader.attributes().value(QLatin1String("val")).toString();
2291 if( pos.compare(QLatin1String("r"), Qt::CaseInsensitive) == 0)
2292 {
2293 // legendPos = Chart::ChartAxisPos::Right;
2294 legendPos = Chart::Right;
2295 }
2296 else
2297 if( pos.compare(QLatin1String("l"), Qt::CaseInsensitive) == 0)
2298 {
2299 // legendPos = Chart::ChartAxisPos::Left;
2300 legendPos = Chart::Left;
2301 }
2302 else
2303 if( pos.compare(QLatin1String("t"), Qt::CaseInsensitive) == 0)
2304 {
2305 // legendPos = Chart::ChartAxisPos::Top;
2306 legendPos = Chart::Top;
2307 }
2308 else
2309 if( pos.compare(QLatin1String("b"), Qt::CaseInsensitive) == 0)
2310 {
2311 // legendPos = Chart::ChartAxisPos::Bottom;
2312 legendPos = Chart::Bottom;
2313 }
2314 else
2315 {
2316 // legendPos = Chart::ChartAxisPos::None;
2317 legendPos = Chart::None;
2318 }
2319 }
2320 else
2321 if (reader.name() == QLatin1String("overlay")) // c:legendPos
2322 {
2323 QString pos = reader.attributes().value(QLatin1String("val")).toString();
2324 if( pos.compare(QLatin1String("1"), Qt::CaseInsensitive) == 0 )
2325 {
2326 legendOverlay = true;
2327 }
2328 else
2329 {
2330 legendOverlay = false;
2331 }
2332 }
2333 }
2334 }
2335
2336 return false;
2337 }
2338
2339 QT_END_NAMESPACE_XLSX
2340