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 update();
00238 }
00239
00240 void AbstractDiagram::setModel( QAbstractItemModel * newModel )
00241 {
00242 if( model() )
00243 {
00244 disconnect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00245 disconnect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00246 disconnect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00247 disconnect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00248 disconnect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
00249 disconnect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
00250 disconnect( model(), SIGNAL( dataChanged(QModelIndex,QModelIndex) ), this, SIGNAL( modelDataChanged() ));
00251 }
00252 QAbstractItemView::setModel( newModel );
00253 AttributesModel* amodel = new PrivateAttributesModel( newModel, this );
00254 amodel->initFrom( d->attributesModel );
00255 d->setAttributesModel(amodel);
00256 scheduleDelayedItemsLayout();
00257 setDataBoundariesDirty();
00258 if( model() )
00259 {
00260 connect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00261 connect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00262 connect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00263 connect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00264 connect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
00265 connect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
00266 connect( model(), SIGNAL( dataChanged(QModelIndex,QModelIndex) ), this, SIGNAL( modelDataChanged() ));
00267 }
00268 emit modelsChanged();
00269 }
00270
00271 void AbstractDiagram::setSelectionModel( QItemSelectionModel* newSelectionModel )
00272 {
00273 if( selectionModel() )
00274 {
00275 disconnect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
00276 disconnect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
00277 }
00278 QAbstractItemView::setSelectionModel( newSelectionModel );
00279 if( selectionModel() )
00280 {
00281 connect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
00282 connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
00283 }
00284 emit modelsChanged();
00285 }
00286
00292 void AbstractDiagram::setAttributesModel( AttributesModel* amodel )
00293 {
00294 if( amodel->sourceModel() != model() ) {
00295 qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
00296 "Trying to set an attributesmodel which works on a different "
00297 "model than the diagram.");
00298 return;
00299 }
00300 if( qobject_cast<PrivateAttributesModel*>(amodel) ) {
00301 qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
00302 "Trying to set an attributesmodel that is private to another diagram.");
00303 return;
00304 }
00305 d->setAttributesModel(amodel);
00306 scheduleDelayedItemsLayout();
00307 setDataBoundariesDirty();
00308 emit modelsChanged();
00309 }
00310
00311 bool AbstractDiagram::usesExternalAttributesModel()const
00312 {
00313 return d->usesExternalAttributesModel();
00314 }
00315
00317 AttributesModel* AbstractDiagram::attributesModel() const
00318 {
00319 return d->attributesModel;
00320 }
00321
00322 QModelIndex AbstractDiagram::conditionallyMapFromSource( const QModelIndex & index ) const
00323 {
00324 Q_ASSERT( !index.isValid() || index.model() == attributesModel() || index.model() == attributesModel()->sourceModel() );
00325 return index.model() == attributesModel()
00326 ? index
00327 : attributesModel()->mapFromSource( index );
00328 }
00329
00331 void AbstractDiagram::setRootIndex ( const QModelIndex& idx )
00332 {
00333 QAbstractItemView::setRootIndex(idx);
00334 setAttributesModelRootIndex( d->attributesModel->mapFromSource(idx) );
00335 }
00336
00338 void AbstractDiagram::setAttributesModelRootIndex( const QModelIndex& idx )
00339 {
00340 d->attributesModelRootIndex=idx;
00341 setDataBoundariesDirty();
00342 scheduleDelayedItemsLayout();
00343 }
00344
00347 QModelIndex AbstractDiagram::attributesModelRootIndex() const
00348 {
00349 if ( !d->attributesModelRootIndex.isValid() )
00350 d->attributesModelRootIndex = d->attributesModel->mapFromSource( rootIndex() );
00351 return d->attributesModelRootIndex;
00352 }
00353
00354 void AbstractDiagram::setCoordinatePlane( AbstractCoordinatePlane* parent )
00355 {
00356 d->plane = parent;
00357 }
00358
00359 void AbstractDiagram::doItemsLayout()
00360 {
00361 if ( d->plane ) {
00362 d->plane->layoutDiagrams();
00363 update();
00364 }
00365 QAbstractItemView::doItemsLayout();
00366 }
00367
00368 void AbstractDiagram::dataChanged( const QModelIndex &topLeft,
00369 const QModelIndex &bottomRight )
00370 {
00371 Q_UNUSED( topLeft );
00372 Q_UNUSED( bottomRight );
00373
00374 setDataBoundariesDirty();
00375 scheduleDelayedItemsLayout();
00376 }
00377
00378
00379 void AbstractDiagram::setHidden( const QModelIndex & index, bool hidden )
00380 {
00381 d->attributesModel->setData(
00382 conditionallyMapFromSource( index ),
00383 qVariantFromValue( hidden ),
00384 DataHiddenRole );
00385 emit dataHidden();
00386 }
00387
00388 void AbstractDiagram::setHidden( int dataset, bool hidden )
00389 {
00390
00391
00392
00393 d->setDatasetAttrs( dataset, qVariantFromValue( hidden ), DataHiddenRole );
00394 emit dataHidden();
00395 }
00396
00397 void AbstractDiagram::setHidden( bool hidden )
00398 {
00399 d->attributesModel->setModelData(
00400 qVariantFromValue( hidden ),
00401 DataHiddenRole );
00402 emit dataHidden();
00403 }
00404
00405 bool AbstractDiagram::isHidden() const
00406 {
00407 return qVariantValue<bool>(
00408 attributesModel()->modelData( DataHiddenRole ) );
00409 }
00410
00411 bool AbstractDiagram::isHidden( int dataset ) const
00412 {
00413 const QVariant boolFlag( d->datasetAttrs( dataset, DataHiddenRole ) );
00414 if( boolFlag.isValid() )
00415 return qVariantValue< bool >( boolFlag );
00416 return isHidden();
00417 }
00418
00419 bool AbstractDiagram::isHidden( const QModelIndex & index ) const
00420 {
00421 return qVariantValue<bool>(
00422 attributesModel()->data(
00423 conditionallyMapFromSource(index),
00424 DataHiddenRole ) );
00425 }
00426
00427
00428 void AbstractDiagram::setDataValueAttributes( const QModelIndex & index,
00429 const DataValueAttributes & a )
00430 {
00431 d->attributesModel->setData(
00432 conditionallyMapFromSource( index ),
00433 qVariantFromValue( a ),
00434 DataValueLabelAttributesRole );
00435 emit propertiesChanged();
00436 }
00437
00438
00439 void AbstractDiagram::setDataValueAttributes( int dataset, const DataValueAttributes & a )
00440 {
00441 d->setDatasetAttrs( dataset, qVariantFromValue( a ), DataValueLabelAttributesRole );
00442 emit propertiesChanged();
00443 }
00444
00445 DataValueAttributes AbstractDiagram::dataValueAttributes() const
00446 {
00447 return qVariantValue<DataValueAttributes>(
00448 attributesModel()->modelData( KDChart::DataValueLabelAttributesRole ) );
00449 }
00450
00451 DataValueAttributes AbstractDiagram::dataValueAttributes( int dataset ) const
00452 {
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 const QVariant headerAttrs(
00465 d->datasetAttrs( dataset, KDChart::DataValueLabelAttributesRole ) );
00466 if( headerAttrs.isValid() )
00467 return qVariantValue< DataValueAttributes >( headerAttrs );
00468 return dataValueAttributes();
00469 }
00470
00471 DataValueAttributes AbstractDiagram::dataValueAttributes( const QModelIndex & index ) const
00472 {
00473 return qVariantValue<DataValueAttributes>(
00474 attributesModel()->data(
00475 conditionallyMapFromSource( index ),
00476 KDChart::DataValueLabelAttributesRole ) );
00477 }
00478
00479 void AbstractDiagram::setDataValueAttributes( const DataValueAttributes & a )
00480 {
00481 d->attributesModel->setModelData( qVariantFromValue( a ), DataValueLabelAttributesRole );
00482 emit propertiesChanged();
00483 }
00484
00485 void AbstractDiagram::setAllowOverlappingDataValueTexts( bool allow )
00486 {
00487 d->allowOverlappingDataValueTexts = allow;
00488 emit propertiesChanged();
00489 }
00490
00491 bool AbstractDiagram::allowOverlappingDataValueTexts() const
00492 {
00493 return d->allowOverlappingDataValueTexts;
00494 }
00495
00496 void AbstractDiagram::setAntiAliasing( bool enabled )
00497 {
00498 d->antiAliasing = enabled;
00499 emit propertiesChanged();
00500 }
00501
00502 bool AbstractDiagram::antiAliasing() const
00503 {
00504 return d->antiAliasing;
00505 }
00506
00507 void AbstractDiagram::setPercentMode ( bool percent )
00508 {
00509 d->percent = percent;
00510 emit propertiesChanged();
00511 }
00512
00513 bool AbstractDiagram::percentMode() const
00514 {
00515 return d->percent;
00516 }
00517
00518
00519 void AbstractDiagram::paintDataValueText( QPainter* painter,
00520 const QModelIndex& index,
00521 const QPointF& pos,
00522 double value )
00523 {
00524 d->paintDataValueText( this, painter, index, pos, value );
00525 }
00526
00527
00528 QString AbstractDiagram::roundValues( double value,
00529 const int decimalPos,
00530 const int decimalDigits ) const
00531 {
00532 return d->roundValues( value, decimalPos, decimalDigits );
00533 }
00534
00535 void AbstractDiagram::paintDataValueTexts( QPainter* painter )
00536 {
00537 if ( !checkInvariants() ) return;
00538 const int rowCount = model()->rowCount(rootIndex());
00539 const int columnCount = model()->columnCount(rootIndex());
00540 d->clearListOfAlreadyDrawnDataValueTexts();
00541 for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
00542 for ( int j=0; j< rowCount; ++j ) {
00543 const QModelIndex index = model()->index( j, i, rootIndex() );
00544 double value = model()->data( index ).toDouble();
00545 const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
00546 paintDataValueText( painter, index, pos, value );
00547 }
00548 }
00549 }
00550
00551
00552 void AbstractDiagram::paintMarker( QPainter* painter,
00553 const DataValueAttributes& a,
00554 const QModelIndex& index,
00555 const QPointF& pos )
00556 {
00557 if ( !checkInvariants() || !a.isVisible() ) return;
00558 const MarkerAttributes ma = a.markerAttributes();
00559 if ( !ma.isVisible() ) return;
00560
00561 const PainterSaver painterSaver( painter );
00562
00563 const QSizeF maSize( ma.markerSize().width() / painter->matrix().m11(),
00564 ma.markerSize().height() / painter->matrix().m22() );
00565 QBrush indexBrush( brush( index ) );
00566 QPen indexPen( ma.pen() );
00567 if ( ma.markerColor().isValid() )
00568 indexBrush.setColor( ma.markerColor() );
00569
00570 paintMarker( painter, ma, indexBrush, indexPen, pos, maSize );
00571
00572
00573
00574
00575
00576
00577 d->reverseMapper.addCircle( index.row(), index.column(), pos, 2 * maSize );
00578 }
00579
00580 void AbstractDiagram::paintMarker( QPainter* painter,
00581 const QModelIndex& index,
00582 const QPointF& pos )
00583 {
00584 if ( !checkInvariants() ) return;
00585 paintMarker( painter, dataValueAttributes( index ), index, pos );
00586 }
00587
00588 void AbstractDiagram::paintMarker( QPainter* painter,
00589 const MarkerAttributes& markerAttributes,
00590 const QBrush& brush,
00591 const QPen& pen,
00592 const QPointF& pos,
00593 const QSizeF& maSize )
00594 {
00595 const QPen oldPen( painter->pen() );
00596
00597
00598 const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels);
00599 if( isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel) ){
00600
00601 painter->setPen( PrintingParameters::scalePen( QPen( brush.color().light() ) ) );
00602 if( isFourPixels ){
00603 const qreal x = pos.x();
00604 const qreal y = pos.y();
00605 painter->drawLine( QPointF(x-1.0,y-1.0),
00606 QPointF(x+1.0,y-1.0) );
00607 painter->drawLine( QPointF(x-1.0,y),
00608 QPointF(x+1.0,y) );
00609 painter->drawLine( QPointF(x-1.0,y+1.0),
00610 QPointF(x+1.0,y+1.0) );
00611 }
00612 painter->drawPoint( pos );
00613 }else{
00614 const PainterSaver painterSaver( painter );
00615
00616 QPen painterPen( pen );
00617 painterPen.setStyle( Qt::SolidLine );
00618 painter->setPen( PrintingParameters::scalePen( painterPen ) );
00619 painter->setBrush( brush );
00620 painter->setRenderHint ( QPainter::Antialiasing );
00621 painter->translate( pos );
00622 switch ( markerAttributes.markerStyle() ) {
00623 case MarkerAttributes::MarkerCircle:
00624 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00625 maSize.height(), maSize.width()) );
00626 break;
00627 case MarkerAttributes::MarkerSquare:
00628 {
00629 QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2,
00630 maSize.width(), maSize.height() );
00631 painter->drawRect( rect );
00632 break;
00633 }
00634 case MarkerAttributes::MarkerDiamond:
00635 {
00636 QVector <QPointF > diamondPoints;
00637 QPointF top, left, bottom, right;
00638 top = QPointF( 0, 0 - maSize.height()/2 );
00639 left = QPointF( 0 - maSize.width()/2, 0 );
00640 bottom = QPointF( 0, maSize.height()/2 );
00641 right = QPointF( maSize.width()/2, 0 );
00642 diamondPoints << top << left << bottom << right;
00643 painter->drawPolygon( diamondPoints );
00644 break;
00645 }
00646
00647 case MarkerAttributes::Marker1Pixel:
00648 case MarkerAttributes::Marker4Pixels:
00649 break;
00650 case MarkerAttributes::MarkerRing:
00651 {
00652 painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
00653 painter->setBrush( Qt::NoBrush );
00654 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00655 maSize.height(), maSize.width()) );
00656 break;
00657 }
00658 case MarkerAttributes::MarkerCross:
00659 {
00660
00661
00662 const qreal w02 = maSize.width() * 0.2;
00663 const qreal w05 = maSize.width() * 0.5;
00664 const qreal h02 = maSize.height()* 0.2;
00665 const qreal h05 = maSize.height()* 0.5;
00666 QVector <QPointF > crossPoints;
00667 QPointF p[12];
00668 p[ 0] = QPointF( -w02, -h05 );
00669 p[ 1] = QPointF( w02, -h05 );
00670 p[ 2] = QPointF( w02, -h02 );
00671 p[ 3] = QPointF( w05, -h02 );
00672 p[ 4] = QPointF( w05, h02 );
00673 p[ 5] = QPointF( w02, h02 );
00674 p[ 6] = QPointF( w02, h05 );
00675 p[ 7] = QPointF( -w02, h05 );
00676 p[ 8] = QPointF( -w02, h02 );
00677 p[ 9] = QPointF( -w05, h02 );
00678 p[10] = QPointF( -w05, -h02 );
00679 p[11] = QPointF( -w02, -h02 );
00680 for( int i=0; i<12; ++i )
00681 crossPoints << p[i];
00682 crossPoints << p[0];
00683 painter->drawPolygon( crossPoints );
00684 break;
00685 }
00686 case MarkerAttributes::MarkerFastCross:
00687 {
00688 QPointF left, right, top, bottom;
00689 left = QPointF( -maSize.width()/2, 0 );
00690 right = QPointF( maSize.width()/2, 0 );
00691 top = QPointF( 0, -maSize.height()/2 );
00692 bottom= QPointF( 0, maSize.height()/2 );
00693 painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
00694 painter->drawLine( left, right );
00695 painter->drawLine( top, bottom );
00696 break;
00697 }
00698 case MarkerAttributes::NoMarker:
00699 break;
00700 default:
00701 Q_ASSERT_X ( false, "paintMarkers()",
00702 "Type item does not match a defined Marker Type." );
00703 }
00704 }
00705 painter->setPen( oldPen );
00706 }
00707
00708 void AbstractDiagram::paintMarkers( QPainter* painter )
00709 {
00710 if ( !checkInvariants() ) return;
00711 const int rowCount = model()->rowCount(rootIndex());
00712 const int columnCount = model()->columnCount(rootIndex());
00713 for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
00714 for ( int j=0; j< rowCount; ++j ) {
00715 const QModelIndex index = model()->index( j, i, rootIndex() );
00716 double value = model()->data( index ).toDouble();
00717 const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
00718 paintMarker( painter, index, pos );
00719 }
00720 }
00721 }
00722
00723
00724 void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen )
00725 {
00726 attributesModel()->setData(
00727 conditionallyMapFromSource( index ),
00728 qVariantFromValue( pen ), DatasetPenRole );
00729 emit propertiesChanged();
00730 }
00731
00732 void AbstractDiagram::setPen( const QPen& pen )
00733 {
00734 attributesModel()->setModelData(
00735 qVariantFromValue( pen ), DatasetPenRole );
00736 emit propertiesChanged();
00737 }
00738
00739 void AbstractDiagram::setPen( int dataset, const QPen& pen )
00740 {
00741 d->setDatasetAttrs( dataset, qVariantFromValue( pen ), DatasetPenRole );
00742 emit propertiesChanged();
00743 }
00744
00745 QPen AbstractDiagram::pen() const
00746 {
00747 return qVariantValue<QPen>(
00748 attributesModel()->data( DatasetPenRole ) );
00749 }
00750
00751 QPen AbstractDiagram::pen( int dataset ) const
00752 {
00753 const QVariant penSettings( d->datasetAttrs( dataset, DatasetPenRole ) );
00754 if( penSettings.isValid() )
00755 return qVariantValue< QPen >( penSettings );
00756 return pen();
00757 }
00758
00759 QPen AbstractDiagram::pen( const QModelIndex& index ) const
00760 {
00761 return qVariantValue<QPen>(
00762 attributesModel()->data(
00763 conditionallyMapFromSource( index ),
00764 DatasetPenRole ) );
00765 }
00766
00767 void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush )
00768 {
00769 attributesModel()->setData(
00770 conditionallyMapFromSource( index ),
00771 qVariantFromValue( brush ), DatasetBrushRole );
00772 emit propertiesChanged();
00773 }
00774
00775 void AbstractDiagram::setBrush( const QBrush& brush )
00776 {
00777 attributesModel()->setModelData(
00778 qVariantFromValue( brush ), DatasetBrushRole );
00779 emit propertiesChanged();
00780 }
00781
00782 void AbstractDiagram::setBrush( int dataset, const QBrush& brush )
00783 {
00784 d->setDatasetAttrs( dataset, qVariantFromValue( brush ), DatasetBrushRole );
00785 emit propertiesChanged();
00786 }
00787
00788 QBrush AbstractDiagram::brush() const
00789 {
00790 return qVariantValue<QBrush>(
00791 attributesModel()->data( DatasetBrushRole ) );
00792 }
00793
00794 QBrush AbstractDiagram::brush( int dataset ) const
00795 {
00796 const QVariant brushSettings( d->datasetAttrs( dataset, DatasetBrushRole ) );
00797 if( brushSettings.isValid() )
00798 return qVariantValue< QBrush >( brushSettings );
00799 return brush();
00800 }
00801
00802 QBrush AbstractDiagram::brush( const QModelIndex& index ) const
00803 {
00804 return qVariantValue<QBrush>(
00805 attributesModel()->data( conditionallyMapFromSource( index ), DatasetBrushRole ) );
00806 }
00807
00814 void AbstractDiagram::setUnitPrefix( const QString& prefix, int column, Qt::Orientation orientation )
00815 {
00816 d->unitPrefixMap[ column ][ orientation ]= prefix;
00817 }
00818
00824 void AbstractDiagram::setUnitPrefix( const QString& prefix, Qt::Orientation orientation )
00825 {
00826 d->unitPrefix[ orientation ] = prefix;
00827 }
00828
00835 void AbstractDiagram::setUnitSuffix( const QString& suffix, int column, Qt::Orientation orientation )
00836 {
00837 d->unitSuffixMap[ column ][ orientation ]= suffix;
00838 }
00839
00845 void AbstractDiagram::setUnitSuffix( const QString& suffix, Qt::Orientation orientation )
00846 {
00847 d->unitSuffix[ orientation ] = suffix;
00848 }
00849
00857 QString AbstractDiagram::unitPrefix( int column, Qt::Orientation orientation, bool fallback ) const
00858 {
00859 if( !fallback || d->unitPrefixMap[ column ].contains( orientation ) )
00860 return d->unitPrefixMap[ column ][ orientation ];
00861 return d->unitPrefix[ orientation ];
00862 }
00863
00868 QString AbstractDiagram::unitPrefix( Qt::Orientation orientation ) const
00869 {
00870 return d->unitPrefix[ orientation ];
00871 }
00872
00880 QString AbstractDiagram::unitSuffix( int column, Qt::Orientation orientation, bool fallback ) const
00881 {
00882 if( !fallback || d->unitSuffixMap[ column ].contains( orientation ) )
00883 return d->unitSuffixMap[ column ][ orientation ];
00884 return d->unitSuffix[ orientation ];
00885 }
00886
00891 QString AbstractDiagram::unitSuffix( Qt::Orientation orientation ) const
00892 {
00893 return d->unitSuffix[ orientation ];
00894 }
00895
00896
00897 QRect AbstractDiagram::visualRect( const QModelIndex &index ) const
00898 {
00899 return d->reverseMapper.boundingRect( index.row(), index.column() ).toRect();
00900 }
00901
00902 void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint )
00903 {}
00904
00905
00906
00907 QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers )
00908 { return QModelIndex(); }
00909
00910 int AbstractDiagram::horizontalOffset() const
00911 { return 0; }
00912
00913 int AbstractDiagram::verticalOffset() const
00914 { return 0; }
00915
00916 bool AbstractDiagram::isIndexHidden(const QModelIndex &) const
00917 { return true; }
00918
00919 void AbstractDiagram::setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags command )
00920 {
00921 const QModelIndexList indexes = d->indexesIn( rect );
00922 QItemSelection selection;
00923 KDAB_FOREACH( const QModelIndex& index, indexes )
00924 {
00925 selection.append( QItemSelectionRange( index ) );
00926 }
00927 selectionModel()->select( selection, command );
00928 }
00929
00930 QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &selection) const
00931 {
00932 QPolygonF polygon;
00933 KDAB_FOREACH( const QModelIndex& index, selection.indexes() )
00934 {
00935 polygon << d->reverseMapper.polygon(index.row(), index.column());
00936 }
00937 return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
00938 }
00939
00940 QRegion AbstractDiagram::visualRegion(const QModelIndex &index) const
00941 {
00942 QPolygonF polygon = d->reverseMapper.polygon(index.row(), index.column());
00943 return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
00944 }
00945
00946 void KDChart::AbstractDiagram::useDefaultColors( )
00947 {
00948 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault );
00949 }
00950
00951 void KDChart::AbstractDiagram::useSubduedColors( )
00952 {
00953 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued );
00954 }
00955
00956 void KDChart::AbstractDiagram::useRainbowColors( )
00957 {
00958 d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow );
00959 }
00960
00961 QStringList AbstractDiagram::itemRowLabels() const
00962 {
00963 QStringList ret;
00964 if( model() ){
00965
00966 const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
00967 for( int i = 0; i < rowCount; ++i ){
00968
00969 ret << unitPrefix( i, Qt::Horizontal, true ) +
00970 attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString() +
00971 unitSuffix( i, Qt::Horizontal, true );
00972 }
00973 }
00974 return ret;
00975 }
00976
00977 QStringList AbstractDiagram::datasetLabels() const
00978 {
00979 QStringList ret;
00980 if( model() == 0 )
00981 return ret;
00982
00983 const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
00984 for( int i = 0; i < columnCount; i += datasetDimension() )
00985 ret << attributesModel()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString();
00986
00987 return ret;
00988 }
00989
00990 QList<QBrush> AbstractDiagram::datasetBrushes() const
00991 {
00992 QList<QBrush> ret;
00993 if( model() == 0 )
00994 return ret;
00995
00996 const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
00997 for ( int dataset = 0; dataset < datasetCount; dataset++ )
00998 ret << brush( dataset );
00999
01000 return ret;
01001 }
01002
01003 QList<QPen> AbstractDiagram::datasetPens() const
01004 {
01005 QList<QPen> ret;
01006 if( model() == 0 )
01007 return ret;
01008
01009 const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
01010 for ( int dataset = 0; dataset < datasetCount; dataset++ )
01011 ret << pen( dataset );
01012
01013 return ret;
01014 }
01015
01016 QList<MarkerAttributes> AbstractDiagram::datasetMarkers() const
01017 {
01018 QList<MarkerAttributes> ret;
01019 if( model() == 0 )
01020 return ret;
01021
01022 const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
01023 for ( int dataset = 0; dataset < datasetCount; dataset++ )
01024 ret << dataValueAttributes( dataset ).markerAttributes();
01025
01026 return ret;
01027 }
01028
01029 bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const
01030 {
01031 if( ! justReturnTheStatus ){
01032 Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()",
01033 "There is no usable model set, for the diagram." );
01034
01035 Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()",
01036 "There is no usable coordinate plane set, for the diagram." );
01037 }
01038 return model() && coordinatePlane();
01039 }
01040
01041 int AbstractDiagram::datasetDimension( ) const
01042 {
01043 return d->datasetDimension;
01044 }
01045
01046 void AbstractDiagram::setDatasetDimension( int dimension )
01047 {
01048 Q_UNUSED( dimension );
01049 qDebug() << "Setting the dataset dimension using AbstractDiagram::setDatasetDimension is obsolete. Use the specific diagram types instead.";
01050 }
01051
01052 void AbstractDiagram::setDatasetDimensionInternal( int dimension )
01053 {
01054 Q_ASSERT( dimension != 0 );
01055
01056 if ( d->datasetDimension == dimension ) return;
01057 d->datasetDimension = dimension;
01058 setDataBoundariesDirty();
01059 emit layoutChanged( this );
01060 }
01061
01062 double AbstractDiagram::valueForCell( int row, int column ) const
01063 {
01064 return d->attributesModel->data(
01065 d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toDouble();
01066 }
01067
01068 void AbstractDiagram::update() const
01069 {
01070
01071 if( d->plane )
01072 d->plane->update();
01073 }
01074
01075 QModelIndex AbstractDiagram::indexAt( const QPoint& point ) const
01076 {
01077 return d->indexAt( point );
01078 }
01079
01080 QModelIndexList AbstractDiagram::indexesAt( const QPoint& point ) const
01081 {
01082 return d->indexesAt( point );
01083 }
01084