KD Chart API Documentation 3.1
Loading...
Searching...
No Matches
KDChartWidget.cpp
Go to the documentation of this file.
1/****************************************************************************
2**
3** This file is part of the KD Chart library.
4**
5** SPDX-FileCopyrightText: 2001 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6**
7** SPDX-License-Identifier: MIT
8**
9****************************************************************************/
10
11#include <KDChartWidget.h>
12#include <KDChartWidget_p.h>
13
16#include <KDChartBarDiagram.h>
17#include <KDChartChart.h>
18#include <KDChartLegend.h>
19#include <KDChartLineDiagram.h>
20#include <KDChartPieDiagram.h>
21#include <KDChartPlotter.h>
22#include <KDChartPolarDiagram.h>
23#include <KDChartRingDiagram.h>
24
25#include <QDebug>
26
27#include <KDABLibFakes>
28
29#define d d_func()
30
31using namespace KDChart;
32
33Widget::Private::Private(Widget *qq)
34 : q(qq)
35 , layout(q)
36 , m_model(q)
37 , m_chart(q)
38 , m_cartPlane(&m_chart)
39 , m_polPlane(&m_chart)
40 , usedDatasetWidth(0)
41{
43 KDAB_SET_OBJECT_NAME(m_model);
44 KDAB_SET_OBJECT_NAME(m_chart);
45
46 layout.addWidget(&m_chart);
47}
48
49Widget::Private::~Private()
50{
51}
52
65Widget::Widget(QWidget *parent)
66 : QWidget(parent)
67 , _d(new Private(this))
68{
69 // as default we have a cartesian coordinate plane ...
70 // ... and a line diagram
72}
73
78{
79 delete _d;
80 _d = nullptr;
81}
82
83void Widget::init()
84{
85}
86
87void Widget::setDataset(int column, const QVector<qreal> &data, const QString &title)
88{
89 if (!checkDatasetWidth(1))
90 return;
91
92 QStandardItemModel &model = d->m_model;
93
94 justifyModelSize(data.size(), column + 1);
95
96 for (int i = 0; i < data.size(); ++i) {
97 const QModelIndex index = model.index(i, column);
98 model.setData(index, QVariant(data[i]), Qt::DisplayRole);
99 }
100 if (!title.isEmpty())
101 model.setHeaderData(column, Qt::Horizontal, QVariant(title));
102}
103
104void Widget::setDataset(int column, const QVector<QPair<qreal, qreal>> &data, const QString &title)
105{
106 if (!checkDatasetWidth(2))
107 return;
108
109 QStandardItemModel &model = d->m_model;
110
111 justifyModelSize(data.size(), (column + 1) * 2);
112
113 for (int i = 0; i < data.size(); ++i) {
114 QModelIndex index = model.index(i, column * 2);
115 model.setData(index, QVariant(data[i].first), Qt::DisplayRole);
116
117 index = model.index(i, column * 2 + 1);
118 model.setData(index, QVariant(data[i].second), Qt::DisplayRole);
119 }
120 if (!title.isEmpty()) {
121 model.setHeaderData(column, Qt::Horizontal, QVariant(title));
122 }
123}
124
125void Widget::setDataCell(int row, int column, qreal data)
126{
127 if (!checkDatasetWidth(1))
128 return;
129
130 QStandardItemModel &model = d->m_model;
131
132 justifyModelSize(row + 1, column + 1);
133
134 const QModelIndex index = model.index(row, column);
135 model.setData(index, QVariant(data), Qt::DisplayRole);
136}
137
138void Widget::setDataCell(int row, int column, QPair<qreal, qreal> data)
139{
140 if (!checkDatasetWidth(2))
141 return;
142
143 QStandardItemModel &model = d->m_model;
144
145 justifyModelSize(row + 1, (column + 1) * 2);
146
147 QModelIndex index = model.index(row, column * 2);
148 model.setData(index, QVariant(data.first), Qt::DisplayRole);
149
150 index = model.index(row, column * 2 + 1);
151 model.setData(index, QVariant(data.second), Qt::DisplayRole);
152}
153
154/*
155 * Resets all data.
156 */
158{
159 d->m_model.clear();
160 d->usedDatasetWidth = 0;
161}
162
166void Widget::setGlobalLeading(int left, int top, int right, int bottom)
167{
168 d->m_chart.setGlobalLeading(left, top, right, bottom);
169}
170
175{
176 d->m_chart.setGlobalLeadingLeft(leading);
177}
178
183{
184 return d->m_chart.globalLeadingLeft();
185}
186
191{
192 d->m_chart.setGlobalLeadingTop(leading);
193}
194
199{
200 return d->m_chart.globalLeadingTop();
201}
202
207{
208 d->m_chart.setGlobalLeadingRight(leading);
209}
210
215{
216 return d->m_chart.globalLeadingRight();
217}
218
223{
224 d->m_chart.setGlobalLeadingBottom(leading);
225}
226
231{
232 return d->m_chart.globalLeadingBottom();
233}
234
239{
240 return d->m_chart.headerFooter();
241}
242
247{
248 return d->m_chart.headerFooters();
249}
250
256 Position position)
257{
258 auto *newHeader = new HeaderFooter(&d->m_chart);
259 newHeader->setType(type);
260 newHeader->setPosition(position);
261 newHeader->setText(text);
262 d->m_chart.addHeaderFooter(newHeader); // we need this explicit call !
263}
264
269{
270 header->setParent(&d->m_chart);
271 d->m_chart.addHeaderFooter(header); // we need this explicit call !
272}
273
275{
276 header->setParent(&d->m_chart);
277 d->m_chart.replaceHeaderFooter(header, oldHeader);
278}
279
281{
282 d->m_chart.takeHeaderFooter(header);
283}
284
289{
290 return d->m_chart.legend();
291}
292
297{
298 return d->m_chart.legends();
299}
300
305{
306 auto *legend = new Legend(diagram(), &d->m_chart);
307 legend->setPosition(position);
308 d->m_chart.addLegend(legend);
309}
310
315{
317 legend->setParent(&d->m_chart);
318 d->m_chart.addLegend(legend);
319}
320
321void Widget::replaceLegend(Legend *legend, Legend *oldLegend)
322{
324 legend->setParent(&d->m_chart);
325 d->m_chart.replaceLegend(legend, oldLegend);
326}
327
329{
330 d->m_chart.takeLegend(legend);
331}
332
334{
335 if (coordinatePlane() == nullptr)
336 qDebug() << "diagram(): coordinatePlane() was NULL";
337
338 return coordinatePlane()->diagram();
339}
340
342{
343 return dynamic_cast<BarDiagram *>(diagram());
344}
346{
347 return dynamic_cast<LineDiagram *>(diagram());
348}
350{
351 return dynamic_cast<Plotter *>(diagram());
352}
354{
355 return dynamic_cast<PieDiagram *>(diagram());
356}
358{
359 return dynamic_cast<RingDiagram *>(diagram());
360}
362{
363 return dynamic_cast<PolarDiagram *>(diagram());
364}
365
367{
368 return d->m_chart.coordinatePlane();
369}
370
372{
373 return (type == KDChart::Widget::Bar) || (type == KDChart::Widget::Line);
374}
375
377{
378 return (type == KDChart::Widget::Pie)
379 || (type == KDChart::Widget::Ring)
380 || (type == KDChart::Widget::Polar);
381}
382
383void Widget::setType(ChartType chartType, SubType chartSubType)
384{
385 AbstractDiagram *diag = nullptr;
386 const ChartType oldType = type();
387
388 if (chartType != oldType) {
389 if (chartType != NoType) {
391 if (coordinatePlane() == &d->m_polPlane) {
392 d->m_chart.takeCoordinatePlane(&d->m_polPlane);
393 d->m_chart.addCoordinatePlane(&d->m_cartPlane);
394 } else {
395 d->m_chart.replaceCoordinatePlane(&d->m_cartPlane);
396 }
397 } else if (isPolar(chartType) && !isPolar(oldType)) {
398 if (coordinatePlane() == &d->m_cartPlane) {
399 d->m_chart.takeCoordinatePlane(&d->m_cartPlane);
400 d->m_chart.addCoordinatePlane(&d->m_polPlane);
401 } else {
402 d->m_chart.replaceCoordinatePlane(&d->m_polPlane);
403 }
404 }
405 }
406 switch (chartType) {
407 case Bar:
408 diag = new BarDiagram(&d->m_chart, &d->m_cartPlane);
409 break;
410 case Line:
411 diag = new LineDiagram(&d->m_chart, &d->m_cartPlane);
412 break;
413 case Plot:
414 diag = new Plotter(&d->m_chart, &d->m_cartPlane);
415 break;
416 case Pie:
417 diag = new PieDiagram(&d->m_chart, &d->m_polPlane);
418 break;
419 case Polar:
420 diag = new PolarDiagram(&d->m_chart, &d->m_polPlane);
421 break;
422 case Ring:
423 diag = new RingDiagram(&d->m_chart, &d->m_polPlane);
424 break;
425 case NoType:
426 break;
427 }
428 if (diag != nullptr) {
430 auto *oldDiag =
432 auto *newDiag =
434 const auto constAxes = oldDiag->axes();
435 for (CartesianAxis *axis : constAxes) {
436 oldDiag->takeAxis(axis);
437 newDiag->addAxis(axis);
438 }
439 }
440
441 const auto constLegends = d->m_chart.legends();
442 for (Legend *l : constLegends) {
443 l->setDiagram(diag);
444 }
445
446 diag->setModel(&d->m_model);
448
449 // checkDatasetWidth( d->usedDatasetWidth );
450 }
451 // coordinatePlane()->setGridNeedsRecalculate();
452 }
453
454 if (chartType != NoType) {
455 if (chartType != oldType || chartSubType != subType())
457 d->m_chart.resize(size()); // triggering immediate update
458 }
459}
460
461template<class DiagramType, class Subtype>
462void setSubtype(AbstractDiagram *_dia, Subtype st)
463{
464 if (auto *dia = qobject_cast<DiagramType *>(_dia)) {
465 dia->setType(st);
466 }
467}
468
470{
471 // ### at least PieDiagram, PolarDiagram and RingDiagram are unhandled here
472
474 switch (subType) {
475 case Normal:
479 break;
480 case Stacked:
483 // setSubtype< Plotter >( dia, Plotter::Stacked );
484 break;
485 case Percent:
489 break;
490 case Rows:
491 setSubtype<BarDiagram>(dia, BarDiagram::Rows);
492 break;
493 default:
494 Q_ASSERT_X(false, "Widget::setSubType", "Sub-type not supported!");
495 break;
496 }
497}
498
503{
504 // PENDING(christoph) save the type out-of-band:
505 AbstractDiagram *const dia = const_cast<Widget *>(this)->diagram();
507 return Bar;
509 return Line;
511 return Plot;
513 return Pie;
515 return Polar;
517 return Ring;
518 else
519 return NoType;
520}
521
523{
524 // PENDING(christoph) save the type out-of-band:
526
527 AbstractDiagram *const dia = const_cast<Widget *>(this)->diagram();
531
532 // FIXME(khz): Add the impl for these chart types - or remove them from here:
533 // PieDiagram* pieDia = qobject_cast< PieDiagram* >( diagram() );
534 // PolarDiagram* polarDia = qobject_cast< PolarDiagram* >( diagram() );
535 // RingDiagram* ringDia = qobject_cast< RingDiagram* >( diagram() );
536
537#define TEST_SUB_TYPE(DIAGRAM, INTERNALSUBTYPE, SUBTYPE) \
538 { \
539 if (DIAGRAM && DIAGRAM->type() == INTERNALSUBTYPE) \
540 retVal = SUBTYPE; \
541 }
543 switch (mainType) {
544 case Bar:
548 TEST_SUB_TYPE(barDia, BarDiagram::Rows, Rows);
549 break;
550 case Line:
554 break;
555 case Plot:
558 break;
559 case Pie:
560 // no impl. yet
561 break;
562 case Polar:
563 // no impl. yet
564 break;
565 case Ring:
566 // no impl. yet
567 break;
568 default:
569 Q_ASSERT_X(false,
570 "Widget::subType", "Chart type not supported!");
571 break;
572 }
573 return retVal;
574}
575
579bool Widget::checkDatasetWidth(int width)
580{
581 if (width == diagram()->datasetDimension()) {
582 d->usedDatasetWidth = width;
583 return true;
584 }
585 qDebug() << "The current diagram type doesn't support this data dimension.";
586 return false;
587 /* if ( d->usedDatasetWidth == width || d->usedDatasetWidth == 0 ) {
588 d->usedDatasetWidth = width;
589 diagram()->setDatasetDimension( width );
590 return true;
591 }
592 qDebug() << "It's impossible to mix up the different setDataset() methods on the same widget.";
593 return false;*/
594}
595
599void Widget::justifyModelSize(int rows, int columns)
600{
601 QAbstractItemModel &model = d->m_model;
602 const int currentRows = model.rowCount();
603 const int currentCols = model.columnCount();
604
605 if (currentCols < columns)
606 if (!model.insertColumns(currentCols, columns - currentCols))
607 qDebug() << "justifyModelSize: could not increase model size.";
608 if (currentRows < rows)
609 if (!model.insertRows(currentRows, rows - currentRows))
610 qDebug() << "justifyModelSize: could not increase model size.";
611
612 Q_ASSERT(model.rowCount() >= rows);
613 Q_ASSERT(model.columnCount() >= columns);
614}
#define KDAB_SET_OBJECT_NAME(x)
void setSubtype(AbstractDiagram *_dia, Subtype st)
static bool isCartesian(KDChart::Widget::ChartType type)
#define TEST_SUB_TYPE(DIAGRAM, INTERNALSUBTYPE, SUBTYPE)
static bool isPolar(KDChart::Widget::ChartType type)
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane,...
virtual void replaceDiagram(AbstractDiagram *diagram, AbstractDiagram *oldDiagram=nullptr)
AbstractDiagram defines the interface for diagram classes.
BarDiagram defines a common bar diagram.
A header or footer displaying text above or below charts.
void setParent(QObject *parent)
Legend defines the interface for the legend drawing class.
void setDiagram(KDChart::AbstractDiagram *newDiagram)
A convenience method doing the same as replaceDiagram( newDiagram, 0 );.
void setPosition(Position position)
Specify the position of a non-floating legend.
LineDiagram defines a common line diagram.
PieDiagram defines a common pie diagram.
Plotter defines a diagram type plotting two-dimensional data.
PolarDiagram defines a common polar diagram.
Defines a position, using compass terminology.
RingDiagram defines a common ring diagram.
The KD Chart widget for usage without Model/View.
void replaceHeaderFooter(HeaderFooter *header, HeaderFooter *oldHeader=nullptr)
void setSubType(SubType subType)
Sets the type of the chart without changing the main type.
BarDiagram * barDiagram()
AbstractDiagram * diagram()
void setGlobalLeading(int left, int top, int right, int bottom)
int globalLeadingBottom() const
int globalLeadingLeft() const
Plotter * plotter()
SubType subType() const
void takeHeaderFooter(HeaderFooter *header)
PieDiagram * pieDiagram()
AbstractCoordinatePlane * coordinatePlane()
void setGlobalLeadingRight(int leading)
LineDiagram * lineDiagram()
void replaceLegend(Legend *legend, Legend *oldLegend=nullptr)
void setGlobalLeadingBottom(int leading)
RingDiagram * ringDiagram()
HeaderFooter * firstHeaderFooter()
void addHeaderFooter(const QString &text, HeaderFooter::HeaderFooterType type, Position position)
QList< Legend * > allLegends()
QList< HeaderFooter * > allHeadersFooters()
PolarDiagram * polarDiagram()
void setType(ChartType chartType, SubType subType=Normal)
void takeLegend(Legend *legend)
ChartType type() const
void setDataset(int column, const QVector< qreal > &data, const QString &title=QString())
void setDataCell(int row, int column, qreal data)
int globalLeadingRight() const
int globalLeadingTop() const
void setGlobalLeadingTop(int leading)
void setGlobalLeadingLeft(int leading)
void addLegend(Position position)
virtual int columnCount(const QModelIndex &parent) const const=0
virtual bool insertColumns(int column, int count, const QModelIndex &parent)
virtual bool insertRows(int row, int count, const QModelIndex &parent)
virtual int rowCount(const QModelIndex &parent) const const=0
T qobject_cast(QObject *object)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
virtual bool setData(const QModelIndex &index, const QVariant &value, int role) override
virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) override
bool isEmpty() const const
DisplayRole
Horizontal
int size() const const
void setParent(QWidget *parent)

© 2001 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-chart/
Generated on Wed May 1 2024 00:01:10 for KD Chart API Documentation by doxygen 1.9.8