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