00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "KDChartAbstractDiagram.h"
00024 #include "KDChartAbstractDiagram_p.h"
00025
00026 #include <QPainter>
00027 #include <QDebug>
00028 #include <QApplication>
00029 #include <QAbstractProxyModel>
00030 #include <QAbstractTextDocumentLayout>
00031 #include <QStandardItemModel>
00032 #include <QSizeF>
00033 #include <QTextDocument>
00034
00035 #include "KDChartAbstractCoordinatePlane.h"
00036 #include "KDChartChart.h"
00037 #include "KDChartDataValueAttributes.h"
00038 #include "KDChartTextAttributes.h"
00039 #include "KDChartMarkerAttributes.h"
00040 #include "KDChartAbstractThreeDAttributes.h"
00041 #include "KDChartThreeDLineAttributes.h"
00042
00043 #include <KDABLibFakes>
00044
00045 #define PI 3.141592653589793
00046
00047 using namespace KDChart;
00048
00049 AbstractDiagram::Private::Private()
00050 : plane( 0 )
00051 , attributesModel( new PrivateAttributesModel(0,0) )
00052 , allowOverlappingDataValueTexts( false )
00053 , antiAliasing( true )
00054 , percent( false )
00055 , datasetDimension( 1 )
00056 , databoundariesDirty(true)
00057 , lastRoundedValue()
00058 , lastX( 0 )
00059 , mCachedFontMetrics( QFontMetrics( qApp->font() ) )
00060 {
00061 }
00062
00063 AbstractDiagram::Private::~Private()
00064 {
00065 if( attributesModel && qobject_cast<PrivateAttributesModel*>(attributesModel) )
00066 delete attributesModel;
00067 }
00068
00069 void AbstractDiagram::Private::init()
00070 {
00071 }
00072
00073 void AbstractDiagram::Private::init( AbstractCoordinatePlane* newPlane )
00074 {
00075 plane = newPlane;
00076 }
00077
00078 bool AbstractDiagram::Private::usesExternalAttributesModel()const
00079 {
00080 return ( ! attributesModel.isNull() ) &&
00081 ( ! qobject_cast<PrivateAttributesModel*>(attributesModel) );
00082 }
00083
00084 void AbstractDiagram::Private::setAttributesModel( AttributesModel* amodel )
00085 {
00086 if( !attributesModel.isNull() &&
00087 qobject_cast<PrivateAttributesModel*>(attributesModel) ) {
00088 delete attributesModel;
00089 }
00090 attributesModel = amodel;
00091 }
00092
00093 AbstractDiagram::Private::Private( const AbstractDiagram::Private& rhs ) :
00094
00095 plane( 0 ),
00096 attributesModelRootIndex( QModelIndex() ),
00097 attributesModel( rhs.attributesModel ),
00098 allowOverlappingDataValueTexts( rhs.allowOverlappingDataValueTexts ),
00099 antiAliasing( rhs.antiAliasing ),
00100 percent( rhs.percent ),
00101 datasetDimension( rhs.datasetDimension ),
00102 mCachedFontMetrics( rhs.cachedFontMetrics() )
00103 {
00104 attributesModel = new PrivateAttributesModel( 0, 0);
00105 attributesModel->initFrom( rhs.attributesModel );
00106 }
00107
00108 #define d d_func()
00109
00110 AbstractDiagram::AbstractDiagram ( QWidget* parent, AbstractCoordinatePlane* plane )
00111 : QAbstractItemView ( parent ), _d( new Private() )
00112 {
00113 _d->init( plane );
00114 init();
00115 }
00116
00117 AbstractDiagram::~AbstractDiagram()
00118 {
00119 emit aboutToBeDestroyed();
00120 delete _d;
00121 }
00122
00123 void AbstractDiagram::init()
00124 {
00125 d->reverseMapper.setDiagram( this );
00126 }
00127
00128
00129 bool AbstractDiagram::compare( const AbstractDiagram* other )const
00130 {
00131 if( other == this ) return true;
00132 if( ! other ){
00133
00134 return false;
00135 }
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 return
00183 (horizontalScrollBarPolicy() == other->horizontalScrollBarPolicy()) &&
00184 (verticalScrollBarPolicy() == other->verticalScrollBarPolicy()) &&
00185
00186 (frameShadow() == other->frameShadow()) &&
00187 (frameShape() == other->frameShape()) &&
00188
00189
00190 (lineWidth() == other->lineWidth()) &&
00191 (midLineWidth() == other->midLineWidth()) &&
00192
00193 (alternatingRowColors() == other->alternatingRowColors()) &&
00194 (hasAutoScroll() == other->hasAutoScroll()) &&
00195 #if QT_VERSION > 0x040199
00196 (dragDropMode() == other->dragDropMode()) &&
00197 (dragDropOverwriteMode() == other->dragDropOverwriteMode()) &&
00198 (horizontalScrollMode() == other->horizontalScrollMode ()) &&
00199 (verticalScrollMode() == other->verticalScrollMode()) &&
00200 #endif
00201 (dragEnabled() == other->dragEnabled()) &&
00202 (editTriggers() == other->editTriggers()) &&
00203 (iconSize() == other->iconSize()) &&
00204 (selectionBehavior() == other->selectionBehavior()) &&
00205 (selectionMode() == other->selectionMode()) &&
00206 (showDropIndicator() == other->showDropIndicator()) &&
00207 (tabKeyNavigation() == other->tabKeyNavigation()) &&
00208 (textElideMode() == other->textElideMode()) &&
00209
00210 attributesModel()->compare( other->attributesModel() ) &&
00211
00212 (rootIndex().column() == other->rootIndex().column()) &&
00213 (rootIndex().row() == other->rootIndex().row()) &&
00214 (allowOverlappingDataValueTexts() == other->allowOverlappingDataValueTexts()) &&
00215 (antiAliasing() == other->antiAliasing()) &&
00216 (percentMode() == other->percentMode()) &&
00217 (datasetDimension() == other->datasetDimension());
00218 }
00219
00220 AbstractCoordinatePlane* AbstractDiagram::coordinatePlane() const
00221 {
00222 return d->plane;
00223 }
00224
00225 const QPair<QPointF, QPointF> AbstractDiagram::dataBoundaries () const
00226 {
00227 if( d->databoundariesDirty ){
00228 d->databoundaries = calculateDataBoundaries ();
00229 d->databoundariesDirty = false;
00230 }
00231 return d->databoundaries;
00232 }
00233
00234 void AbstractDiagram::setDataBoundariesDirty() const
00235 {
00236 d->databoundariesDirty = true;
00237 }
00238
00239 void AbstractDiagram::setModel( QAbstractItemModel * newModel )
00240 {
00241 if( model() )
00242 {
00243 disconnect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00244 disconnect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00245 disconnect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00246 disconnect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00247 disconnect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
00248 disconnect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
00249 disconnect( model(), SIGNAL( dataChanged(QModelIndex,QModelIndex) ), this, SIGNAL( modelDataChanged() ));
00250 }
00251 QAbstractItemView::setModel( newModel );
00252 AttributesModel* amodel = new PrivateAttributesModel( newModel, this );
00253 amodel->initFrom( d->attributesModel );
00254 d->setAttributesModel(amodel);
00255 scheduleDelayedItemsLayout();
00256 setDataBoundariesDirty();
00257 if( model() )
00258 {
00259 connect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00260 connect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00261 connect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00262 connect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00263 connect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
00264 connect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
00265 connect( model(), SIGNAL( dataChanged(QModelIndex,QModelIndex) ), this, SIGNAL( modelDataChanged() ));
00266 }
00267 emit modelsChanged();
00268 }
00269
00270 void AbstractDiagram::setSelectionModel( QItemSelectionModel* newSelectionModel )
00271 {
00272 if( selectionModel() )
00273 {
00274 disconnect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
00275 disconnect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
00276 }
00277 QAbstractItemView::setSelectionModel( newSelectionModel );
00278 if( selectionModel() )
00279 {
00280 connect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
00281 connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
00282 }
00283 emit modelsChanged();
00284 }
00285
00291 void AbstractDiagram::setAttributesModel( AttributesModel* amodel )
00292 {
00293 if( amodel->sourceModel() != model() ) {
00294 qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
00295 "Trying to set an attributesmodel which works on a different "
00296 "model than the diagram.");
00297 return;
00298 }
00299 if( qobject_cast<PrivateAttributesModel*>(amodel) ) {
00300 qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
00301 "Trying to set an attributesmodel that is private to another diagram.");
00302 return;
00303 }
00304 d->setAttributesModel(amodel);
00305 scheduleDelayedItemsLayout();
00306 setDataBoundariesDirty();
00307 emit modelsChanged();
00308 }
00309
00310 bool AbstractDiagram::usesExternalAttributesModel()const
00311 {
00312 return d->usesExternalAttributesModel();
00313 }
00314
00316 AttributesModel* AbstractDiagram::attributesModel() const
00317 {
00318 return d->attributesModel;
00319 }
00320
00321 QModelIndex AbstractDiagram::conditionallyMapFromSource( const QModelIndex & index ) const
00322 {
00323 Q_ASSERT( !index.isValid() || index.model() == attributesModel() || index.model() == attributesModel()->sourceModel() );
00324 return index.model() == attributesModel()
00325 ? index
00326 : attributesModel()->mapFromSource( index );
00327 }
00328
00330 void AbstractDiagram::setRootIndex ( const QModelIndex& idx )
00331 {
00332 QAbstractItemView::setRootIndex(idx);
00333 setAttributesModelRootIndex( d->attributesModel->mapFromSource(idx) );
00334 }
00335
00337 void AbstractDiagram::setAttributesModelRootIndex( const QModelIndex& idx )
00338 {
00339 d->attributesModelRootIndex=idx;
00340 setDataBoundariesDirty();
00341 scheduleDelayedItemsLayout();
00342 }
00343
00346 QModelIndex AbstractDiagram::attributesModelRootIndex() const
00347 {
00348 if ( !d->attributesModelRootIndex.isValid() )
00349 d->attributesModelRootIndex = d->attributesModel->mapFromSource( rootIndex() );
00350 return d->attributesModelRootIndex;
00351 }
00352
00353 void AbstractDiagram::setCoordinatePlane( AbstractCoordinatePlane* parent )
00354 {
00355 d->plane = parent;
00356 }
00357
00358 void AbstractDiagram::doItemsLayout()
00359 {
00360 if ( d->plane ) {
00361 d->plane->layoutDiagrams();
00362 update();
00363 }
00364 QAbstractItemView::doItemsLayout();
00365 }
00366
00367 void AbstractDiagram::dataChanged( const QModelIndex &topLeft,
00368 const QModelIndex &bottomRight )
00369 {
00370 Q_UNUSED( topLeft );
00371 Q_UNUSED( bottomRight );
00372
00373 setDataBoundariesDirty();
00374 scheduleDelayedItemsLayout();
00375 }
00376
00377
00378 void AbstractDiagram::setHidden( const QModelIndex & index, bool hidden )
00379 {
00380 d->attributesModel->setData(
00381 conditionallyMapFromSource( index ),
00382 qVariantFromValue( hidden ),
00383 DataHiddenRole );
00384 emit dataHidden();
00385 }
00386
00387 void AbstractDiagram::setHidden( int dataset, bool hidden )
00388 {
00389
00390
00391
00392 d->setDatasetAttrs( dataset, qVariantFromValue( hidden ), DataHiddenRole );
00393 emit dataHidden();
00394 }
00395
00396 void AbstractDiagram::setHidden( bool hidden )
00397 {
00398 d->attributesModel->setModelData(
00399 qVariantFromValue( hidden ),
00400 DataHiddenRole );
00401 emit dataHidden();
00402 }
00403
00404 bool AbstractDiagram::isHidden() const
00405 {
00406 return qVariantValue<bool>(
00407 attributesModel()->modelData( DataHiddenRole ) );
00408 }
00409
00410 bool AbstractDiagram::isHidden( int dataset ) const
00411 {
00412 const QVariant boolFlag( d->datasetAttrs( dataset, DataHiddenRole ) );
00413 if( boolFlag.isValid() )
00414 return qVariantValue< bool >( boolFlag );
00415 return isHidden();
00416 }
00417
00418 bool AbstractDiagram::isHidden( const QModelIndex & index ) const
00419 {
00420 return qVariantValue<bool>(
00421 attributesModel()->data(
00422 conditionallyMapFromSource(index),
00423 DataHiddenRole ) );
00424 }
00425
00426
00427 void AbstractDiagram::setDataValueAttributes( const QModelIndex & index,
00428 const DataValueAttributes & a )
00429 {
00430 d->attributesModel->setData(
00431 conditionallyMapFromSource( index ),
00432 qVariantFromValue( a ),
00433 DataValueLabelAttributesRole );
00434 emit propertiesChanged();
00435 }
00436
00437
00438 void AbstractDiagram::setDataValueAttributes( int dataset, const DataValueAttributes & a )
00439 {
00440 d->setDatasetAttrs( dataset, qVariantFromValue( a ), DataValueLabelAttributesRole );
00441 emit propertiesChanged();
00442 }
00443
00444 DataValueAttributes AbstractDiagram::dataValueAttributes() const
00445 {
00446 return qVariantValue<DataValueAttributes>(
00447 attributesModel()->modelData( KDChart::DataValueLabelAttributesRole ) );
00448 }
00449
00450 DataValueAttributes AbstractDiagram::dataValueAttributes( int dataset ) const
00451 {
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 const QVariant headerAttrs(
00464 d->datasetAttrs( dataset, KDChart::DataValueLabelAttributesRole ) );
00465 if( headerAttrs.isValid() )
00466 return qVariantValue< DataValueAttributes >( headerAttrs );
00467 return dataValueAttributes();
00468 }
00469
00470 DataValueAttributes AbstractDiagram::dataValueAttributes( const QModelIndex & index ) const
00471 {
00472 return qVariantValue<DataValueAttributes>(
00473 attributesModel()->data(
00474 conditionallyMapFromSource( index ),
00475 KDChart::DataValueLabelAttributesRole ) );
00476 }
00477
00478 void AbstractDiagram::setDataValueAttributes( const DataValueAttributes & a )
00479 {
00480 d->attributesModel->setModelData( qVariantFromValue( a ), DataValueLabelAttributesRole );
00481 emit propertiesChanged();
00482 }
00483
00484 void AbstractDiagram::setAllowOverlappingDataValueTexts( bool allow )
00485 {
00486 d->allowOverlappingDataValueTexts = allow;
00487 emit propertiesChanged();
00488 }
00489
00490 bool AbstractDiagram::allowOverlappingDataValueTexts() const
00491 {
00492 return d->allowOverlappingDataValueTexts;
00493 }
00494
00495 void AbstractDiagram::setAntiAliasing( bool enabled )
00496 {
00497 d->antiAliasing = enabled;
00498 emit propertiesChanged();
00499 }
00500
00501 bool AbstractDiagram::antiAliasing() const
00502 {
00503 return d->antiAliasing;
00504 }
00505
00506 void AbstractDiagram::setPercentMode ( bool percent )
00507 {
00508 d->percent = percent;
00509 emit propertiesChanged();
00510 }
00511
00512 bool AbstractDiagram::percentMode() const
00513 {
00514 return d->percent;
00515 }
00516
00517
00518 void AbstractDiagram::paintDataValueText( QPainter* painter,
00519 const QModelIndex& index,
00520 const QPointF& pos,
00521 double value )
00522 {
00523 d->paintDataValueText( this, painter, index, pos, value );
00524 }
00525
00526
00527 QString AbstractDiagram::roundValues( double value,
00528 const int decimalPos,
00529 const int decimalDigits ) const
00530 {
00531 return d->roundValues( value, decimalPos, decimalDigits );
00532 }
00533
00534 void AbstractDiagram::paintDataValueTexts( QPainter* painter )
00535 {
00536 if ( !checkInvariants() ) return;
00537 const int rowCount = model()->rowCount(rootIndex());
00538 const int columnCount = model()->columnCount(rootIndex());
00539 d->clearListOfAlreadyDrawnDataValueTexts();
00540 for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
00541 for ( int j=0; j< rowCount; ++j ) {
00542 const QModelIndex index = model()->index( j, i, rootIndex() );
00543 double value = model()->data( index ).toDouble();
00544 const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
00545 paintDataValueText( painter, index, pos, value );
00546 }
00547 }
00548 }
00549
00550
00551 void AbstractDiagram::paintMarker( QPainter* painter,
00552 const DataValueAttributes& a,
00553 const QModelIndex& index,
00554 const QPointF& pos )
00555 {
00556 if ( !checkInvariants() || !a.isVisible() ) return;
00557 const MarkerAttributes ma = a.markerAttributes();
00558 if ( !ma.isVisible() ) return;
00559
00560 const PainterSaver painterSaver( painter );
00561
00562 const QSizeF maSize( ma.markerSize().width() / painter->matrix().m11(),
00563 ma.markerSize().height() / painter->matrix().m22() );
00564 QBrush indexBrush( brush( index ) );
00565 QPen indexPen( ma.pen() );
00566 if ( ma.markerColor().isValid() )
00567 indexBrush.setColor( ma.markerColor() );
00568
00569 paintMarker( painter, ma, indexBrush, indexPen, pos, maSize );
00570
00571
00572
00573
00574
00575
00576 d->reverseMapper.addCircle( index.row(), index.column(), pos, 2 * maSize );
00577 }
00578
00579 void AbstractDiagram::paintMarker( QPainter* painter,
00580 const QModelIndex& index,
00581 const QPointF& pos )
00582 {
00583 if ( !checkInvariants() ) return;
00584 paintMarker( painter, dataValueAttributes( index ), index, pos );
00585 }
00586
00587 void AbstractDiagram::paintMarker( QPainter* painter,
00588 const MarkerAttributes& markerAttributes,
00589 const QBrush& brush,
00590 const QPen& pen,
00591 const QPointF& pos,
00592 const QSizeF& maSize )
00593 {
00594 const QPen oldPen( painter->pen() );
00595
00596
00597 const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels);
00598 if( isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel) ){
00599
00600 painter->setPen( PrintingParameters::scalePen( QPen( brush.color().light() ) ) );
00601 if( isFourPixels ){
00602 const qreal x = pos.x();
00603 const qreal y = pos.y();
00604 painter->drawLine( QPointF(x-1.0,y-1.0),
00605 QPointF(x+1.0,y-1.0) );
00606 painter->drawLine( QPointF(x-1.0,y),
00607 QPointF(x+1.0,y) );
00608 painter->drawLine( QPointF(x-1.0,y+1.0),
00609 QPointF(x+1.0,y+1.0) );
00610 }
00611 painter->drawPoint( pos );
00612 }else{
00613 const PainterSaver painterSaver( painter );
00614
00615 QPen painterPen( pen );
00616 painterPen.setStyle( Qt::SolidLine );
00617 painter->setPen( PrintingParameters::scalePen( painterPen ) );
00618 painter->setBrush( brush );
00619 painter->setRenderHint ( QPainter::Antialiasing );
00620 painter->translate( pos );
00621 switch ( markerAttributes.markerStyle() ) {
00622 case MarkerAttributes::MarkerCircle:
00623 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00624 maSize.height(), maSize.width()) );
00625 break;
00626 case MarkerAttributes::MarkerSquare:
00627 {
00628 QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2,
00629 maSize.width(), maSize.height() );
00630 painter->drawRect( rect );
00631 break;
00632 }
00633 case MarkerAttributes::MarkerDiamond:
00634 {
00635 QVector <QPointF > diamondPoints;
00636 QPointF top, left, bottom, right;
00637 top = QPointF( 0, 0 - maSize.height()/2 );
00638 left = QPointF( 0 - maSize.width()/2, 0 );
00639 bottom = QPointF( 0, maSize.height()/2 );
00640 right = QPointF( maSize.width()/2, 0 );
00641 diamondPoints << top << left << bottom << right;
00642 painter->drawPolygon( diamondPoints );
00643 break;
00644 }
00645
00646 case MarkerAttributes::Marker1Pixel:
00647 case MarkerAttributes::Marker4Pixels:
00648 break;
00649 case MarkerAttributes::MarkerRing:
00650 {
00651 painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
00652 painter->setBrush( Qt::NoBrush );
00653 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00654 maSize.height(), maSize.width()) );
00655 break;
00656 }
00657 case MarkerAttributes::MarkerCross:
00658 {
00659
00660
00661 const qreal w02 = maSize.width() * 0.2;
00662 const qreal w05 = maSize.width() * 0.5;
00663 const qreal h02 = maSize.height()* 0.2;
00664 const qreal h05 = maSize.height()* 0.5;
00665 QVector <QPointF > crossPoints;
00666 QPointF p[12];
00667 p[ 0] = QPointF( -w02, -h05 );
00668 p[ 1] = QPointF( w02, -h05 );
00669 p[ 2] = QPointF( w02, -h02 );
00670 p[ 3] = QPointF( w05, -h02 );
00671 p[ 4] = QPointF( w05, h02 );
00672 p[ 5] = QPointF( w02, h02 );
00673 p[ 6] = QPointF( w02, h05 );
00674 p[ 7] = QPointF( -w02, h05 );
00675 p[ 8] = QPointF( -w02, h02 );
00676 p[ 9] = QPointF( -w05, h02 );
00677 p[10] = QPointF( -w05, -h02 );
00678 p[11] = QPointF( -w02, -h02 );
00679 for( int i=0; i<12; ++i )
00680 crossPoints << p[i];
00681 crossPoints << p[0];
00682 painter->drawPolygon( crossPoints );
00683 break;
00684 }
00685 case MarkerAttributes::MarkerFastCross:
00686 {
00687 QPointF left, right, top, bottom;
00688 left = QPointF( -maSize.width()/2, 0 );
00689 right = QPointF( maSize.width()/2, 0 );
00690 top = QPointF( 0, -maSize.height()/2 );
00691 bottom= QPointF( 0, maSize.height()/2 );
00692 painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
00693 painter->drawLine( left, right );
00694 painter->drawLine( top, bottom );
00695 break;
00696 }
00697 case MarkerAttributes::NoMarker:
00698 break;
00699 default:
00700 Q_ASSERT_X ( false, "paintMarkers()",
00701 "Type item does not match a defined Marker Type." );
00702 }
00703 }
00704 painter->setPen( oldPen );
00705 }
00706
00707 void AbstractDiagram::paintMarkers( QPainter* painter )
00708 {
00709 if ( !checkInvariants() ) return;
00710 const int rowCount = model()->rowCount(rootIndex());
00711 const int columnCount = model()->columnCount(rootIndex());
00712 for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
00713 for ( int j=0; j< rowCount; ++j ) {
00714 const QModelIndex index = model()->index( j, i, rootIndex() );
00715 double value = model()->data( index ).toDouble();
00716 const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
00717 paintMarker( painter, index, pos );
00718 }
00719 }
00720 }
00721
00722
00723 void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen )
00724 {
00725 attributesModel()->setData(
00726 conditionallyMapFromSource( index ),
00727 qVariantFromValue( pen ), DatasetPenRole );
00728 emit propertiesChanged();
00729 }
00730
00731 void AbstractDiagram::setPen( const QPen& pen )
00732 {
00733 attributesModel()->setModelData(
00734 qVariantFromValue( pen ), DatasetPenRole );
00735 emit propertiesChanged();
00736 }
00737
00738 void AbstractDiagram::setPen( int dataset, const QPen& pen )
00739 {
00740 d->setDatasetAttrs( dataset, qVariantFromValue( pen ), DatasetPenRole );
00741 emit propertiesChanged();
00742 }
00743
00744 QPen AbstractDiagram::pen() const
00745 {
00746 return qVariantValue<QPen>(
00747 attributesModel()->data( DatasetPenRole ) );
00748 }
00749
00750 QPen AbstractDiagram::pen( int dataset ) const
00751 {
00752 const QVariant penSettings( d->datasetAttrs( dataset, DatasetPenRole ) );
00753 if( penSettings.isValid() )
00754 return qVariantValue< QPen >( penSettings );
00755 return pen();
00756 }
00757
00758 QPen AbstractDiagram::pen( const QModelIndex& index ) const
00759 {
00760 return qVariantValue<QPen>(
00761 attributesModel()->data(
00762 conditionallyMapFromSource( index ),
00763 DatasetPenRole ) );
00764 }
00765
00766 void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush )
00767 {
00768 attributesModel()->setData(
00769 conditionallyMapFromSource( index ),
00770 qVariantFromValue( brush ), DatasetBrushRole );
00771 emit propertiesChanged();
00772 }
00773
00774 void AbstractDiagram::setBrush( const QBrush& brush )
00775 {
00776 attributesModel()->setModelData(
00777 qVariantFromValue( brush ), DatasetBrushRole );
00778 emit propertiesChanged();
00779 }
00780
00781 void AbstractDiagram::setBrush( int dataset, const QBrush& brush )
00782 {
00783 d->setDatasetAttrs( dataset, qVariantFromValue( brush ), DatasetBrushRole );
00784 emit propertiesChanged();
00785 }
00786
00787 QBrush AbstractDiagram::brush() const
00788 {
00789 return qVariantValue<QBrush>(
00790 attributesModel()->data( DatasetBrushRole ) );
00791 }
00792
00793 QBrush AbstractDiagram::brush( int dataset ) const
00794 {
00795 const QVariant brushSettings( d->datasetAttrs( dataset, DatasetBrushRole ) );
00796 if( brushSettings.isValid() )
00797 return qVariantValue< QBrush >( brushSettings );
00798 return brush();
00799 }
00800
00801 QBrush AbstractDiagram::brush( const QModelIndex& index ) const
00802 {
00803 return qVariantValue<QBrush>(
00804 attributesModel()->data( conditionallyMapFromSource( index ), DatasetBrushRole ) );
00805 }
00806
00813 void AbstractDiagram::setUnitPrefix( const QString& prefix, int column, Qt::Orientation orientation )
00814 {
00815 d->unitPrefixMap[ column ][ orientation ]= prefix;
00816 }
00817
00823 void AbstractDiagram::setUnitPrefix( const QString& prefix, Qt::Orientation orientation )
00824 {
00825 d->unitPrefix[ orientation ] = prefix;
00826 }
00827
00834 void AbstractDiagram::setUnitSuffix( const QString& suffix, int column, Qt::Orientation orientation )
00835 {
00836 d->unitSuffixMap[ column ][ orientation ]= suffix;
00837 }
00838
00844 void AbstractDiagram::setUnitSuffix( const QString& suffix, Qt::Orientation orientation )
00845 {
00846 d->unitSuffix[ orientation ] = suffix;
00847 }
00848
00856 QString AbstractDiagram::unitPrefix( int column, Qt::Orientation orientation, bool fallback ) const
00857 {
00858 if( !fallback || d->unitPrefixMap[ column ].contains( orientation ) )
00859 return d->unitPrefixMap[ column ][ orientation ];
00860 return d->unitPrefix[ orientation ];
00861 }
00862
00867 QString AbstractDiagram::unitPrefix( Qt::Orientation orientation ) const
00868 {
00869 return d->unitPrefix[ orientation ];
00870 }
00871
00879 QString AbstractDiagram::unitSuffix( int column, Qt::Orientation orientation, bool fallback ) const
00880 {
00881 if( !fallback || d->unitSuffixMap[ column ].contains( orientation ) )
00882 return d->unitSuffixMap[ column ][ orientation ];
00883 return d->unitSuffix[ orientation ];
00884 }
00885
00890 QString AbstractDiagram::unitSuffix( Qt::Orientation orientation ) const
00891 {
00892 return d->unitSuffix[ orientation ];
00893 }
00894
00895
00896 QRect AbstractDiagram::visualRect( const QModelIndex &index ) const
00897 {
00898 return d->reverseMapper.boundingRect( index.row(), index.column() ).toRect();
00899 }
00900
00901 void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint )
00902 {}
00903
00904
00905
00906 QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers )
00907 { return QModelIndex(); }
00908
00909 int AbstractDiagram::horizontalOffset() const
00910 { return 0; }
00911
00912 int AbstractDiagram::verticalOffset() const
00913 { return 0; }
00914
00915 bool AbstractDiagram::isIndexHidden(const QModelIndex &) const
00916 { return true; }
00917
00918 void AbstractDiagram::setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags command )
00919 {
00920 const QModelIndexList indexes = d->indexesIn( rect );
00921 QItemSelection selection;
00922 KDAB_FOREACH( const QModelIndex& index, indexes )
00923 {
00924 selection.append( QItemSelectionRange( index ) );
00925 }
00926 selectionModel()->select( selection, command );
00927 }
00928
00929 QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &selection) const
00930 {
00931 QPolygonF polygon;
00932 KDAB_FOREACH( const QModelIndex& index, selection.indexes() )
00933 {
00934 polygon << d->reverseMapper.polygon(index.row(), index.column());
00935 }
00936 return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
00937 }
00938
00939 QRegion AbstractDiagram::visualRegion(const QModelIndex &index) const
00940 {
00941 QPolygonF polygon = d->reverseMapper.polygon(index.row(), index.column());
00942 return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
00943 }
00944
00945 void KDChart::AbstractDiagram::useDefaultColors( )
00946 {
00947 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault );
00948 }
00949
00950 void KDChart::AbstractDiagram::useSubduedColors( )
00951 {
00952 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued );
00953 }
00954
00955 void KDChart::AbstractDiagram::useRainbowColors( )
00956 {
00957 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow );
00958 }
00959
00960 QStringList AbstractDiagram::itemRowLabels() const
00961 {
00962 QStringList ret;
00963 if( model() ){
00964
00965 const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
00966 for( int i = 0; i < rowCount; ++i ){
00967
00968 ret << unitPrefix( i, Qt::Horizontal, true ) +
00969 attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString() +
00970 unitSuffix( i, Qt::Horizontal, true );
00971 }
00972 }
00973 return ret;
00974 }
00975
00976 QStringList AbstractDiagram::datasetLabels() const
00977 {
00978 QStringList ret;
00979 if( model() == 0 )
00980 return ret;
00981
00982 const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
00983 for( int i = 0; i < columnCount; i += datasetDimension() )
00984 ret << attributesModel()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString();
00985
00986 return ret;
00987 }
00988
00989 QList<QBrush> AbstractDiagram::datasetBrushes() const
00990 {
00991 QList<QBrush> ret;
00992 if( model() == 0 )
00993 return ret;
00994
00995 const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
00996 for ( int dataset = 0; dataset < datasetCount; dataset++ )
00997 ret << brush( dataset );
00998
00999 return ret;
01000 }
01001
01002 QList<QPen> AbstractDiagram::datasetPens() const
01003 {
01004 QList<QPen> ret;
01005 if( model() == 0 )
01006 return ret;
01007
01008 const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
01009 for ( int dataset = 0; dataset < datasetCount; dataset++ )
01010 ret << pen( dataset );
01011
01012 return ret;
01013 }
01014
01015 QList<MarkerAttributes> AbstractDiagram::datasetMarkers() const
01016 {
01017 QList<MarkerAttributes> ret;
01018 if( model() == 0 )
01019 return ret;
01020
01021 const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
01022 for ( int dataset = 0; dataset < datasetCount; dataset++ )
01023 ret << dataValueAttributes( dataset ).markerAttributes();
01024
01025 return ret;
01026 }
01027
01028 bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const
01029 {
01030 if( ! justReturnTheStatus ){
01031 Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()",
01032 "There is no usable model set, for the diagram." );
01033
01034 Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()",
01035 "There is no usable coordinate plane set, for the diagram." );
01036 }
01037 return model() && coordinatePlane();
01038 }
01039
01040 int AbstractDiagram::datasetDimension( ) const
01041 {
01042 return d->datasetDimension;
01043 }
01044
01045 void AbstractDiagram::setDatasetDimension( int dimension )
01046 {
01047 Q_UNUSED( dimension );
01048 qDebug() << "Setting the dataset dimension using AbstractDiagram::setDatasetDimension is obsolete. Use the specific diagram types instead.";
01049 }
01050
01051 void AbstractDiagram::setDatasetDimensionInternal( int dimension )
01052 {
01053 Q_ASSERT( dimension != 0 );
01054
01055 if ( d->datasetDimension == dimension ) return;
01056 d->datasetDimension = dimension;
01057 setDataBoundariesDirty();
01058 emit layoutChanged( this );
01059 }
01060
01061 double AbstractDiagram::valueForCell( int row, int column ) const
01062 {
01063 return d->attributesModel->data(
01064 d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toDouble();
01065 }
01066
01067 void AbstractDiagram::update() const
01068 {
01069
01070 if( d->plane )
01071 d->plane->update();
01072 }
01073
01074 QModelIndex AbstractDiagram::indexAt( const QPoint& point ) const
01075 {
01076 return d->indexAt( point );
01077 }
01078
01079 QModelIndexList AbstractDiagram::indexesAt( const QPoint& point ) const
01080 {
01081 return d->indexesAt( point );
01082 }
01083