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