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