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 "KDChartLineDiagram.h" 00024 #include "KDChartLineDiagram_p.h" 00025 00026 #include "KDChartBarDiagram.h" 00027 #include "KDChartPalette.h" 00028 #include "KDChartPosition.h" 00029 #include "KDChartTextAttributes.h" 00030 #include "KDChartAttributesModel.h" 00031 #include "KDChartAbstractGrid.h" 00032 #include "KDChartDataValueAttributes.h" 00033 #include "KDChartPainterSaver_p.h" 00034 00035 #include <KDABLibFakes> 00036 00037 #include "KDChartNormalLineDiagram_p.h" 00038 #include "KDChartStackedLineDiagram_p.h" 00039 #include "KDChartPercentLineDiagram_p.h" 00040 00041 #include <QDebug> 00042 #include <QPainter> 00043 #include <QString> 00044 #include <QPainterPath> 00045 #include <QPen> 00046 #include <QVector> 00047 00048 using namespace KDChart; 00049 00050 LineDiagram::Private::Private() 00051 { 00052 } 00053 00054 LineDiagram::Private::~Private() {} 00055 00056 00057 #define d d_func() 00058 00059 00060 LineDiagram::LineDiagram( QWidget* parent, CartesianCoordinatePlane* plane ) : 00061 AbstractCartesianDiagram( new Private(), parent, plane ) 00062 { 00063 init(); 00064 } 00065 00066 void LineDiagram::init() 00067 { 00068 d->normalDiagram = new NormalLineDiagram( this ); 00069 d->stackedDiagram = new StackedLineDiagram( this ); 00070 d->percentDiagram = new PercentLineDiagram( this ); 00071 d->implementor = d->normalDiagram; 00072 d->centerDataPoints = false; 00073 d->reverseDatasetOrder = false; 00074 } 00075 00076 LineDiagram::~LineDiagram() 00077 { 00078 delete d->normalDiagram; 00079 delete d->stackedDiagram; 00080 delete d->percentDiagram; 00081 } 00082 00086 LineDiagram * LineDiagram::clone() const 00087 { 00088 LineDiagram* newDiagram = new LineDiagram( new Private( *d ) ); 00089 newDiagram->setType( type() ); 00090 return newDiagram; 00091 } 00092 00093 00094 bool LineDiagram::compare( const LineDiagram* other ) const 00095 { 00096 if( other == this ) return true; 00097 if( ! other ){ 00098 return false; 00099 } 00100 return // compare the base class 00101 ( static_cast<const AbstractCartesianDiagram*>(this)->compare( other ) ) && 00102 // compare own properties 00103 (type() == other->type()) && 00104 (centerDataPoints() == other->centerDataPoints()) && 00105 (reverseDatasetOrder() == other->reverseDatasetOrder()); 00106 } 00107 00112 void LineDiagram::setType( const LineType type ) 00113 { 00114 if ( d->implementor->type() == type ) return; 00115 if ( type != LineDiagram::Normal && datasetDimension() > 1 ) { 00116 Q_ASSERT_X ( false, "setType()", 00117 "This line chart type can't be used with multi-dimensional data." ); 00118 return; 00119 } 00120 switch( type ) { 00121 case Normal: 00122 d->implementor = d->normalDiagram; 00123 break; 00124 case Stacked: 00125 d->implementor = d->stackedDiagram; 00126 break; 00127 case Percent: 00128 d->implementor = d->percentDiagram; 00129 break; 00130 default: 00131 Q_ASSERT_X( false, "LineDiagram::setType", "unknown diagram subtype" ); 00132 }; 00133 00134 // d->lineType = type; 00135 Q_ASSERT( d->implementor->type() == type ); 00136 00137 // AbstractAxis settings - see AbstractDiagram and CartesianAxis 00138 setPercentMode( type == LineDiagram::Percent ); 00139 setDataBoundariesDirty(); 00140 emit layoutChanged( this ); 00141 emit propertiesChanged(); 00142 } 00143 00147 LineDiagram::LineType LineDiagram::type() const 00148 { 00149 return d->implementor->type(); 00150 } 00151 00152 void LineDiagram::setCenterDataPoints( bool center ) 00153 { 00154 d->centerDataPoints = center; 00155 emit propertiesChanged(); 00156 } 00157 00158 bool LineDiagram::centerDataPoints() const 00159 { 00160 return d->centerDataPoints; 00161 } 00162 00163 void LineDiagram::setReverseDatasetOrder( bool reverse ) 00164 { 00165 d->reverseDatasetOrder = reverse; 00166 } 00167 00168 bool LineDiagram::reverseDatasetOrder() const 00169 { 00170 return d->reverseDatasetOrder; 00171 } 00172 00176 void LineDiagram::setLineAttributes( const LineAttributes& la ) 00177 { 00178 d->attributesModel->setModelData( 00179 qVariantFromValue( la ), 00180 LineAttributesRole ); 00181 emit propertiesChanged(); 00182 } 00183 00187 void LineDiagram::setLineAttributes( 00188 int column, 00189 const LineAttributes& la ) 00190 { 00191 d->setDatasetAttrs( column, qVariantFromValue( la ), LineAttributesRole ); 00192 emit propertiesChanged(); 00193 } 00194 00198 void LineDiagram::resetLineAttributes( int column ) 00199 { 00200 d->resetDatasetAttrs( column, LineAttributesRole ); 00201 emit propertiesChanged(); 00202 } 00203 00207 void LineDiagram::setLineAttributes( 00208 const QModelIndex& index, 00209 const LineAttributes& la ) 00210 { 00211 d->attributesModel->setData( 00212 d->attributesModel->mapFromSource(index), 00213 qVariantFromValue( la ), 00214 LineAttributesRole ); 00215 emit propertiesChanged(); 00216 } 00217 00221 void LineDiagram::resetLineAttributes( const QModelIndex & index ) 00222 { 00223 d->attributesModel->resetData( 00224 d->attributesModel->mapFromSource(index), LineAttributesRole ); 00225 emit propertiesChanged(); 00226 } 00227 00231 LineAttributes LineDiagram::lineAttributes() const 00232 { 00233 return qVariantValue<LineAttributes>( 00234 d->attributesModel->data( KDChart::LineAttributesRole ) ); 00235 } 00236 00240 LineAttributes LineDiagram::lineAttributes( int column ) const 00241 { 00242 const QVariant attrs( d->datasetAttrs( column, LineAttributesRole ) ); 00243 if( attrs.isValid() ) 00244 return qVariantValue< LineAttributes >( attrs ); 00245 return lineAttributes(); 00246 } 00247 00251 LineAttributes LineDiagram::lineAttributes( 00252 const QModelIndex& index ) const 00253 { 00254 return qVariantValue<LineAttributes>( 00255 d->attributesModel->data( 00256 d->attributesModel->mapFromSource(index), 00257 KDChart::LineAttributesRole ) ); 00258 } 00259 00263 void LineDiagram::setThreeDLineAttributes( 00264 const ThreeDLineAttributes& la ) 00265 { 00266 setDataBoundariesDirty(); 00267 d->attributesModel->setModelData( 00268 qVariantFromValue( la ), 00269 ThreeDLineAttributesRole ); 00270 emit propertiesChanged(); 00271 } 00272 00276 void LineDiagram::setThreeDLineAttributes( 00277 int column, 00278 const ThreeDLineAttributes& la ) 00279 { 00280 setDataBoundariesDirty(); 00281 d->setDatasetAttrs( column, qVariantFromValue( la ), ThreeDLineAttributesRole ); 00282 emit propertiesChanged(); 00283 } 00284 00288 void LineDiagram::setThreeDLineAttributes( 00289 const QModelIndex & index, 00290 const ThreeDLineAttributes& la ) 00291 { 00292 setDataBoundariesDirty(); 00293 d->attributesModel->setData( 00294 d->attributesModel->mapFromSource(index), 00295 qVariantFromValue( la ), 00296 ThreeDLineAttributesRole ); 00297 emit propertiesChanged(); 00298 } 00299 00303 ThreeDLineAttributes LineDiagram::threeDLineAttributes() const 00304 { 00305 return qVariantValue<ThreeDLineAttributes>( 00306 d->attributesModel->data( KDChart::ThreeDLineAttributesRole ) ); 00307 } 00308 00312 ThreeDLineAttributes LineDiagram::threeDLineAttributes( int column ) const 00313 { 00314 const QVariant attrs( d->datasetAttrs( column, ThreeDLineAttributesRole ) ); 00315 if( attrs.isValid() ) 00316 return qVariantValue< ThreeDLineAttributes >( attrs ); 00317 return threeDLineAttributes(); 00318 } 00319 00323 ThreeDLineAttributes LineDiagram::threeDLineAttributes( const QModelIndex& index ) const 00324 { 00325 return qVariantValue<ThreeDLineAttributes>( 00326 d->attributesModel->data( 00327 d->attributesModel->mapFromSource( index ), 00328 KDChart::ThreeDLineAttributesRole ) ); 00329 } 00330 00331 qreal LineDiagram::threeDItemDepth( const QModelIndex& index ) const 00332 { 00333 return threeDLineAttributes( index ).validDepth(); 00334 } 00335 00336 qreal LineDiagram::threeDItemDepth( int column ) const 00337 { 00338 return threeDLineAttributes( column ).validDepth(); 00339 } 00340 00344 void LineDiagram::setValueTrackerAttributes( const QModelIndex & index, 00345 const ValueTrackerAttributes & va ) 00346 { 00347 d->attributesModel->setData( d->attributesModel->mapFromSource(index), 00348 qVariantFromValue( va ), 00349 KDChart::ValueTrackerAttributesRole ); 00350 emit propertiesChanged(); 00351 } 00352 00356 ValueTrackerAttributes LineDiagram::valueTrackerAttributes( 00357 const QModelIndex & index ) const 00358 { 00359 return qVariantValue<ValueTrackerAttributes>( d->attributesModel->data( 00360 d->attributesModel->mapFromSource( index ), 00361 KDChart::ValueTrackerAttributesRole ) ); 00362 } 00363 00364 void LineDiagram::resizeEvent ( QResizeEvent* ) 00365 { 00366 } 00367 00368 const QPair<QPointF, QPointF> LineDiagram::calculateDataBoundaries() const 00369 { 00370 d->compressor.setResolution( static_cast<int>( this->size().width() * coordinatePlane()->zoomFactorX() ), 00371 static_cast<int>( this->size().height() * coordinatePlane()->zoomFactorY() ) ); 00372 00373 if ( !checkInvariants( true ) ) return QPair<QPointF, QPointF>( QPointF( 0, 0 ), QPointF( 0, 0 ) ); 00374 00375 // note: calculateDataBoundaries() is ignoring the hidden flags. 00376 // That's not a bug but a feature: Hiding data does not mean removing them. 00377 // For totally removing data from KD Chart's view people can use e.g. a proxy model ... 00378 00379 // calculate boundaries for different line types Normal - Stacked - Percent - Default Normal 00380 return d->implementor->calculateDataBoundaries(); 00381 } 00382 00383 00384 void LineDiagram::paintEvent ( QPaintEvent*) 00385 { 00386 QPainter painter ( viewport() ); 00387 PaintContext ctx; 00388 ctx.setPainter ( &painter ); 00389 ctx.setRectangle ( QRectF ( 0, 0, width(), height() ) ); 00390 paint ( &ctx ); 00391 } 00392 00393 00394 qreal LineDiagram::valueForCellTesting( int row, int column, 00395 bool& bOK, 00396 bool showHiddenCellsAsInvalid ) const 00397 { 00398 if ( !model()->hasIndex( row, column, rootIndex() ) ) { 00399 bOK = false; 00400 return 0.0; 00401 } 00402 qreal value; 00403 if( showHiddenCellsAsInvalid && isHidden( model()->index( row, column, rootIndex() ) ) ) // checked 00404 bOK = false; 00405 else 00406 value = d->attributesModel->data( 00407 d->attributesModel->index( row, column, attributesModelRootIndex() ) // checked 00408 ).toReal( &bOK ); 00409 return bOK ? value : 0.0; 00410 } 00411 00412 LineAttributes::MissingValuesPolicy LineDiagram::getCellValues( 00413 int row, int column, 00414 bool shiftCountedXValuesByHalfSection, 00415 qreal& valueX, qreal& valueY ) const 00416 { 00417 LineAttributes::MissingValuesPolicy policy = LineAttributes::MissingValuesPolicyIgnored; 00418 00419 bool bOK = true; 00420 valueX = ( datasetDimension() > 1 && column > 0 ) 00421 ? valueForCellTesting( row, column-1, bOK, true ) 00422 : ((shiftCountedXValuesByHalfSection ? 0.5 : 0.0) + row); 00423 if( bOK ) 00424 valueY = valueForCellTesting( row, column, bOK, true ); 00425 else if ( model()->hasIndex( row, column, rootIndex() ) ) { 00426 // missing value: find out the policy 00427 QModelIndex index = model()->index( row, column, rootIndex() ); // checked 00428 LineAttributes la = lineAttributes( index ); 00429 policy = la.missingValuesPolicy(); 00430 } 00431 return policy; 00432 } 00433 00434 void LineDiagram::paint( PaintContext* ctx ) 00435 { 00436 // note: Not having any data model assigned is no bug 00437 // but we can not draw a diagram then either. 00438 if ( !checkInvariants( true ) ) return; 00439 if ( !AbstractGrid::isBoundariesValid(dataBoundaries()) ) return; 00440 const PainterSaver p( ctx->painter() ); 00441 if( model()->rowCount( rootIndex() ) == 0 || model()->columnCount( rootIndex() ) == 0 ) 00442 return; // nothing to paint for us 00443 00444 AbstractCoordinatePlane* const plane = ctx->coordinatePlane(); 00445 ctx->setCoordinatePlane( plane->sharedAxisMasterPlane( ctx->painter() ) ); 00446 00447 00448 // paint different line types Normal - Stacked - Percent - Default Normal 00449 d->implementor->paint( ctx ); 00450 00451 ctx->setCoordinatePlane( plane ); 00452 } 00453 00454 void LineDiagram::resize ( const QSizeF& size ) 00455 { 00456 d->compressor.setResolution( static_cast<int>( size.width() * coordinatePlane()->zoomFactorX() ), 00457 static_cast<int>( size.height() * coordinatePlane()->zoomFactorY() ) ); 00458 setDataBoundariesDirty(); 00459 } 00460 00461 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE) 00462 const 00463 #endif 00464 int LineDiagram::numberOfAbscissaSegments () const 00465 { 00466 return d->attributesModel->rowCount(attributesModelRootIndex()); 00467 } 00468 00469 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE) 00470 const 00471 #endif 00472 int LineDiagram::numberOfOrdinateSegments () const 00473 { 00474 return d->attributesModel->columnCount(attributesModelRootIndex()); 00475 }