1
/****************************************************************************
2
** Copyright (C) 2007 Klaralvdalens Datakonsult AB. All rights reserved.
4
** This file is part of the KD Chart library.
6
** This file may be used under the terms of the GNU General Public
7
** License versions 2.0 or 3.0 as published by the Free Software
8
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
9
** included in the packaging of this file. Alternatively you may (at
10
** your option) use any later version of the GNU General Public
11
** License if such license has been publicly approved by
12
** Klarälvdalens Datakonsult AB (or its successors, if any).
14
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
15
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
16
** A PARTICULAR PURPOSE. Klarälvdalens Datakonsult AB reserves all rights
17
** not expressly granted herein.
19
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22
**********************************************************************/
24
#include "KDChartAbstractDiagram.h"
25
#include "KDChartAbstractDiagram_p.h"
29
#include <QApplication>
30
#include <QAbstractProxyModel>
31
#include <QAbstractTextDocumentLayout>
32
#include <QStandardItemModel>
34
#include <QTextDocument>
36
#include "KDChartAbstractCoordinatePlane.h"
37
#include "KDChartChart.h"
38
#include "KDChartDataValueAttributes.h"
39
#include "KDChartTextAttributes.h"
40
#include "KDChartMarkerAttributes.h"
41
#include "KDChartAbstractThreeDAttributes.h"
42
#include "KDChartThreeDLineAttributes.h"
44
#include <KDABLibFakes>
46
#define PI 3.141592653589793
48
using namespace KDChart;
50
AbstractDiagram::Private::Private()
52
, attributesModel( new PrivateAttributesModel(0,0) )
53
, allowOverlappingDataValueTexts( false )
54
, antiAliasing( true )
56
, datasetDimension( 1 )
57
, databoundariesDirty(true)
60
, mCachedFontMetrics( QFontMetrics( qApp->font() ) )
64
AbstractDiagram::Private::~Private()
66
if( attributesModel && qobject_cast<PrivateAttributesModel*>(attributesModel) )
67
delete attributesModel;
70
void AbstractDiagram::Private::init()
74
void AbstractDiagram::Private::init( AbstractCoordinatePlane* newPlane )
79
bool AbstractDiagram::Private::usesExternalAttributesModel()const
81
return ( ! attributesModel.isNull() ) &&
82
( ! qobject_cast<PrivateAttributesModel*>(attributesModel) );
85
void AbstractDiagram::Private::setAttributesModel( AttributesModel* amodel )
87
if( !attributesModel.isNull() &&
88
qobject_cast<PrivateAttributesModel*>(attributesModel) ) {
89
delete attributesModel;
91
attributesModel = amodel;
94
AbstractDiagram::Private::Private( const AbstractDiagram::Private& rhs ) :
95
// Do not copy the plane
97
attributesModelRootIndex( QModelIndex() ),
98
attributesModel( rhs.attributesModel ),
99
allowOverlappingDataValueTexts( rhs.allowOverlappingDataValueTexts ),
100
antiAliasing( rhs.antiAliasing ),
101
percent( rhs.percent ),
102
datasetDimension( rhs.datasetDimension ),
103
mCachedFontMetrics( rhs.cachedFontMetrics() )
105
attributesModel = new PrivateAttributesModel( 0, 0);
106
attributesModel->initFrom( rhs.attributesModel );
111
AbstractDiagram::AbstractDiagram ( QWidget* parent, AbstractCoordinatePlane* plane )
112
: QAbstractItemView ( parent ), _d( new Private() )
118
AbstractDiagram::~AbstractDiagram()
123
void AbstractDiagram::init()
125
d->reverseMapper.setDiagram( this );
129
bool AbstractDiagram::compare( const AbstractDiagram* other )const
131
if( other == this ) return true;
133
//qDebug() << "AbstractDiagram::compare() cannot compare to Null pointer";
137
qDebug() << "\n AbstractDiagram::compare() QAbstractScrollArea:";
138
// compare QAbstractScrollArea properties
140
((horizontalScrollBarPolicy() == other->horizontalScrollBarPolicy()) &&
141
(verticalScrollBarPolicy() == other->verticalScrollBarPolicy()));
142
qDebug() << "AbstractDiagram::compare() QFrame:";
143
// compare QFrame properties
145
((frameShadow() == other->frameShadow()) &&
146
(frameShape() == other->frameShape()) &&
147
(frameWidth() == other->frameWidth()) &&
148
(lineWidth() == other->lineWidth()) &&
149
(midLineWidth() == other->midLineWidth()));
150
qDebug() << "AbstractDiagram::compare() QAbstractItemView:";
151
// compare QAbstractItemView properties
153
((alternatingRowColors() == other->alternatingRowColors()) &&
154
(hasAutoScroll() == other->hasAutoScroll()) &&
155
#if QT_VERSION > 0x040199
156
(dragDropMode() == other->dragDropMode()) &&
157
(dragDropOverwriteMode() == other->dragDropOverwriteMode()) &&
158
(horizontalScrollMode() == other->horizontalScrollMode ()) &&
159
(verticalScrollMode() == other->verticalScrollMode()) &&
161
(dragEnabled() == other->dragEnabled()) &&
162
(editTriggers() == other->editTriggers()) &&
163
(iconSize() == other->iconSize()) &&
164
(selectionBehavior() == other->selectionBehavior()) &&
165
(selectionMode() == other->selectionMode()) &&
166
(showDropIndicator() == other->showDropIndicator()) &&
167
(tabKeyNavigation() == other->tabKeyNavigation()) &&
168
(textElideMode() == other->textElideMode()));
169
qDebug() << "AbstractDiagram::compare() AttributesModel: ";
170
// compare all of the properties stored in the attributes model
171
qDebug() << attributesModel()->compare( other->attributesModel() );
172
qDebug() << "AbstractDiagram::compare() own:";
173
// compare own properties
175
((rootIndex().column() == other->rootIndex().column()) &&
176
(rootIndex().row() == other->rootIndex().row()) &&
177
(allowOverlappingDataValueTexts() == other->allowOverlappingDataValueTexts()) &&
178
(antiAliasing() == other->antiAliasing()) &&
179
(percentMode() == other->percentMode()) &&
180
(datasetDimension() == other->datasetDimension()));
182
return // compare QAbstractScrollArea properties
183
(horizontalScrollBarPolicy() == other->horizontalScrollBarPolicy()) &&
184
(verticalScrollBarPolicy() == other->verticalScrollBarPolicy()) &&
185
// compare QFrame properties
186
(frameShadow() == other->frameShadow()) &&
187
(frameShape() == other->frameShape()) &&
188
// frameWidth is a read-only property defined by the style, it should not be in here:
189
// (frameWidth() == other->frameWidth()) &&
190
(lineWidth() == other->lineWidth()) &&
191
(midLineWidth() == other->midLineWidth()) &&
192
// compare QAbstractItemView properties
193
(alternatingRowColors() == other->alternatingRowColors()) &&
194
(hasAutoScroll() == other->hasAutoScroll()) &&
195
#if QT_VERSION > 0x040199
196
(dragDropMode() == other->dragDropMode()) &&
197
(dragDropOverwriteMode() == other->dragDropOverwriteMode()) &&
198
(horizontalScrollMode() == other->horizontalScrollMode ()) &&
199
(verticalScrollMode() == other->verticalScrollMode()) &&
201
(dragEnabled() == other->dragEnabled()) &&
202
(editTriggers() == other->editTriggers()) &&
203
(iconSize() == other->iconSize()) &&
204
(selectionBehavior() == other->selectionBehavior()) &&
205
(selectionMode() == other->selectionMode()) &&
206
(showDropIndicator() == other->showDropIndicator()) &&
207
(tabKeyNavigation() == other->tabKeyNavigation()) &&
208
(textElideMode() == other->textElideMode()) &&
209
// compare all of the properties stored in the attributes model
210
attributesModel()->compare( other->attributesModel() ) &&
211
// compare own properties
212
(rootIndex().column() == other->rootIndex().column()) &&
213
(rootIndex().row() == other->rootIndex().row()) &&
214
(allowOverlappingDataValueTexts() == other->allowOverlappingDataValueTexts()) &&
215
(antiAliasing() == other->antiAliasing()) &&
216
(percentMode() == other->percentMode()) &&
217
(datasetDimension() == other->datasetDimension());
220
AbstractCoordinatePlane* AbstractDiagram::coordinatePlane() const
225
const QPair<QPointF, QPointF> AbstractDiagram::dataBoundaries () const
227
if( d->databoundariesDirty ){
228
d->databoundaries = calculateDataBoundaries ();
229
d->databoundariesDirty = false;
231
return d->databoundaries;
234
void AbstractDiagram::setDataBoundariesDirty() const
236
d->databoundariesDirty = true;
239
void AbstractDiagram::setModel( QAbstractItemModel * newModel )
243
disconnect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
244
disconnect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
245
disconnect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
246
disconnect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
247
disconnect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
248
disconnect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
250
QAbstractItemView::setModel( newModel );
251
AttributesModel* amodel = new PrivateAttributesModel( newModel, this );
252
amodel->initFrom( d->attributesModel );
253
d->setAttributesModel(amodel);
254
scheduleDelayedItemsLayout();
255
setDataBoundariesDirty();
258
connect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
259
connect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
260
connect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
261
connect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
262
connect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
263
connect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
265
emit modelsChanged();
268
void AbstractDiagram::setSelectionModel( QItemSelectionModel* newSelectionModel )
270
if( selectionModel() )
272
disconnect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
273
disconnect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
275
QAbstractItemView::setSelectionModel( newSelectionModel );
276
if( selectionModel() )
278
connect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
279
connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
281
emit modelsChanged();
284
/*! Sets an external AttributesModel on this diagram. By default, a diagram has it's
285
own internal set of attributes, but an external one can be set. This can be used to
286
share attributes between several diagrams. The diagram does not take ownership of the
289
void AbstractDiagram::setAttributesModel( AttributesModel* amodel )
291
if( amodel->sourceModel() != model() ) {
292
qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
293
"Trying to set an attributesmodel which works on a different "
294
"model than the diagram.");
297
if( qobject_cast<PrivateAttributesModel*>(amodel) ) {
298
qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
299
"Trying to set an attributesmodel that is private to another diagram.");
302
d->setAttributesModel(amodel);
303
scheduleDelayedItemsLayout();
304
setDataBoundariesDirty();
305
emit modelsChanged();
308
bool AbstractDiagram::usesExternalAttributesModel()const
310
return d->usesExternalAttributesModel();
313
/*! \returns a pointer to the AttributesModel currently used by this diagram. */
314
AttributesModel* AbstractDiagram::attributesModel() const
316
return d->attributesModel;
319
QModelIndex AbstractDiagram::conditionallyMapFromSource( const QModelIndex & index ) const
321
Q_ASSERT( !index.isValid() || index.model() == attributesModel() || index.model() == attributesModel()->sourceModel() );
322
return index.model() == attributesModel()
324
: attributesModel()->mapFromSource( index );
328
void AbstractDiagram::setRootIndex ( const QModelIndex& idx )
330
QAbstractItemView::setRootIndex(idx);
331
setAttributesModelRootIndex( d->attributesModel->mapFromSource(idx) );
335
void AbstractDiagram::setAttributesModelRootIndex( const QModelIndex& idx )
337
d->attributesModelRootIndex=idx;
338
setDataBoundariesDirty();
339
scheduleDelayedItemsLayout();
342
/*! returns a QModelIndex pointing into the AttributesModel that corresponds to the
343
root index of the diagram. */
344
QModelIndex AbstractDiagram::attributesModelRootIndex() const
346
if ( !d->attributesModelRootIndex.isValid() )
347
d->attributesModelRootIndex = d->attributesModel->mapFromSource( rootIndex() );
348
return d->attributesModelRootIndex;
351
void AbstractDiagram::setCoordinatePlane( AbstractCoordinatePlane* parent )
356
void AbstractDiagram::doItemsLayout()
359
d->plane->layoutDiagrams();
362
QAbstractItemView::doItemsLayout();
365
void AbstractDiagram::dataChanged( const QModelIndex &topLeft,
366
const QModelIndex &bottomRight )
369
Q_UNUSED( bottomRight );
370
// We are still too dumb to do intelligent updates...
371
setDataBoundariesDirty();
372
scheduleDelayedItemsLayout();
376
void AbstractDiagram::setHidden( const QModelIndex & index, bool hidden )
378
d->attributesModel->setData(
379
conditionallyMapFromSource( index ),
380
qVariantFromValue( hidden ),
385
void AbstractDiagram::setHidden( int dataset, bool hidden )
387
// To store the flag for a dataset, we use the first column
388
// that's associated with it. (i.e., with a dataset dimension
389
// of two, the column of the keys)
390
const int column = dataset * datasetDimension();
391
d->attributesModel->setHeaderData(
392
column, Qt::Vertical,
393
qVariantFromValue( hidden ),
398
void AbstractDiagram::setHidden( bool hidden )
400
d->attributesModel->setModelData(
401
qVariantFromValue( hidden ),
406
bool AbstractDiagram::isHidden() const
408
return qVariantValue<bool>(
409
attributesModel()->modelData( DataHiddenRole ) );
412
bool AbstractDiagram::isHidden( int dataset ) const
414
// To store the flag for a dataset, we use the first column
415
// that's associated with it. (i.e., with a dataset dimension
416
// of two, the column of the keys)
417
const int column = dataset * datasetDimension();
418
const QVariant boolFlag(
419
attributesModel()->headerData( column, Qt::Vertical,
421
if( boolFlag.isValid() )
422
return qVariantValue< bool >( boolFlag );
426
bool AbstractDiagram::isHidden( const QModelIndex & index ) const
428
return qVariantValue<bool>(
429
attributesModel()->data(
430
conditionallyMapFromSource(index),
435
void AbstractDiagram::setDataValueAttributes( const QModelIndex & index,
436
const DataValueAttributes & a )
438
d->attributesModel->setData(
439
conditionallyMapFromSource( index ),
440
qVariantFromValue( a ),
441
DataValueLabelAttributesRole );
442
emit propertiesChanged();
446
void AbstractDiagram::setDataValueAttributes( int dataset, const DataValueAttributes & a )
448
// To store the attributes for a dataset, we use the first column
449
// that's associated with it. (i.e., with a dataset dimension
450
// of two, the column of the keys)
451
const int column = dataset * datasetDimension();
452
d->attributesModel->setHeaderData(
453
column, Qt::Vertical,
454
qVariantFromValue( a ), DataValueLabelAttributesRole );
455
emit propertiesChanged();
458
DataValueAttributes AbstractDiagram::dataValueAttributes() const
460
return qVariantValue<DataValueAttributes>(
461
attributesModel()->modelData( KDChart::DataValueLabelAttributesRole ) );
464
DataValueAttributes AbstractDiagram::dataValueAttributes( int dataset ) const
467
The following did not work!
469
If there was some attrs specified for the 0-th cells of a dataset,
470
then this logic would return the cell's settings instead of the header settings:
472
return qVariantValue<DataValueAttributes>(
473
attributesModel()->data( attributesModel()->mapFromSource(columnToIndex( column )),
474
KDChart::DataValueLabelAttributesRole ) );
477
// To store the attributes for a dataset, we use the first column
478
// that's associated with it. (i.e., with a dataset dimension
479
// of two, the column of the keys)
480
const int column = dataset * datasetDimension();
482
const QVariant headerAttrs(
483
attributesModel()->headerData( column, Qt::Horizontal,
484
KDChart::DataValueLabelAttributesRole ) );
485
if( headerAttrs.isValid() )
486
return qVariantValue< DataValueAttributes >( headerAttrs );
487
return dataValueAttributes();
490
DataValueAttributes AbstractDiagram::dataValueAttributes( const QModelIndex & index ) const
492
return qVariantValue<DataValueAttributes>(
493
attributesModel()->data(
494
conditionallyMapFromSource( index ),
495
KDChart::DataValueLabelAttributesRole ) );
498
void AbstractDiagram::setDataValueAttributes( const DataValueAttributes & a )
500
d->attributesModel->setModelData( qVariantFromValue( a ), DataValueLabelAttributesRole );
501
emit propertiesChanged();
504
void AbstractDiagram::setAllowOverlappingDataValueTexts( bool allow )
506
d->allowOverlappingDataValueTexts = allow;
507
emit propertiesChanged();
510
bool AbstractDiagram::allowOverlappingDataValueTexts() const
512
return d->allowOverlappingDataValueTexts;
515
void AbstractDiagram::setAntiAliasing( bool enabled )
517
d->antiAliasing = enabled;
518
emit propertiesChanged();
521
bool AbstractDiagram::antiAliasing() const
523
return d->antiAliasing;
526
void AbstractDiagram::setPercentMode ( bool percent )
528
d->percent = percent;
529
emit propertiesChanged();
532
bool AbstractDiagram::percentMode() const
538
void AbstractDiagram::paintDataValueText( QPainter* painter,
539
const QModelIndex& index,
543
d->paintDataValueText( this, painter, index, pos, value );
547
QString AbstractDiagram::roundValues( double value,
548
const int decimalPos,
549
const int decimalDigits ) const
551
return d->roundValues( value, decimalPos, decimalDigits );
554
void AbstractDiagram::paintDataValueTexts( QPainter* painter )
556
if ( !checkInvariants() ) return;
557
const int rowCount = model()->rowCount(rootIndex());
558
const int columnCount = model()->columnCount(rootIndex());
559
d->clearListOfAlreadyDrawnDataValueTexts();
560
for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
561
for ( int j=0; j< rowCount; ++j ) {
562
const QModelIndex index = model()->index( j, i, rootIndex() );
563
double value = model()->data( index ).toDouble();
564
const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
565
paintDataValueText( painter, index, pos, value );
571
void AbstractDiagram::paintMarker( QPainter* painter,
572
const DataValueAttributes& a,
573
const QModelIndex& index,
576
if ( !checkInvariants() || !a.isVisible() ) return;
577
const MarkerAttributes ma = a.markerAttributes();
578
if ( !ma.isVisible() ) return;
580
const PainterSaver painterSaver( painter );
581
// the size of the marker - unscaled
582
const QSizeF maSize( ma.markerSize().width() / painter->matrix().m11(),
583
ma.markerSize().height() / painter->matrix().m22() );
584
QBrush indexBrush( brush( index ) );
585
QPen indexPen( ma.pen() );
586
if ( ma.markerColor().isValid() )
587
indexBrush.setColor( ma.markerColor() );
589
paintMarker( painter, ma, indexBrush, indexPen, pos, maSize );
591
// workaround: BC cannot be changed, otherwise we would pass the
592
// index down to next-lower paintMarker function. So far, we
593
// basically save a circle of radius maSize at pos in the
594
// reverseMapper. This means that ^^^ this version of paintMarker
595
// needs to be called to reverse-map the marker.
596
d->reverseMapper.addCircle( index.row(), index.column(), pos, 2 * maSize );
599
void AbstractDiagram::paintMarker( QPainter* painter,
600
const QModelIndex& index,
603
if ( !checkInvariants() ) return;
604
paintMarker( painter, dataValueAttributes( index ), index, pos );
607
void AbstractDiagram::paintMarker( QPainter* painter,
608
const MarkerAttributes& markerAttributes,
612
const QSizeF& maSize )
614
const QPen oldPen( painter->pen() );
615
// Pen is used to paint 4Pixels - 1 Pixel - Ring and FastCross types.
616
// make sure to use the brush color - see above in those cases.
617
const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels);
618
if( isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel) ){
619
// for high-performance point charts with tiny point markers:
620
painter->setPen( PrintingParameters::scalePen( QPen( brush.color().light() ) ) );
622
const qreal x = pos.x();
623
const qreal y = pos.y();
624
painter->drawLine( QPointF(x-1.0,y-1.0),
625
QPointF(x+1.0,y-1.0) );
626
painter->drawLine( QPointF(x-1.0,y),
628
painter->drawLine( QPointF(x-1.0,y+1.0),
629
QPointF(x+1.0,y+1.0) );
631
painter->drawPoint( pos );
633
const PainterSaver painterSaver( painter );
634
// we only a solid line surrounding the markers
635
QPen painterPen( pen );
636
painterPen.setStyle( Qt::SolidLine );
637
painter->setPen( PrintingParameters::scalePen( painterPen ) );
638
painter->setBrush( brush );
639
painter->setRenderHint ( QPainter::Antialiasing );
640
painter->translate( pos );
641
switch ( markerAttributes.markerStyle() ) {
642
case MarkerAttributes::MarkerCircle:
643
painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
644
maSize.height(), maSize.width()) );
646
case MarkerAttributes::MarkerSquare:
648
QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2,
649
maSize.width(), maSize.height() );
650
painter->drawRect( rect );
653
case MarkerAttributes::MarkerDiamond:
655
QVector <QPointF > diamondPoints;
656
QPointF top, left, bottom, right;
657
top = QPointF( 0, 0 - maSize.height()/2 );
658
left = QPointF( 0 - maSize.width()/2, 0 );
659
bottom = QPointF( 0, maSize.height()/2 );
660
right = QPointF( maSize.width()/2, 0 );
661
diamondPoints << top << left << bottom << right;
662
painter->drawPolygon( diamondPoints );
665
// both handled on top of the method:
666
case MarkerAttributes::Marker1Pixel:
667
case MarkerAttributes::Marker4Pixels:
669
case MarkerAttributes::MarkerRing:
671
painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
672
painter->setBrush( Qt::NoBrush );
673
painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
674
maSize.height(), maSize.width()) );
677
case MarkerAttributes::MarkerCross:
679
// Note: Markers can have outline,
680
// so just drawing two rects is NOT the solution here!
681
const qreal w02 = maSize.width() * 0.2;
682
const qreal w05 = maSize.width() * 0.5;
683
const qreal h02 = maSize.height()* 0.2;
684
const qreal h05 = maSize.height()* 0.5;
685
QVector <QPointF > crossPoints;
687
p[ 0] = QPointF( -w02, -h05 );
688
p[ 1] = QPointF( w02, -h05 );
689
p[ 2] = QPointF( w02, -h02 );
690
p[ 3] = QPointF( w05, -h02 );
691
p[ 4] = QPointF( w05, h02 );
692
p[ 5] = QPointF( w02, h02 );
693
p[ 6] = QPointF( w02, h05 );
694
p[ 7] = QPointF( -w02, h05 );
695
p[ 8] = QPointF( -w02, h02 );
696
p[ 9] = QPointF( -w05, h02 );
697
p[10] = QPointF( -w05, -h02 );
698
p[11] = QPointF( -w02, -h02 );
699
for( int i=0; i<12; ++i )
702
painter->drawPolygon( crossPoints );
705
case MarkerAttributes::MarkerFastCross:
707
QPointF left, right, top, bottom;
708
left = QPointF( -maSize.width()/2, 0 );
709
right = QPointF( maSize.width()/2, 0 );
710
top = QPointF( 0, -maSize.height()/2 );
711
bottom= QPointF( 0, maSize.height()/2 );
712
painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
713
painter->drawLine( left, right );
714
painter->drawLine( top, bottom );
718
Q_ASSERT_X ( false, "paintMarkers()",
719
"Type item does not match a defined Marker Type." );
722
painter->setPen( oldPen );
725
void AbstractDiagram::paintMarkers( QPainter* painter )
727
if ( !checkInvariants() ) return;
728
const int rowCount = model()->rowCount(rootIndex());
729
const int columnCount = model()->columnCount(rootIndex());
730
for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
731
for ( int j=0; j< rowCount; ++j ) {
732
const QModelIndex index = model()->index( j, i, rootIndex() );
733
double value = model()->data( index ).toDouble();
734
const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
735
paintMarker( painter, index, pos );
741
void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen )
743
attributesModel()->setData(
744
conditionallyMapFromSource( index ),
745
qVariantFromValue( pen ), DatasetPenRole );
746
emit propertiesChanged();
749
void AbstractDiagram::setPen( const QPen& pen )
751
attributesModel()->setModelData(
752
qVariantFromValue( pen ), DatasetPenRole );
753
emit propertiesChanged();
756
void AbstractDiagram::setPen( int dataset, const QPen& pen )
758
// To store the pen for a dataset, we use the first column
759
// that's associated with it. (i.e., with a dataset dimension
760
// of two, the column of the keys)
761
const int column = dataset * datasetDimension();
763
attributesModel()->setHeaderData(
764
column, Qt::Horizontal,
765
qVariantFromValue( pen ),
767
emit propertiesChanged();
770
QPen AbstractDiagram::pen() const
772
return qVariantValue<QPen>(
773
attributesModel()->data( DatasetPenRole ) );
776
QPen AbstractDiagram::pen( int dataset ) const
778
// To store the pen for a dataset, we use the first column
779
// that's associated with it. (i.e., with a dataset dimension
780
// of two, the column of the keys)
781
const int column = dataset * datasetDimension();
783
const QVariant penSettings(
784
attributesModel()->headerData( column, Qt::Horizontal,
786
if( penSettings.isValid() )
787
return qVariantValue< QPen >( penSettings );
791
QPen AbstractDiagram::pen( const QModelIndex& index ) const
793
return qVariantValue<QPen>(
794
attributesModel()->data(
795
conditionallyMapFromSource( index ),
799
void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush )
801
attributesModel()->setData(
802
conditionallyMapFromSource( index ),
803
qVariantFromValue( brush ), DatasetBrushRole );
804
emit propertiesChanged();
807
void AbstractDiagram::setBrush( const QBrush& brush )
809
attributesModel()->setModelData(
810
qVariantFromValue( brush ), DatasetBrushRole );
811
emit propertiesChanged();
814
void AbstractDiagram::setBrush( int dataset, const QBrush& brush )
816
// To store the brush for a dataset, we use the first column
817
// that's associated with it. (i.e., with a dataset dimension
818
// of two, the column of the keys)
819
const int column = dataset * datasetDimension();
821
attributesModel()->setHeaderData(
822
column, Qt::Horizontal,
823
qVariantFromValue( brush ),
825
emit propertiesChanged();
828
QBrush AbstractDiagram::brush() const
830
return qVariantValue<QBrush>(
831
attributesModel()->data( DatasetBrushRole ) );
834
QBrush AbstractDiagram::brush( int dataset ) const
836
// To store the brush for a dataset, we use the first column
837
// that's associated with it. (i.e., with a dataset dimension
838
// of two, the column of the keys)
839
const int column = dataset * datasetDimension();
841
const QVariant brushSettings(
842
attributesModel()->headerData( column, Qt::Horizontal,
843
DatasetBrushRole ) );
844
if( brushSettings.isValid() )
845
return qVariantValue< QBrush >( brushSettings );
849
QBrush AbstractDiagram::brush( const QModelIndex& index ) const
851
return qVariantValue<QBrush>(
852
attributesModel()->data( conditionallyMapFromSource( index ), DatasetBrushRole ) );
856
* Sets the unit prefix for one value
857
* @param prefix the prefix to be set
858
* @param column the value using that prefix
859
* @param orientation the orientantion of the axis to set
861
void AbstractDiagram::setUnitPrefix( const QString& prefix, int column, Qt::Orientation orientation )
863
d->unitPrefixMap[ column ][ orientation ]= prefix;
867
* Sets the unit prefix for all values
868
* @param prefix the prefix to be set
869
* @param orientation the orientantion of the axis to set
871
void AbstractDiagram::setUnitPrefix( const QString& prefix, Qt::Orientation orientation )
873
d->unitPrefix[ orientation ] = prefix;
877
* Sets the unit suffix for one value
878
* @param suffix the suffix to be set
879
* @param column the value using that suffix
880
* @param orientation the orientantion of the axis to set
882
void AbstractDiagram::setUnitSuffix( const QString& suffix, int column, Qt::Orientation orientation )
884
d->unitSuffixMap[ column ][ orientation ]= suffix;
888
* Sets the unit suffix for all values
889
* @param suffix the suffix to be set
890
* @param orientation the orientantion of the axis to set
892
void AbstractDiagram::setUnitSuffix( const QString& suffix, Qt::Orientation orientation )
894
d->unitSuffix[ orientation ] = suffix;
898
* Returns the unit prefix for a special value
899
* @param column the value which's prefix is requested
900
* @param orientation the orientation of the axis
901
* @param fallback if true, the global prefix is return when no specific one is set for that value
902
* @return the unit prefix
904
QString AbstractDiagram::unitPrefix( int column, Qt::Orientation orientation, bool fallback ) const
906
if( !fallback || d->unitPrefixMap[ column ].contains( orientation ) )
907
return d->unitPrefixMap[ column ][ orientation ];
908
return d->unitPrefix[ orientation ];
911
/** Returns the global unit prefix
912
* @param orientation the orientation of the axis
913
* @return the unit prefix
915
QString AbstractDiagram::unitPrefix( Qt::Orientation orientation ) const
917
return d->unitPrefix[ orientation ];
921
* Returns the unit suffix for a special value
922
* @param column the value which's suffix is requested
923
* @param orientation the orientation of the axis
924
* @param fallback if true, the global suffix is return when no specific one is set for that value
925
* @return the unit suffix
927
QString AbstractDiagram::unitSuffix( int column, Qt::Orientation orientation, bool fallback ) const
929
if( !fallback || d->unitSuffixMap[ column ].contains( orientation ) )
930
return d->unitSuffixMap[ column ][ orientation ];
931
return d->unitSuffix[ orientation ];
934
/** Returns the global unit suffix
935
* @param orientation the orientation of the axis
936
* @return the unit siffix
938
QString AbstractDiagram::unitSuffix( Qt::Orientation orientation ) const
940
return d->unitSuffix[ orientation ];
943
// implement QAbstractItemView:
944
QRect AbstractDiagram::visualRect( const QModelIndex &index ) const
946
return d->reverseMapper.boundingRect( index.row(), index.column() ).toRect();
949
void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint )
952
// indexAt ... down below
954
QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers )
955
{ return QModelIndex(); }
957
int AbstractDiagram::horizontalOffset() const
960
int AbstractDiagram::verticalOffset() const
963
bool AbstractDiagram::isIndexHidden(const QModelIndex &) const
966
void AbstractDiagram::setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags command )
968
const QModelIndexList indexes = d->indexesIn( rect );
969
QItemSelection selection;
970
KDAB_FOREACH( const QModelIndex& index, indexes )
972
selection.append( QItemSelectionRange( index ) );
974
selectionModel()->select( selection, command );
977
QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &selection) const
980
KDAB_FOREACH( const QModelIndex& index, selection.indexes() )
982
polygon << d->reverseMapper.polygon(index.row(), index.column());
984
return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
987
QRegion AbstractDiagram::visualRegion(const QModelIndex &index) const
989
QPolygonF polygon = d->reverseMapper.polygon(index.row(), index.column());
990
return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
993
void KDChart::AbstractDiagram::useDefaultColors( )
995
d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault );
998
void KDChart::AbstractDiagram::useSubduedColors( )
1000
d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued );
1003
void KDChart::AbstractDiagram::useRainbowColors( )
1005
d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow );
1008
QStringList AbstractDiagram::itemRowLabels() const
1012
//qDebug() << "AbstractDiagram::itemRowLabels(): " << attributesModel()->rowCount(attributesModelRootIndex()) << "entries";
1013
const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
1014
for( int i = 0; i < rowCount; ++i ){
1015
//qDebug() << "item row label: " << attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString();
1016
ret << unitPrefix( i, Qt::Horizontal, true ) +
1017
attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString() +
1018
unitSuffix( i, Qt::Horizontal, true );
1024
QStringList AbstractDiagram::datasetLabels() const
1030
const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
1031
for( int i = 0; i < columnCount; i += datasetDimension() )
1032
ret << attributesModel()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString();
1037
QList<QBrush> AbstractDiagram::datasetBrushes() const
1043
const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
1044
for ( int dataset = 0; dataset < datasetCount; dataset++ )
1045
ret << brush( dataset );
1050
QList<QPen> AbstractDiagram::datasetPens() const
1056
const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
1057
for ( int dataset = 0; dataset < datasetCount; dataset++ )
1058
ret << pen( dataset );
1063
QList<MarkerAttributes> AbstractDiagram::datasetMarkers() const
1065
QList<MarkerAttributes> ret;
1069
const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
1070
for ( int dataset = 0; dataset < datasetCount; dataset++ )
1071
ret << dataValueAttributes( dataset ).markerAttributes();
1076
bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const
1078
if( ! justReturnTheStatus ){
1079
Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()",
1080
"There is no usable model set, for the diagram." );
1082
Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()",
1083
"There is no usable coordinate plane set, for the diagram." );
1085
return model() && coordinatePlane();
1088
int AbstractDiagram::datasetDimension( ) const
1090
return d->datasetDimension;
1093
void AbstractDiagram::setDatasetDimension( int dimension )
1095
Q_UNUSED( dimension );
1096
qDebug() << "Setting the dataset dimension using AbstractDiagram::setDatasetDimension is obsolete. Use the specific diagram types instead.";
1099
void AbstractDiagram::setDatasetDimensionInternal( int dimension )
1101
Q_ASSERT( dimension != 0 );
1103
if ( d->datasetDimension == dimension ) return;
1104
d->datasetDimension = dimension;
1105
setDataBoundariesDirty();
1106
emit layoutChanged( this );
1109
double AbstractDiagram::valueForCell( int row, int column ) const
1111
return d->attributesModel->data(
1112
d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toDouble();
1115
void AbstractDiagram::update() const
1117
//qDebug("KDChart::AbstractDiagram::update() called");
1122
QModelIndex AbstractDiagram::indexAt( const QPoint& point ) const
1124
return d->indexAt( point );
1127
QModelIndexList AbstractDiagram::indexesAt( const QPoint& point ) const
1129
return d->indexesAt( point );