KDChartLeveyJenningsDiagram.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (C) 2001-2010 Klaralvdalens Datakonsult AB.  All rights reserved.
00003 **
00004 ** This file is part of the KD Chart library.
00005 **
00006 ** Licensees holding valid commercial KD Chart licenses may use this file in
00007 ** accordance with the KD Chart Commercial License Agreement provided with
00008 ** the Software.
00009 **
00010 **
00011 ** This file may be distributed and/or modified under the terms of the
00012 ** GNU General Public License version 2 and version 3 as published by the
00013 ** Free Software Foundation and appearing in the file LICENSE.GPL included.
00014 **
00015 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00016 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00017 **
00018 ** Contact info@kdab.com if any conditions of this licensing are not
00019 ** clear to you.
00020 **
00021 **********************************************************************/
00022 
00023 #include "KDChartLeveyJenningsDiagram.h"
00024 #include "KDChartLeveyJenningsDiagram_p.h"
00025 
00026 #include <QDateTime>
00027 #include <QFontMetrics>
00028 #include <QPainter>
00029 #include <QSvgRenderer>
00030 #include <QVector>
00031 
00032 #include "KDChartChart.h"
00033 #include "KDChartTextAttributes.h"
00034 #include "KDChartAbstractGrid.h"
00035 
00036 #include <KDABLibFakes>
00037 
00038 using namespace KDChart;
00039 using namespace std;
00040 
00041 LeveyJenningsDiagram::Private::Private()
00042 {
00043 }
00044 
00045 LeveyJenningsDiagram::Private::~Private() {}
00046 
00047 
00048 #define d d_func()
00049 
00050 
00051 LeveyJenningsDiagram::LeveyJenningsDiagram( QWidget* parent, LeveyJenningsCoordinatePlane* plane )
00052     : LineDiagram( new Private(), parent, plane )
00053 {
00054     init();
00055 }
00056 
00057 void LeveyJenningsDiagram::init()
00058 {
00059     d->lotChangedPosition = Qt::AlignTop;
00060     d->fluidicsPackChangedPosition = Qt::AlignBottom;
00061     d->sensorChangedPosition = Qt::AlignBottom;
00062 
00063     d->scanLinePen = QPen( Qt::blue );
00064     setPen( d->scanLinePen );
00065 
00066     d->expectedMeanValue = 0.0;
00067     d->expectedStandardDeviation = 0.0;
00068 
00069     d->diagram = this;
00070 
00071     d->icons[ LotChanged ] = QString::fromLatin1( ":/KDAB/kdchart/LeveyJennings/karo_black.svg" );
00072     d->icons[ SensorChanged ] = QString::fromLatin1( ":/KDAB/kdchart/LeveyJennings/karo_red.svg" );
00073     d->icons[ FluidicsPackChanged ] = QString::fromLatin1( ":/KDAB/kdchart/LeveyJennings/karo_blue.svg" );
00074     d->icons[ OkDataPoint ] = QString::fromLatin1( ":/KDAB/kdchart/LeveyJennings/circle_blue.svg" );
00075     d->icons[ NotOkDataPoint ] = QString::fromLatin1( ":/KDAB/kdchart/LeveyJennings/circle_blue_red.svg" );
00076 
00077     setSelectionMode( QAbstractItemView::SingleSelection );
00078 }
00079 
00080 LeveyJenningsDiagram::~LeveyJenningsDiagram()
00081 {
00082 }
00083 
00087 LineDiagram * LeveyJenningsDiagram::clone() const
00088 {
00089     LeveyJenningsDiagram* newDiagram = new LeveyJenningsDiagram( new Private( *d ) );
00090     return newDiagram;
00091 }
00092 
00093 bool LeveyJenningsDiagram::compare( const LeveyJenningsDiagram* other )const
00094 {
00095     if( other == this ) return true;
00096     if( ! other ){
00097         return false;
00098     }
00099     /*
00100     qDebug() <<"\n             LineDiagram::compare():";
00101             // compare own properties
00102     qDebug() << (type() == other->type());
00103     */
00104     return  // compare the base class
00105             ( static_cast<const LineDiagram*>(this)->compare( other ) );
00106 }
00107 
00112 void LeveyJenningsDiagram::setLotChangedSymbolPosition( Qt::Alignment pos )
00113 {
00114     if( d->lotChangedPosition == pos )
00115         return;
00116 
00117     d->lotChangedPosition = pos;
00118     update();
00119 }
00120 
00124 Qt::Alignment LeveyJenningsDiagram::lotChangedSymbolPosition() const
00125 {
00126     return d->lotChangedPosition;
00127 }
00128 
00133 void LeveyJenningsDiagram::setFluidicsPackChangedSymbolPosition( Qt::Alignment pos )
00134 {
00135     if( d->fluidicsPackChangedPosition == pos )
00136         return;
00137 
00138     d->fluidicsPackChangedPosition = pos;
00139     update();
00140 }
00141 
00145 Qt::Alignment LeveyJenningsDiagram::fluidicsPackChangedSymbolPosition() const
00146 {
00147     return d->fluidicsPackChangedPosition;
00148 }
00149 
00154 void LeveyJenningsDiagram::setSensorChangedSymbolPosition( Qt::Alignment pos )
00155 {
00156     if( d->sensorChangedPosition == pos )
00157         return;
00158 
00159     d->sensorChangedPosition = pos;
00160     update();
00161 }
00162 
00166 Qt::Alignment LeveyJenningsDiagram::sensorChangedSymbolPosition() const
00167 {
00168     return d->sensorChangedPosition;
00169 }
00170 
00174 void LeveyJenningsDiagram::setFluidicsPackChanges( const QVector< QDateTime >& changes )
00175 {
00176     if( d->fluidicsPackChanges == changes )
00177         return;
00178 
00179     d->fluidicsPackChanges = changes;
00180     update();
00181 }
00182 
00186 QVector< QDateTime > LeveyJenningsDiagram::fluidicsPackChanges() const
00187 {
00188     return d->fluidicsPackChanges;
00189 }
00190 
00194 void LeveyJenningsDiagram::setSensorChanges( const QVector< QDateTime >& changes )
00195 {
00196     if( d->sensorChanges == changes )
00197         return;
00198 
00199     d->sensorChanges = changes;
00200     update();
00201 }
00202 
00206 void LeveyJenningsDiagram::setScanLinePen( const QPen& pen )
00207 {
00208     if( d->scanLinePen == pen )
00209         return;
00210 
00211     d->scanLinePen = pen;
00212     update();
00213 }
00214 
00218 QPen LeveyJenningsDiagram::scanLinePen() const
00219 {
00220     return d->scanLinePen;
00221 }
00222 
00226 QString LeveyJenningsDiagram::symbol( Symbol symbol ) const
00227 {
00228     return d->icons[ symbol ];
00229 }
00230 
00234 void LeveyJenningsDiagram::setSymbol( Symbol symbol, const QString& filename )
00235 {
00236     if( d->icons[ symbol ] == filename )
00237         return;
00238 
00239     delete d->iconRenderer[ symbol ];
00240     d->iconRenderer[ symbol ] = 0;
00241 
00242     d->icons[ symbol ] = filename;
00243 
00244     update();
00245 }
00246 
00250 QVector< QDateTime > LeveyJenningsDiagram::sensorChanges() const
00251 {
00252     return d->sensorChanges;
00253 }
00254 
00258 void LeveyJenningsDiagram::setExpectedMeanValue( float meanValue )
00259 {
00260     if( d->expectedMeanValue == meanValue )
00261         return;
00262 
00263     d->expectedMeanValue = meanValue;
00264     d->setYAxisRange();
00265     update();
00266 }
00267 
00271 float LeveyJenningsDiagram::expectedMeanValue() const
00272 {
00273     return d->expectedMeanValue;
00274 }
00275 
00279 void LeveyJenningsDiagram::setExpectedStandardDeviation( float sd )
00280 {
00281     if( d->expectedStandardDeviation == sd )
00282         return;
00283 
00284     d->expectedStandardDeviation = sd;
00285     d->setYAxisRange();
00286     update();
00287 }
00288 
00292 float LeveyJenningsDiagram::expectedStandardDeviation() const
00293 {
00294     return d->expectedStandardDeviation;
00295 }
00296 
00300 float LeveyJenningsDiagram::calculatedMeanValue() const
00301 {
00302     return d->calculatedMeanValue;
00303 }
00304 
00308 float LeveyJenningsDiagram::calculatedStandardDeviation() const
00309 {
00310     return d->calculatedStandardDeviation;
00311 }
00312 
00313 void LeveyJenningsDiagram::setModel( QAbstractItemModel* model )
00314 {
00315     if( this->model() != 0 )
00316     {
00317         disconnect( this->model(), SIGNAL( dataChanged( const QModelIndex&, const QModelIndex& ) ),
00318                                    this, SLOT( calculateMeanAndStandardDeviation() ) );
00319         disconnect( this->model(), SIGNAL( rowsInserted( const QModelIndex&, int, int ) ),
00320                                    this, SLOT( calculateMeanAndStandardDeviation() ) );
00321         disconnect( this->model(), SIGNAL( rowsRemoved( const QModelIndex&, int, int ) ),
00322                                    this, SLOT( calculateMeanAndStandardDeviation() ) );
00323         disconnect( this->model(), SIGNAL( columnsInserted( const QModelIndex&, int, int ) ),
00324                                    this, SLOT( calculateMeanAndStandardDeviation() ) );
00325         disconnect( this->model(), SIGNAL( columnsRemoved( const QModelIndex&, int, int ) ),
00326                                    this, SLOT( calculateMeanAndStandardDeviation() ) );
00327         disconnect( this->model(), SIGNAL( modelReset() ),
00328                                    this, SLOT( calculateMeanAndStandardDeviation() ) );
00329         disconnect( this->model(), SIGNAL( layoutChanged() ),
00330                                    this, SLOT( calculateMeanAndStandardDeviation() ) );
00331     }
00332     LineDiagram::setModel( model );
00333     if( this->model() != 0 )
00334     {
00335         connect( this->model(), SIGNAL( dataChanged( const QModelIndex&, const QModelIndex& ) ),
00336                                 this, SLOT( calculateMeanAndStandardDeviation() ) );
00337         connect( this->model(), SIGNAL( rowsInserted( const QModelIndex&, int, int ) ),
00338                                 this, SLOT( calculateMeanAndStandardDeviation() ) );
00339         connect( this->model(), SIGNAL( rowsRemoved( const QModelIndex&, int, int ) ),
00340                                 this, SLOT( calculateMeanAndStandardDeviation() ) );
00341         connect( this->model(), SIGNAL( columnsInserted( const QModelIndex&, int, int ) ),
00342                                 this, SLOT( calculateMeanAndStandardDeviation() ) );
00343         connect( this->model(), SIGNAL( columnsRemoved( const QModelIndex&, int, int ) ),
00344                                 this, SLOT( calculateMeanAndStandardDeviation() ) );
00345         connect( this->model(), SIGNAL( modelReset() ),
00346                                 this, SLOT( calculateMeanAndStandardDeviation() ) );
00347         connect( this->model(), SIGNAL( layoutChanged() ),
00348                                 this, SLOT( calculateMeanAndStandardDeviation() ) );
00349 
00350         calculateMeanAndStandardDeviation();
00351     }
00352 }
00353 
00354 // TODO: This is the 'easy' solution
00355 // evaluate whether this is enough or we need some better one or even boost here
00356 void LeveyJenningsDiagram::calculateMeanAndStandardDeviation() const
00357 {
00358     QVector< double > values;
00359     // first fetch all values
00360     const QAbstractItemModel& m = *model();
00361     const int rowCount = m.rowCount( rootIndex() );
00362 
00363     for( int row = 0; row < rowCount; ++row )
00364     {
00365         const QVariant var = m.data( m.index( row, 1, rootIndex() ) );
00366         if( !var.isValid() )
00367             continue;
00368         const double value = var.toDouble();
00369         if( ISNAN( value ) )
00370             continue;
00371         values << value;
00372     }
00373 
00374     double sum = 0.0;
00375     double sumSquares = 0.0;
00376     KDAB_FOREACH( double value, values )
00377     {
00378         sum += value;
00379         sumSquares += value * value;
00380     }
00381 
00382     const int N = values.count();
00383 
00384     d->calculatedMeanValue = sum / N;
00385     d->calculatedStandardDeviation = sqrt( ( static_cast< double >( N ) * sumSquares - sum * sum ) / ( N * ( N - 1 ) ) );
00386 }
00387 
00388 // calculates the largest QDate not greater than \a dt.
00389 static QDate floorDay( const QDateTime& dt )
00390 {
00391     return dt.date();
00392 }
00393 
00394 // calculates the smallest QDate not less than \a dt.
00395 static QDate ceilDay( const QDateTime& dt )
00396 {
00397     QDate result = dt.date();
00398 
00399     if( QDateTime( result, QTime() ) < dt )
00400         result = result.addDays( 1 );
00401 
00402     return result;
00403 }
00404 
00405 // calculates the largest QDateTime like xx:00 not greater than \a dt.
00406 static QDateTime floorHour( const QDateTime& dt )
00407 {
00408     return QDateTime( dt.date(), QTime( dt.time().hour(), 0 ) );
00409 }
00410 
00411 // calculates the smallest QDateTime like xx:00 not less than \a dt.
00412 static QDateTime ceilHour( const QDateTime& dt )
00413 {
00414     QDateTime result( dt.date(), QTime( dt.time().hour(), 0 ) );
00415 
00416     if( result < dt )
00417         result = result.addSecs( 3600 );
00418 
00419     return result;
00420 }
00421 
00423 const QPair<QPointF, QPointF> LeveyJenningsDiagram::calculateDataBoundaries() const
00424 {
00425     const double yMin = d->expectedMeanValue - 4 * d->expectedStandardDeviation;
00426     const double yMax = d->expectedMeanValue + 4 * d->expectedStandardDeviation;
00427 
00428     d->setYAxisRange();
00429 
00430     // rounded down/up to the prev/next midnight (at least that's the default)
00431     const QPair< QDateTime, QDateTime > range = timeRange();
00432     const unsigned int minTime = range.first.toTime_t();
00433     const unsigned int maxTime = range.second.toTime_t();
00434 
00435     const double xMin = minTime / static_cast< double >( 24 * 60 * 60 );
00436     const double xMax = maxTime / static_cast< double >( 24 * 60 * 60 ) - xMin;
00437 
00438     const QPointF bottomLeft( QPointF( 0, yMin ) );
00439     const QPointF topRight( QPointF( xMax, yMax ) );
00440 
00441     return QPair< QPointF, QPointF >( bottomLeft, topRight );
00442 }
00443 
00447 QPair< QDateTime, QDateTime > LeveyJenningsDiagram::timeRange() const
00448 {
00449     if( d->timeRange != QPair< QDateTime, QDateTime >() )
00450         return d->timeRange;
00451 
00452     const QAbstractItemModel& m = *model();
00453     const int rowCount = m.rowCount( rootIndex() );
00454 
00455     const QDateTime begin = m.data( m.index( 0, 3, rootIndex() ) ).toDateTime();
00456     const QDateTime end = m.data( m.index( rowCount - 1, 3, rootIndex() ) ).toDateTime();
00457 
00458     if( begin.secsTo( end ) > 86400 )
00459     {
00460         // if begin to end is more than 24h
00461         // round down/up to the prev/next midnight
00462         const QDate min = floorDay( begin );
00463         const QDate max = ceilDay( end );
00464         return QPair< QDateTime, QDateTime >( QDateTime( min ), QDateTime( max ) );
00465     }
00466     else if( begin.secsTo( end ) > 3600 )
00467     {
00468         // more than 1h: rond down up to the prex/next hour
00469         // if begin to end is more than 24h
00470         const QDateTime min = floorHour( begin );
00471         const QDateTime max = ceilHour( end );
00472         return QPair< QDateTime, QDateTime >( min, max );
00473     }
00474     return QPair< QDateTime, QDateTime >( begin, end );
00475 }
00476 
00481 void LeveyJenningsDiagram::setTimeRange( const QPair< QDateTime, QDateTime >& timeRange )
00482 {
00483     if( d->timeRange == timeRange )
00484         return;
00485 
00486     d->timeRange = timeRange;
00487     update();
00488 }
00489 
00493 void LeveyJenningsDiagram::drawChanges( PaintContext* ctx )
00494 {
00495     const unsigned int minTime = timeRange().first.toTime_t();
00496 
00497     KDAB_FOREACH( const QDateTime& dt, d->fluidicsPackChanges )
00498     {
00499         const double xValue = ( dt.toTime_t() - minTime ) / static_cast< double >( 24 * 60 * 60 );
00500         const QPointF point( xValue, 0.0 );
00501         drawFluidicsPackChangedSymbol( ctx, point );
00502     }
00503 
00504     KDAB_FOREACH( const QDateTime& dt, d->sensorChanges )
00505     {
00506         const double xValue = ( dt.toTime_t() - minTime ) / static_cast< double >( 24 * 60 * 60 );
00507         const QPointF point( xValue, 0.0 );
00508         drawSensorChangedSymbol( ctx, point );
00509     }
00510 }
00511 
00513 void LeveyJenningsDiagram::paint( PaintContext* ctx )
00514 {
00515     d->reverseMapper.clear();
00516 
00517     // note: Not having any data model assigned is no bug
00518     //       but we can not draw a diagram then either.
00519     if ( !checkInvariants( true ) ) return;
00520     if ( !AbstractGrid::isBoundariesValid(dataBoundaries()) ) return;
00521 
00522     QPainter* const painter = ctx->painter();
00523     const PainterSaver p( painter );
00524     if( model()->rowCount( rootIndex() ) == 0 || model()->columnCount( rootIndex() ) < 4 )
00525         return; // nothing to paint for us
00526 
00527     AbstractCoordinatePlane* const plane = ctx->coordinatePlane();
00528     ctx->setCoordinatePlane( plane->sharedAxisMasterPlane( painter ) );
00529 
00530     const QAbstractItemModel& m = *model();
00531     const int rowCount = m.rowCount( rootIndex() );
00532 
00533     const unsigned int minTime = timeRange().first.toTime_t();
00534 
00535     painter->setRenderHint( QPainter::Antialiasing, true );
00536 
00537     int prevLot = -1;
00538     QPointF prevPoint;
00539     bool hadMissingValue = false;
00540 
00541     for( int row = 0; row < rowCount; ++row )
00542     {
00543         const QModelIndex lotIndex = m.index( row, 0, rootIndex() );
00544         const QModelIndex valueIndex = m.index( row, 1, rootIndex() );
00545         const QModelIndex okIndex = m.index( row, 2, rootIndex() );
00546         const QModelIndex timeIndex = m.index( row, 3, rootIndex() );
00547         const QModelIndex expectedMeanIndex = m.index( row, 4, rootIndex() );
00548         const QModelIndex expectedSDIndex = m.index( row, 5, rootIndex() );
00549 
00550         painter->setPen( pen( lotIndex ) );
00551 
00552         QVariant vValue = m.data( valueIndex );
00553         double value = vValue.toDouble();
00554         const int lot = m.data( lotIndex ).toInt();
00555         const bool ok = m.data( okIndex ).toBool();
00556         const QDateTime time = m.data( timeIndex ).toDateTime();
00557         const double xValue = ( time.toTime_t() - minTime ) / static_cast< double >( 24 * 60 * 60 );
00558 
00559         QVariant vExpectedMean = m.data( expectedMeanIndex );
00560         const double expectedMean = vExpectedMean.toDouble();
00561         QVariant vExpectedSD = m.data( expectedSDIndex );
00562         const double expectedSD = vExpectedSD.toDouble();
00563 
00564         QPointF point = ctx->coordinatePlane()->translate( QPointF( xValue, value ) );
00565 
00566         if( vValue.isNull() )
00567         {
00568             hadMissingValue = true;
00569         }
00570         else
00571         {
00572             if( !vExpectedMean.isNull() && !vExpectedSD.isNull() )
00573             {
00574                 // this calculates the 'logical' value relative to the expected mean and SD of this point
00575                 value -= expectedMean;
00576                 value /= expectedSD;
00577                 value *= d->expectedStandardDeviation;
00578                 value += d->expectedMeanValue;
00579                 point = ctx->coordinatePlane()->translate( QPointF( xValue, value ) );
00580             }
00581 
00582             if( prevLot == lot )
00583             {
00584                 const QPen pen = painter->pen();
00585                 QPen newPen = pen;
00586 
00587                 if( hadMissingValue )
00588                 {
00589                     newPen.setDashPattern( QVector< qreal >() << 4.0 << 4.0 );
00590                 }
00591 
00592                 painter->setPen( newPen );
00593                 painter->drawLine( prevPoint, point );
00594                 painter->setPen( pen );
00595                 // d->reverseMapper.addLine( valueIndex.row(), valueIndex.column(), prevPoint, point );
00596             }
00597             else if( row > 0 )
00598             {
00599                 drawLotChangeSymbol( ctx, QPointF( xValue, value ) );
00600             }
00601 
00602             if( value <= d->expectedMeanValue + 4 * d->expectedStandardDeviation &&
00603                 value >= d->expectedMeanValue - 4 * d->expectedStandardDeviation )
00604             {
00605                 const QPointF location( xValue, value );
00606                 drawDataPointSymbol( ctx, location, ok );
00607                 d->reverseMapper.addCircle( valueIndex.row(),
00608                                             valueIndex.column(),
00609                                             ctx->coordinatePlane()->translate( location ),
00610                                             iconRect().size() );
00611             }
00612             prevLot = lot;
00613             prevPoint = point;
00614             hadMissingValue = false;
00615         }
00616 
00617         const QModelIndex current = selectionModel()->currentIndex();
00618         if( selectionModel()->rowIntersectsSelection( lotIndex.row(), lotIndex.parent() ) || current.sibling( current.row(), 0 ) == lotIndex )
00619         {
00620             const QPen pen = ctx->painter()->pen();
00621             painter->setPen( d->scanLinePen );
00622             painter->drawLine( ctx->coordinatePlane()->translate( QPointF( xValue, d->expectedMeanValue - 4 *
00623                                                                                    d->expectedStandardDeviation ) ),
00624                                ctx->coordinatePlane()->translate( QPointF( xValue, d->expectedMeanValue + 4 *
00625                                                                                    d->expectedStandardDeviation ) ) );
00626             painter->setPen( pen );
00627         }
00628     }
00629 
00630     drawChanges( ctx );
00631 
00632     ctx->setCoordinatePlane( plane );
00633 }
00634 
00640 void LeveyJenningsDiagram::drawDataPointSymbol( PaintContext* ctx, const QPointF& pos, bool ok )
00641 {
00642     const Symbol type = ok ? OkDataPoint : NotOkDataPoint;
00643 
00644     QPainter* const painter = ctx->painter();
00645     const PainterSaver ps( painter );
00646     const QPointF transPos = ctx->coordinatePlane()->translate( pos ).toPoint();
00647     painter->translate( transPos );
00648 
00649     painter->setClipping( false );
00650     iconRenderer( type )->render( painter, iconRect() );
00651 }
00652 
00658 void LeveyJenningsDiagram::drawLotChangeSymbol( PaintContext* ctx, const QPointF& pos )
00659 {
00660     const QPointF transPos = ctx->coordinatePlane()->translate(
00661         QPointF( pos.x(), d->lotChangedPosition & Qt::AlignTop ? d->expectedMeanValue +
00662                                                                  4 * d->expectedStandardDeviation
00663                                                                : d->expectedMeanValue -
00664                                                                  4 * d->expectedStandardDeviation ) );
00665 
00666 
00667     QPainter* const painter = ctx->painter();
00668     const PainterSaver ps( painter );
00669     painter->setClipping( false );
00670     painter->translate( transPos );
00671     iconRenderer( LotChanged )->render( painter, iconRect() );
00672 }
00673 
00679 void LeveyJenningsDiagram::drawSensorChangedSymbol( PaintContext* ctx, const QPointF& pos )
00680 {
00681     const QPointF transPos = ctx->coordinatePlane()->translate(
00682         QPointF( pos.x(), d->sensorChangedPosition & Qt::AlignTop ? d->expectedMeanValue +
00683                                                                     4 * d->expectedStandardDeviation
00684                                                                   : d->expectedMeanValue -
00685                                                                     4 * d->expectedStandardDeviation ) );
00686 
00687     QPainter* const painter = ctx->painter();
00688     const PainterSaver ps( painter );
00689     painter->setClipping( false );
00690     painter->translate( transPos );
00691     iconRenderer( SensorChanged )->render( painter, iconRect() );
00692 }
00693 
00699 void LeveyJenningsDiagram::drawFluidicsPackChangedSymbol( PaintContext* ctx, const QPointF& pos )
00700 {
00701     const QPointF transPos = ctx->coordinatePlane()->translate(
00702         QPointF( pos.x(), d->fluidicsPackChangedPosition & Qt::AlignTop ? d->expectedMeanValue +
00703                                                                           4 * d->expectedStandardDeviation
00704                                                                         : d->expectedMeanValue -
00705                                                                           4 * d->expectedStandardDeviation ) );
00706 
00707     QPainter* const painter = ctx->painter();
00708     const PainterSaver ps( painter );
00709     painter->setClipping( false );
00710     painter->translate( transPos );
00711     iconRenderer( FluidicsPackChanged )->render( painter, iconRect() );
00712 }
00713 
00717 QRectF LeveyJenningsDiagram::iconRect() const
00718 {
00719     const Measure m( 12.5, KDChartEnums::MeasureCalculationModeAuto, KDChartEnums::MeasureOrientationAuto );
00720     TextAttributes test;
00721     test.setFontSize( m );
00722     const QFontMetrics fm( test.calculatedFont( coordinatePlane()->parent(), KDChartEnums::MeasureOrientationAuto ) );
00723     const qreal height = fm.height() / 1.2;
00724     return QRectF( -height / 2.0, -height / 2.0, height, height );
00725 }
00726 
00730 QSvgRenderer* LeveyJenningsDiagram::iconRenderer( Symbol symbol )
00731 {
00732     if( d->iconRenderer[ symbol ] == 0 )
00733         d->iconRenderer[ symbol ] = new QSvgRenderer( d->icons[ symbol ], this );
00734 
00735     return d->iconRenderer[ symbol ];
00736 }