KD Chart 2  [rev.2.7]
KDChartPlotter.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2020 Klaralvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Chart library.
5 **
6 ** Licensees holding valid commercial KD Chart licenses may use this file in
7 ** accordance with the KD Chart Commercial License Agreement provided with
8 ** the Software.
9 **
10 **
11 ** This file may be distributed and/or modified under the terms of the
12 ** GNU General Public License version 2 and version 3 as published by the
13 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contact info@kdab.com if any conditions of this licensing are not
19 ** clear to you.
20 **
21 **********************************************************************/
22 
23 #include "KDChartPlotter.h"
24 #include "KDChartPlotter_p.h"
25 
26 #include "KDChartAbstractGrid.h"
27 #include "KDChartPainterSaver_p.h"
28 
29 #include <KDABLibFakes>
30 
31 #include "KDChartNormalPlotter_p.h"
32 #include "KDChartPercentPlotter_p.h"
33 
34 using namespace KDChart;
35 
36 Plotter::Private::Private()
37  : implementor( 0 )
38  , normalPlotter( 0 )
39  , percentPlotter( 0 )
40 {
41 }
42 
43 Plotter::Private::~Private()
44 {
45  delete normalPlotter;
46  delete percentPlotter;
47 }
48 
49 
50 #define d d_func()
51 
52 
54  AbstractCartesianDiagram( new Private(), parent, plane )
55 {
56  init();
57 }
58 
59 void Plotter::init()
60 {
61  d->diagram = this;
62  d->normalPlotter = new NormalPlotter( this );
63  d->percentPlotter = new PercentPlotter( this );
64  d->implementor = d->normalPlotter;
65  QObject* test = d->implementor->plotterPrivate();
66  connect( this, SIGNAL( boundariesChanged() ), test, SLOT( changedProperties() ) );
67  // The signal is connected to the superclass's slot at this point because the connection happened
68  // in its constructor when "its type was not Plotter yet".
69  disconnect( this, SIGNAL( attributesModelAboutToChange( AttributesModel*, AttributesModel* ) ),
70  this, SLOT( connectAttributesModel( AttributesModel* ) ) );
71  connect( this, SIGNAL( attributesModelAboutToChange( AttributesModel*, AttributesModel* ) ),
72  this, SLOT( connectAttributesModel( AttributesModel* ) ) );
74 }
75 
77 {
78 }
79 
84 {
85  Plotter* newDiagram = new Plotter( new Private( *d ) );
86  newDiagram->setType( type() );
87  return newDiagram;
88 }
89 
90 bool Plotter::compare( const Plotter* other ) const
91 {
92  if ( other == this )
93  return true;
94  if ( other == 0 )
95  return false;
96  return // compare the base class
97  ( static_cast< const AbstractCartesianDiagram* >( this )->compare( other ) ) &&
98  // compare own properties
99  ( type() == other->type() );
100 }
101 
103 {
104  // Order of setting the AttributesModel in compressor and diagram is very important due to slot
105  // invocation order. Refer to the longer comment in
106  // AbstractCartesianDiagram::connectAttributesModel() for details.
107 
109  {
110  d->plotterCompressor.setModel( 0 );
112  }
113  else
114  {
115  d->compressor.setModel( 0 );
116  if ( attributesModel() != d->plotterCompressor.model() )
117  {
118  d->plotterCompressor.setModel( attributesModel() );
119  connect( &d->plotterCompressor, SIGNAL( boundariesChanged() ), this, SLOT(setDataBoundariesDirty() ) );
121  {
122  connect( coordinatePlane(), SIGNAL( internal_geometryChanged( QRect,QRect ) ),
123  this, SLOT( setDataBoundariesDirty() ) );
124  connect( coordinatePlane(), SIGNAL( geometryChanged( QRect,QRect ) ),
125  this, SLOT( setDataBoundariesDirty() ) );
126  calcMergeRadius();
127  }
128  }
129  }
130 }
131 
133 {
134  return d->implementor->useCompression();
135 }
136 
138 {
139  if ( useDataCompression() != value )
140  {
141  d->implementor->setUseCompression( value );
143  {
144  d->compressor.setModel( NULL );
145  if ( attributesModel() != d->plotterCompressor.model() )
146  d->plotterCompressor.setModel( attributesModel() );
147  }
148  }
149 }
150 
152 {
153  return d->plotterCompressor.maxSlopeChange();
154 }
155 
156 void Plotter::setMaxSlopeChange( qreal value )
157 {
158  d->plotterCompressor.setMaxSlopeChange( value );
159 }
160 
161 qreal Plotter::mergeRadiusPercentage() const
162 {
163  return d->mergeRadiusPercentage;
164 }
165 
167 {
168  if ( d->mergeRadiusPercentage != value )
169  {
170  d->mergeRadiusPercentage = value;
171  //d->plotterCompressor.setMergeRadiusPercentage( value );
172  //update();
173  }
174 }
175 
180 {
181  if ( d->implementor->type() == type ) {
182  return;
183  }
184  if ( datasetDimension() != 2 ) {
185  Q_ASSERT_X ( false, "setType()",
186  "This line chart type can only be used with two-dimensional data." );
187  return;
188  }
189  switch ( type ) {
190  case Normal:
191  d->implementor = d->normalPlotter;
192  break;
193  case Percent:
194  d->implementor = d->percentPlotter;
195  break;
196  default:
197  Q_ASSERT_X( false, "Plotter::setType", "unknown plotter subtype" );
198  }
199  bool connection = connect( this, SIGNAL( boundariesChanged() ),
200  d->implementor->plotterPrivate(), SLOT( changedProperties() ) );
201  Q_ASSERT( connection );
202  Q_UNUSED( connection );
203 
204  // d->lineType = type;
205  Q_ASSERT( d->implementor->type() == type );
206 
208  emit layoutChanged( this );
209  emit propertiesChanged();
210 }
211 
216 {
217  return d->implementor->type();
218 }
219 
224 {
225  d->attributesModel->setModelData( qVariantFromValue( la ), LineAttributesRole );
226  emit propertiesChanged();
227 }
228 
232 void Plotter::setLineAttributes( int column, const LineAttributes& la )
233 {
234  d->setDatasetAttrs( column, qVariantFromValue( la ), LineAttributesRole );
235  emit propertiesChanged();
236 }
237 
242 {
243  d->resetDatasetAttrs( column, LineAttributesRole );
244  emit propertiesChanged();
245 }
246 
250 void Plotter::setLineAttributes( const QModelIndex & index, const LineAttributes& la )
251 {
252  d->attributesModel->setData( d->attributesModel->mapFromSource( index ),
253  qVariantFromValue( la ), LineAttributesRole );
254  emit propertiesChanged();
255 }
256 
260 void Plotter::resetLineAttributes( const QModelIndex & index )
261 {
262  d->attributesModel->resetData(
263  d->attributesModel->mapFromSource(index), LineAttributesRole );
264  emit propertiesChanged();
265 }
266 
271 {
272  return d->attributesModel->data( KDChart::LineAttributesRole ).value<LineAttributes>();
273 }
274 
279 {
280  const QVariant attrs( d->datasetAttrs( column, LineAttributesRole ) );
281  if ( attrs.isValid() )
282  return attrs.value<LineAttributes>();
283  return lineAttributes();
284 }
285 
289 LineAttributes Plotter::lineAttributes( const QModelIndex& index ) const
290 {
291  return d->attributesModel->data(
292  d->attributesModel->mapFromSource( index ), KDChart::LineAttributesRole ).value<LineAttributes>();
293 }
294 
299 {
301  d->attributesModel->setModelData( qVariantFromValue( la ), ThreeDLineAttributesRole );
302  emit propertiesChanged();
303 }
304 
309 {
311  d->setDatasetAttrs( column, qVariantFromValue( la ), ThreeDLineAttributesRole );
312  emit propertiesChanged();
313 }
314 
318 void Plotter::setThreeDLineAttributes( const QModelIndex& index, const ThreeDLineAttributes& la )
319 {
321  d->attributesModel->setData( d->attributesModel->mapFromSource( index ), qVariantFromValue( la ),
323  emit propertiesChanged();
324 }
325 
330 {
331  return d->attributesModel->data( KDChart::ThreeDLineAttributesRole ).value<ThreeDLineAttributes>();
332 }
333 
338 {
339  const QVariant attrs( d->datasetAttrs( column, ThreeDLineAttributesRole ) );
340  if ( attrs.isValid() ) {
341  return attrs.value<ThreeDLineAttributes>();
342  }
343  return threeDLineAttributes();
344 }
345 
349 ThreeDLineAttributes Plotter::threeDLineAttributes( const QModelIndex& index ) const
350 {
351  return d->attributesModel->data(
352  d->attributesModel->mapFromSource( index ), KDChart::ThreeDLineAttributesRole ).value<ThreeDLineAttributes>();
353 }
354 
355 qreal Plotter::threeDItemDepth( const QModelIndex & index ) const
356 {
357  return threeDLineAttributes( index ).validDepth();
358 }
359 
360 qreal Plotter::threeDItemDepth( int column ) const
361 {
362  return threeDLineAttributes( column ).validDepth();
363 }
364 
368 void Plotter::setValueTrackerAttributes( const QModelIndex & index, const ValueTrackerAttributes & va )
369 {
370  d->attributesModel->setData( d->attributesModel->mapFromSource( index ),
371  qVariantFromValue( va ), KDChart::ValueTrackerAttributesRole );
372  emit propertiesChanged();
373 }
374 
378 ValueTrackerAttributes Plotter::valueTrackerAttributes( const QModelIndex & index ) const
379 {
380  return d->attributesModel->data(
381  d->attributesModel->mapFromSource( index ), KDChart::ValueTrackerAttributesRole ).value<ValueTrackerAttributes>();
382 }
383 
384 void Plotter::resizeEvent ( QResizeEvent* )
385 {
386 }
387 
389 {
390  if ( !checkInvariants( true ) )
391  return QPair< QPointF, QPointF >( QPointF( 0, 0 ), QPointF( 0, 0 ) );
392 
393  // note: calculateDataBoundaries() is ignoring the hidden flags.
394  // That's not a bug but a feature: Hiding data does not mean removing them.
395  // For totally removing data from KD Chart's view people can use e.g. a proxy model ...
396 
397  // calculate boundaries for different line types Normal - Stacked - Percent - Default Normal
398  return d->implementor->calculateDataBoundaries();
399 }
400 
401 
402 void Plotter::paintEvent ( QPaintEvent*)
403 {
404  QPainter painter ( viewport() );
405  PaintContext ctx;
406  ctx.setPainter ( &painter );
407  ctx.setRectangle ( QRectF ( 0, 0, width(), height() ) );
408  paint ( &ctx );
409 }
410 
412 {
413  // note: Not having any data model assigned is no bug
414  // but we can not draw a diagram then either.
415  if ( !checkInvariants( true ) ) return;
416 
417  AbstractCoordinatePlane* const plane = ctx->coordinatePlane();
418  if ( ! plane ) return;
419  d->setCompressorResolution( size(), plane );
420 
421  if ( !AbstractGrid::isBoundariesValid(dataBoundaries()) ) return;
422 
423  const PainterSaver p( ctx->painter() );
424  if ( model()->rowCount( rootIndex() ) == 0 || model()->columnCount( rootIndex() ) == 0 )
425  return; // nothing to paint for us
426 
427  ctx->setCoordinatePlane( plane->sharedAxisMasterPlane( ctx->painter() ) );
428 
429  // paint different line types Normal - Stacked - Percent - Default Normal
430  d->implementor->paint( ctx );
431 
432  ctx->setCoordinatePlane( plane );
433 }
434 
435 void Plotter::resize ( const QSizeF& size )
436 {
437  d->setCompressorResolution( size, coordinatePlane() );
439  {
440  d->plotterCompressor.cleanCache();
441  calcMergeRadius();
442  }
444  QAbstractItemView::resize( size.toSize() );
445 }
446 
448 {
451  {
452  calcMergeRadius();
453  //d->plotterCompressor.setMergeRadiusPercentage( d->mergeRadiusPercentage );
454  }
455 }
456 
458 {
460  Q_ASSERT( plane );
461  //Q_ASSERT( plane->translate( plane->translateBack( plane->visibleDiagramArea().topLeft() ) ) == plane->visibleDiagramArea().topLeft() );
462  QRectF range = plane->visibleDataRange();
463  //qDebug() << range;
464  const qreal radius = std::sqrt( ( range.x() + range.width() ) * ( range.y() + range.height() ) );
465  //qDebug() << radius;
466  //qDebug() << radius * d->mergeRadiusPercentage;
467  //qDebug() << d->mergeRadiusPercentage;
468  d->plotterCompressor.setMergeRadius( radius * d->mergeRadiusPercentage );
469 }
470 
471 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE)
472 const
473 #endif
475 {
476  return d->attributesModel->rowCount( attributesModelRootIndex() );
477 }
478 
479 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE)
480 const
481 #endif
483 {
484  return d->attributesModel->columnCount( attributesModelRootIndex() );
485 }
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane.
virtual AbstractCoordinatePlane * sharedAxisMasterPlane(QPainter *p=0)
qreal maxSlopeChange() const
void setPainter(QPainter *painter)
virtual bool checkInvariants(bool justReturnTheStatus=false) const
AbstractCoordinatePlane * coordinatePlane() const
#define d
QPainter * painter() const
virtual AttributesModel * attributesModel() const
Returns the AttributesModel, that is used by this diagram.
AbstractCoordinatePlane * coordinatePlane() const
The coordinate plane associated with the diagram.
void paint(PaintContext *paintContext) override
Draw the diagram contents to the rectangle and painter, that are passed in as part of the paint conte...
void setValueTrackerAttributes(const QModelIndex &index, const ValueTrackerAttributes &a)
Sets the value tracker attributes of the model index index to va.
virtual Plotter * clone() const
Creates an exact copy of this diagram.
Plotter(QWidget *parent=0, CartesianCoordinatePlane *plane=0)
void setDatasetDimensionInternal(int dimension)
Plotter defines a diagram type plotting two-dimensional data.
ThreeDLineAttributes threeDLineAttributes() const
void setMergeRadiusPercentage(qreal value)
Set of attributes for changing the appearance of line charts.
const QPair< QPointF, QPointF > dataBoundaries() const
Return the bottom left and top right data point, that the diagram will display (unless the grid adjus...
void connectAttributesModel(AttributesModel *)
void setThreeDLineAttributes(const ThreeDLineAttributes &a)
Sets the global 3D line attributes to la.
void setType(const PlotType type)
Sets the plotter&#39;s type to type.
bool compare(const Plotter *other) const
Returns true if both diagrams have the same settings.
void resize(const QSizeF &area) override
Called by the widget&#39;s sizeEvent.
void resetLineAttributes(int column)
Resets the line attributes of data set column.
qreal threeDItemDepth(const QModelIndex &index) const override
void propertiesChanged()
Emitted upon change of a property of the Diagram.
A proxy model used for decorating data with attributes.
void paintEvent(QPaintEvent *) override
PlotType type() const
LineAttributes lineAttributes() const
Cell-specific attributes regarding value tracking.
void setMaxSlopeChange(qreal value)
Base class for diagrams based on a cartesian coordianate system.
Stores information about painting diagrams.
void setUseDataCompression(CompressionMode value)
void resizeEvent(QResizeEvent *) override
const int numberOfOrdinateSegments() const
void layoutChanged(AbstractDiagram *)
Diagrams are supposed to emit this signal, when the layout of one of their element changes...
const int numberOfAbscissaSegments() const
QModelIndex attributesModelRootIndex() const
qreal mergeRadiusPercentage() const
Class only listed here to document inheritance of some KDChart classes.
void boundariesChanged()
Emitted upon change of a data boundary.
void setCoordinatePlane(AbstractCoordinatePlane *plane)
void setLineAttributes(const LineAttributes &a)
Sets the global line attributes to la.
const QPair< QPointF, QPointF > calculateDataBoundaries() const override
[reimplemented]
void setRectangle(const QRectF &rect)
Class only listed here to document inheritance of some KDChart classes.
void attributesModelAboutToChange(AttributesModel *newModel, AttributesModel *oldModel)
This signal is emitted just before the new attributes model is connected internally.
ValueTrackerAttributes valueTrackerAttributes(const QModelIndex &index) const
Returns the value tracker attributes of the model index index.
int datasetDimension() const
The dataset dimension of a diagram determines how many value dimensions it expects each datapoint to ...
QRectF visibleDataRange() const
Returns the currently visible data range.
CompressionMode useDataCompression() const
A set of 3D line attributes.

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/