KD Chart 2  [rev.2.7]
KDChartAbstractDiagram_p.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 //
24 // W A R N I N G
25 // -------------
26 //
27 // This file is not part of the KD Chart API. It exists purely as an
28 // implementation detail. This header file may change from version to
29 // version without notice, or even be removed.
30 //
31 // We mean it.
32 //
33 
34 #include "KDChartAbstractDiagram_p.h"
35 
36 #include "KDChartBarDiagram.h"
37 #include "KDChartFrameAttributes.h"
38 #include "KDChartPainterSaver_p.h"
39 
40 #include <QAbstractTextDocumentLayout>
41 #include <QTextBlock>
42 #include <QApplication>
43 
44 #include <KDABLibFakes>
45 
46 
47 using namespace KDChart;
48 
49 LabelPaintInfo::LabelPaintInfo() :
50  isValuePositive( false )
51 {
52 }
53 
54 LabelPaintInfo::LabelPaintInfo( const QModelIndex& _index, const DataValueAttributes& _attrs,
55  const QPainterPath& _labelArea, const QPointF& _markerPos,
56  bool _isValuePositive, const QString& _value )
57  : index( _index )
58  , attrs( _attrs )
59  , labelArea( _labelArea )
60  , markerPos( _markerPos )
61  , isValuePositive( _isValuePositive )
62  , value( _value )
63 {
64 }
65 
66 LabelPaintInfo::LabelPaintInfo( const LabelPaintInfo& other )
67  : index( other.index )
68  , attrs( other.attrs )
69  , labelArea( other.labelArea )
70  , markerPos( other.markerPos )
71  , isValuePositive( other.isValuePositive )
72  , value( other.value )
73 {
74 }
75 
76 AbstractDiagram::Private::Private()
77  : diagram( 0 )
78  , doDumpPaintTime( false )
79  , plane( 0 )
80  , attributesModel( new PrivateAttributesModel(0,0) )
81  , allowOverlappingDataValueTexts( false )
82  , antiAliasing( true )
83  , percent( false )
84  , datasetDimension( 1 )
85  , databoundariesDirty( true )
86  , mCachedFontMetrics( QFontMetrics( qApp->font() ) )
87 {
88 }
89 
90 AbstractDiagram::Private::~Private()
91 {
92  if ( attributesModel && qobject_cast<PrivateAttributesModel*>(attributesModel) )
93  delete attributesModel;
94 }
95 
96 void AbstractDiagram::Private::init()
97 {
98 }
99 
100 void AbstractDiagram::Private::init( AbstractCoordinatePlane* newPlane )
101 {
102  plane = newPlane;
103 }
104 
105 bool AbstractDiagram::Private::usesExternalAttributesModel() const
106 {
107  return ( ! attributesModel.isNull() ) &&
108  ( ! qobject_cast<PrivateAttributesModel*>(attributesModel) );
109 }
110 
111 void AbstractDiagram::Private::setAttributesModel( AttributesModel* amodel )
112 {
113  if ( attributesModel == amodel ) {
114  return;
115  }
116 
117  if ( !attributesModel.isNull() ) {
118  if ( qobject_cast< PrivateAttributesModel* >( attributesModel ) ) {
119  delete attributesModel;
120  } else {
121  disconnect( attributesModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ),
122  diagram, SLOT( setDataBoundariesDirty() ) );
123  disconnect( attributesModel, SIGNAL( columnsInserted( QModelIndex, int, int ) ),
124  diagram, SLOT( setDataBoundariesDirty() ) );
125  disconnect( attributesModel, SIGNAL( rowsRemoved( QModelIndex, int, int ) ),
126  diagram, SLOT( setDataBoundariesDirty() ) );
127  disconnect( attributesModel, SIGNAL( columnsRemoved( QModelIndex, int, int ) ),
128  diagram, SLOT( setDataBoundariesDirty() ) );
129  disconnect( attributesModel, SIGNAL( modelReset() ),
130  diagram, SLOT( setDataBoundariesDirty() ) );
131  disconnect( attributesModel, SIGNAL( layoutChanged() ),
132  diagram, SLOT( setDataBoundariesDirty() ) );
133  disconnect( attributesModel, SIGNAL( dataChanged( QModelIndex, QModelIndex ) ),
134  diagram, SIGNAL( modelDataChanged() ));
135  }
136  }
137 
138  emit diagram->attributesModelAboutToChange( amodel, attributesModel );
139 
140  connect( amodel, SIGNAL( rowsInserted( QModelIndex, int, int ) ),
141  diagram, SLOT( setDataBoundariesDirty() ) );
142  connect( amodel, SIGNAL( columnsInserted( QModelIndex, int, int ) ),
143  diagram, SLOT( setDataBoundariesDirty() ) );
144  connect( amodel, SIGNAL( rowsRemoved( QModelIndex, int, int ) ),
145  diagram, SLOT( setDataBoundariesDirty() ) );
146  connect( amodel, SIGNAL( columnsRemoved( QModelIndex, int, int ) ),
147  diagram, SLOT( setDataBoundariesDirty() ) );
148  connect( amodel, SIGNAL( modelReset() ),
149  diagram, SLOT( setDataBoundariesDirty() ) );
150  connect( amodel, SIGNAL( layoutChanged() ),
151  diagram, SLOT( setDataBoundariesDirty() ) );
152  connect( amodel, SIGNAL( dataChanged( QModelIndex, QModelIndex ) ),
153  diagram, SIGNAL( modelDataChanged() ));
154 
155  attributesModel = amodel;
156 }
157 
158 AbstractDiagram::Private::Private( const AbstractDiagram::Private& rhs ) :
159  diagram( 0 ),
160  doDumpPaintTime( rhs.doDumpPaintTime ),
161  // Do not copy the plane
162  plane( 0 ),
163  attributesModelRootIndex( QModelIndex() ),
164  attributesModel( rhs.attributesModel ),
165  allowOverlappingDataValueTexts( rhs.allowOverlappingDataValueTexts ),
166  antiAliasing( rhs.antiAliasing ),
167  percent( rhs.percent ),
169  mCachedFontMetrics( rhs.cachedFontMetrics() )
170 {
171  attributesModel = new PrivateAttributesModel( 0, 0);
172  attributesModel->initFrom( rhs.attributesModel );
173 }
174 
175 // FIXME: Optimize if necessary
176 qreal AbstractDiagram::Private::calcPercentValue( const QModelIndex & index ) const
177 {
178  qreal sum = 0.0;
179  for ( int col = 0; col < attributesModel->columnCount( QModelIndex() ); col++ )
180  sum += attributesModel->data( attributesModel->index( index.row(), col, QModelIndex() ) ).toReal(); // checked
181  if ( sum == 0.0 )
182  return 0.0;
183  return attributesModel->data( attributesModel->mapFromSource( index ) ).toReal() / sum * 100.0;
184 }
185 
186 void AbstractDiagram::Private::addLabel(
187  LabelPaintCache* cache,
188  const QModelIndex& index,
189  const CartesianDiagramDataCompressor::CachePosition* position,
190  const PositionPoints& points,
191  const Position& autoPositionPositive, const Position& autoPositionNegative,
192  const qreal value, qreal favoriteAngle /* = 0.0 */ )
193 {
194  CartesianDiagramDataCompressor::AggregatedDataValueAttributes allAttrs(
195  aggregatedAttrs( index, position ) );
196 
198  for ( it = allAttrs.constBegin(); it != allAttrs.constEnd(); ++it ) {
199  DataValueAttributes dva = it.value();
200  if ( !dva.isVisible() ) {
201  continue;
202  }
203 
204  const bool isPositive = ( value >= 0.0 );
205 
206  RelativePosition relPos( dva.position( isPositive ) );
207  relPos.setReferencePoints( points );
208  if ( relPos.referencePosition().isUnknown() ) {
209  relPos.setReferencePosition( isPositive ? autoPositionPositive : autoPositionNegative );
210  }
211 
212  // Rotate the label position (not the label itself) if the diagram is rotated so that the defaults still work
213  if ( isTransposed() ) {
214  KDChartEnums::PositionValue posValue = relPos.referencePosition().value();
215  if ( posValue >= KDChartEnums::PositionNorthWest && posValue <= KDChartEnums::PositionWest ) {
216  // rotate 90 degrees clockwise
217  posValue = static_cast< KDChartEnums::PositionValue >( posValue + 2 );
218  if ( posValue > KDChartEnums::PositionWest ) {
219  // wraparound
220  posValue = static_cast< KDChartEnums::PositionValue >( posValue -
222  }
223  relPos.setReferencePosition( Position( posValue ) );
224  }
225  }
226 
227  const QPointF referencePoint = relPos.referencePoint();
228  if ( !diagram->coordinatePlane()->isVisiblePoint( referencePoint ) ) {
229  continue;
230  }
231 
232  const qreal fontHeight = cachedFontMetrics( dva.textAttributes().
233  calculatedFont( plane, KDChartEnums::MeasureOrientationMinimum ), diagram )->height();
234 
235  // Note: When printing data value texts and padding's Measure is using automatic reference area
236  // detection, the font height is used as reference size for both horizontal and vertical
237  // padding.
238  QSizeF relativeMeasureSize( fontHeight, fontHeight );
239 
240  if ( !dva.textAttributes().hasRotation() ) {
241  TextAttributes ta = dva.textAttributes();
242  ta.setRotation( favoriteAngle );
243  dva.setTextAttributes( ta );
244  }
245 
246  // get the size of the label text using a subset of the information going into the final layout
247  const QString text = formatDataValueText( dva, index, value );
248  QTextDocument doc;
249  doc.setDocumentMargin( 0 );
250  if ( Qt::mightBeRichText( text ) ) {
251  doc.setHtml( text );
252  } else {
253  doc.setPlainText( text );
254  }
255  const QFont calculatedFont( dva.textAttributes()
257  doc.setDefaultFont( calculatedFont );
258 
259  const QRectF plainRect = doc.documentLayout()->frameBoundingRect( doc.rootFrame() );
260 
296  QTransform transform;
297  {
298  // move to the general area where the label should be
299  QPointF calcPoint = relPos.calculatedPoint( relativeMeasureSize );
300  transform.translate( calcPoint.x(), calcPoint.y() );
301  // align the text rect; find out by how many half-widths / half-heights to move.
302  int dx = -1;
303  if ( relPos.alignment() & Qt::AlignLeft ) {
304  dx -= 1;
305  } else if ( relPos.alignment() & Qt::AlignRight ) {
306  dx += 1;
307  }
308 
309  int dy = -1;
310  if ( relPos.alignment() & Qt::AlignTop ) {
311  dy -= 1;
312  } else if ( relPos.alignment() & Qt::AlignBottom ) {
313  dy += 1;
314  }
315  transform.translate( qreal( dx ) * plainRect.width() * 0.5,
316  qreal( dy ) * plainRect.height() * 0.5 );
317 
318  // rotate the text rect around its center
319  transform.translate( plainRect.center().x(), plainRect.center().y() );
320  int rotation = dva.textAttributes().rotation();
321  if ( !isPositive && dva.mirrorNegativeValueTextRotation() ) {
322  rotation *= -1;
323  }
324  transform.rotate( rotation );
325  transform.translate( -plainRect.center().x(), -plainRect.center().y() );
326  }
327 
328  QPainterPath labelArea;
329  //labelArea.addPolygon( transform.mapToPolygon( plainRect.toRect() ) );
330  //labelArea.closeSubpath();
331  // Not doing that because QTransform has a special case for 180° that gives a different than
332  // usual ordering of the points in the polygon returned by mapToPolygon( const QRect & ).
333  // We expect a particular ordering in paintDataValueTextsAndMarkers() by using elementAt( 0 ),
334  // and similar things might happen elsewhere.
335  labelArea.addPolygon( transform.map( QPolygon( plainRect.toRect(), true ) ) );
336 
337  // store the label geometry and auxiliary data
338  cache->paintReplay.append( LabelPaintInfo( it.key(), dva, labelArea,
339  referencePoint, value >= 0.0, text ) );
340  }
341 }
342 
343 const QFontMetrics* AbstractDiagram::Private::cachedFontMetrics( const QFont& font,
344  const QPaintDevice* paintDevice) const
345 {
346  if ( ( font != mCachedFont ) || ( paintDevice != mCachedPaintDevice ) ) {
347  mCachedFontMetrics = QFontMetrics( font, const_cast<QPaintDevice *>( paintDevice ) );
348  // TODO what about setting mCachedFont and mCachedPaintDevice?
349  }
350  return &mCachedFontMetrics;
351 }
352 
353 const QFontMetrics AbstractDiagram::Private::cachedFontMetrics() const
354 {
355  return mCachedFontMetrics;
356 }
357 
358 QString AbstractDiagram::Private::formatNumber( qreal value, int decimalDigits ) const
359 {
360  const int digits = qMax(decimalDigits, 0);
361  const qreal roundingEpsilon = pow( 0.1, digits ) * ( value >= 0.0 ? 0.5 : -0.5 );
362  QString asString = QString::number( value + roundingEpsilon, 'f' );
363  const int decimalPos = asString.indexOf( QLatin1Char( '.' ) );
364  if ( decimalPos < 0 ) {
365  return asString;
366  }
367 
368  int last = qMin( decimalPos + digits, asString.length() - 1 );
369  // remove trailing zeros (and maybe decimal dot)
370  while ( last > decimalPos && asString[ last ] == QLatin1Char( '0' ) ) {
371  last--;
372  }
373  if ( last == decimalPos ) {
374  last--;
375  }
376  asString.chop( asString.length() - last - 1 );
377  return asString;
378 }
379 
380 void AbstractDiagram::Private::forgetAlreadyPaintedDataValues()
381 {
382  alreadyDrawnDataValueTexts.clear();
383  prevPaintedDataValueText.clear();
384 }
385 
386 void AbstractDiagram::Private::paintDataValueTextsAndMarkers(
387  PaintContext* ctx,
388  const LabelPaintCache &cache,
389  bool paintMarkers,
390  bool justCalculateRect /* = false */,
391  QRectF* cumulatedBoundingRect /* = 0 */ )
392 {
393  if ( justCalculateRect && !cumulatedBoundingRect ) {
394  qWarning() << Q_FUNC_INFO << "Neither painting nor finding the bounding rect, what are we doing?";
395  }
396 
397  const PainterSaver painterSaver( ctx->painter() );
398  ctx->painter()->setClipping( false );
399 
400  if ( paintMarkers && !justCalculateRect ) {
401  KDAB_FOREACH ( const LabelPaintInfo& info, cache.paintReplay ) {
402  diagram->paintMarker( ctx->painter(), info.index, info.markerPos );
403  }
404  }
405 
406  TextAttributes ta;
407  {
410  m.setReferenceArea( ctx->coordinatePlane() );
411  ta.setFontSize( m );
412  m.setAbsoluteValue( 6.0 );
413  ta.setMinimalFontSize( m );
414  }
415 
416  forgetAlreadyPaintedDataValues();
417 
418  KDAB_FOREACH ( const LabelPaintInfo& info, cache.paintReplay ) {
419  const QPointF pos = info.labelArea.elementAt( 0 );
420  paintDataValueText( ctx->painter(), info.attrs, pos, info.isValuePositive,
421  info.value, justCalculateRect, cumulatedBoundingRect );
422 
423  const QString comment = info.index.data( KDChart::CommentRole ).toString();
424  if ( comment.isEmpty() ) {
425  continue;
426  }
427  TextBubbleLayoutItem item( comment, ta, ctx->coordinatePlane()->parent(),
429  Qt::AlignHCenter | Qt::AlignVCenter );
430  const QRect rect( pos.toPoint(), item.sizeHint() );
431 
432  if (cumulatedBoundingRect) {
433  (*cumulatedBoundingRect) |= rect;
434  }
435  if ( !justCalculateRect ) {
436  item.setGeometry( rect );
437  item.paint( ctx->painter() );
438  }
439  }
440  if ( cumulatedBoundingRect ) {
441  *cumulatedBoundingRect = ctx->painter()->transform().inverted().mapRect( *cumulatedBoundingRect );
442  }
443 }
444 
445 QString AbstractDiagram::Private::formatDataValueText( const DataValueAttributes &dva,
446  const QModelIndex& index, qreal value ) const
447 {
448  if ( !dva.isVisible() ) {
449  return QString();
450  }
451  if ( dva.usePercentage() ) {
452  value = calcPercentValue( index );
453  }
454 
455  QString ret;
456  if ( dva.dataLabel().isNull() ) {
457  ret = formatNumber( value, dva.decimalDigits() );
458  } else {
459  ret = dva.dataLabel();
460  }
461 
462  ret.prepend( dva.prefix() );
463  ret.append( dva.suffix() );
464 
465  return ret;
466 }
467 
468 void AbstractDiagram::Private::paintDataValueText(
469  QPainter* painter,
470  const QModelIndex& index,
471  const QPointF& pos,
472  qreal value,
473  bool justCalculateRect /* = false */,
474  QRectF* cumulatedBoundingRect /* = 0 */ )
475 {
476  const DataValueAttributes dva( diagram->dataValueAttributes( index ) );
477  const QString text = formatDataValueText( dva, index, value );
478  paintDataValueText( painter, dva, pos, value >= 0.0, text,
479  justCalculateRect, cumulatedBoundingRect );
480 }
481 
482 void AbstractDiagram::Private::paintDataValueText(
483  QPainter* painter,
484  const DataValueAttributes& attrs,
485  const QPointF& pos,
486  bool valueIsPositive,
487  const QString& text,
488  bool justCalculateRect /* = false */,
489  QRectF* cumulatedBoundingRect /* = 0 */ )
490 {
491  if ( !attrs.isVisible() ) {
492  return;
493  }
494 
495  const TextAttributes ta( attrs.textAttributes() );
496  if ( !ta.isVisible() || ( !attrs.showRepetitiveDataLabels() && prevPaintedDataValueText == text ) ) {
497  return;
498  }
499  prevPaintedDataValueText = text;
500 
501  QTextDocument doc;
502  doc.setDocumentMargin( 0.0 );
503  if ( Qt::mightBeRichText( text ) ) {
504  doc.setHtml( text );
505  } else {
506  doc.setPlainText( text );
507  }
508 
509  const QFont calculatedFont( ta.calculatedFont( plane, KDChartEnums::MeasureOrientationMinimum ) );
510 
511  const PainterSaver painterSaver( painter );
512  painter->setPen( PrintingParameters::scalePen( ta.pen() ) );
513 
514  doc.setDefaultFont( calculatedFont );
515  QAbstractTextDocumentLayout::PaintContext context;
516  context.palette = diagram->palette();
517  context.palette.setColor( QPalette::Text, ta.pen().color() );
518 
519  QAbstractTextDocumentLayout* const layout = doc.documentLayout();
520  layout->setPaintDevice( painter->device() );
521 
522  painter->translate( pos.x(), pos.y() );
523  int rotation = ta.rotation();
524  if ( !valueIsPositive && attrs.mirrorNegativeValueTextRotation() ) {
525  rotation *= -1;
526  }
527  painter->rotate( rotation );
528 
529  // do overlap detection "as seen by the painter"
530  QTransform transform = painter->worldTransform();
531 
532  bool drawIt = true;
533  // note: This flag can be set differently for every label text!
534  // In theory a user could e.g. have some small red text on one of the
535  // values that she wants to have written in any case - so we just
536  // do not test if such texts would cover some of the others.
537  if ( !attrs.showOverlappingDataLabels() ) {
538  const QRectF br( layout->frameBoundingRect( doc.rootFrame() ) );
539  QPolygon pr = transform.mapToPolygon( br.toRect() );
540  // Using QPainterPath allows us to use intersects() (which has many early-exits)
541  // instead of QPolygon::intersected (which calculates a slow and precise intersection polygon)
542  QPainterPath path;
543  path.addPolygon( pr );
544 
545  // iterate backwards because recently added items are more likely to overlap, so we spend
546  // less time checking irrelevant items when there is overlap
547  for ( int i = alreadyDrawnDataValueTexts.count() - 1; i >= 0; i-- ) {
548  if ( alreadyDrawnDataValueTexts.at( i ).intersects( path ) ) {
549  // qDebug() << "not painting this label due to overlap";
550  drawIt = false;
551  break;
552  }
553  }
554  if ( drawIt ) {
555  alreadyDrawnDataValueTexts << path;
556  }
557  }
558 
559  if ( drawIt ) {
560  QRectF rect = layout->frameBoundingRect( doc.rootFrame() );
561  if ( cumulatedBoundingRect ) {
562  (*cumulatedBoundingRect) |= transform.mapRect( rect );
563  }
564  if ( !justCalculateRect ) {
565  bool paintBack = false;
567  if ( back.isVisible() ) {
568  paintBack = true;
569  painter->setBrush( back.brush() );
570  } else {
571  painter->setBrush( QBrush() );
572  }
573 
574  qreal radius = 0.0;
575  FrameAttributes frame( attrs.frameAttributes() );
576  if ( frame.isVisible() ) {
577  paintBack = true;
578  painter->setPen( frame.pen() );
579  radius = frame.cornerRadius();
580  }
581 
582  if ( paintBack ) {
583  QRectF borderRect( QPointF( 0, 0 ), rect.size() );
584  painter->drawRoundedRect( borderRect, radius, radius );
585  }
586  layout->draw( painter, context );
587  }
588  }
589 }
590 
591 QModelIndex AbstractDiagram::Private::indexAt( const QPoint& point ) const
592 {
593  QModelIndexList l = indexesAt( point );
594  qSort( l );
595  if ( !l.isEmpty() )
596  return l.first();
597  else
598  return QModelIndex();
599 }
600 
601 QModelIndexList AbstractDiagram::Private::indexesAt( const QPoint& point ) const
602 {
603  return reverseMapper.indexesAt( point ); // which could be empty
604 }
605 
606 QModelIndexList AbstractDiagram::Private::indexesIn( const QRect& rect ) const
607 {
608  return reverseMapper.indexesIn( rect );
609 }
610 
611 CartesianDiagramDataCompressor::AggregatedDataValueAttributes AbstractDiagram::Private::aggregatedAttrs(
612  const QModelIndex& index,
613  const CartesianDiagramDataCompressor::CachePosition* position ) const
614 {
615  Q_UNUSED( position ); // used by cartesian diagrams only
616  CartesianDiagramDataCompressor::AggregatedDataValueAttributes allAttrs;
617  allAttrs[index] = diagram->dataValueAttributes( index );
618  return allAttrs;
619 }
620 
621 void AbstractDiagram::Private::setDatasetAttrs( int dataset, const QVariant& data, int role )
622 {
623  // To store attributes for a dataset, we use the first column
624  // that's associated with it. (i.e., with a dataset dimension
625  // of two, the column of the keys). In most cases however, there's
626  // only one data dimension, and thus also only one column per data set.
627  int column = dataset * datasetDimension;
628 
629  // For DataHiddenRole, also store the flag in the other data points that belong to this data set,
630  // otherwise it's impossible to hide data points in a plotter diagram because there will always
631  // be one model index that belongs to this data point that is not hidden.
632  // For more details on how hiding works, see the data compressor.
633  // Also see KDCH-503 for which this is a workaround.
634  int columnSpan = role == DataHiddenRole ? datasetDimension : 1;
635 
636  for ( int i = 0; i < columnSpan; i++ ) {
637  attributesModel->setHeaderData( column + i, Qt::Horizontal, data, role );
638  }
639 }
640 
641 QVariant AbstractDiagram::Private::datasetAttrs( int dataset, int role ) const
642 {
643  // See setDataSetAttrs for explanation of column
644  int column = dataset * datasetDimension;
645  return attributesModel->headerData( column, Qt::Horizontal, role );
646 }
647 
648 void AbstractDiagram::Private::resetDatasetAttrs( int dataset, int role )
649 {
650  // See setDataSetAttrs for explanation of column
651  int column = dataset * datasetDimension;
652  attributesModel->resetHeaderData( column, Qt::Horizontal, role );
653 }
654 
655 bool AbstractDiagram::Private::isTransposed() const
656 {
657  // Determine the diagram that specifies the orientation.
658  // That diagram is the reference diagram, if it exists, or otherwise the diagram itself.
659  // Note: In KDChart 2.3 or earlier, only a bar diagram can be transposed.
660  const AbstractCartesianDiagram* refDiagram = qobject_cast< const AbstractCartesianDiagram * >( diagram );
661  if ( !refDiagram ) {
662  return false;
663  }
664  if ( refDiagram->referenceDiagram() ) {
665  refDiagram = refDiagram->referenceDiagram();
666  }
667  const BarDiagram* barDiagram = qobject_cast< const BarDiagram* >( refDiagram );
668  if ( !barDiagram ) {
669  return false;
670  }
671  return barDiagram->orientation() == Qt::Horizontal;
672 }
673 
674 LineAttributesInfo::LineAttributesInfo()
675 {
676 }
677 
678 LineAttributesInfo::LineAttributesInfo( const QModelIndex& _index, const QPointF& _value, const QPointF& _nextValue )
679  : index( _index )
680  , value ( _value )
681  , nextValue ( _nextValue )
682 {
683 }
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane.
QString prefix() const
Returns the string used as a prefix to the data value text.
bool mirrorNegativeValueTextRotation() const
If true, rotation of negative value labels is negated, so that negative values are rotated in opposit...
Diagram attributes dealing with data value labels.
AbstractCoordinatePlane * coordinatePlane() const
QString dataLabel() const
Returns the string displayed instead of the data value label.
BackgroundAttributes backgroundAttributes() const
QModelIndex index(int row, int col, const QModelIndex &index) const override
QPainter * painter() const
A set of attributes for frames around items.
PrivateAttributesModel(QAbstractItemModel *model, QObject *parent=0)
BarDiagram defines a common bar diagram.
QVariant data(int role) const
Returns the data that were specified at global level, or the default data, or QVariant().
const RelativePosition position(bool positive) const
void setRotation(int rotation)
Set the rotation angle to use for the text.
void setGeometry(const QRect &r) override
pure virtual in QLayoutItem
void setFontSize(const Measure &measure)
Set the size of the font used for rendering text.
void setTextAttributes(const TextAttributes &a)
Set the text attributes to use for the data value labels.
A proxy model used for decorating data with attributes.
const QFont calculatedFont(const QObject *autoReferenceArea, KDChartEnums::MeasureOrientation autoReferenceOrientation) const
Returns the font in the size that is used at drawing time.
virtual AbstractCartesianDiagram * referenceDiagram() const
Qt::Orientation orientation() const
Base class for diagrams based on a cartesian coordianate system.
PositionValue
Numerical values of the static KDChart::Position instances, for using a Position::value() with a swit...
Definition: KDChartEnums.h:192
Stores information about painting diagrams.
Stores the absolute target points of a Position.
Class only listed here to document inheritance of some KDChart classes.
Measure is used to specify relative and absolute sizes in KDChart, e.g.
QString suffix() const
Returns the string used as a suffix to the data value text.
Defines relative position information: reference area, position in this area (reference position)...
void setMinimalFontSize(const Measure &measure)
Set the minimal size of the font used for rendering text.
static QPen scalePen(const QPen &pen)
Defines a position, using compass terminology.
void setReferencePoints(const PositionPoints &points)
Set a set of points from which the anchor point will be selected.
A set of text attributes.
Set of attributes usable for background pixmaps.
Internally used class just adding a special constructor used by AbstractDiagram.

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/