KChart

KChartPlotter.cpp
1 /*
2  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "KChartPlotter.h"
21 #include "KChartPlotter_p.h"
22 
23 #include "KChartAbstractGrid.h"
24 #include "KChartPainterSaver_p.h"
25 #include "KChartMath_p.h"
26 
27 #include "KChartNormalPlotter_p.h"
28 #include "KChartPercentPlotter_p.h"
29 #include "KChartStackedPlotter_p.h"
30 
31 using namespace KChart;
32 
33 Plotter::Private::Private()
34  : implementor( nullptr )
35  , normalPlotter( nullptr )
36  , percentPlotter( nullptr )
37  , stackedPlotter( nullptr )
38 {
39 }
40 
41 Plotter::Private::~Private()
42 {
43  delete normalPlotter;
44  delete percentPlotter;
45  delete stackedPlotter;
46 }
47 
48 
49 #define d d_func()
50 
51 
52 Plotter::Plotter( QWidget* parent, CartesianCoordinatePlane* plane ) :
53  AbstractCartesianDiagram( new Private(), parent, plane )
54 {
55  init();
56 }
57 
58 void Plotter::init()
59 {
60  d->diagram = this;
61  d->normalPlotter = new NormalPlotter( this );
62  d->percentPlotter = new PercentPlotter( this );
63  d->stackedPlotter = new StackedPlotter( 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".
70  this, SLOT(connectAttributesModel(AttributesModel*)) );
72  this, SLOT(connectAttributesModel(AttributesModel*)) );
73  setDatasetDimensionInternal( 2 );
74 }
75 
76 Plotter::~Plotter()
77 {
78 }
79 
81 {
82  Plotter* newDiagram = new Plotter( new Private( *d ) );
83  newDiagram->setType( type() );
84  return newDiagram;
85 }
86 
87 bool Plotter::compare( const Plotter* other ) const
88 {
89  if ( other == this )
90  return true;
91  if ( other == nullptr )
92  return false;
93  return // compare the base class
94  ( static_cast< const AbstractCartesianDiagram* >( this )->compare( other ) ) &&
95  // compare own properties
96  ( type() == other->type() );
97 }
98 
99 void Plotter::connectAttributesModel( AttributesModel* newModel )
100 {
101  // Order of setting the AttributesModel in compressor and diagram is very important due to slot
102  // invocation order. Refer to the longer comment in
103  // AbstractCartesianDiagram::connectAttributesModel() for details.
104 
105  if ( useDataCompression() == Plotter::NONE )
106  {
107  d->plotterCompressor.setModel( nullptr );
108  AbstractCartesianDiagram::connectAttributesModel( newModel );
109  }
110  else
111  {
112  d->compressor.setModel( nullptr );
113  if ( attributesModel() != d->plotterCompressor.model() )
114  {
115  d->plotterCompressor.setModel( attributesModel() );
116  connect( &d->plotterCompressor, SIGNAL(boundariesChanged()), this, SLOT(setDataBoundariesDirty()) );
117  if ( useDataCompression() != Plotter::SLOPE )
118  {
119  connect( coordinatePlane(), SIGNAL(internal_geometryChanged(QRect,QRect)),
120  this, SLOT(setDataBoundariesDirty()) );
121  connect( coordinatePlane(), SIGNAL(geometryChanged(QRect,QRect)),
122  this, SLOT(setDataBoundariesDirty()) );
123  calcMergeRadius();
124  }
125  }
126  }
127 }
128 
129 Plotter::CompressionMode Plotter::useDataCompression() const
130 {
131  return d->implementor->useCompression();
132 }
133 
134 void Plotter::setUseDataCompression( Plotter::CompressionMode value )
135 {
136  if ( useDataCompression() != value )
137  {
138  d->implementor->setUseCompression( value );
139  if ( useDataCompression() != Plotter::NONE )
140  {
141  d->compressor.setModel( nullptr );
142  if ( attributesModel() != d->plotterCompressor.model() )
143  d->plotterCompressor.setModel( attributesModel() );
144  }
145  }
146 }
147 
148 qreal Plotter::maxSlopeChange() const
149 {
150  return d->plotterCompressor.maxSlopeChange();
151 }
152 
153 void Plotter::setMaxSlopeChange( qreal value )
154 {
155  d->plotterCompressor.setMaxSlopeChange( value );
156 }
157 
158 qreal Plotter::mergeRadiusPercentage() const
159 {
160  return d->mergeRadiusPercentage;
161 }
162 
163 void Plotter::setMergeRadiusPercentage( qreal value )
164 {
165  if ( d->mergeRadiusPercentage != value )
166  {
167  d->mergeRadiusPercentage = value;
168  //d->plotterCompressor.setMergeRadiusPercentage( value );
169  //update();
170  }
171 }
172 
173 void Plotter::setType( const PlotType type )
174 {
175  if ( d->implementor->type() == type ) {
176  return;
177  }
178  if ( datasetDimension() != 2 ) {
179  Q_ASSERT_X ( false, "setType()",
180  "This line chart type can only be used with two-dimensional data." );
181  return;
182  }
183  switch ( type ) {
184  case Normal:
185  d->implementor = d->normalPlotter;
186  break;
187  case Percent:
188  d->implementor = d->percentPlotter;
189  break;
190  case Stacked:
191  d->implementor = d->stackedPlotter;
192  break;
193  default:
194  Q_ASSERT_X( false, "Plotter::setType", "unknown plotter subtype" );
195  }
196  bool connection = connect( this, SIGNAL(boundariesChanged()),
197  d->implementor->plotterPrivate(), SLOT(changedProperties()) );
198  Q_ASSERT( connection );
199  Q_UNUSED( connection );
200 
201  // d->lineType = type;
202  Q_ASSERT( d->implementor->type() == type );
203 
204  setDataBoundariesDirty();
205  Q_EMIT layoutChanged( this );
207 }
208 
209 Plotter::PlotType Plotter::type() const
210 {
211  return d->implementor->type();
212 }
213 
215 {
216  d->attributesModel->setModelData( QVariant::fromValue( la ), LineAttributesRole );
218 }
219 
220 void Plotter::setLineAttributes( int column, const LineAttributes& la )
221 {
222  d->setDatasetAttrs( column, QVariant::fromValue( la ), LineAttributesRole );
224 }
225 
227 {
228  d->resetDatasetAttrs( column, LineAttributesRole );
230 }
231 
232 void Plotter::setLineAttributes( const QModelIndex & index, const LineAttributes& la )
233 {
234  d->attributesModel->setData( d->attributesModel->mapFromSource( index ),
235  QVariant::fromValue( la ), LineAttributesRole );
237 }
238 
240 {
241  d->attributesModel->resetData(
242  d->attributesModel->mapFromSource(index), LineAttributesRole );
244 }
245 
247 {
248  return d->attributesModel->data( KChart::LineAttributesRole ).value<LineAttributes>();
249 }
250 
252 {
253  const QVariant attrs( d->datasetAttrs( column, LineAttributesRole ) );
254  if ( attrs.isValid() )
255  return attrs.value<LineAttributes>();
256  return lineAttributes();
257 }
258 
260 {
261  return d->attributesModel->data(
262  d->attributesModel->mapFromSource( index ), KChart::LineAttributesRole ).value<LineAttributes>();
263 }
264 
266 {
267  setDataBoundariesDirty();
268  d->attributesModel->setModelData( QVariant::fromValue( la ), ThreeDLineAttributesRole );
270 }
271 
273 {
274  setDataBoundariesDirty();
275  d->setDatasetAttrs( column, QVariant::fromValue( la ), ThreeDLineAttributesRole );
277 }
278 
280 {
281  setDataBoundariesDirty();
282  d->attributesModel->setData( d->attributesModel->mapFromSource( index ), QVariant::fromValue( la ),
283  ThreeDLineAttributesRole );
285 }
286 
288 {
289  return d->attributesModel->data( KChart::ThreeDLineAttributesRole ).value<ThreeDLineAttributes>();
290 }
291 
293 {
294  const QVariant attrs( d->datasetAttrs( column, ThreeDLineAttributesRole ) );
295  if ( attrs.isValid() ) {
296  return attrs.value<ThreeDLineAttributes>();
297  }
298  return threeDLineAttributes();
299 }
300 
302 {
303  return d->attributesModel->data(
304  d->attributesModel->mapFromSource( index ), KChart::ThreeDLineAttributesRole ).value<ThreeDLineAttributes>();
305 }
306 
307 qreal Plotter::threeDItemDepth( const QModelIndex & index ) const
308 {
309  return threeDLineAttributes( index ).validDepth();
310 }
311 
312 qreal Plotter::threeDItemDepth( int column ) const
313 {
314  return threeDLineAttributes( column ).validDepth();
315 }
316 
318 {
319  d->attributesModel->setData( d->attributesModel->mapFromSource( index ),
320  QVariant::fromValue( va ), KChart::ValueTrackerAttributesRole );
322 }
323 
325 {
326  return d->attributesModel->data(
327  d->attributesModel->mapFromSource( index ), KChart::ValueTrackerAttributesRole ).value<ValueTrackerAttributes>();
328 }
329 
330 void Plotter::resizeEvent ( QResizeEvent* )
331 {
332 }
333 
335 {
336  if ( !checkInvariants( true ) )
337  return QPair< QPointF, QPointF >( QPointF( 0, 0 ), QPointF( 0, 0 ) );
338 
339  // note: calculateDataBoundaries() is ignoring the hidden flags.
340  // That's not a bug but a feature: Hiding data does not mean removing them.
341  // For totally removing data from KD Chart's view people can use e.g. a proxy model ...
342 
343  // calculate boundaries for different line types Normal - Stacked - Percent - Default Normal
344  return d->implementor->calculateDataBoundaries();
345 }
346 
347 
348 void Plotter::paintEvent ( QPaintEvent*)
349 {
350  QPainter painter ( viewport() );
351  PaintContext ctx;
352  ctx.setPainter ( &painter );
353  ctx.setRectangle ( QRectF ( 0, 0, width(), height() ) );
354  paint ( &ctx );
355 }
356 
358 {
359  // note: Not having any data model assigned is no bug
360  // but we can not draw a diagram then either.
361  if ( !checkInvariants( true ) ) return;
362 
363  AbstractCoordinatePlane* const plane = ctx->coordinatePlane();
364  if ( ! plane ) return;
365  d->setCompressorResolution( size(), plane );
366 
368 
369  const PainterSaver p( ctx->painter() );
370  if ( model()->rowCount( rootIndex() ) == 0 || model()->columnCount( rootIndex() ) == 0 )
371  return; // nothing to paint for us
372 
373  ctx->setCoordinatePlane( plane->sharedAxisMasterPlane( ctx->painter() ) );
374 
375  // paint different line types Normal - Stacked - Percent - Default Normal
376  d->implementor->paint( ctx );
377 
378  ctx->setCoordinatePlane( plane );
379 }
380 
381 void Plotter::resize ( const QSizeF& size )
382 {
383  d->setCompressorResolution( size, coordinatePlane() );
384  if ( useDataCompression() == Plotter::BOTH || useDataCompression() == Plotter::DISTANCE )
385  {
386  d->plotterCompressor.cleanCache();
387  calcMergeRadius();
388  }
389  setDataBoundariesDirty();
391 }
392 
393 void Plotter::setDataBoundariesDirty()
394 {
395  AbstractCartesianDiagram::setDataBoundariesDirty();
396  if ( useDataCompression() == Plotter::DISTANCE || useDataCompression() == Plotter::BOTH )
397  {
398  calcMergeRadius();
399  //d->plotterCompressor.setMergeRadiusPercentage( d->mergeRadiusPercentage );
400  }
401 }
402 
403 void Plotter::calcMergeRadius()
404 {
406  Q_ASSERT( plane );
407  //Q_ASSERT( plane->translate( plane->translateBack( plane->visibleDiagramArea().topLeft() ) ) == plane->visibleDiagramArea().topLeft() );
408  QRectF range = plane->visibleDataRange();
409  //qDebug() << range;
410  const qreal radius = std::sqrt( ( range.x() + range.width() ) * ( range.y() + range.height() ) );
411  //qDebug() << radius;
412  //qDebug() << radius * d->mergeRadiusPercentage;
413  //qDebug() << d->mergeRadiusPercentage;
414  d->plotterCompressor.setMergeRadius( radius * d->mergeRadiusPercentage );
415 }
416 
417 #if defined(Q_COMPILER_MANGLES_RETURN_TYPE)
418 const
419 #endif
420 int Plotter::numberOfAbscissaSegments () const
421 {
422  return d->attributesModel->rowCount( attributesModelRootIndex() );
423 }
424 
425 #if defined(Q_COMPILER_MANGLES_RETURN_TYPE)
426 const
427 #endif
428 int Plotter::numberOfOrdinateSegments () const
429 {
430  return d->attributesModel->columnCount( attributesModelRootIndex() );
431 }
Class only listed here to document inheritance of some KChart classes.
virtual int rowCount(const QModelIndex &parent) const const =0
A set of 3D line attributes.
Plotter defines a diagram type plotting two-dimensional data.
Definition: KChartPlotter.h:35
qreal x() const const
qreal y() const const
static bool isBoundariesValid(const QRectF &r)
Checks whether both coordinates of r are valid according to isValueValid.
const QPair< QPointF, QPointF > calculateDataBoundaries() const override
bool compare(const Plotter *other) const
Returns true if both diagrams have the same settings.
QModelIndex attributesModelRootIndex() const
T value() const const
QWidget * viewport() const const
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 resize(const QSizeF &area) override
Called by the widget&#39;s sizeEvent.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
void setType(const PlotType type)
Sets the plotter&#39;s type to type.
Set of attributes for changing the appearance of line charts.
int width() const const
void paint(PaintContext *paintContext) override
virtual AttributesModel * attributesModel() const
Returns the AttributesModel, that is used by this diagram.
QSize size() const const
void propertiesChanged()
Emitted upon change of a property of the Diagram.
KGuiItem test()
Stores information about painting diagrams.
Class only listed here to document inheritance of some KChart classes.
Base class for diagrams based on a cartesian coordianate system.
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane.
void layoutChanged(AbstractDiagram *)
Diagrams are supposed to emit this signal, when the layout of one of their element changes...
ThreeDLineAttributes threeDLineAttributes() const
bool compare(const AbstractPieDiagram *other) const
Returns true if both diagrams have the same settings.
A proxy model used for decorating data with attributes.
void resetLineAttributes(int column)
Resets the line attributes of data set column.
ValueTrackerAttributes valueTrackerAttributes(const QModelIndex &index) const
Returns the value tracker attributes of the model index index.
Cell-specific attributes regarding value tracking.
QVariant fromValue(const T &value)
QCA_EXPORT void init()
QModelIndex rootIndex() const const
virtual void resize(const QSizeF &area)
Called by the widget&#39;s sizeEvent.
qreal width() const const
virtual int columnCount(const QModelIndex &parent) const const =0
qreal threeDItemDepth(const QModelIndex &index) const override
AbstractCoordinatePlane * coordinatePlane() const
The coordinate plane associated with the diagram.
void setThreeDLineAttributes(const ThreeDLineAttributes &la)
Sets the global 3D line attributes to la.
void attributesModelAboutToChange(AttributesModel *newModel, AttributesModel *oldModel)
This signal is emitted just before the new attributes model is connected internally.
qreal height() const const
void boundariesChanged()
Emitted upon change of a data boundary.
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 &va)
Sets the value tracker attributes of the model index index to va.
QAbstractItemModel * model() const const
Global namespace.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
void setLineAttributes(const LineAttributes &la)
Sets the global line attributes to la.
virtual Plotter * clone() const
Creates an exact copy of this diagram.
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.
int height() const const
Q_EMITQ_EMIT
PlotType type() const
LineAttributes lineAttributes() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Wed Jan 20 2021 22:39:31 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.