34 #include "KDChartAbstractDiagram_p.h" 38 #include "KDChartPainterSaver_p.h" 40 #include <QAbstractTextDocumentLayout> 42 #include <QApplication> 44 #include <KDABLibFakes> 49 LabelPaintInfo::LabelPaintInfo() :
50 isValuePositive( false )
54 LabelPaintInfo::LabelPaintInfo(
const QModelIndex& _index,
const DataValueAttributes& _attrs,
55 const QPainterPath& _labelArea,
const QPointF& _markerPos,
56 bool _isValuePositive,
const QString& _value )
59 , labelArea( _labelArea )
60 , markerPos( _markerPos )
61 , isValuePositive( _isValuePositive )
66 LabelPaintInfo::LabelPaintInfo(
const LabelPaintInfo& other )
68 , attrs( other.attrs )
69 , labelArea( other.labelArea )
70 , markerPos( other.markerPos )
71 , isValuePositive( other.isValuePositive )
72 , value( other.value )
76 AbstractDiagram::Private::Private()
78 , doDumpPaintTime( false )
81 , allowOverlappingDataValueTexts( false )
82 , antiAliasing( true )
85 , databoundariesDirty( true )
86 , mCachedFontMetrics( QFontMetrics( qApp->font() ) )
90 AbstractDiagram::Private::~Private()
92 if ( attributesModel && qobject_cast<PrivateAttributesModel*>(attributesModel) )
93 delete attributesModel;
96 void AbstractDiagram::Private::init()
105 bool AbstractDiagram::Private::usesExternalAttributesModel()
const 107 return ( ! attributesModel.isNull() ) &&
108 ( ! qobject_cast<PrivateAttributesModel*>(attributesModel) );
111 void AbstractDiagram::Private::setAttributesModel(
AttributesModel* amodel )
113 if ( attributesModel == amodel ) {
117 if ( !attributesModel.isNull() ) {
118 if ( qobject_cast< PrivateAttributesModel* >( attributesModel ) ) {
119 delete attributesModel;
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() ));
138 emit diagram->attributesModelAboutToChange( amodel, attributesModel );
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() ));
155 attributesModel = amodel;
158 AbstractDiagram::Private::Private(
const AbstractDiagram::Private& rhs ) :
160 doDumpPaintTime( rhs.doDumpPaintTime ),
163 attributesModelRootIndex( QModelIndex() ),
164 attributesModel( rhs.attributesModel ),
165 allowOverlappingDataValueTexts( rhs.allowOverlappingDataValueTexts ),
166 antiAliasing( rhs.antiAliasing ),
167 percent( rhs.percent ),
169 mCachedFontMetrics( rhs.cachedFontMetrics() )
172 attributesModel->initFrom( rhs.attributesModel );
176 qreal AbstractDiagram::Private::calcPercentValue(
const QModelIndex &
index )
const 179 for (
int col = 0; col < attributesModel->columnCount( QModelIndex() ); col++ )
180 sum += attributesModel->data( attributesModel->index( index.row(), col, QModelIndex() ) ).toReal();
183 return attributesModel->data( attributesModel->mapFromSource( index ) ).toReal() / sum * 100.0;
186 void AbstractDiagram::Private::addLabel(
187 LabelPaintCache* cache,
188 const QModelIndex& index,
189 const CartesianDiagramDataCompressor::CachePosition* position,
192 const qreal value, qreal favoriteAngle )
194 CartesianDiagramDataCompressor::AggregatedDataValueAttributes allAttrs(
195 aggregatedAttrs( index, position ) );
198 for ( it = allAttrs.constBegin(); it != allAttrs.constEnd(); ++it ) {
204 const bool isPositive = ( value >= 0.0 );
208 if ( relPos.referencePosition().isUnknown() ) {
209 relPos.setReferencePosition( isPositive ? autoPositionPositive : autoPositionNegative );
213 if ( isTransposed() ) {
223 relPos.setReferencePosition(
Position( posValue ) );
227 const QPointF referencePoint = relPos.referencePoint();
228 if ( !diagram->coordinatePlane()->isVisiblePoint( referencePoint ) ) {
238 QSizeF relativeMeasureSize( fontHeight, fontHeight );
247 const QString text = formatDataValueText( dva, index, value );
249 doc.setDocumentMargin( 0 );
250 if ( Qt::mightBeRichText( text ) ) {
253 doc.setPlainText( text );
257 doc.setDefaultFont( calculatedFont );
259 const QRectF plainRect = doc.documentLayout()->frameBoundingRect( doc.rootFrame() );
296 QTransform transform;
299 QPointF calcPoint = relPos.calculatedPoint( relativeMeasureSize );
300 transform.translate( calcPoint.x(), calcPoint.y() );
303 if ( relPos.alignment() & Qt::AlignLeft ) {
305 }
else if ( relPos.alignment() & Qt::AlignRight ) {
310 if ( relPos.alignment() & Qt::AlignTop ) {
312 }
else if ( relPos.alignment() & Qt::AlignBottom ) {
315 transform.translate( qreal( dx ) * plainRect.width() * 0.5,
316 qreal( dy ) * plainRect.height() * 0.5 );
319 transform.translate( plainRect.center().x(), plainRect.center().y() );
324 transform.rotate( rotation );
325 transform.translate( -plainRect.center().x(), -plainRect.center().y() );
328 QPainterPath labelArea;
335 labelArea.addPolygon( transform.map( QPolygon( plainRect.toRect(), true ) ) );
338 cache->paintReplay.append( LabelPaintInfo( it.key(), dva, labelArea,
339 referencePoint, value >= 0.0, text ) );
343 const QFontMetrics* AbstractDiagram::Private::cachedFontMetrics(
const QFont& font,
346 if ( ( font != mCachedFont ) || ( paintDevice != mCachedPaintDevice ) ) {
347 mCachedFontMetrics = QFontMetrics( font, const_cast<QPaintDevice *>( paintDevice ) );
350 return &mCachedFontMetrics;
353 const QFontMetrics AbstractDiagram::Private::cachedFontMetrics()
const 355 return mCachedFontMetrics;
358 QString AbstractDiagram::Private::formatNumber( qreal value,
int decimalDigits )
const 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 ) {
368 int last = qMin( decimalPos + digits, asString.length() - 1 );
370 while ( last > decimalPos && asString[ last ] == QLatin1Char(
'0' ) ) {
373 if ( last == decimalPos ) {
376 asString.chop( asString.length() - last - 1 );
380 void AbstractDiagram::Private::forgetAlreadyPaintedDataValues()
382 alreadyDrawnDataValueTexts.clear();
383 prevPaintedDataValueText.clear();
386 void AbstractDiagram::Private::paintDataValueTextsAndMarkers(
388 const LabelPaintCache &cache,
390 bool justCalculateRect ,
391 QRectF* cumulatedBoundingRect )
393 if ( justCalculateRect && !cumulatedBoundingRect ) {
394 qWarning() << Q_FUNC_INFO <<
"Neither painting nor finding the bounding rect, what are we doing?";
397 const PainterSaver painterSaver( ctx->
painter() );
398 ctx->
painter()->setClipping(
false );
400 if ( paintMarkers && !justCalculateRect ) {
401 KDAB_FOREACH (
const LabelPaintInfo& info, cache.paintReplay ) {
402 diagram->paintMarker( ctx->
painter(), info.index, info.markerPos );
412 m.setAbsoluteValue( 6.0 );
416 forgetAlreadyPaintedDataValues();
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 );
424 if ( comment.isEmpty() ) {
429 Qt::AlignHCenter | Qt::AlignVCenter );
430 const QRect rect( pos.toPoint(), item.sizeHint() );
432 if (cumulatedBoundingRect) {
433 (*cumulatedBoundingRect) |= rect;
435 if ( !justCalculateRect ) {
440 if ( cumulatedBoundingRect ) {
441 *cumulatedBoundingRect = ctx->
painter()->transform().inverted().mapRect( *cumulatedBoundingRect );
446 const QModelIndex& index, qreal value )
const 452 value = calcPercentValue( index );
462 ret.prepend( dva.
prefix() );
463 ret.append( dva.
suffix() );
468 void AbstractDiagram::Private::paintDataValueText(
470 const QModelIndex& index,
473 bool justCalculateRect ,
474 QRectF* cumulatedBoundingRect )
477 const QString text = formatDataValueText( dva, index, value );
478 paintDataValueText( painter, dva, pos, value >= 0.0, text,
479 justCalculateRect, cumulatedBoundingRect );
482 void AbstractDiagram::Private::paintDataValueText(
486 bool valueIsPositive,
488 bool justCalculateRect ,
489 QRectF* cumulatedBoundingRect )
499 prevPaintedDataValueText = text;
502 doc.setDocumentMargin( 0.0 );
503 if ( Qt::mightBeRichText( text ) ) {
506 doc.setPlainText( text );
511 const PainterSaver painterSaver( painter );
514 doc.setDefaultFont( calculatedFont );
515 QAbstractTextDocumentLayout::PaintContext context;
516 context.palette = diagram->palette();
517 context.palette.setColor( QPalette::Text, ta.
pen().color() );
519 QAbstractTextDocumentLayout*
const layout = doc.documentLayout();
520 layout->setPaintDevice( painter->device() );
522 painter->translate( pos.x(), pos.y() );
527 painter->rotate( rotation );
530 QTransform transform = painter->worldTransform();
538 const QRectF br( layout->frameBoundingRect( doc.rootFrame() ) );
539 QPolygon pr = transform.mapToPolygon( br.toRect() );
543 path.addPolygon( pr );
547 for (
int i = alreadyDrawnDataValueTexts.count() - 1; i >= 0; i-- ) {
548 if ( alreadyDrawnDataValueTexts.at( i ).intersects( path ) ) {
555 alreadyDrawnDataValueTexts << path;
560 QRectF rect = layout->frameBoundingRect( doc.rootFrame() );
561 if ( cumulatedBoundingRect ) {
562 (*cumulatedBoundingRect) |= transform.mapRect( rect );
564 if ( !justCalculateRect ) {
565 bool paintBack =
false;
567 if ( back.isVisible() ) {
571 painter->setBrush( QBrush() );
576 if ( frame.isVisible() ) {
578 painter->
setPen( frame.pen() );
579 radius = frame.cornerRadius();
583 QRectF borderRect( QPointF( 0, 0 ), rect.size() );
584 painter->drawRoundedRect( borderRect, radius, radius );
586 layout->draw( painter, context );
591 QModelIndex AbstractDiagram::Private::indexAt(
const QPoint& point )
const 593 QModelIndexList l = indexesAt( point );
598 return QModelIndex();
601 QModelIndexList AbstractDiagram::Private::indexesAt(
const QPoint& point )
const 603 return reverseMapper.indexesAt( point );
606 QModelIndexList AbstractDiagram::Private::indexesIn(
const QRect& rect )
const 608 return reverseMapper.indexesIn( rect );
611 CartesianDiagramDataCompressor::AggregatedDataValueAttributes AbstractDiagram::Private::aggregatedAttrs(
612 const QModelIndex& index,
613 const CartesianDiagramDataCompressor::CachePosition* position )
const 615 Q_UNUSED( position );
616 CartesianDiagramDataCompressor::AggregatedDataValueAttributes allAttrs;
617 allAttrs[
index] = diagram->dataValueAttributes( index );
621 void AbstractDiagram::Private::setDatasetAttrs(
int dataset,
const QVariant&
data,
int role )
636 for (
int i = 0; i < columnSpan; i++ ) {
637 attributesModel->setHeaderData( column + i, Qt::Horizontal, data, role );
641 QVariant AbstractDiagram::Private::datasetAttrs(
int dataset,
int role )
const 645 return attributesModel->headerData( column, Qt::Horizontal, role );
648 void AbstractDiagram::Private::resetDatasetAttrs(
int dataset,
int role )
652 attributesModel->resetHeaderData( column, Qt::Horizontal, role );
655 bool AbstractDiagram::Private::isTransposed()
const 671 return barDiagram->
orientation() == Qt::Horizontal;
674 LineAttributesInfo::LineAttributesInfo()
678 LineAttributesInfo::LineAttributesInfo(
const QModelIndex& _index,
const QPointF& _value,
const QPointF& _nextValue )
681 , nextValue ( _nextValue )
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.
bool usePercentage() const
BackgroundAttributes backgroundAttributes() const
int datasetDimension() const
QModelIndex index(int row, int col, const QModelIndex &index) const override
QPainter * painter() const
A set of attributes for frames around items.
bool showOverlappingDataLabels() const
PrivateAttributesModel(QAbstractItemModel *model, QObject *parent=0)
BarDiagram defines a common bar diagram.
bool showRepetitiveDataLabels() const
void setPen(const QPen &pen)
QVariant data(int role) const
Returns the data that were specified at global level, or the default data, or QVariant().
int decimalDigits() const
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
TextAttributes textAttributes() const
void setBrush(const QBrush &brush)
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...
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.
FrameAttributes frameAttributes() const
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.