KChart

KChartAbstractDiagram.cpp
1 /*
2  * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #include "KChartAbstractDiagram.h"
10 #include "KChartAbstractDiagram_p.h"
11 
12 #include <QPainter>
13 #include <QPainterPath>
14 #include <QDebug>
15 #include <QApplication>
16 #include <QAbstractProxyModel>
17 #include <QSizeF>
18 #include <QPainterPath>
19 
20 #include "KChartAbstractCoordinatePlane.h"
21 #include "KChartChart.h"
23 #include "KChartTextAttributes.h"
24 #include "KChartMarkerAttributes.h"
25 #include "KChartAbstractThreeDAttributes.h"
26 #include "KChartThreeDLineAttributes.h"
27 #include "KChartPainterSaver_p.h"
28 
29 #include <limits>
30 
31 using namespace KChart;
32 
33 #define d d_func()
34 
35 AbstractDiagram::AbstractDiagram ( QWidget* parent, AbstractCoordinatePlane* plane )
36  : QAbstractItemView ( parent ), _d( new Private() )
37 {
38  _d->init( plane );
39  init();
40 }
41 
42 AbstractDiagram::~AbstractDiagram()
43 {
44  Q_EMIT aboutToBeDestroyed();
45  delete _d;
46 }
47 
48 void AbstractDiagram::init()
49 {
50  _d->diagram = this;
51  d->reverseMapper.setDiagram( this );
52 }
53 
54 
55 bool AbstractDiagram::compare( const AbstractDiagram* other ) const
56 {
57  if ( other == this ) return true;
58  if ( !other ) {
59  return false;
60  }
61  return // compare QAbstractScrollArea properties
62  (horizontalScrollBarPolicy() == other->horizontalScrollBarPolicy()) &&
63  (verticalScrollBarPolicy() == other->verticalScrollBarPolicy()) &&
64  // compare QFrame properties
65  (frameShadow() == other->frameShadow()) &&
66  (frameShape() == other->frameShape()) &&
67 // frameWidth is a read-only property defined by the style, it should not be in here:
68  // (frameWidth() == other->frameWidth()) &&
69  (lineWidth() == other->lineWidth()) &&
70  (midLineWidth() == other->midLineWidth()) &&
71  // compare QAbstractItemView properties
72  (alternatingRowColors() == other->alternatingRowColors()) &&
73  (hasAutoScroll() == other->hasAutoScroll()) &&
74  (dragDropMode() == other->dragDropMode()) &&
75  (dragDropOverwriteMode() == other->dragDropOverwriteMode()) &&
76  (horizontalScrollMode() == other->horizontalScrollMode ()) &&
77  (verticalScrollMode() == other->verticalScrollMode()) &&
78  (dragEnabled() == other->dragEnabled()) &&
79  (editTriggers() == other->editTriggers()) &&
80  (iconSize() == other->iconSize()) &&
81  (selectionBehavior() == other->selectionBehavior()) &&
82  (selectionMode() == other->selectionMode()) &&
83  (showDropIndicator() == other->showDropIndicator()) &&
84  (tabKeyNavigation() == other->tabKeyNavigation()) &&
85  (textElideMode() == other->textElideMode()) &&
86  // compare all of the properties stored in the attributes model
87  attributesModel()->compare( other->attributesModel() ) &&
88  // compare own properties
89  (rootIndex().column() == other->rootIndex().column()) &&
90  (rootIndex().row() == other->rootIndex().row()) &&
91  (allowOverlappingDataValueTexts() == other->allowOverlappingDataValueTexts()) &&
92  (antiAliasing() == other->antiAliasing()) &&
93  (percentMode() == other->percentMode()) &&
94  (datasetDimension() == other->datasetDimension());
95 }
96 
98 {
99  return d->plane;
100 }
101 
103 {
104  if ( d->databoundariesDirty ) {
105  d->databoundaries = calculateDataBoundaries ();
106  d->databoundariesDirty = false;
107  }
108  return d->databoundaries;
109 }
110 
111 void AbstractDiagram::setDataBoundariesDirty() const
112 {
113  d->databoundariesDirty = true;
114  update();
115 }
116 
118 {
119  d->diagramSize = size;
121 }
122 
124 {
125  if ( newModel == model() ) {
126  return;
127  }
128 
129  AttributesModel* amodel = new PrivateAttributesModel( newModel, this );
130  amodel->initFrom( d->attributesModel );
131  d->setAttributesModel(amodel);
132 
133  QAbstractItemView::setModel( newModel );
134 
135  scheduleDelayedItemsLayout();
136  setDataBoundariesDirty();
137  Q_EMIT modelsChanged();
138 }
139 
141 {
142  if ( selectionModel() )
143  {
144  disconnect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SIGNAL(modelsChanged()) );
145  disconnect( selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SIGNAL(modelsChanged()) );
146  }
147  QAbstractItemView::setSelectionModel( newSelectionModel );
148  if ( selectionModel() )
149  {
150  connect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SIGNAL(modelsChanged()) );
151  connect( selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SIGNAL(modelsChanged()) );
152  }
153  Q_EMIT modelsChanged();
154 }
155 
156 /* Sets an external AttributesModel on this diagram. By default, a diagram has it's
157  own internal set of attributes, but an external one can be set. This can be used to
158  share attributes between several diagrams. The diagram does not take ownership of the
159  attributesmodel.
160 
161  @param amodel The AttributesModel to use for this diagram.
162 */
164 {
165  if ( amodel->sourceModel() != model() ) {
166  qWarning("KChart::AbstractDiagram::setAttributesModel() failed: "
167  "Trying to set an attributesmodel which works on a different "
168  "model than the diagram.");
169  return;
170  }
171  if ( qobject_cast<PrivateAttributesModel*>(amodel) ) {
172  qWarning("KChart::AbstractDiagram::setAttributesModel() failed: "
173  "Trying to set an attributesmodel that is private to another diagram.");
174  return;
175  }
176 
177  d->setAttributesModel( amodel );
178  scheduleDelayedItemsLayout();
179  setDataBoundariesDirty();
180  Q_EMIT modelsChanged();
181 }
182 
184 {
185  return d->usesExternalAttributesModel();
186 }
187 
189 {
190  return d->attributesModel;
191 }
192 
193 QModelIndex AbstractDiagram::conditionallyMapFromSource( const QModelIndex & index ) const
194 {
195  Q_ASSERT( !index.isValid() || index.model() == attributesModel() || index.model() == attributesModel()->sourceModel() );
196  return index.model() == attributesModel() ? index : attributesModel()->mapFromSource( index );
197 }
198 
199 /* \reimpl */
201 {
203  setAttributesModelRootIndex( d->attributesModel->mapFromSource( idx ) );
204 }
205 
207 {
208  d->attributesModelRootIndex = idx;
209  setDataBoundariesDirty();
210  scheduleDelayedItemsLayout();
211 }
212 
214 {
215  if ( !d->attributesModelRootIndex.isValid() )
216  d->attributesModelRootIndex = d->attributesModel->mapFromSource( rootIndex() );
217  return d->attributesModelRootIndex;
218 }
219 
221 {
222  d->plane = parent;
223 }
224 
226 {
227  if ( d->plane ) {
228  d->plane->layoutDiagrams();
229  update();
230  }
231  QAbstractItemView::doItemsLayout();
232 }
233 
235  const QModelIndex &bottomRight,
236  const QVector<int> & )
237 {
238  Q_UNUSED( topLeft );
239  Q_UNUSED( bottomRight );
240  // We are still too dumb to do intelligent updates...
241  setDataBoundariesDirty();
242  scheduleDelayedItemsLayout();
243 }
244 
245 
246 void AbstractDiagram::setHidden( const QModelIndex & index, bool hidden )
247 {
248  d->attributesModel->setData(
249  conditionallyMapFromSource( index ),
250  QVariant::fromValue( hidden ),
251  DataHiddenRole );
252  Q_EMIT dataHidden();
253 }
254 
255 void AbstractDiagram::setHidden( int dataset, bool hidden )
256 {
257  d->setDatasetAttrs( dataset, QVariant::fromValue( hidden ), DataHiddenRole );
258  Q_EMIT dataHidden();
259 }
260 
261 void AbstractDiagram::setHidden( bool hidden )
262 {
263  d->attributesModel->setModelData( QVariant::fromValue( hidden ), DataHiddenRole );
264  Q_EMIT dataHidden();
265 }
266 
268 {
269  return attributesModel()->modelData( DataHiddenRole ).value< bool >();
270 }
271 
272 bool AbstractDiagram::isHidden( int dataset ) const
273 {
274  const QVariant boolFlag( d->datasetAttrs( dataset, DataHiddenRole ) );
275  if ( boolFlag.isValid() )
276  return boolFlag.value< bool >();
277  return isHidden();
278 }
279 
280 bool AbstractDiagram::isHidden( const QModelIndex & index ) const
281 {
282  const QVariant boolFlag( attributesModel()->data( conditionallyMapFromSource( index ),
283  DataHiddenRole ) );
284  if ( boolFlag.isValid() ) {
285  return boolFlag.value< bool >();
286  }
287  int dataset = index.column() / d->datasetDimension;
288  return isHidden( dataset );
289 }
290 
291 
293  const DataValueAttributes & a )
294 {
295  d->attributesModel->setData( conditionallyMapFromSource( index ), QVariant::fromValue( a ),
296  DataValueLabelAttributesRole );
297  Q_EMIT propertiesChanged();
298 }
299 
300 
302 {
303  d->setDatasetAttrs( dataset, QVariant::fromValue( a ), DataValueLabelAttributesRole );
304  Q_EMIT propertiesChanged();
305 }
306 
308 {
309  return attributesModel()->modelData( KChart::DataValueLabelAttributesRole ).value< DataValueAttributes >();
310 }
311 
313 {
314  /*
315  The following did not work!
316  (khz, 2008-01-25)
317  If there was some attrs specified for the 0-th cells of a dataset,
318  then this logic would return the cell's settings instead of the header settings:
319 
320  return qVariantValue<DataValueAttributes>(
321  attributesModel()->data( attributesModel()->mapFromSource(columnToIndex( column )),
322  KChart::DataValueLabelAttributesRole ) );
323  */
324 
325  const QVariant headerAttrs(
326  d->datasetAttrs( dataset, KChart::DataValueLabelAttributesRole ) );
327  if ( headerAttrs.isValid() )
328  return headerAttrs.value< DataValueAttributes >();
329  return dataValueAttributes();
330 }
331 
333 {
334  return attributesModel()->data(
335  conditionallyMapFromSource( index ),
336  KChart::DataValueLabelAttributesRole ).value< DataValueAttributes >();
337 }
338 
340 {
341  d->attributesModel->setModelData( QVariant::fromValue( a ), DataValueLabelAttributesRole );
342  Q_EMIT propertiesChanged();
343 }
344 
346 {
347  DataValueAttributes attrs = dataValueAttributes();
348  attrs.setShowOverlappingDataLabels( allow );
349  setDataValueAttributes( attrs );
350  d->allowOverlappingDataValueTexts = allow;
351  Q_EMIT propertiesChanged();
352 }
353 
355 {
356  return d->allowOverlappingDataValueTexts;
357 }
358 
360 {
361  d->antiAliasing = enabled;
362  Q_EMIT propertiesChanged();
363 }
364 
366 {
367  return d->antiAliasing;
368 }
369 
370 void AbstractDiagram::setPercentMode ( bool percent )
371 {
372  d->percent = percent;
373  Q_EMIT propertiesChanged();
374 }
375 
377 {
378  return d->percent;
379 }
380 
381 
382 void AbstractDiagram::paintDataValueText( QPainter* painter,
383  const QModelIndex& index,
384  const QPointF& pos,
385  qreal value )
386 {
387  d->paintDataValueText( painter, index, pos, value );
388 }
389 
390 
392 {
393  if ( !checkInvariants() ) {
394  return;
395  }
396 
397  d->forgetAlreadyPaintedDataValues();
398  const int rowCount = model()->rowCount( rootIndex() );
399  const int columnCount = model()->columnCount( rootIndex() );
400  for ( int column = 0; column < columnCount; column += datasetDimension() ) {
401  for ( int row = 0; row < rowCount; ++row ) {
402  QModelIndex index = model()->index( row, column, rootIndex() ); // checked
403  qreal x;
404  qreal y;
405  if ( datasetDimension() == 1 ) {
406  x = row;
407  y = index.data().toReal();
408  } else {
409  x = index.data().toReal();
410  y = model()->index( row, column + 1, rootIndex() ).data().toReal();
411  }
412  paintDataValueText( painter, index, coordinatePlane()->translate( QPointF( x, y ) ), y );
413  }
414  }
415 }
416 
417 
418 void AbstractDiagram::paintMarker( QPainter* painter,
419  const DataValueAttributes& a,
420  const QModelIndex& index,
421  const QPointF& pos )
422 {
423  if ( !checkInvariants() || !a.isVisible() ) return;
424  const MarkerAttributes ma = a.markerAttributes();
425  if ( !ma.isVisible() ) return;
426 
427  const PainterSaver painterSaver( painter );
428 
429  QSizeF maSize = ma.markerSize();
430  const qreal diagramWidth = d->diagramSize.width();
431  const qreal diagramHeight = d->diagramSize.height();
432 
433  switch( ma.markerSizeMode() ) {
435  // Unscaled, i.e. without the painter's "zoom"
436  maSize.rwidth() /= painter->matrix().m11();
437  maSize.rheight() /= painter->matrix().m22();
438  break;
440  // Keep maSize as is. It is specified directly in pixels and desired
441  // to be effected by the painter's "zoom".
442  break;
444  maSize *= qMin( diagramWidth, diagramHeight );
445  break;
446  }
447 
448  QBrush indexBrush( brush( index ) );
449  QPen indexPen( ma.pen() );
450  if ( ma.markerColor().isValid() )
451  indexBrush.setColor( ma.markerColor() );
452 
453  paintMarker( painter, ma, indexBrush, indexPen, pos, maSize );
454 
455  // workaround: BC cannot be changed, otherwise we would pass the
456  // index down to next-lower paintMarker function. So far, we
457  // basically save a circle of radius maSize at pos in the
458  // reverseMapper. This means that ^^^ this version of paintMarker
459  // needs to be called to reverse-map the marker.
460  d->reverseMapper.addCircle( index.row(), index.column(), pos, 2 * maSize );
461 }
462 
463 void AbstractDiagram::paintMarker( QPainter* painter,
464  const QModelIndex& index,
465  const QPointF& pos )
466 {
467  if ( !checkInvariants() ) return;
468  paintMarker( painter, dataValueAttributes( index ), index, pos );
469 }
470 
471 void AbstractDiagram::paintMarker( QPainter* painter,
472  const MarkerAttributes& markerAttributes,
473  const QBrush& brush,
474  const QPen& pen,
475  const QPointF& pos,
476  const QSizeF& maSize )
477 {
478  const QPen oldPen( painter->pen() );
479  // Pen is used to paint 4Pixels - 1 Pixel - Ring and FastCross types.
480  // make sure to use the brush color - see above in those cases.
481  const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels);
482  if ( isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel) ) {
483  // for high-performance point charts with tiny point markers:
484  painter->setPen( PrintingParameters::scalePen( QPen( brush.color().lighter() ) ) );
485  if ( isFourPixels ) {
486  const qreal x = pos.x();
487  const qreal y = pos.y();
488  painter->drawLine( QPointF(x-1.0,y-1.0),
489  QPointF(x+1.0,y-1.0) );
490  painter->drawLine( QPointF(x-1.0,y),
491  QPointF(x+1.0,y) );
492  painter->drawLine( QPointF(x-1.0,y+1.0),
493  QPointF(x+1.0,y+1.0) );
494  }
495  painter->drawPoint( pos );
496  } else {
497  const PainterSaver painterSaver( painter );
498  QPen painterPen( pen );
499  painter->setPen( PrintingParameters::scalePen( painterPen ) );
500  painter->setBrush( brush );
502  painter->translate( pos );
503  switch ( markerAttributes.markerStyle() ) {
504  case MarkerAttributes::MarkerCircle:
505  {
506  if ( markerAttributes.threeD() ) {
507  QRadialGradient grad;
509  QColor drawColor = brush.color();
510  grad.setCenter( 0.5, 0.5 );
511  grad.setRadius( 1.0 );
512  grad.setFocalPoint( 0.35, 0.35 );
513  grad.setColorAt( 0.00, drawColor.lighter( 150 ) );
514  grad.setColorAt( 0.20, drawColor );
515  grad.setColorAt( 0.50, drawColor.darker( 150 ) );
516  grad.setColorAt( 0.75, drawColor.darker( 200 ) );
517  grad.setColorAt( 0.95, drawColor.darker( 250 ) );
518  grad.setColorAt( 1.00, drawColor.darker( 200 ) );
519  QBrush newBrush( grad );
520  newBrush.setMatrix( brush.matrix() );
521  painter->setBrush( newBrush );
522  }
523  painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
524  maSize.height(), maSize.width()) );
525  }
526  break;
527  case MarkerAttributes::MarkerSquare:
528  {
529  QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2,
530  maSize.width(), maSize.height() );
531  painter->drawRect( rect );
532  break;
533  }
534  case MarkerAttributes::MarkerDiamond:
535  {
536  QVector <QPointF > diamondPoints;
537  QPointF top, left, bottom, right;
538  top = QPointF( 0, 0 - maSize.height()/2 );
539  left = QPointF( 0 - maSize.width()/2, 0 );
540  bottom = QPointF( 0, maSize.height()/2 );
541  right = QPointF( maSize.width()/2, 0 );
542  diamondPoints << top << left << bottom << right;
543  painter->drawPolygon( diamondPoints );
544  break;
545  }
546  // both handled on top of the method:
547  case MarkerAttributes::Marker1Pixel:
548  case MarkerAttributes::Marker4Pixels:
549  break;
550  case MarkerAttributes::MarkerRing:
551  {
552  painter->setBrush( Qt::NoBrush );
553  painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
554  painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
555  maSize.height(), maSize.width()) );
556  break;
557  }
558  case MarkerAttributes::MarkerCross:
559  {
560  // Note: Markers can have outline,
561  // so just drawing two rects is NOT the solution here!
562  const qreal w02 = maSize.width() * 0.2;
563  const qreal w05 = maSize.width() * 0.5;
564  const qreal h02 = maSize.height()* 0.2;
565  const qreal h05 = maSize.height()* 0.5;
566  QVector <QPointF > crossPoints;
567  QPointF p[12];
568  p[ 0] = QPointF( -w02, -h05 );
569  p[ 1] = QPointF( w02, -h05 );
570  p[ 2] = QPointF( w02, -h02 );
571  p[ 3] = QPointF( w05, -h02 );
572  p[ 4] = QPointF( w05, h02 );
573  p[ 5] = QPointF( w02, h02 );
574  p[ 6] = QPointF( w02, h05 );
575  p[ 7] = QPointF( -w02, h05 );
576  p[ 8] = QPointF( -w02, h02 );
577  p[ 9] = QPointF( -w05, h02 );
578  p[10] = QPointF( -w05, -h02 );
579  p[11] = QPointF( -w02, -h02 );
580  for ( int i=0; i<12; ++i )
581  crossPoints << p[i];
582  crossPoints << p[0];
583  painter->drawPolygon( crossPoints );
584  break;
585  }
586  case MarkerAttributes::MarkerFastCross:
587  {
588  QPointF left, right, top, bottom;
589  left = QPointF( -maSize.width()/2, 0 );
590  right = QPointF( maSize.width()/2, 0 );
591  top = QPointF( 0, -maSize.height()/2 );
592  bottom= QPointF( 0, maSize.height()/2 );
593  painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
594  painter->drawLine( left, right );
595  painter->drawLine( top, bottom );
596  break;
597  }
598  case MarkerAttributes::MarkerArrowDown:
599  {
600  QVector <QPointF > arrowPoints;
601  QPointF topLeft, topRight, bottom;
602  topLeft = QPointF( 0 - maSize.width()/2, 0 - maSize.height()/2 );
603  topRight = QPointF( maSize.width()/2, 0 - maSize.height()/2 );
604  bottom = QPointF( 0, maSize.height()/2 );
605  arrowPoints << topLeft << bottom << topRight;
606  painter->drawPolygon( arrowPoints );
607  break;
608  }
609  case MarkerAttributes::MarkerArrowUp:
610  {
611  QVector <QPointF > arrowPoints;
612  QPointF top, bottomLeft, bottomRight;
613  top = QPointF( 0, 0 - maSize.height()/2 );
614  bottomLeft = QPointF( 0 - maSize.width()/2, maSize.height()/2 );
615  bottomRight = QPointF( maSize.width()/2, maSize.height()/2 );
616  arrowPoints << top << bottomLeft << bottomRight;
617  painter->drawPolygon( arrowPoints );
618  break;
619  }
620  case MarkerAttributes::MarkerArrowRight:
621  {
622  QVector <QPointF > arrowPoints;
623  QPointF right, topLeft, bottomLeft;
624  right = QPointF( maSize.width()/2, 0 );
625  topLeft = QPointF( 0 - maSize.width()/2, 0 - maSize.height()/2 );
626  bottomLeft = QPointF( 0 - maSize.width()/2, maSize.height()/2 );
627  arrowPoints << topLeft << bottomLeft << right;
628  painter->drawPolygon( arrowPoints );
629  break;
630  }
631  case MarkerAttributes::MarkerArrowLeft:
632  {
633  QVector <QPointF > arrowPoints;
634  QPointF left, topRight, bottomRight;
635  left = QPointF( 0 - maSize.width()/2, 0 );
636  topRight = QPointF( maSize.width()/2, 0 - maSize.height()/2 );
637  bottomRight = QPointF( maSize.width()/2, maSize.height()/2 );
638  arrowPoints << left << bottomRight << topRight;
639  painter->drawPolygon( arrowPoints );
640  break;
641  }
642  case MarkerAttributes::MarkerBowTie:
643  case MarkerAttributes::MarkerHourGlass:
644  {
645  QVector <QPointF > points;
646  QPointF topLeft, topRight, bottomLeft, bottomRight;
647  topLeft = QPointF( 0 - maSize.width()/2, 0 - maSize.height()/2);
648  topRight = QPointF( maSize.width()/2, 0 - maSize.height()/2 );
649  bottomLeft = QPointF( 0 - maSize.width()/2, maSize.height()/2 );
650  bottomRight = QPointF( maSize.width()/2, maSize.height()/2 );
651  if ( markerAttributes.markerStyle() == MarkerAttributes::MarkerBowTie)
652  points << topLeft << bottomLeft << topRight << bottomRight;
653  else
654  points << topLeft << bottomRight << bottomLeft << topRight;
655  painter->drawPolygon( points );
656  break;
657  }
658  case MarkerAttributes::MarkerStar:
659  {
660  const qreal w01 = maSize.width() * 0.1;
661  const qreal w05 = maSize.width() * 0.5;
662  const qreal h01 = maSize.height() * 0.1;
663  const qreal h05 = maSize.height() * 0.5;
664  QVector <QPointF > points;
665  QPointF p1 = QPointF( 0, -h05 );
666  QPointF p2 = QPointF( -w01, -h01 );
667  QPointF p3 = QPointF( -w05, 0 );
668  QPointF p4 = QPointF( -w01, h01 );
669  QPointF p5 = QPointF( 0, h05 );
670  QPointF p6 = QPointF( w01, h01 );
671  QPointF p7 = QPointF( w05, 0 );
672  QPointF p8 = QPointF( w01, -h01 );
673  points << p1 << p2 << p3 << p4 << p5 << p6 << p7 << p8;
674  painter->drawPolygon( points );
675  break;
676  }
677  case MarkerAttributes::MarkerX:
678  {
679  const qreal w01 = maSize.width() * 0.1;
680  const qreal w04 = maSize.width() * 0.4;
681  const qreal w05 = maSize.width() * 0.5;
682  const qreal h01 = maSize.height() * 0.1;
683  const qreal h04 = maSize.height() * 0.4;
684  const qreal h05 = maSize.height() * 0.5;
685  QVector <QPointF > crossPoints;
686  QPointF p1 = QPointF( -w04, -h05 );
687  QPointF p2 = QPointF( -w05, -h04 );
688  QPointF p3 = QPointF( -w01, 0 );
689  QPointF p4 = QPointF( -w05, h04 );
690  QPointF p5 = QPointF( -w04, h05 );
691  QPointF p6 = QPointF( 0, h01 );
692  QPointF p7 = QPointF( w04, h05 );
693  QPointF p8 = QPointF( w05, h04 );
694  QPointF p9 = QPointF( w01, 0 );
695  QPointF p10 = QPointF( w05, -h04 );
696  QPointF p11 = QPointF( w04, -h05 );
697  QPointF p12 = QPointF( 0, -h01 );
698  crossPoints << p1 << p2 << p3 << p4 << p5 << p6
699  << p7 << p8 << p9 << p10 << p11 << p12;
700  painter->drawPolygon( crossPoints );
701  break;
702  }
703  case MarkerAttributes::MarkerAsterisk:
704  {
705  // Note: Markers can have outline,
706  // so just drawing three lines is NOT the solution here!
707  // The idea that we use is to draw 3 lines anyway, but convert their
708  // outlines to QPainterPaths which are then united and filled.
709  const qreal w04 = maSize.width() * 0.4;
710  const qreal h02 = maSize.height() * 0.2;
711  const qreal h05 = maSize.height() * 0.5;
712  //QVector <QPointF > crossPoints;
713  QPointF p1 = QPointF( 0, -h05 );
714  QPointF p2 = QPointF( -w04, -h02 );
715  QPointF p3 = QPointF( -w04, h02 );
716  QPointF p4 = QPointF( 0, h05 );
717  QPointF p5 = QPointF( w04, h02 );
718  QPointF p6 = QPointF( w04, -h02 );
719  QPen pen = painter->pen();
720  QPainterPathStroker stroker;
721  stroker.setWidth( pen.widthF() );
722  stroker.setCapStyle( pen.capStyle() );
723 
724  QPainterPath path;
725  QPainterPath dummyPath;
726  dummyPath.moveTo( p1 );
727  dummyPath.lineTo( p4 );
728  path = stroker.createStroke( dummyPath );
729 
730  dummyPath = QPainterPath();
731  dummyPath.moveTo( p2 );
732  dummyPath.lineTo( p5 );
733  path = path.united( stroker.createStroke( dummyPath ) );
734 
735  dummyPath = QPainterPath();
736  dummyPath.moveTo( p3 );
737  dummyPath.lineTo( p6 );
738  path = path.united( stroker.createStroke( dummyPath ) );
739 
740  painter->drawPath( path );
741  break;
742  }
743  case MarkerAttributes::MarkerHorizontalBar:
744  {
745  const qreal w05 = maSize.width() * 0.5;
746  const qreal h02 = maSize.height()* 0.2;
747  QVector <QPointF > points;
748  QPointF p1 = QPointF( -w05, -h02 );
749  QPointF p2 = QPointF( -w05, h02 );
750  QPointF p3 = QPointF( w05, h02 );
751  QPointF p4 = QPointF( w05, -h02 );
752  points << p1 << p2 << p3 << p4;
753  painter->drawPolygon( points );
754  break;
755  }
756  case MarkerAttributes::MarkerVerticalBar:
757  {
758  const qreal w02 = maSize.width() * 0.2;
759  const qreal h05 = maSize.height()* 0.5;
760  QVector <QPointF > points;
761  QPointF p1 = QPointF( -w02, -h05 );
762  QPointF p2 = QPointF( -w02, h05 );
763  QPointF p3 = QPointF( w02, h05 );
764  QPointF p4 = QPointF( w02, -h05 );
765  points << p1 << p2 << p3 << p4;
766  painter->drawPolygon( points );
767  break;
768  }
769  case MarkerAttributes::NoMarker:
770  break;
771  case MarkerAttributes::PainterPathMarker:
772  {
773  QPainterPath path = markerAttributes.customMarkerPath();
774  const QRectF pathBoundingRect = path.boundingRect();
775  const qreal xScaling = maSize.height() / pathBoundingRect.height();
776  const qreal yScaling = maSize.width() / pathBoundingRect.width();
777  const qreal scaling = qMin( xScaling, yScaling );
778  painter->scale( scaling, scaling );
779  painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
780  painter->drawPath(path);
781  break;
782  }
783  default:
784  Q_ASSERT_X ( false, "paintMarkers()",
785  "Type item does not match a defined Marker Type." );
786  }
787  }
788  painter->setPen( oldPen );
789 }
790 
792 {
793  if ( !checkInvariants() ) {
794  return;
795  }
796 
797  const int rowCount = model()->rowCount( rootIndex() );
798  const int columnCount = model()->columnCount( rootIndex() );
799  for ( int column = 0; column < columnCount; column += datasetDimension() ) {
800  for ( int row = 0; row < rowCount; ++row ) {
801  QModelIndex index = model()->index( row, column, rootIndex() ); // checked
802  qreal x;
803  qreal y;
804  if ( datasetDimension() == 1 ) {
805  x = row;
806  y = index.data().toReal();
807  } else {
808  x = index.data().toReal();
809  y = model()->index( row, column + 1, rootIndex() ).data().toReal();
810  }
811  paintMarker( painter, index, coordinatePlane()->translate( QPointF( x, y ) ) );
812  }
813  }
814 }
815 
816 
817 void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen )
818 {
819  attributesModel()->setData(
820  conditionallyMapFromSource( index ),
821  QVariant::fromValue( pen ), DatasetPenRole );
822  Q_EMIT propertiesChanged();
823 }
824 
825 void AbstractDiagram::setPen( const QPen& pen )
826 {
827  attributesModel()->setModelData(
828  QVariant::fromValue( pen ), DatasetPenRole );
829  Q_EMIT propertiesChanged();
830 }
831 
832 void AbstractDiagram::setPen( int dataset, const QPen& pen )
833 {
834  d->setDatasetAttrs( dataset, QVariant::fromValue( pen ), DatasetPenRole );
835  Q_EMIT propertiesChanged();
836 }
837 
839 {
840  return attributesModel()->data( DatasetPenRole ).value< QPen >();
841 }
842 
843 QPen AbstractDiagram::pen( int dataset ) const
844 {
845  const QVariant penSettings( d->datasetAttrs( dataset, DatasetPenRole ) );
846  if ( penSettings.isValid() )
847  return penSettings.value< QPen >();
848  return pen();
849 }
850 
851 QPen AbstractDiagram::pen( const QModelIndex& index ) const
852 {
853  return attributesModel()->data(
854  conditionallyMapFromSource( index ),
855  DatasetPenRole ).value< QPen >();
856 }
857 
858 void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush )
859 {
860  attributesModel()->setData(
861  conditionallyMapFromSource( index ),
862  QVariant::fromValue( brush ), DatasetBrushRole );
863  Q_EMIT propertiesChanged();
864 }
865 
866 void AbstractDiagram::setBrush( const QBrush& brush )
867 {
868  attributesModel()->setModelData(
869  QVariant::fromValue( brush ), DatasetBrushRole );
870  Q_EMIT propertiesChanged();
871 }
872 
873 void AbstractDiagram::setBrush( int dataset, const QBrush& brush )
874 {
875  d->setDatasetAttrs( dataset, QVariant::fromValue( brush ), DatasetBrushRole );
876  Q_EMIT propertiesChanged();
877 }
878 
880 {
881  return attributesModel()->data( DatasetBrushRole ).value< QBrush >();
882 }
883 
884 QBrush AbstractDiagram::brush( int dataset ) const
885 {
886  const QVariant brushSettings( d->datasetAttrs( dataset, DatasetBrushRole ) );
887  if ( brushSettings.isValid() )
888  return brushSettings.value< QBrush >();
889  return brush();
890 }
891 
893 {
894  return
895  attributesModel()->data( conditionallyMapFromSource( index ), DatasetBrushRole ).value< QBrush >();
896 }
897 
898 /*
899  * Sets the unit prefix for one value
900  * @param prefix the prefix to be set
901  * @param column the value using that prefix
902  * @param orientation the orientantion of the axis to set
903  */
904 void AbstractDiagram::setUnitPrefix( const QString& prefix, int column, Qt::Orientation orientation )
905 {
906  d->unitPrefixMap[ column ][ orientation ]= prefix;
907 }
908 
909 /*
910  * Sets the unit prefix for all values
911  * @param prefix the prefix to be set
912  * @param orientation the orientantion of the axis to set
913  */
914 void AbstractDiagram::setUnitPrefix( const QString& prefix, Qt::Orientation orientation )
915 {
916  d->unitPrefix[ orientation ] = prefix;
917 }
918 
919 /*
920  * Sets the unit suffix for one value
921  * @param suffix the suffix to be set
922  * @param column the value using that suffix
923  * @param orientation the orientantion of the axis to set
924  */
925 void AbstractDiagram::setUnitSuffix( const QString& suffix, int column, Qt::Orientation orientation )
926 {
927  d->unitSuffixMap[ column ][ orientation ]= suffix;
928 }
929 
930 /*
931  * Sets the unit suffix for all values
932  * @param suffix the suffix to be set
933  * @param orientation the orientantion of the axis to set
934  */
935 void AbstractDiagram::setUnitSuffix( const QString& suffix, Qt::Orientation orientation )
936 {
937  d->unitSuffix[ orientation ] = suffix;
938 }
939 
940 /*
941  * Returns the unit prefix for a special value
942  * @param column the value which's prefix is requested
943  * @param orientation the orientation of the axis
944  * @param fallback if true, the global prefix is return when no specific one is set for that value
945  * @return the unit prefix
946  */
947 QString AbstractDiagram::unitPrefix( int column, Qt::Orientation orientation, bool fallback ) const
948 {
949  if ( !fallback || d->unitPrefixMap[ column ].contains( orientation ) )
950  return d->unitPrefixMap[ column ][ orientation ];
951  return d->unitPrefix[ orientation ];
952 }
953 
954 /* Returns the global unit prefix
955  * @param orientation the orientation of the axis
956  * @return the unit prefix
957  */
959 {
960  return d->unitPrefix[ orientation ];
961 }
962 
963 /*
964  * Returns the unit suffix for a special value
965  * @param column the value which's suffix is requested
966  * @param orientation the orientation of the axis
967  * @param fallback if true, the global suffix is return when no specific one is set for that value
968  * @return the unit suffix
969  */
970 QString AbstractDiagram::unitSuffix( int column, Qt::Orientation orientation, bool fallback ) const
971 {
972  if ( !fallback || d->unitSuffixMap[ column ].contains( orientation ) )
973  return d->unitSuffixMap[ column ][ orientation ];
974  return d->unitSuffix[ orientation ];
975 }
976 
977 /* Returns the global unit suffix
978  * @param orientation the orientation of the axis
979  * @return the unit suffix
980  */
982 {
983  return d->unitSuffix[ orientation ];
984 }
985 
986 // implement QAbstractItemView:
988 {
989  return d->reverseMapper.boundingRect( index.row(), index.column() ).toRect();
990 }
991 
993 {}
994 
995 // indexAt ... down below
996 
998 { return QModelIndex(); }
999 
1001 { return 0; }
1002 
1004 { return 0; }
1005 
1007 { return true; }
1008 
1010 {
1011  const QModelIndexList indexes = d->indexesIn( rect );
1012  QItemSelection selection;
1013  for ( const QModelIndex& index : indexes )
1014  {
1015  selection.append( QItemSelectionRange( index ) );
1016  }
1017  selectionModel()->select( selection, command );
1018 }
1019 
1021 {
1022  QPolygonF polygon;
1023  const auto indexes = selection.indexes();
1024  polygon.reserve(indexes.count());
1025  for ( const QModelIndex& index : indexes )
1026  {
1027  polygon << d->reverseMapper.polygon(index.row(), index.column());
1028  }
1029  return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
1030 }
1031 
1032 QRegion AbstractDiagram::visualRegion(const QModelIndex &index) const
1033 {
1034  QPolygonF polygon = d->reverseMapper.polygon(index.row(), index.column());
1035  return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
1036 }
1037 
1039 {
1040  d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault );
1041 }
1042 
1044 {
1045  d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued );
1046 }
1047 
1049 {
1050  d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow );
1051 }
1052 
1054 {
1055  QStringList ret;
1056  if ( model() ) {
1057  //qDebug() << "AbstractDiagram::itemRowLabels(): " << attributesModel()->rowCount(attributesModelRootIndex()) << "entries";
1058  const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
1059  for ( int i = 0; i < rowCount; ++i ) {
1060  //qDebug() << "item row label: " << attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString();
1061  ret << unitPrefix( i, Qt::Horizontal, true ) +
1062  attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString() +
1063  unitSuffix( i, Qt::Horizontal, true );
1064  }
1065  }
1066  return ret;
1067 }
1068 
1070 {
1071  QStringList ret;
1072  if ( !model() ) {
1073  return ret;
1074  }
1075  const int datasetCount = d->datasetCount();
1076  for ( int i = 0; i < datasetCount; ++i ) {
1077  ret << d->datasetAttrs( i, Qt::DisplayRole ).toString();
1078  }
1079  return ret;
1080 }
1081 
1083 {
1084  QList<QBrush> ret;
1085  if ( !model() ) {
1086  return ret;
1087  }
1088  const int datasetCount = d->datasetCount();
1089  for ( int i = 0; i < datasetCount; ++i ) {
1090  ret << brush( i );
1091  }
1092  return ret;
1093 }
1094 
1096 {
1097  QList<QPen> ret;
1098  if ( !model() ) {
1099  return ret;
1100  }
1101  const int datasetCount = d->datasetCount();
1102  for ( int i = 0; i < datasetCount; ++i ) {
1103  ret << pen( i );
1104  }
1105  return ret;
1106 }
1107 
1109 {
1111  if ( !model() ) {
1112  return ret;
1113  }
1114  const int datasetCount = d->datasetCount();
1115  for ( int i = 0; i < datasetCount; ++i ) {
1116  ret << dataValueAttributes( i ).markerAttributes();
1117  }
1118  return ret;
1119 }
1120 
1121 bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const
1122 {
1123  if ( ! justReturnTheStatus ) {
1124  Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()",
1125  "There is no usable model set, for the diagram." );
1126 
1127  Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()",
1128  "There is no usable coordinate plane set, for the diagram." );
1129  }
1130  return model() && coordinatePlane();
1131 }
1132 
1134 {
1135  return d->datasetDimension;
1136 }
1137 
1139 {
1140  Q_UNUSED( dimension );
1141  qDebug() << "Setting the dataset dimension using AbstractDiagram::setDatasetDimension is "
1142  "obsolete. Use the specific diagram types instead.";
1143 }
1144 
1145 void AbstractDiagram::setDatasetDimensionInternal( int dimension )
1146 {
1147  Q_ASSERT( dimension != 0 );
1148  if ( d->datasetDimension == dimension ) {
1149  return;
1150  }
1151  d->datasetDimension = dimension;
1152  d->attributesModel->setDatasetDimension( dimension );
1153  setDataBoundariesDirty();
1154  Q_EMIT layoutChanged( this );
1155 }
1156 
1157 qreal AbstractDiagram::valueForCell( int row, int column ) const
1158 {
1159  if ( !d->attributesModel->hasIndex( row, column, attributesModelRootIndex() ) ) {
1160  qWarning() << "AbstractDiagram::valueForCell(): Requesting value for invalid index!";
1161  return std::numeric_limits<qreal>::quiet_NaN();
1162  }
1163  return d->attributesModel->data(
1164  d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toReal(); // checked
1165 }
1166 
1167 void AbstractDiagram::update() const
1168 {
1169  if ( d->plane ) {
1170  d->plane->update();
1171  }
1172 }
1173 
1175 {
1176  return d->indexAt( point );
1177 }
1178 
1179 QModelIndexList AbstractDiagram::indexesAt( const QPoint& point ) const
1180 {
1181  return d->indexesAt( point );
1182 }
1183 
1184 QModelIndexList AbstractDiagram::indexesIn( const QRect& rect ) const
1185 {
1186  return d->indexesIn( rect );
1187 }
QList< MarkerAttributes > datasetMarkers() const
The set of dataset markers currently used, for use in legends, etc.
QModelIndexList indexes() const const
QRectF boundingRect() const const
virtual void setRootIndex(const QModelIndex &index)
void resize(int w, int h)
void setWidth(qreal width)
virtual void setSelectionModel(QItemSelectionModel *selectionModel)
void setAntiAliasing(bool enabled)
Set whether anti-aliasing is to be used while rendering this diagram.
void setPercentMode(bool percent)
Deprecated method that turns the percent mode of this diagram on or off.
Class only listed here to document inheritance of some KChart classes.
int verticalOffset() const override
typedef KeyboardModifiers
QPolygon toPolygon() const const
QModelIndexList indexesAt(const QPoint &point) const
This method is added alongside with indexAt from QAIM, since in KChart multiple indexes can be displa...
QColor darker(int factor) const const
AbstractDiagram defines the interface for diagram classes.
Class only listed here to document inheritance of some KChart classes.
void setRenderHint(QPainter::RenderHint hint, bool on)
virtual bool usesExternalAttributesModel() const
Returns whether the diagram is using its own built-in attributes model or an attributes model that wa...
void setColorAt(qreal position, const QColor &color)
A set of attributes controlling the appearance of data set markers.
void initFrom(const AttributesModel *other)
Copies the internal data (maps and palette) of another AttributesModel* into this one...
qreal & rwidth()
virtual void setModel(QAbstractItemModel *model)
void scale(qreal sx, qreal sy)
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles=QVector< int >()) override
QModelIndex attributesModelRootIndex() const
QModelIndex indexAt(const QPoint &point) const override
T value() const const
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
Diagram attributes dealing with data value labels.
void moveTo(const QPointF &point)
const QPair< QPointF, QPointF > dataBoundaries() const
Return the bottom left and top right data point, that the diagram will display (unless the grid adjus...
QStringList itemRowLabels() const
The set of item row labels currently displayed, for use in Abscissa axes, etc.
QList< QBrush > datasetBrushes() const
The set of dataset brushes currently used, for use in legends, etc.
void drawLine(const QLineF &line)
void setFocalPoint(const QPointF &focalPoint)
the marker size is relative to the diagram&#39;s min(width, height)
Declaring the class KChart::DataValueAttributes.
bool isHidden() const
Retrieve the hidden status specified globally.
QList< QPen > datasetPens() const
The set of dataset pens currently used, for use in legends, etc.
virtual void paintMarkers(QPainter *painter)
bool hasAutoScroll() const const
const QColor & color() const const
virtual AttributesModel * attributesModel() const
Returns the AttributesModel, that is used by this diagram.
qreal m22() const const
qreal m11() const const
void drawRect(const QRectF &rectangle)
void setAttributesModelRootIndex(const QModelIndex &)
bool isValid() const const
virtual void setAttributesModel(AttributesModel *model)
Associate an AttributesModel with this diagram.
qreal x() const const
qreal y() const const
void append(const T &value)
the marker size is directly specified in pixels
void drawPoint(const QPointF &position)
void setAllowOverlappingDataValueTexts(bool allow)
Set whether data value labels are allowed to overlap.
QPainterPath united(const QPainterPath &p) const const
void setPen(const QColor &color)
void lineTo(const QPointF &endPoint)
void drawEllipse(const QRectF &rectangle)
QSize toSize() const const
QPen pen() const
Retrieve the pen to be used for painting datapoints globally.
DisplayRole
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane.
int row() const const
void setBrush(const QBrush &brush)
QPainterPath createStroke(const QPainterPath &path) const const
A proxy model used for decorating data with attributes.
QRect visualRect(const QModelIndex &index) const override
void setRadius(qreal radius)
virtual void setCoordinatePlane(AbstractCoordinatePlane *plane)
Set the coordinate plane associated with the diagram.
bool compare(const AbstractDiagram *other) const
Returns true if both diagrams have the same settings.
the marker size is specified in pixels, but scaled by the painter&#39;s zoom level
Internally used class just adding a special constructor used by AbstractDiagram.
void setCoordinateMode(QGradient::CoordinateMode mode)
MarkerAttributes markerAttributes() const
void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) override
bool allowOverlappingDataValueTexts() const
bool percentMode() const
Returns whether this diagram is drawn in percent mode.
void reserve(int size)
int horizontalOffset() const override
void setCenter(const QPointF &center)
bool isIndexHidden(const QModelIndex &index) const override
QColor lighter(int factor) const const
QVariant fromValue(const T &value)
QCA_EXPORT void init()
QModelIndex rootIndex() const const
void setDatasetDimension(int dimension)
void setSelectionModel(QItemSelectionModel *selectionModel) override
Associate a seleection model with the diagrom.
void setDataValueAttributes(const QModelIndex &index, const DataValueAttributes &a)
Set the DataValueAttributes for the given index.
QBrush brush() const
Retrieve the brush to be used for painting datapoints globally.
void useSubduedColors()
Set the palette to be used, for painting datasets to the subdued palette.
void setHidden(const QModelIndex &index, bool hidden)
Hide (or unhide, resp.) a data cell.
virtual void resize(const QSizeF &area)
Called by the widget&#39;s sizeEvent.
qreal width() const const
const QAbstractItemModel * model() const const
void drawPath(const QPainterPath &path)
QVariant data(int role) const const
DataValueAttributes dataValueAttributes() const
Retrieve the DataValueAttributes specified globally.
QString unitPrefix(int column, Qt::Orientation orientation, bool fallback=false) const
Retrieves the axis unit prefix for a specific column.
const QMatrix & matrix() const const
QRegion visualRegionForSelection(const QItemSelection &selection) const override
bool isEmpty() const const
void setRootIndex(const QModelIndex &idx) override
Set the root index in the model, where the diagram starts referencing data for display.
Qt::PenCapStyle capStyle() const const
qreal valueForCell(int row, int column) const
Helper method, retrieving the data value (DisplayRole) for a given row and column.
void setCapStyle(Qt::PenCapStyle style)
QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override
void scrollTo(const QModelIndex &index, ScrollHint hint=EnsureVisible) override
int column() const const
qreal widthF() const const
AbstractCoordinatePlane * coordinatePlane() const
The coordinate plane associated with the diagram.
void translate(const QPointF &offset)
void setModel(QAbstractItemModel *model) override
Associate a model with the diagram.
bool isValid() const const
qreal height() const const
void setMatrix(const QMatrix &matrix)
void setUnitPrefix(const QString &prefix, int column, Qt::Orientation orientation)
Set the unit prefix to be used on axes for one specific column.
Orientation
qreal & rheight()
qreal toReal(bool *ok) const const
virtual void paintDataValueTexts(QPainter *painter)
QString unitSuffix(int column, Qt::Orientation orientation, bool fallback=false) const
Retrieves the axis unit suffix for a specific column.
qreal height() const const
Global namespace.
void useDefaultColors()
Set the palette to be used, for painting datasets to the default palette.
void useRainbowColors()
Set the palette to be used, for painting datasets to the rainbow palette.
void setColor(const QColor &color)
const QPen & pen() const const
QStringList datasetLabels() const
The set of dataset labels currently displayed, for use in legends, etc.
int datasetDimension() const
The dataset dimension of a diagram determines how many value dimensions it expects each datapoint to ...
void setShowOverlappingDataLabels(bool showOverlappingDataLabels)
Set whether data value texts overlapping other data value texts of the same diagram should be drawn...
void setPen(const QModelIndex &index, const QPen &pen)
Set the pen to be used, for painting the datapoint at the given index.
qreal width() const const
const QMatrix & matrix() const const
bool isValid() const const
void setBrush(const QModelIndex &index, const QBrush &brush)
Set the brush to be used, for painting the datapoint at the given index.
void setUnitSuffix(const QString &suffix, int column, Qt::Orientation orientation)
Set the unit prefix to be used on axes for one specific column.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Sep 26 2021 22:37:20 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.