KD Chart API Documentation  3.1
KDChartPlotter.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 "KDChartPlotter.h"
12 #include "KDChartPlotter_p.h"
13 
14 #include "KDChartAbstractGrid.h"
15 #include "KDChartPainterSaver_p.h"
16 
17 #include <KDABLibFakes>
18 
19 #include "KDChartNormalPlotter_p.h"
20 #include "KDChartPercentPlotter_p.h"
21 
22 using namespace KDChart;
23 
24 Plotter::Private::Private()
25 {
26 }
27 
28 Plotter::Private::~Private()
29 {
30  delete normalPlotter;
31  delete percentPlotter;
32 }
33 
34 #define d d_func()
35 
37  : AbstractCartesianDiagram(new Private(), parent, plane)
38 {
39  init();
40 }
41 
42 void Plotter::init()
43 {
44  d->diagram = this;
45  d->normalPlotter = new NormalPlotter(this);
46  d->percentPlotter = new PercentPlotter(this);
47  d->implementor = d->normalPlotter;
48  Private *test = d->implementor->plotterPrivate();
49  connect(this, &Plotter::boundariesChanged, test, &Private::changedProperties);
50  // The signal is connected to the superclass's AbstractDiagram slot at this point because the connection happened
51  // in its constructor when "its type was not Plotter yet".
57 }
58 
60 {
61 }
62 
67 {
68  auto *newDiagram = new Plotter(new Private(*d));
69  newDiagram->setType(type());
70  return newDiagram;
71 }
72 
73 bool Plotter::compare(const Plotter *other) const
74 {
75  if (other == this)
76  return true;
77  if (other == nullptr)
78  return false;
79  return // compare the base class
80  (static_cast<const AbstractCartesianDiagram *>(this)->compare(other)) &&
81  // compare own properties
82  (type() == other->type());
83 }
84 
86 {
87  // Order of setting the AttributesModel in compressor and diagram is very important due to slot
88  // invocation order. Refer to the longer comment in
89  // AbstractCartesianDiagram::connectAttributesModel() for details.
90 
92  d->plotterCompressor.setModel(nullptr);
94  } else {
95  d->compressor.setModel(nullptr);
96  if (attributesModel() != d->plotterCompressor.model()) {
97  d->plotterCompressor.setModel(attributesModel());
104  calcMergeRadius();
105  }
106  }
107  }
108 }
109 
111 {
112  return d->implementor->useCompression();
113 }
114 
116 {
117  if (useDataCompression() != value) {
118  d->implementor->setUseCompression(value);
120  d->compressor.setModel(nullptr);
121  if (attributesModel() != d->plotterCompressor.model())
122  d->plotterCompressor.setModel(attributesModel());
123  }
124  }
125 }
126 
128 {
129  return d->plotterCompressor.maxSlopeChange();
130 }
131 
132 void Plotter::setMaxSlopeChange(qreal value)
133 {
134  d->plotterCompressor.setMaxSlopeChange(value);
135 }
136 
138 {
139  return d->mergeRadiusPercentage;
140 }
141 
143 {
144  if (d->mergeRadiusPercentage != value) {
145  d->mergeRadiusPercentage = value;
146  // d->plotterCompressor.setMergeRadiusPercentage( value );
147  // update();
148  }
149 }
150 
154 void Plotter::setType(const PlotType type)
155 {
156  if (d->implementor->type() == type) {
157  return;
158  }
159  if (datasetDimension() != 2) {
160  Q_ASSERT_X(false, "setType()",
161  "This line chart type can only be used with two-dimensional data.");
162  return;
163  }
164  switch (type) {
165  case Normal:
166  d->implementor = d->normalPlotter;
167  break;
168  case Percent:
169  d->implementor = d->percentPlotter;
170  break;
171  default:
172  Q_ASSERT_X(false, "Plotter::setType", "unknown plotter subtype");
173  }
174  bool connection = connect(this, &Plotter::boundariesChanged,
175  d->implementor->plotterPrivate(), &KDChart::Plotter::Private::changedProperties);
176  Q_ASSERT(connection);
177  Q_UNUSED(connection);
178 
179  // d->lineType = type;
180  Q_ASSERT(d->implementor->type() == type);
181 
183  Q_EMIT layoutChanged(this);
184  Q_EMIT propertiesChanged();
185 }
186 
191 {
192  return d->implementor->type();
193 }
194 
199 {
200  d->attributesModel->setModelData(QVariant::fromValue(la), LineAttributesRole);
201  Q_EMIT propertiesChanged();
202 }
203 
207 void Plotter::setLineAttributes(int column, const LineAttributes &la)
208 {
209  d->setDatasetAttrs(column, QVariant::fromValue(la), LineAttributesRole);
210  Q_EMIT propertiesChanged();
211 }
212 
217 {
218  d->resetDatasetAttrs(column, LineAttributesRole);
219  Q_EMIT propertiesChanged();
220 }
221 
225 void Plotter::setLineAttributes(const QModelIndex &index, const LineAttributes &la)
226 {
227  d->attributesModel->setData(d->attributesModel->mapFromSource(index),
228  QVariant::fromValue(la), LineAttributesRole);
229  Q_EMIT propertiesChanged();
230 }
231 
235 void Plotter::resetLineAttributes(const QModelIndex &index)
236 {
237  d->attributesModel->resetData(
238  d->attributesModel->mapFromSource(index), LineAttributesRole);
239  Q_EMIT propertiesChanged();
240 }
241 
246 {
247  return d->attributesModel->data(KDChart::LineAttributesRole).value<LineAttributes>();
248 }
249 
254 {
255  const QVariant attrs(d->datasetAttrs(column, LineAttributesRole));
256  if (attrs.isValid())
257  return attrs.value<LineAttributes>();
258  return lineAttributes();
259 }
260 
264 LineAttributes Plotter::lineAttributes(const QModelIndex &index) const
265 {
266  return d->attributesModel->data(
267  d->attributesModel->mapFromSource(index), KDChart::LineAttributesRole)
268  .value<LineAttributes>();
269 }
270 
275 {
277  d->attributesModel->setModelData(QVariant::fromValue(la), ThreeDLineAttributesRole);
278  Q_EMIT propertiesChanged();
279 }
280 
285 {
287  d->setDatasetAttrs(column, QVariant::fromValue(la), ThreeDLineAttributesRole);
288  Q_EMIT propertiesChanged();
289 }
290 
294 void Plotter::setThreeDLineAttributes(const QModelIndex &index, const ThreeDLineAttributes &la)
295 {
297  d->attributesModel->setData(d->attributesModel->mapFromSource(index), QVariant::fromValue(la),
299  Q_EMIT propertiesChanged();
300 }
301 
306 {
307  return d->attributesModel->data(KDChart::ThreeDLineAttributesRole).value<ThreeDLineAttributes>();
308 }
309 
314 {
315  const QVariant attrs(d->datasetAttrs(column, ThreeDLineAttributesRole));
316  if (attrs.isValid()) {
317  return attrs.value<ThreeDLineAttributes>();
318  }
319  return threeDLineAttributes();
320 }
321 
326 {
327  return d->attributesModel->data(
328  d->attributesModel->mapFromSource(index), KDChart::ThreeDLineAttributesRole)
329  .value<ThreeDLineAttributes>();
330 }
331 
332 qreal Plotter::threeDItemDepth(const QModelIndex &index) const
333 {
334  return threeDLineAttributes(index).validDepth();
335 }
336 
337 qreal Plotter::threeDItemDepth(int column) const
338 {
339  return threeDLineAttributes(column).validDepth();
340 }
341 
345 void Plotter::setValueTrackerAttributes(const QModelIndex &index, const ValueTrackerAttributes &va)
346 {
347  d->attributesModel->setData(d->attributesModel->mapFromSource(index),
348  QVariant::fromValue(va), KDChart::ValueTrackerAttributesRole);
349  Q_EMIT propertiesChanged();
350 }
351 
356 {
357  return d->attributesModel->data(
358  d->attributesModel->mapFromSource(index), KDChart::ValueTrackerAttributesRole)
359  .value<ValueTrackerAttributes>();
360 }
361 
362 void Plotter::resizeEvent(QResizeEvent *)
363 {
364 }
365 
366 const QPair<QPointF, QPointF> Plotter::calculateDataBoundaries() const
367 {
368  if (!checkInvariants(true))
369  return QPair<QPointF, QPointF>(QPointF(0, 0), QPointF(0, 0));
370 
371  // note: calculateDataBoundaries() is ignoring the hidden flags.
372  // That's not a bug but a feature: Hiding data does not mean removing them.
373  // For totally removing data from KD Chart's view people can use e.g. a proxy model ...
374 
375  // calculate boundaries for different line types Normal - Stacked - Percent - Default Normal
376  return d->implementor->calculateDataBoundaries();
377 }
378 
379 void Plotter::paintEvent(QPaintEvent *)
380 {
381  QPainter painter(viewport());
382  PaintContext ctx;
383  ctx.setPainter(&painter);
384  ctx.setRectangle(QRectF(0, 0, width(), height()));
385  paint(&ctx);
386 }
387 
389 {
390  // note: Not having any data model assigned is no bug
391  // but we can not draw a diagram then either.
392  if (!checkInvariants(true))
393  return;
394 
395  AbstractCoordinatePlane *const plane = ctx->coordinatePlane();
396  if (!plane)
397  return;
398  d->setCompressorResolution(size(), plane);
399 
401  return;
402 
403  const PainterSaver p(ctx->painter());
404  if (model()->rowCount(rootIndex()) == 0 || model()->columnCount(rootIndex()) == 0)
405  return; // nothing to paint for us
406 
407  ctx->setCoordinatePlane(plane->sharedAxisMasterPlane(ctx->painter()));
408 
409  // paint different line types Normal - Stacked - Percent - Default Normal
410  d->implementor->paint(ctx);
411 
412  ctx->setCoordinatePlane(plane);
413 }
414 
415 void Plotter::resize(const QSizeF &size)
416 {
417  d->setCompressorResolution(size, coordinatePlane());
419  d->plotterCompressor.cleanCache();
420  calcMergeRadius();
421  }
423  QAbstractItemView::resize(size.toSize());
424 }
425 
427 {
430  calcMergeRadius();
431  // d->plotterCompressor.setMergeRadiusPercentage( d->mergeRadiusPercentage );
432  }
433 }
434 
436 {
437  auto *plane = dynamic_cast<CartesianCoordinatePlane *>(coordinatePlane());
438  Q_ASSERT(plane);
439  // Q_ASSERT( plane->translate( plane->translateBack( plane->visibleDiagramArea().topLeft() ) ) == plane->visibleDiagramArea().topLeft() );
440  QRectF range = plane->visibleDataRange();
441  // qDebug() << range;
442  const qreal radius = std::sqrt((range.x() + range.width()) * (range.y() + range.height()));
443  // qDebug() << radius;
444  // qDebug() << radius * d->mergeRadiusPercentage;
445  // qDebug() << d->mergeRadiusPercentage;
446  d->plotterCompressor.setMergeRadius(radius * d->mergeRadiusPercentage);
447 }
448 
449 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && defined(Q_COMPILER_MANGLES_RETURN_TYPE)
450 const
451 #endif
452  int
454 {
455  return d->attributesModel->rowCount(attributesModelRootIndex());
456 }
457 
458 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && defined(Q_COMPILER_MANGLES_RETURN_TYPE)
459 const
460 #endif
461  int
463 {
464  return d->attributesModel->columnCount(attributesModelRootIndex());
465 }
#define d
Base class for diagrams based on a cartesian coordianate system.
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane,...
virtual AbstractCoordinatePlane * sharedAxisMasterPlane(QPainter *p=nullptr)
void internal_geometryChanged(QRect, QRect)
void geometryChanged(QRect, QRect)
virtual AttributesModel * attributesModel() const
virtual bool checkInvariants(bool justReturnTheStatus=false) const
void layoutChanged(AbstractDiagram *)
QModelIndex attributesModelRootIndex() const
returns a QModelIndex pointing into the AttributesModel that corresponds to the root index of the dia...
const QPair< QPointF, QPointF > dataBoundaries() const
Return the bottom left and top right data point, that the diagram will display (unless the grid adjus...
AbstractCoordinatePlane * coordinatePlane() const
void attributesModelAboutToChange(AttributesModel *newModel, AttributesModel *oldModel)
void setDatasetDimensionInternal(int dimension)
static bool isBoundariesValid(const QRectF &r)
A proxy model used for decorating data with attributes.
Set of attributes for changing the appearance of line charts.
Stores information about painting diagrams.
void setPainter(QPainter *painter)
void setCoordinatePlane(AbstractCoordinatePlane *plane)
void setRectangle(const QRectF &rect)
AbstractCoordinatePlane * coordinatePlane() const
QPainter * painter() const
Plotter defines a diagram type plotting two-dimensional data.
bool compare(const Plotter *other) const
void paintEvent(QPaintEvent *) override
void setType(const PlotType type)
int numberOfAbscissaSegments() const override
void resizeEvent(QResizeEvent *) override
Plotter(QWidget *parent=nullptr, CartesianCoordinatePlane *plane=nullptr)
void resize(const QSizeF &area) override
virtual Plotter * clone() const
ThreeDLineAttributes threeDLineAttributes() const
PlotType type() const
void paint(PaintContext *paintContext) override
void setLineAttributes(const LineAttributes &a)
void resetLineAttributes(int column)
void setThreeDLineAttributes(const ThreeDLineAttributes &a)
void setMaxSlopeChange(qreal value)
LineAttributes lineAttributes() const
void setUseDataCompression(CompressionMode value)
qreal maxSlopeChange() const
CompressionMode useDataCompression
const QPair< QPointF, QPointF > calculateDataBoundaries() const override
void setMergeRadiusPercentage(qreal value)
qreal mergeRadiusPercentage
int numberOfOrdinateSegments() const override
void connectAttributesModel(AttributesModel *)
qreal threeDItemDepth(const QModelIndex &index) const override
ValueTrackerAttributes valueTrackerAttributes(const QModelIndex &index) const
void setValueTrackerAttributes(const QModelIndex &index, const ValueTrackerAttributes &a)
Cell-specific attributes regarding value tracking.
@ LineAttributesRole
@ ThreeDLineAttributesRole
@ ValueTrackerAttributesRole

© 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 by doxygen 1.9.1