00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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 "KDChartAbstractDiagram.h"
00041 #include "KDChartAbstractDiagram_p.h"
00042 #include "KDChartAbstractThreeDAttributes.h"
00043 #include "KDChartThreeDLineAttributes.h"
00044
00045 #include <KDABLibFakes>
00046
00047
00048 using namespace KDChart;
00049
00050 AbstractDiagram::Private::Private()
00051 : plane( 0 )
00052 , attributesModel( new PrivateAttributesModel(0,0) )
00053 , allowOverlappingDataValueTexts( false )
00054 , antiAliasing( true )
00055 , percent( false )
00056 , datasetDimension( 1 )
00057 , databoundariesDirty(true)
00058 , lastRoundedValue()
00059 , lastX( 0 )
00060 , mCachedFontMetrics( QFontMetrics( qApp->font() ) )
00061 {
00062 }
00063
00064 AbstractDiagram::Private::~Private()
00065 {
00066 if( attributesModel && qobject_cast<PrivateAttributesModel*>(attributesModel) )
00067 delete attributesModel;
00068 }
00069
00070 void AbstractDiagram::Private::init()
00071 {
00072 }
00073
00074 void AbstractDiagram::Private::init( AbstractCoordinatePlane* newPlane )
00075 {
00076 plane = newPlane;
00077 }
00078
00079 bool AbstractDiagram::Private::usesExternalAttributesModel()const
00080 {
00081 return ( ! attributesModel.isNull() ) &&
00082 ( ! qobject_cast<PrivateAttributesModel*>(attributesModel) );
00083 }
00084
00085 void AbstractDiagram::Private::setAttributesModel( AttributesModel* amodel )
00086 {
00087 if( !attributesModel.isNull() &&
00088 qobject_cast<PrivateAttributesModel*>(attributesModel) ) {
00089 delete attributesModel;
00090 }
00091 attributesModel = amodel;
00092 }
00093
00094 AbstractDiagram::Private::Private( const AbstractDiagram::Private& rhs ) :
00095
00096 plane( 0 ),
00097 attributesModelRootIndex( QModelIndex() ),
00098 attributesModel( rhs.attributesModel ),
00099 allowOverlappingDataValueTexts( rhs.allowOverlappingDataValueTexts ),
00100 antiAliasing( rhs.antiAliasing ),
00101 percent( rhs.percent ),
00102 datasetDimension( rhs.datasetDimension ),
00103 mCachedFontMetrics( rhs.cachedFontMetrics() )
00104 {
00105 attributesModel = new PrivateAttributesModel( 0, 0);
00106 attributesModel->initFrom( rhs.attributesModel );
00107 }
00108
00109 #define d d_func()
00110
00111 AbstractDiagram::AbstractDiagram ( QWidget* parent, AbstractCoordinatePlane* plane )
00112 : QAbstractItemView ( parent ), _d( new Private() )
00113 {
00114 _d->init( plane );
00115 init();
00116 }
00117
00118 AbstractDiagram::~AbstractDiagram()
00119 {
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 QAbstractItemView::setModel( newModel );
00242 AttributesModel* amodel = new PrivateAttributesModel( newModel, this );
00243 amodel->initFrom( d->attributesModel );
00244 d->setAttributesModel(amodel);
00245 scheduleDelayedItemsLayout();
00246 setDataBoundariesDirty();
00247 emit modelsChanged();
00248 }
00249
00255 void AbstractDiagram::setAttributesModel( AttributesModel* amodel )
00256 {
00257 if( amodel->sourceModel() != model() ) {
00258 qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
00259 "Trying to set an attributesmodel which works on a different "
00260 "model than the diagram.");
00261 return;
00262 }
00263 if( qobject_cast<PrivateAttributesModel*>(amodel) ) {
00264 qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
00265 "Trying to set an attributesmodel that is private to another diagram.");
00266 return;
00267 }
00268 d->setAttributesModel(amodel);
00269 scheduleDelayedItemsLayout();
00270 setDataBoundariesDirty();
00271 emit modelsChanged();
00272 }
00273
00274 bool AbstractDiagram::usesExternalAttributesModel()const
00275 {
00276 return d->usesExternalAttributesModel();
00277 }
00278
00280 AttributesModel* AbstractDiagram::attributesModel() const
00281 {
00282 return d->attributesModel;
00283 }
00284
00286 void AbstractDiagram::setRootIndex ( const QModelIndex& idx )
00287 {
00288 QAbstractItemView::setRootIndex(idx);
00289 setAttributesModelRootIndex( d->attributesModel->mapFromSource(idx) );
00290 }
00291
00293 void AbstractDiagram::setAttributesModelRootIndex( const QModelIndex& idx )
00294 {
00295 d->attributesModelRootIndex=idx;
00296 setDataBoundariesDirty();
00297 scheduleDelayedItemsLayout();
00298 }
00299
00302 QModelIndex AbstractDiagram::attributesModelRootIndex() const
00303 {
00304 if ( !d->attributesModelRootIndex.isValid() )
00305 d->attributesModelRootIndex = d->attributesModel->mapFromSource( rootIndex() );
00306 return d->attributesModelRootIndex;
00307 }
00308
00309 QModelIndex AbstractDiagram::columnToIndex( int column ) const
00310 {
00311 if( model() )
00312 return QModelIndex( model()->index( 0, column, rootIndex() ) );
00313 return QModelIndex();
00314 }
00315
00316 void AbstractDiagram::setCoordinatePlane( AbstractCoordinatePlane* parent )
00317 {
00318 d->plane = parent;
00319 }
00320
00321 void AbstractDiagram::doItemsLayout()
00322 {
00323 if ( d->plane ) {
00324 d->plane->layoutDiagrams();
00325 update();
00326 }
00327 QAbstractItemView::doItemsLayout();
00328 }
00329
00330 void AbstractDiagram::dataChanged( const QModelIndex &topLeft,
00331 const QModelIndex &bottomRight )
00332 {
00333 Q_UNUSED( topLeft );
00334 Q_UNUSED( bottomRight );
00335
00336 setDataBoundariesDirty();
00337 scheduleDelayedItemsLayout();
00338 }
00339
00340
00341 void AbstractDiagram::setHidden( const QModelIndex & index, bool hidden )
00342 {
00343 d->attributesModel->setData(
00344 d->attributesModel->mapFromSource( index ),
00345 qVariantFromValue( hidden ),
00346 DataHiddenRole );
00347 emit dataHidden();
00348 }
00349
00350 void AbstractDiagram::setHidden( int column, bool hidden )
00351 {
00352 d->attributesModel->setHeaderData(
00353 column, Qt::Vertical,
00354 qVariantFromValue( hidden ),
00355 DataHiddenRole );
00356 emit dataHidden();
00357 }
00358
00359 void AbstractDiagram::setHidden( bool hidden )
00360 {
00361 d->attributesModel->setModelData(
00362 qVariantFromValue( hidden ),
00363 DataHiddenRole );
00364 emit dataHidden();
00365 }
00366
00367 bool AbstractDiagram::isHidden() const
00368 {
00369 return qVariantValue<bool>(
00370 attributesModel()->modelData( DataHiddenRole ) );
00371 }
00372
00373 bool AbstractDiagram::isHidden( int column ) const
00374 {
00375 return qVariantValue<bool>(
00376 attributesModel()->data(
00377 attributesModel()->mapFromSource(columnToIndex( column )),
00378 DataHiddenRole ) );
00379 }
00380 bool AbstractDiagram::isHidden( const QModelIndex & index ) const
00381 {
00382 return qVariantValue<bool>(
00383 attributesModel()->data(
00384 attributesModel()->mapFromSource(index),
00385 DataHiddenRole ) );
00386 }
00387
00388
00389 void AbstractDiagram::setDataValueAttributes( const QModelIndex & index,
00390 const DataValueAttributes & a )
00391 {
00392 d->attributesModel->setData(
00393 d->attributesModel->mapFromSource( index ),
00394 qVariantFromValue( a ),
00395 DataValueLabelAttributesRole );
00396 emit propertiesChanged();
00397 }
00398
00399
00400 void AbstractDiagram::setDataValueAttributes( int column, const DataValueAttributes & a )
00401 {
00402 d->attributesModel->setHeaderData(
00403 column, Qt::Vertical,
00404 qVariantFromValue( a ), DataValueLabelAttributesRole );
00405 emit propertiesChanged();
00406 }
00407
00408 DataValueAttributes AbstractDiagram::dataValueAttributes() const
00409 {
00410 return qVariantValue<DataValueAttributes>(
00411 attributesModel()->modelData( KDChart::DataValueLabelAttributesRole ) );
00412 }
00413
00414 DataValueAttributes AbstractDiagram::dataValueAttributes( int column ) const
00415 {
00416 return qVariantValue<DataValueAttributes>(
00417 attributesModel()->data( attributesModel()->mapFromSource(columnToIndex( column )),
00418 KDChart::DataValueLabelAttributesRole ) );
00419 }
00420
00421 DataValueAttributes AbstractDiagram::dataValueAttributes( const QModelIndex & index ) const
00422 {
00423 return qVariantValue<DataValueAttributes>(
00424 attributesModel()->data( attributesModel()->mapFromSource(index),
00425 KDChart::DataValueLabelAttributesRole ) );
00426 }
00427
00428 void AbstractDiagram::setDataValueAttributes( const DataValueAttributes & a )
00429 {
00430 d->attributesModel->setModelData( qVariantFromValue( a ), DataValueLabelAttributesRole );
00431 emit propertiesChanged();
00432 }
00433
00434 void AbstractDiagram::setAllowOverlappingDataValueTexts( bool allow )
00435 {
00436 d->allowOverlappingDataValueTexts = allow;
00437 emit propertiesChanged();
00438 }
00439
00440 bool AbstractDiagram::allowOverlappingDataValueTexts() const
00441 {
00442 return d->allowOverlappingDataValueTexts;
00443 }
00444
00445 void AbstractDiagram::setAntiAliasing( bool enabled )
00446 {
00447 d->antiAliasing = enabled;
00448 emit propertiesChanged();
00449 }
00450
00451 bool AbstractDiagram::antiAliasing() const
00452 {
00453 return d->antiAliasing;
00454 }
00455
00456 void AbstractDiagram::setPercentMode ( bool percent )
00457 {
00458 d->percent = percent;
00459 emit propertiesChanged();
00460 }
00461
00462 bool AbstractDiagram::percentMode() const
00463 {
00464 return d->percent;
00465 }
00466
00467
00468 void AbstractDiagram::paintDataValueText( QPainter* painter,
00469 const QModelIndex& index,
00470 const QPointF& pos,
00471 double value )
00472 {
00473
00474 const DataValueAttributes a( dataValueAttributes(index) );
00475 if ( !a.isVisible() ) return;
00476
00477
00478 int decimalDigits = a.decimalDigits();
00479 int decimalPos = QString::number( value ).indexOf( QLatin1Char( '.' ) );
00480 QString roundedValue;
00481 if ( a.dataLabel().isNull() ) {
00482 if ( decimalPos > 0 && value != 0 )
00483 roundedValue = roundValues ( value, decimalPos, decimalDigits );
00484 else
00485 roundedValue = QString::number( value );
00486 } else
00487 roundedValue = a.dataLabel();
00488
00489 if ( !a.prefix().isNull() )
00490 roundedValue.prepend( a.prefix() );
00491
00492 if ( !a.suffix().isNull() )
00493 roundedValue.append( a.suffix() );
00494
00495 const TextAttributes ta( a.textAttributes() );
00496
00497 if ( ta.isVisible() ) {
00498
00499 QPointF pt( pos );
00500
00501
00502
00503
00504
00505
00506
00507 QTextDocument doc;
00508 if( Qt::mightBeRichText( roundedValue ) )
00509 doc.setHtml( roundedValue );
00510 else
00511 doc.setPlainText( roundedValue );
00512
00513 const RelativePosition relPos( a.position( value >= 0.0 ) );
00514 const Qt::Alignment alignBottomLeft = Qt::AlignBottom | Qt::AlignLeft;
00515 const QFont calculatedFont( ta.calculatedFont( d->plane, KDChartEnums::MeasureOrientationMinimum ) );
00516 const QRectF boundRect( d->cachedFontMetrics( calculatedFont, painter->device() )->boundingRect( doc.toPlainText() ) );
00517
00518
00519 pt.ry() -= boundRect.height();
00520
00521
00522
00523 if( (relPos.alignment() & alignBottomLeft) != alignBottomLeft ){
00524 if( relPos.alignment() & Qt::AlignRight )
00525 pt.rx() -= boundRect.width();
00526 else if( relPos.alignment() & Qt::AlignHCenter )
00527 pt.rx() -= 0.5 * boundRect.width();
00528
00529 if( relPos.alignment() & Qt::AlignTop )
00530 pt.ry() += boundRect.height();
00531 else if( relPos.alignment() & Qt::AlignVCenter )
00532 pt.ry() += 0.5 * boundRect.height();
00533 }
00534
00535
00536
00537 if ( a.showRepetitiveDataLabels() ||
00538 pos.x() <= d->lastX ||
00539 d->lastRoundedValue != roundedValue ) {
00540 d->lastRoundedValue = roundedValue;
00541 d->lastX = pos.x();
00542 PainterSaver painterSaver( painter );
00543
00544 doc.setDefaultFont( calculatedFont );
00545 QAbstractTextDocumentLayout::PaintContext context;
00546 context.palette = palette();
00547 context.palette.setColor(QPalette::Text, ta.pen().color() );
00548
00549 painter->translate( pt );
00550 painter->rotate( ta.rotation() );
00551
00552 QAbstractTextDocumentLayout* layout = doc.documentLayout();
00553 layout->draw( painter, context );
00554 }
00555 }
00556 }
00557
00558
00559 QString AbstractDiagram::roundValues( double value,
00560 const int decimalPos,
00561 const int decimalDigits ) const {
00562
00563 QString digits( QString::number( value ).mid( decimalPos+1 ) );
00564 QString num( QString::number( value ) );
00565 num.truncate( decimalPos );
00566 int count = 0;
00567 for ( int i = digits.length(); i >= decimalDigits ; --i ) {
00568 count += 1;
00569 int lastval = QString( digits.data() [i] ).toInt();
00570 int val = QString( digits.data() [i-1] ) .toInt();
00571 if ( lastval >= 5 ) {
00572 val += 1;
00573 digits.replace( digits.length() - count,1 , QString::number( val ) );
00574 }
00575 }
00576
00577 digits.truncate( decimalDigits );
00578 num.append( QLatin1Char( '.' ) + digits );
00579
00580 return num;
00581
00582 }
00583
00584 void AbstractDiagram::paintDataValueTexts( QPainter* painter )
00585 {
00586 if ( !checkInvariants() ) return;
00587 const int rowCount = model()->rowCount(rootIndex());
00588 const int columnCount = model()->columnCount(rootIndex());
00589 for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
00590 for ( int j=0; j< rowCount; ++j ) {
00591 const QModelIndex index = model()->index( j, i, rootIndex() );
00592 double value = model()->data( index ).toDouble();
00593 const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
00594 paintDataValueText( painter, index, pos, value );
00595 }
00596 }
00597 }
00598
00599
00600 void AbstractDiagram::paintMarker( QPainter* painter,
00601 const QModelIndex& index,
00602 const QPointF& pos )
00603 {
00604 if ( !checkInvariants() ) return;
00605 DataValueAttributes a = dataValueAttributes(index);
00606 if ( !a.isVisible() ) return;
00607 const MarkerAttributes &ma = a.markerAttributes();
00608 if ( !ma.isVisible() ) return;
00609
00610 PainterSaver painterSaver( painter );
00611 QSizeF maSize( ma.markerSize() );
00612 QBrush indexBrush( brush( index ) );
00613 QPen indexPen( ma.pen() );
00614 if ( ma.markerColor().isValid() )
00615 indexBrush.setColor( ma.markerColor() );
00616
00617 paintMarker( painter, ma, indexBrush, indexPen, pos, maSize );
00618
00619
00620
00621
00622
00623
00624 d->reverseMapper.addCircle( index.row(), index.column(), pos, 2 * maSize );
00625 }
00626
00627 void AbstractDiagram::paintMarker( QPainter* painter,
00628 const MarkerAttributes& markerAttributes,
00629 const QBrush& brush,
00630 const QPen& pen,
00631 const QPointF& pos,
00632 const QSizeF& maSize )
00633 {
00634 const QPen oldPen( painter->pen() );
00635
00636
00637 const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels);
00638 if( isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel) ){
00639
00640 painter->setPen( QPen( brush.color().light() ) );
00641 if( isFourPixels ){
00642 const qreal x = pos.x();
00643 const qreal y = pos.y();
00644 painter->drawLine( QPointF(x-1.0,y-1.0),
00645 QPointF(x+1.0,y-1.0) );
00646 painter->drawLine( QPointF(x-1.0,y),
00647 QPointF(x+1.0,y) );
00648 painter->drawLine( QPointF(x-1.0,y+1.0),
00649 QPointF(x+1.0,y+1.0) );
00650 }
00651 painter->drawPoint( pos );
00652 }else{
00653 PainterSaver painterSaver( painter );
00654
00655 QPen painterPen( pen );
00656 painterPen.setStyle( Qt::SolidLine );
00657 painter->setPen( painterPen );
00658 painter->setBrush( brush );
00659 painter->setRenderHint ( QPainter::Antialiasing );
00660 painter->translate( pos );
00661 switch ( markerAttributes.markerStyle() ) {
00662 case MarkerAttributes::MarkerCircle:
00663 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00664 maSize.height(), maSize.width()) );
00665 break;
00666 case MarkerAttributes::MarkerSquare:
00667 {
00668 QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2,
00669 maSize.width(), maSize.height() );
00670 painter->drawRect( rect );
00671 break;
00672 }
00673 case MarkerAttributes::MarkerDiamond:
00674 {
00675 QVector <QPointF > diamondPoints;
00676 QPointF top, left, bottom, right;
00677 top = QPointF( 0, 0 - maSize.height()/2 );
00678 left = QPointF( 0 - maSize.width()/2, 0 );
00679 bottom = QPointF( 0, maSize.height()/2 );
00680 right = QPointF( maSize.width()/2, 0 );
00681 diamondPoints << top << left << bottom << right;
00682 painter->drawPolygon( diamondPoints );
00683 break;
00684 }
00685
00686 case MarkerAttributes::Marker1Pixel:
00687 case MarkerAttributes::Marker4Pixels:
00688 break;
00689 case MarkerAttributes::MarkerRing:
00690 {
00691 painter->setPen( QPen( brush.color() ) );
00692 painter->setBrush( Qt::NoBrush );
00693 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00694 maSize.height(), maSize.width()) );
00695 break;
00696 }
00697 case MarkerAttributes::MarkerCross:
00698 {
00699 QRectF rect( maSize.width()*-0.5, maSize.height()*-0.2,
00700 maSize.width(), maSize.height()*0.4 );
00701 painter->drawRect( rect );
00702 rect.setTopLeft(QPointF( maSize.width()*-0.2, maSize.height()*-0.5 ));
00703 rect.setSize(QSizeF( maSize.width()*0.4, maSize.height() ));
00704 painter->drawRect( rect );
00705 break;
00706 }
00707 case MarkerAttributes::MarkerFastCross:
00708 {
00709 QPointF left, right, top, bottom;
00710 left = QPointF( -maSize.width()/2, 0 );
00711 right = QPointF( maSize.width()/2, 0 );
00712 top = QPointF( 0, -maSize.height()/2 );
00713 bottom= QPointF( 0, maSize.height()/2 );
00714 painter->setPen( QPen( brush.color() ) );
00715 painter->drawLine( left, right );
00716 painter->drawLine( top, bottom );
00717 break;
00718 }
00719 default:
00720 Q_ASSERT_X ( false, "paintMarkers()",
00721 "Type item does not match a defined Marker Type." );
00722 }
00723 }
00724 painter->setPen( oldPen );
00725 }
00726
00727 void AbstractDiagram::paintMarkers( QPainter* painter )
00728 {
00729 if ( !checkInvariants() ) return;
00730 const int rowCount = model()->rowCount(rootIndex());
00731 const int columnCount = model()->columnCount(rootIndex());
00732 for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
00733 for ( int j=0; j< rowCount; ++j ) {
00734 const QModelIndex index = model()->index( j, i, rootIndex() );
00735 double value = model()->data( index ).toDouble();
00736 const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
00737 paintMarker( painter, index, pos );
00738 }
00739 }
00740 }
00741
00742
00743 void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen )
00744 {
00745 if( datasetDimension() > 1 )
00746 return setPen( index.column(), pen );
00747 attributesModel()->setData(
00748 attributesModel()->mapFromSource( index ),
00749 qVariantFromValue( pen ), DatasetPenRole );
00750 emit propertiesChanged();
00751 }
00752
00753 void AbstractDiagram::setPen( const QPen& pen )
00754 {
00755 attributesModel()->setModelData(
00756 qVariantFromValue( pen ), DatasetPenRole );
00757 emit propertiesChanged();
00758 }
00759
00760 void AbstractDiagram::setPen( int column,const QPen& pen )
00761 {
00762 if( datasetDimension() > 1 )
00763 column *= datasetDimension();
00764 attributesModel()->setHeaderData(
00765 column, Qt::Vertical,
00766 qVariantFromValue( pen ),
00767 DatasetPenRole );
00768 emit propertiesChanged();
00769 }
00770
00771 QPen AbstractDiagram::pen() const
00772 {
00773 return qVariantValue<QPen>(
00774 attributesModel()->data( DatasetPenRole ) );
00775 }
00776
00777 QPen AbstractDiagram::pen( int dataset ) const
00778 {
00779 if( datasetDimension() > 1 )
00780 dataset /= datasetDimension();
00781
00782 return qVariantValue<QPen>(
00783 attributesModel()->data(
00784 attributesModel()->mapFromSource( columnToIndex( dataset ) ),
00785 DatasetPenRole ) );
00786 }
00787
00788 QPen AbstractDiagram::pen( const QModelIndex& index ) const
00789 {
00790 if( datasetDimension() > 1 )
00791 return pen( index.column() );
00792 return qVariantValue<QPen>(
00793 attributesModel()->data(
00794 attributesModel()->mapFromSource( index ),
00795 DatasetPenRole ) );
00796 }
00797
00798 void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush )
00799 {
00800 attributesModel()->setData(
00801 attributesModel()->mapFromSource( index ),
00802 qVariantFromValue( brush ), DatasetBrushRole );
00803 emit propertiesChanged();
00804 }
00805
00806 void AbstractDiagram::setBrush( const QBrush& brush )
00807 {
00808 attributesModel()->setModelData(
00809 qVariantFromValue( brush ), DatasetBrushRole );
00810 emit propertiesChanged();
00811 }
00812
00813 void AbstractDiagram::setBrush( int column, const QBrush& brush )
00814 {
00815 attributesModel()->setHeaderData(
00816 column, Qt::Vertical,
00817 qVariantFromValue( brush ),
00818 DatasetBrushRole );
00819 emit propertiesChanged();
00820 }
00821
00822 QBrush AbstractDiagram::brush() const
00823 {
00824 return qVariantValue<QBrush>(
00825 attributesModel()->data( DatasetBrushRole ) );
00826 }
00827
00828 QBrush AbstractDiagram::brush( int dataset ) const
00829 {
00830 if( datasetDimension() > 1 )
00831 dataset /= datasetDimension();
00832 return qVariantValue<QBrush>(
00833 attributesModel()->data(
00834 attributesModel()->mapFromSource( columnToIndex( dataset ) ),
00835 DatasetBrushRole ) );
00836 }
00837
00838 QBrush AbstractDiagram::brush( const QModelIndex& index ) const
00839 {
00840 if( datasetDimension() > 1 )
00841 return brush( index.column() );
00842 return qVariantValue<QBrush>(
00843 attributesModel()->data(
00844 attributesModel()->mapFromSource( index ),
00845 DatasetBrushRole ) );
00846 }
00847
00854 void AbstractDiagram::setUnitPrefix( const QString& prefix, int column, Qt::Orientation orientation )
00855 {
00856 d->unitPrefixMap[ column ][ orientation ]= prefix;
00857 }
00858
00864 void AbstractDiagram::setUnitPrefix( const QString& prefix, Qt::Orientation orientation )
00865 {
00866 d->unitPrefix[ orientation ] = prefix;
00867 }
00868
00875 void AbstractDiagram::setUnitSuffix( const QString& suffix, int column, Qt::Orientation orientation )
00876 {
00877 d->unitSuffixMap[ column ][ orientation ]= suffix;
00878 }
00879
00885 void AbstractDiagram::setUnitSuffix( const QString& suffix, Qt::Orientation orientation )
00886 {
00887 d->unitSuffix[ orientation ] = suffix;
00888 }
00889
00897 QString AbstractDiagram::unitPrefix( int column, Qt::Orientation orientation, bool fallback ) const
00898 {
00899 if( !fallback || d->unitPrefixMap[ column ].contains( orientation ) )
00900 return d->unitPrefixMap[ column ][ orientation ];
00901 return d->unitPrefix[ orientation ];
00902 }
00903
00908 QString AbstractDiagram::unitPrefix( Qt::Orientation orientation ) const
00909 {
00910 return d->unitPrefix[ orientation ];
00911 }
00912
00920 QString AbstractDiagram::unitSuffix( int column, Qt::Orientation orientation, bool fallback ) const
00921 {
00922 if( !fallback || d->unitSuffixMap[ column ].contains( orientation ) )
00923 return d->unitSuffixMap[ column ][ orientation ];
00924 return d->unitSuffix[ orientation ];
00925 }
00926
00931 QString AbstractDiagram::unitSuffix( Qt::Orientation orientation ) const
00932 {
00933 return d->unitSuffix[ orientation ];
00934 }
00935
00936
00937 QRect AbstractDiagram::visualRect(const QModelIndex &) const
00938 {
00939 return QRect();
00940 }
00941
00942 void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint )
00943 {}
00944
00945
00946
00947 QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers )
00948 { return QModelIndex(); }
00949
00950 int AbstractDiagram::horizontalOffset() const
00951 { return 0; }
00952
00953 int AbstractDiagram::verticalOffset() const
00954 { return 0; }
00955
00956 bool AbstractDiagram::isIndexHidden(const QModelIndex &) const
00957 { return true; }
00958
00959 void AbstractDiagram::setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags command )
00960 {
00961 const QModelIndexList indexes = d->indexesIn( rect );
00962 QItemSelection selection;
00963 KDAB_FOREACH( const QModelIndex& index, indexes )
00964 {
00965 selection.append( QItemSelectionRange( index ) );
00966 }
00967 selectionModel()->select( selection, command );
00968 }
00969
00970 QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &) const
00971 { return QRegion(); }
00972
00973
00974 void KDChart::AbstractDiagram::useDefaultColors( )
00975 {
00976 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault );
00977 }
00978
00979 void KDChart::AbstractDiagram::useSubduedColors( )
00980 {
00981 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued );
00982 }
00983
00984 void KDChart::AbstractDiagram::useRainbowColors( )
00985 {
00986 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow );
00987 }
00988
00989 QStringList AbstractDiagram::itemRowLabels() const
00990 {
00991 QStringList ret;
00992 if( model() ){
00993
00994 const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
00995 for( int i = 0; i < rowCount; ++i ){
00996
00997 ret << unitPrefix( i, Qt::Horizontal, true ) +
00998 attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString() +
00999 unitSuffix( i, Qt::Horizontal, true );
01000 }
01001 }
01002 return ret;
01003 }
01004
01005 QStringList AbstractDiagram::datasetLabels() const
01006 {
01007 QStringList ret;
01008 if( model() == 0 )
01009 return ret;
01010
01011 const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
01012 for( int i = 0; i < columnCount / datasetDimension(); ++i )
01013 ret << attributesModel()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString();
01014
01015 return ret;
01016 }
01017
01018 QList<QBrush> AbstractDiagram::datasetBrushes() const
01019 {
01020 QList<QBrush> ret;
01021 if( model() == 0 )
01022 return ret;
01023
01024 const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
01025 for( int i = 0; i < columnCount / datasetDimension(); ++i )
01026 ret << qVariantValue<QBrush>( attributesModel()->headerData( i, Qt::Vertical, DatasetBrushRole ) );
01027
01028 return ret;
01029 }
01030
01031 QList<QPen> AbstractDiagram::datasetPens() const
01032 {
01033 QList<QPen> ret;
01034 if( model() == 0 )
01035 return ret;
01036
01037 const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
01038 for( int i = 0; i < columnCount / datasetDimension(); ++i )
01039 ret << qVariantValue<QPen>( attributesModel()->headerData( i, Qt::Vertical, DatasetPenRole ) );
01040
01041 return ret;
01042 }
01043
01044 QList<MarkerAttributes> AbstractDiagram::datasetMarkers() const
01045 {
01046 QList<MarkerAttributes> ret;
01047 if( model() == 0 )
01048 return ret;
01049
01050 const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
01051 for( int i = 0; i < columnCount / datasetDimension(); ++i )
01052 {
01053 const DataValueAttributes a =
01054 qVariantValue<DataValueAttributes>( attributesModel()->headerData( i, Qt::Vertical, DataValueLabelAttributesRole ) );
01055 ret << a.markerAttributes();
01056 }
01057 return ret;
01058 }
01059
01060 bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const
01061 {
01062 if( ! justReturnTheStatus ){
01063 Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()",
01064 "There is no usable model set, for the diagram." );
01065
01066 Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()",
01067 "There is no usable coordinate plane set, for the diagram." );
01068 }
01069 return model() && coordinatePlane();
01070 }
01071
01072 int AbstractDiagram::datasetDimension( ) const
01073 {
01074 return d->datasetDimension;
01075 }
01076
01077 void AbstractDiagram::setDatasetDimension( int dimension )
01078 {
01079 if ( d->datasetDimension == dimension ) return;
01080 d->datasetDimension = dimension;
01081 setDataBoundariesDirty();
01082 emit layoutChanged( this );
01083 }
01084
01085 double AbstractDiagram::valueForCell( int row, int column ) const
01086 {
01087 return d->attributesModel->data(
01088 d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toDouble();
01089 }
01090
01091 void AbstractDiagram::update() const
01092 {
01093
01094 if( d->plane )
01095 d->plane->update();
01096 }
01097
01098 QModelIndex AbstractDiagram::indexAt( const QPoint& point ) const
01099 {
01100 return d->indexAt( point );
01101 }
01102
01103 QModelIndexList AbstractDiagram::indexesAt( const QPoint& point ) const
01104 {
01105 return d->indexesAt( point );
01106 }
01107