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 "KDChartLeveyJenningsAxis.h"
00027 #include "KDChartLeveyJenningsAxis_p.h"
00028
00029 #include <QDateTime>
00030 #include <QPainter>
00031
00032 #include "KDChartPaintContext.h"
00033 #include "KDChartChart.h"
00034 #include "KDChartAbstractCartesianDiagram.h"
00035 #include "KDChartAbstractGrid.h"
00036 #include "KDChartPainterSaver_p.h"
00037 #include "KDChartLayoutItems.h"
00038 #include "KDChartPrintingParameters.h"
00039
00040 #include <KDABLibFakes>
00041
00042 #include <limits>
00043
00044 using namespace KDChart;
00045
00046 #define d (d_func())
00047
00048 LeveyJenningsAxis::LeveyJenningsAxis ( LeveyJenningsDiagram* diagram )
00049 : CartesianAxis ( new Private( diagram, this ), diagram )
00050 {
00051 init();
00052 }
00053
00054 LeveyJenningsAxis::~LeveyJenningsAxis ()
00055 {
00056
00057
00058 while ( d->mDiagram ) {
00059 LeveyJenningsDiagram *cd = qobject_cast< LeveyJenningsDiagram* >( d->mDiagram );
00060 cd->takeAxis( this );
00061 }
00062 Q_FOREACH( AbstractDiagram *diagram, d->secondaryDiagrams ) {
00063 LeveyJenningsDiagram *cd = qobject_cast< LeveyJenningsDiagram* >( diagram );
00064 cd->takeAxis( this );
00065 }
00066 }
00067
00068 void LeveyJenningsAxis::init ()
00069 {
00070 setType( LeveyJenningsGridAttributes::Expected );
00071 setDateFormat( Qt::TextDate );
00072 const QStringList labels = QStringList() << tr( "-3sd" ) << tr( "-2sd" ) << tr( "mean" )
00073 << tr( "+2sd" ) << tr( "+3sd" );
00074
00075 setLabels( labels );
00076 }
00077
00081 LeveyJenningsGridAttributes::GridType LeveyJenningsAxis::type() const
00082 {
00083 return d->type;
00084 }
00085
00095 void LeveyJenningsAxis::setType( LeveyJenningsGridAttributes::GridType type )
00096 {
00097 if( type != d->type )
00098 {
00099 TextAttributes ta = textAttributes();
00100 QPen pen = ta.pen();
00101 QColor color = type == LeveyJenningsGridAttributes::Expected ? Qt::black : Qt::blue;
00102 if( qobject_cast< const LeveyJenningsDiagram* >( d->diagram() ) &&
00103 qobject_cast< const LeveyJenningsCoordinatePlane* >( d->diagram()->coordinatePlane() ) )
00104 {
00105 color = qobject_cast< const LeveyJenningsCoordinatePlane* >( d->diagram()->coordinatePlane() )->gridAttributes().gridPen( type ).color();
00106 }
00107 pen.setColor( color );
00108 ta.setPen( pen );
00109 setTextAttributes( ta );
00110 }
00111 d->type = type;
00112 }
00113
00114 Qt::DateFormat LeveyJenningsAxis::dateFormat() const
00115 {
00116 return d->format;
00117 }
00118
00119 void LeveyJenningsAxis::setDateFormat(Qt::DateFormat format)
00120 {
00121 d->format = format;
00122 }
00123
00124 bool LeveyJenningsAxis::compare( const LeveyJenningsAxis* other )const
00125 {
00126 if( other == this ) return true;
00127 if( ! other ){
00128
00129 return false;
00130 }
00131 return ( static_cast<const CartesianAxis*>(this)->compare( other ) ) &&
00132 ( type() == other->type() );
00133 }
00134
00135 void LeveyJenningsAxis::paintCtx( PaintContext* context )
00136 {
00137
00138 Q_ASSERT_X ( d->diagram(), "LeveyJenningsAxis::paint",
00139 "Function call not allowed: The axis is not assigned to any diagram." );
00140
00141 LeveyJenningsCoordinatePlane* plane = dynamic_cast<LeveyJenningsCoordinatePlane*>(context->coordinatePlane());
00142 Q_ASSERT_X ( plane, "LeveyJenningsAxis::paint",
00143 "Bad function call: PaintContext::coodinatePlane() NOT a levey jennings plane." );
00144
00145
00146
00147 if( ! d->diagram()->model() )
00148 return;
00149
00150 if( isOrdinate() )
00151 paintAsOrdinate( context );
00152 else
00153 paintAsAbscissa( context );
00154 }
00155
00156 void LeveyJenningsAxis::paintAsOrdinate( PaintContext* context )
00157 {
00158 const LeveyJenningsDiagram* const diag = dynamic_cast< const LeveyJenningsDiagram* >( d->diagram() );
00159
00160 Q_ASSERT( isOrdinate() );
00161 LeveyJenningsCoordinatePlane* plane = dynamic_cast<LeveyJenningsCoordinatePlane*>(context->coordinatePlane());
00162
00163 const qreal meanValue = type() == LeveyJenningsGridAttributes::Expected ? diag->expectedMeanValue()
00164 : diag->calculatedMeanValue();
00165 const qreal standardDeviation = type() == LeveyJenningsGridAttributes::Expected ? diag->expectedStandardDeviation()
00166 : diag->calculatedStandardDeviation();
00167 const TextAttributes labelTA = textAttributes();
00168 const bool drawLabels = labelTA.isVisible();
00169
00170
00171 if( !drawLabels )
00172 return;
00173
00174 const QObject* referenceArea = plane->parent();
00175
00176 const QVector< qreal > values = QVector< qreal >() << ( meanValue - 3 * standardDeviation )
00177 << ( meanValue - 2 * standardDeviation )
00178 << ( meanValue )
00179 << ( meanValue + 2 * standardDeviation )
00180 << ( meanValue + 3 * standardDeviation );
00181
00182 Q_ASSERT_X( values.count() <= labels().count(), "LeveyJenningsAxis::paintAsOrdinate", "Need to have at least 5 labels" );
00183
00184 TextLayoutItem labelItem( tr( "mean" ),
00185 labelTA,
00186 referenceArea,
00187 KDChartEnums::MeasureOrientationMinimum,
00188 Qt::AlignLeft );
00189
00190 QPainter* const painter = context->painter();
00191 const PainterSaver ps( painter );
00192 painter->setRenderHint( QPainter::Antialiasing, true );
00193 painter->setClipping( false );
00194
00195 painter->setPen ( PrintingParameters::scalePen( labelTA.pen() ) );
00196
00197 for( int i = 0; i < values.count(); ++i )
00198 {
00199 const QPointF labelPos = plane->translate( QPointF( 0.0, values.at( i ) ) );
00200 const QString label = customizedLabel( labels().at( i ) );
00201 labelItem.setText( label );
00202 const QSize size = labelItem.sizeHint();
00203 const float xPos = position() == Left ? geometry().right() - size.width() : geometry().left();
00204 labelItem.setGeometry( QRectF( QPointF( xPos, labelPos.y() - size.height() / 2.0 ), size ).toRect() );
00205
00206
00207 if( values.at( i ) > diag->expectedMeanValue() + 4 * diag->expectedStandardDeviation() )
00208 continue;
00209
00210 if( values.at( i ) < diag->expectedMeanValue() - 4 * diag->expectedStandardDeviation() )
00211 continue;
00212
00213 labelItem.paint( painter );
00214 }
00215 }
00216
00217 void LeveyJenningsAxis::paintAsAbscissa( PaintContext* context )
00218 {
00219 Q_ASSERT( isAbscissa() );
00220
00221
00222 setLabels( QStringList() << QString::fromLatin1( " " ) );
00223 CartesianAxis::paintCtx( context );
00224
00225 const LeveyJenningsDiagram* const diag = dynamic_cast< const LeveyJenningsDiagram* >( d->diagram() );
00226 LeveyJenningsCoordinatePlane* plane = dynamic_cast<LeveyJenningsCoordinatePlane*>(context->coordinatePlane());
00227
00228 const QObject* referenceArea = plane->parent();
00229 const TextAttributes labelTA = textAttributes();
00230
00231 const bool drawLabels = labelTA.isVisible();
00232
00233 if( !drawLabels )
00234 return;
00235
00236
00237 const QPair< QDateTime, QDateTime > range = diag->timeRange();
00238
00239 QPainter* const painter = context->painter();
00240 const PainterSaver ps( painter );
00241 painter->setRenderHint( QPainter::Antialiasing, true );
00242 painter->setClipping( false );
00243
00244
00245 TextLayoutItem labelItem( range.first.date().toString( dateFormat() ),
00246 labelTA,
00247 referenceArea,
00248 KDChartEnums::MeasureOrientationMinimum,
00249 Qt::AlignLeft );
00250 QSize origSize = labelItem.sizeHint();
00251 if( range.first.secsTo( range.second ) < 86400 )
00252 labelItem = TextLayoutItem( range.first.toString( dateFormat() ),
00253 labelTA,
00254 referenceArea,
00255 KDChartEnums::MeasureOrientationMinimum,
00256 Qt::AlignLeft );
00257 QSize size = labelItem.sizeHint();
00258
00259 float yPos = position() == Bottom ? geometry().bottom() - size.height() : geometry().top();
00260 labelItem.setGeometry( QRectF( QPointF( geometry().left() - origSize.width() / 2.0, yPos ), size ).toRect() );
00261 labelItem.paint( painter );
00262
00263
00264 TextLayoutItem labelItem2( range.second.date().toString( dateFormat() ),
00265 labelTA,
00266 referenceArea,
00267 KDChartEnums::MeasureOrientationMinimum,
00268 Qt::AlignLeft );
00269 origSize = labelItem2.sizeHint();
00270 if( range.first.secsTo( range.second ) < 86400 )
00271 labelItem2 = TextLayoutItem( range.second.toString( dateFormat() ),
00272 labelTA,
00273 referenceArea,
00274 KDChartEnums::MeasureOrientationMinimum,
00275 Qt::AlignLeft );
00276 size = labelItem2.sizeHint();
00277 yPos = position() == Bottom ? geometry().bottom() - size.height() : geometry().top();
00278 labelItem2.setGeometry( QRectF( QPointF( geometry().right() - size.width() + origSize.width() / 2.0, yPos ), size ).toRect() );
00279 labelItem2.paint( painter );
00280 }