24 #include "KDChartLeveyJenningsDiagram_p.h"
28 #include "KDChartAbstractGrid.h"
29 #include "KDChartPainterSaver_p.h"
32 #include <QFontMetrics>
34 #include <QSvgRenderer>
37 #include <KDABLibFakes>
39 using namespace KDChart;
42 LeveyJenningsDiagram::Private::Private()
46 LeveyJenningsDiagram::Private::~Private() {}
58 void LeveyJenningsDiagram::init()
60 d->lotChangedPosition = Qt::AlignTop;
61 d->fluidicsPackChangedPosition = Qt::AlignBottom;
62 d->sensorChangedPosition = Qt::AlignBottom;
64 d->scanLinePen = QPen( Qt::blue );
67 d->expectedMeanValue = 0.0;
68 d->expectedStandardDeviation = 0.0;
72 d->icons[
LotChanged ] = QString::fromLatin1(
":/KDAB/kdchart/LeveyJennings/karo_black.svg" );
73 d->icons[
SensorChanged ] = QString::fromLatin1(
":/KDAB/kdchart/LeveyJennings/karo_red.svg" );
74 d->icons[
FluidicsPackChanged ] = QString::fromLatin1(
":/KDAB/kdchart/LeveyJennings/karo_blue.svg" );
75 d->icons[
OkDataPoint ] = QString::fromLatin1(
":/KDAB/kdchart/LeveyJennings/circle_blue.svg" );
76 d->icons[
NotOkDataPoint ] = QString::fromLatin1(
":/KDAB/kdchart/LeveyJennings/circle_blue_red.svg" );
78 setSelectionMode( QAbstractItemView::SingleSelection );
96 if ( other ==
this )
return true;
115 if (
d->lotChangedPosition == pos )
118 d->lotChangedPosition = pos;
127 return d->lotChangedPosition;
136 if (
d->fluidicsPackChangedPosition == pos )
139 d->fluidicsPackChangedPosition = pos;
148 return d->fluidicsPackChangedPosition;
157 if (
d->sensorChangedPosition == pos )
160 d->sensorChangedPosition = pos;
169 return d->sensorChangedPosition;
177 if (
d->fluidicsPackChanges == changes )
180 d->fluidicsPackChanges = changes;
189 return d->fluidicsPackChanges;
197 if (
d->sensorChanges == changes )
200 d->sensorChanges = changes;
209 if (
d->scanLinePen == pen )
212 d->scanLinePen =
pen;
221 return d->scanLinePen;
237 if (
d->icons[ symbol ] == filename )
240 delete d->iconRenderer[
symbol ];
253 return d->sensorChanges;
261 if (
d->expectedMeanValue == meanValue )
264 d->expectedMeanValue = meanValue;
274 return d->expectedMeanValue;
282 if (
d->expectedStandardDeviation == sd )
285 d->expectedStandardDeviation = sd;
295 return d->expectedStandardDeviation;
303 return d->calculatedMeanValue;
311 return d->calculatedStandardDeviation;
316 if ( this->model() != 0 )
318 disconnect( this->model(), SIGNAL(
dataChanged(
const QModelIndex&,
const QModelIndex& ) ),
320 disconnect( this->model(), SIGNAL( rowsInserted(
const QModelIndex&,
int,
int ) ),
322 disconnect( this->model(), SIGNAL( rowsRemoved(
const QModelIndex&,
int,
int ) ),
324 disconnect( this->model(), SIGNAL( columnsInserted(
const QModelIndex&,
int,
int ) ),
326 disconnect( this->model(), SIGNAL( columnsRemoved(
const QModelIndex&,
int,
int ) ),
328 disconnect( this->model(), SIGNAL( modelReset() ),
334 if ( this->model() != 0 )
336 connect( this->model(), SIGNAL(
dataChanged(
const QModelIndex&,
const QModelIndex& ) ),
338 connect( this->model(), SIGNAL( rowsInserted(
const QModelIndex&,
int,
int ) ),
340 connect( this->model(), SIGNAL( rowsRemoved(
const QModelIndex&,
int,
int ) ),
342 connect( this->model(), SIGNAL( columnsInserted(
const QModelIndex&,
int,
int ) ),
344 connect( this->model(), SIGNAL( columnsRemoved(
const QModelIndex&,
int,
int ) ),
346 connect( this->model(), SIGNAL( modelReset() ),
361 const QAbstractItemModel& m = *model();
362 const int rowCount = m.rowCount( rootIndex() );
364 for (
int row = 0; row < rowCount; ++row )
366 const QVariant var = m.data( m.index( row, 1, rootIndex() ) );
367 if ( !var.isValid() )
369 const qreal value = var.toReal();
370 if ( ISNAN( value ) )
376 qreal sumSquares = 0.0;
377 KDAB_FOREACH( qreal value, values )
380 sumSquares += value * value;
383 const int N = values.count();
385 d->calculatedMeanValue = sum / N;
386 d->calculatedStandardDeviation = sqrt( ( static_cast< qreal >( N ) * sumSquares - sum * sum ) / ( N * ( N - 1 ) ) );
398 QDate result = dt.date();
400 if ( QDateTime( result, QTime() ) < dt )
401 result = result.addDays( 1 );
409 return QDateTime( dt.date(), QTime( dt.time().hour(), 0 ) );
415 QDateTime result( dt.date(), QTime( dt.time().hour(), 0 ) );
418 result = result.addSecs( 3600 );
426 const qreal yMin =
d->expectedMeanValue - 4 *
d->expectedStandardDeviation;
427 const qreal yMax =
d->expectedMeanValue + 4 *
d->expectedStandardDeviation;
433 const unsigned int minTime = range.first.toTime_t();
434 const unsigned int maxTime = range.second.toTime_t();
436 const qreal xMin = minTime /
static_cast< qreal
>( 24 * 60 * 60 );
437 const qreal xMax = maxTime /
static_cast< qreal
>( 24 * 60 * 60 ) - xMin;
439 const QPointF bottomLeft( QPointF( 0, yMin ) );
440 const QPointF topRight( QPointF( xMax, yMax ) );
453 const QAbstractItemModel& m = *model();
454 const int rowCount = m.rowCount( rootIndex() );
456 const QDateTime begin = m.data( m.index( 0, 3, rootIndex() ) ).toDateTime();
457 const QDateTime end = m.data( m.index( rowCount - 1, 3, rootIndex() ) ).toDateTime();
459 if ( begin.secsTo( end ) > 86400 )
463 const QDate min =
floorDay( begin );
464 const QDate max =
ceilDay( end );
467 else if ( begin.secsTo( end ) > 3600 )
471 const QDateTime min =
floorHour( begin );
472 const QDateTime max =
ceilHour( end );
484 if (
d->timeRange == timeRange )
496 const unsigned int minTime =
timeRange().first.toTime_t();
498 KDAB_FOREACH(
const QDateTime& dt,
d->fluidicsPackChanges )
500 const qreal xValue = ( dt.toTime_t() - minTime ) / static_cast< qreal >( 24 * 60 * 60 );
501 const QPointF point( xValue, 0.0 );
505 KDAB_FOREACH(
const QDateTime& dt,
d->sensorChanges )
507 const qreal xValue = ( dt.toTime_t() - minTime ) / static_cast< qreal >( 24 * 60 * 60 );
508 const QPointF point( xValue, 0.0 );
516 d->reverseMapper.clear();
523 QPainter*
const painter = ctx->
painter();
524 const PainterSaver p( painter );
525 if ( model()->rowCount( rootIndex() ) == 0 || model()->columnCount( rootIndex() ) < 4 )
531 const QAbstractItemModel& m = *model();
532 const int rowCount = m.rowCount( rootIndex() );
534 const unsigned int minTime =
timeRange().first.toTime_t();
536 painter->setRenderHint( QPainter::Antialiasing,
true );
540 bool hadMissingValue =
false;
542 for (
int row = 0; row < rowCount; ++row )
544 const QModelIndex lotIndex = m.index( row, 0, rootIndex() );
545 const QModelIndex valueIndex = m.index( row, 1, rootIndex() );
546 const QModelIndex okIndex = m.index( row, 2, rootIndex() );
547 const QModelIndex timeIndex = m.index( row, 3, rootIndex() );
548 const QModelIndex expectedMeanIndex = m.index( row, 4, rootIndex() );
549 const QModelIndex expectedSDIndex = m.index( row, 5, rootIndex() );
551 painter->setPen(
pen( lotIndex ) );
553 QVariant vValue = m.data( valueIndex );
554 qreal value = vValue.toReal();
555 const int lot = m.data( lotIndex ).toInt();
556 const bool ok = m.data( okIndex ).toBool();
557 const QDateTime time = m.data( timeIndex ).toDateTime();
558 const qreal xValue = ( time.toTime_t() - minTime ) / static_cast< qreal >( 24 * 60 * 60 );
560 QVariant vExpectedMean = m.data( expectedMeanIndex );
561 const qreal expectedMean = vExpectedMean.toReal();
562 QVariant vExpectedSD = m.data( expectedSDIndex );
563 const qreal expectedSD = vExpectedSD.toReal();
567 if ( vValue.isNull() )
569 hadMissingValue =
true;
573 if ( !vExpectedMean.isNull() && !vExpectedSD.isNull() )
576 value -= expectedMean;
578 value *=
d->expectedStandardDeviation;
579 value +=
d->expectedMeanValue;
583 if ( prevLot == lot )
585 const QPen
pen = painter->pen();
588 if ( hadMissingValue )
593 painter->setPen( newPen );
594 painter->drawLine( prevPoint, point );
595 painter->setPen( pen );
604 value >=
d->expectedMeanValue - 4 *
d->expectedStandardDeviation )
606 const QPointF location( xValue, value );
608 d->reverseMapper.addCircle( valueIndex.row(),
615 hadMissingValue =
false;
618 const QModelIndex current = selectionModel()->currentIndex();
619 if ( selectionModel()->rowIntersectsSelection( lotIndex.row(), lotIndex.parent() ) || current.sibling( current.row(), 0 ) == lotIndex )
622 painter->setPen(
d->scanLinePen );
624 d->expectedStandardDeviation ) ),
626 d->expectedStandardDeviation ) ) );
627 painter->setPen( pen );
645 QPainter*
const painter = ctx->
painter();
646 const PainterSaver ps( painter );
648 painter->translate( transPos );
650 painter->setClipping(
false );
662 QPointF( pos.x(),
d->lotChangedPosition & Qt::AlignTop ?
d->expectedMeanValue +
663 4 *
d->expectedStandardDeviation
664 :
d->expectedMeanValue -
665 4 *
d->expectedStandardDeviation ) );
668 QPainter*
const painter = ctx->
painter();
669 const PainterSaver ps( painter );
670 painter->setClipping(
false );
671 painter->translate( transPos );
683 QPointF( pos.x(),
d->sensorChangedPosition & Qt::AlignTop ?
d->expectedMeanValue +
684 4 *
d->expectedStandardDeviation
685 :
d->expectedMeanValue -
686 4 *
d->expectedStandardDeviation ) );
688 QPainter*
const painter = ctx->
painter();
689 const PainterSaver ps( painter );
690 painter->setClipping(
false );
691 painter->translate( transPos );
703 QPointF( pos.x(),
d->fluidicsPackChangedPosition & Qt::AlignTop ?
d->expectedMeanValue +
704 4 *
d->expectedStandardDeviation
705 :
d->expectedMeanValue -
706 4 *
d->expectedStandardDeviation ) );
708 QPainter*
const painter = ctx->
painter();
709 const PainterSaver ps( painter );
710 painter->setClipping(
false );
711 painter->translate( transPos );
724 const qreal height = fm.height() / 1.2;
725 return QRectF( -height / 2.0, -height / 2.0, height, height );
733 if (
d->iconRenderer[ symbol ] == 0 )
734 d->iconRenderer[
symbol ] =
new QSvgRenderer(
d->icons[ symbol ],
this );
736 return d->iconRenderer[
symbol ];