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 "KDChartPlotter.h" 00024 #include "KDChartPlotter_p.h" 00025 00026 #include "KDChartAbstractGrid.h" 00027 #include "KDChartPainterSaver_p.h" 00028 00029 #include <KDABLibFakes> 00030 00031 #include "KDChartNormalPlotter_p.h" 00032 #include "KDChartPercentPlotter_p.h" 00033 00034 using namespace KDChart; 00035 00036 Plotter::Private::Private() 00037 : implementor( 0 ) 00038 , normalPlotter( 0 ) 00039 , percentPlotter( 0 ) 00040 { 00041 } 00042 00043 Plotter::Private::~Private() 00044 { 00045 delete normalPlotter; 00046 delete percentPlotter; 00047 } 00048 00049 00050 #define d d_func() 00051 00052 00053 Plotter::Plotter( QWidget* parent, CartesianCoordinatePlane* plane ) : 00054 AbstractCartesianDiagram( new Private(), parent, plane ) 00055 { 00056 init(); 00057 } 00058 00059 void Plotter::init() 00060 { 00061 d->diagram = this; 00062 d->normalPlotter = new NormalPlotter( this ); 00063 d->percentPlotter = new PercentPlotter( this ); 00064 d->implementor = d->normalPlotter; 00065 QObject* test = d->implementor->plotterPrivate(); 00066 bool connection = connect( this, SIGNAL( boundariesChanged() ), test, SLOT( changedProperties() ) ); 00067 Q_ASSERT( connection ); 00068 Q_UNUSED( connection ); 00069 00070 setDatasetDimensionInternal( 2 ); 00071 } 00072 00073 Plotter::~Plotter() 00074 { 00075 } 00076 00080 Plotter* Plotter::clone() const 00081 { 00082 Plotter* newDiagram = new Plotter( new Private( *d ) ); 00083 newDiagram->setType( type() ); 00084 return newDiagram; 00085 } 00086 00087 bool Plotter::compare( const Plotter* other ) const 00088 { 00089 if( other == this ) 00090 return true; 00091 if( other == 0 ) 00092 return false; 00093 return // compare the base class 00094 ( static_cast< const AbstractCartesianDiagram* >( this )->compare( other ) ) && 00095 // compare own properties 00096 ( type() == other->type() ); 00097 } 00098 00099 void Plotter::setModel( QAbstractItemModel *model ) 00100 { 00101 d->plotterCompressor.setModel( NULL ); 00102 AbstractCartesianDiagram::setModel( model ); 00103 if ( useDataCompression() != Plotter::NONE ) 00104 { 00105 d->compressor.setModel( NULL ); 00106 if ( attributesModel() != d->plotterCompressor.model() ) 00107 { 00108 d->plotterCompressor.setModel( attributesModel() ); 00109 connect( &d->plotterCompressor, SIGNAL( boundariesChanged() ), this, SLOT(setDataBoundariesDirty() ) ); 00110 if ( useDataCompression() != Plotter::SLOPE ) 00111 { 00112 connect( coordinatePlane(), SIGNAL( internal_geometryChanged( QRect,QRect ) ), this, SLOT( setDataBoundariesDirty() ), Qt::QueuedConnection ); 00113 connect( coordinatePlane(), SIGNAL( geometryChanged( QRect,QRect ) ), this, SLOT( setDataBoundariesDirty() ), Qt::QueuedConnection ); 00114 calcMergeRadius(); 00115 } 00116 } 00117 } 00118 } 00119 00120 Plotter::CompressionMode Plotter::useDataCompression() const 00121 { 00122 return d->implementor->useCompression(); 00123 } 00124 00125 void Plotter::setUseDataCompression( Plotter::CompressionMode value ) 00126 { 00127 if ( useDataCompression() != value ) 00128 { 00129 d->implementor->setUseCompression( value ); 00130 if ( useDataCompression() != Plotter::NONE ) 00131 { 00132 d->compressor.setModel( NULL ); 00133 if ( attributesModel() != d->plotterCompressor.model() ) 00134 d->plotterCompressor.setModel( attributesModel() ); 00135 } 00136 } 00137 } 00138 00139 qreal Plotter::maxSlopeChange() const 00140 { 00141 return d->plotterCompressor.maxSlopeChange(); 00142 } 00143 00144 void Plotter::setMaxSlopeChange( qreal value ) 00145 { 00146 d->plotterCompressor.setMaxSlopeChange( value ); 00147 } 00148 00149 qreal Plotter::mergeRadiusPercentage() const 00150 { 00151 return d->mergeRadiusPercentage; 00152 } 00153 00154 void Plotter::setMergeRadiusPercentage( qreal value ) 00155 { 00156 if ( d->mergeRadiusPercentage != value ) 00157 { 00158 d->mergeRadiusPercentage = value; 00159 //d->plotterCompressor.setMergeRadiusPercentage( value ); 00160 //update(); 00161 } 00162 } 00163 00167 void Plotter::setType( const PlotType type ) 00168 { 00169 if ( d->implementor->type() == type ) { 00170 return; 00171 } 00172 if ( datasetDimension() != 2 ) { 00173 Q_ASSERT_X ( false, "setType()", 00174 "This line chart type can only be used with two-dimensional data." ); 00175 return; 00176 } 00177 switch ( type ) { 00178 case Normal: 00179 d->implementor = d->normalPlotter; 00180 break; 00181 case Percent: 00182 d->implementor = d->percentPlotter; 00183 break; 00184 default: 00185 Q_ASSERT_X( false, "Plotter::setType", "unknown plotter subtype" ); 00186 } 00187 bool connection = connect( this, SIGNAL( boundariesChanged() ), 00188 d->implementor->plotterPrivate(), SLOT( changedProperties() ) ); 00189 Q_ASSERT( connection ); 00190 Q_UNUSED( connection ); 00191 00192 // d->lineType = type; 00193 Q_ASSERT( d->implementor->type() == type ); 00194 00195 setDataBoundariesDirty(); 00196 emit layoutChanged( this ); 00197 emit propertiesChanged(); 00198 } 00199 00203 Plotter::PlotType Plotter::type() const 00204 { 00205 return d->implementor->type(); 00206 } 00207 00211 void Plotter::setLineAttributes( const LineAttributes& la ) 00212 { 00213 d->attributesModel->setModelData( qVariantFromValue( la ), LineAttributesRole ); 00214 emit propertiesChanged(); 00215 } 00216 00220 void Plotter::setLineAttributes( int column, const LineAttributes& la ) 00221 { 00222 d->setDatasetAttrs( column, qVariantFromValue( la ), LineAttributesRole ); 00223 emit propertiesChanged(); 00224 } 00225 00229 void Plotter::resetLineAttributes( int column ) 00230 { 00231 d->resetDatasetAttrs( column, LineAttributesRole ); 00232 emit propertiesChanged(); 00233 } 00234 00238 void Plotter::setLineAttributes( const QModelIndex & index, const LineAttributes& la ) 00239 { 00240 d->attributesModel->setData( d->attributesModel->mapFromSource( index ), 00241 qVariantFromValue( la ), LineAttributesRole ); 00242 emit propertiesChanged(); 00243 } 00244 00248 void Plotter::resetLineAttributes( const QModelIndex & index ) 00249 { 00250 d->attributesModel->resetData( 00251 d->attributesModel->mapFromSource(index), LineAttributesRole ); 00252 emit propertiesChanged(); 00253 } 00254 00258 LineAttributes Plotter::lineAttributes() const 00259 { 00260 return qVariantValue<LineAttributes>( d->attributesModel->data( KDChart::LineAttributesRole ) ); 00261 } 00262 00266 LineAttributes Plotter::lineAttributes( int column ) const 00267 { 00268 const QVariant attrs( d->datasetAttrs( column, LineAttributesRole ) ); 00269 if( attrs.isValid() ) 00270 return qVariantValue< LineAttributes >( attrs ); 00271 return lineAttributes(); 00272 } 00273 00277 LineAttributes Plotter::lineAttributes( const QModelIndex& index ) const 00278 { 00279 return qVariantValue< LineAttributes >( d->attributesModel->data( 00280 d->attributesModel->mapFromSource( index ), KDChart::LineAttributesRole ) ); 00281 } 00282 00286 void Plotter::setThreeDLineAttributes( const ThreeDLineAttributes& la ) 00287 { 00288 setDataBoundariesDirty(); 00289 d->attributesModel->setModelData( qVariantFromValue( la ), ThreeDLineAttributesRole ); 00290 emit propertiesChanged(); 00291 } 00292 00296 void Plotter::setThreeDLineAttributes( int column, const ThreeDLineAttributes& la ) 00297 { 00298 setDataBoundariesDirty(); 00299 d->setDatasetAttrs( column, qVariantFromValue( la ), ThreeDLineAttributesRole ); 00300 emit propertiesChanged(); 00301 } 00302 00306 void Plotter::setThreeDLineAttributes( const QModelIndex& index, const ThreeDLineAttributes& la ) 00307 { 00308 setDataBoundariesDirty(); 00309 d->attributesModel->setData( d->attributesModel->mapFromSource( index ), qVariantFromValue( la ), 00310 ThreeDLineAttributesRole ); 00311 emit propertiesChanged(); 00312 } 00313 00317 ThreeDLineAttributes Plotter::threeDLineAttributes() const 00318 { 00319 return qVariantValue<ThreeDLineAttributes>( 00320 d->attributesModel->data( KDChart::ThreeDLineAttributesRole ) ); 00321 } 00322 00326 ThreeDLineAttributes Plotter::threeDLineAttributes( int column ) const 00327 { 00328 const QVariant attrs( d->datasetAttrs( column, ThreeDLineAttributesRole ) ); 00329 if( attrs.isValid() ) { 00330 return qVariantValue< ThreeDLineAttributes >( attrs ); 00331 } 00332 return threeDLineAttributes(); 00333 } 00334 00338 ThreeDLineAttributes Plotter::threeDLineAttributes( const QModelIndex& index ) const 00339 { 00340 return qVariantValue< ThreeDLineAttributes >( d->attributesModel->data( 00341 d->attributesModel->mapFromSource( index ), KDChart::ThreeDLineAttributesRole ) ); 00342 } 00343 00344 qreal Plotter::threeDItemDepth( const QModelIndex & index ) const 00345 { 00346 return threeDLineAttributes( index ).validDepth(); 00347 } 00348 00349 qreal Plotter::threeDItemDepth( int column ) const 00350 { 00351 return threeDLineAttributes( column ).validDepth(); 00352 } 00353 00357 void Plotter::setValueTrackerAttributes( const QModelIndex & index, const ValueTrackerAttributes & va ) 00358 { 00359 d->attributesModel->setData( d->attributesModel->mapFromSource( index ), 00360 qVariantFromValue( va ), KDChart::ValueTrackerAttributesRole ); 00361 emit propertiesChanged(); 00362 } 00363 00367 ValueTrackerAttributes Plotter::valueTrackerAttributes( const QModelIndex & index ) const 00368 { 00369 return qVariantValue<ValueTrackerAttributes>( d->attributesModel->data( 00370 d->attributesModel->mapFromSource( index ), KDChart::ValueTrackerAttributesRole ) ); 00371 } 00372 00373 void Plotter::resizeEvent ( QResizeEvent* ) 00374 { 00375 } 00376 00377 const QPair< QPointF, QPointF > Plotter::calculateDataBoundaries() const 00378 { 00379 if ( !checkInvariants( true ) ) 00380 return QPair< QPointF, QPointF >( QPointF( 0, 0 ), QPointF( 0, 0 ) ); 00381 00382 // note: calculateDataBoundaries() is ignoring the hidden flags. 00383 // That's not a bug but a feature: Hiding data does not mean removing them. 00384 // For totally removing data from KD Chart's view people can use e.g. a proxy model ... 00385 00386 // calculate boundaries for different line types Normal - Stacked - Percent - Default Normal 00387 return d->implementor->calculateDataBoundaries(); 00388 } 00389 00390 00391 void Plotter::paintEvent ( QPaintEvent*) 00392 { 00393 QPainter painter ( viewport() ); 00394 PaintContext ctx; 00395 ctx.setPainter ( &painter ); 00396 ctx.setRectangle ( QRectF ( 0, 0, width(), height() ) ); 00397 paint ( &ctx ); 00398 } 00399 00400 void Plotter::paint( PaintContext* ctx ) 00401 { 00402 // note: Not having any data model assigned is no bug 00403 // but we can not draw a diagram then either. 00404 if ( !checkInvariants( true ) ) return; 00405 00406 AbstractCoordinatePlane* const plane = ctx->coordinatePlane(); 00407 if( ! plane ) return; 00408 d->setCompressorResolution( size(), plane ); 00409 00410 if ( !AbstractGrid::isBoundariesValid(dataBoundaries()) ) return; 00411 00412 const PainterSaver p( ctx->painter() ); 00413 if( model()->rowCount( rootIndex() ) == 0 || model()->columnCount( rootIndex() ) == 0 ) 00414 return; // nothing to paint for us 00415 00416 ctx->setCoordinatePlane( plane->sharedAxisMasterPlane( ctx->painter() ) ); 00417 00418 // paint different line types Normal - Stacked - Percent - Default Normal 00419 d->implementor->paint( ctx ); 00420 00421 ctx->setCoordinatePlane( plane ); 00422 } 00423 00424 void Plotter::resize ( const QSizeF& size ) 00425 { 00426 d->setCompressorResolution( size, coordinatePlane() ); 00427 if ( useDataCompression() == Plotter::BOTH || useDataCompression() == Plotter::DISTANCE ) 00428 { 00429 d->plotterCompressor.cleanCache(); 00430 calcMergeRadius(); 00431 } 00432 setDataBoundariesDirty(); 00433 } 00434 00435 void Plotter::setDataBoundariesDirty() 00436 { 00437 AbstractCartesianDiagram::setDataBoundariesDirty(); 00438 if ( useDataCompression() == Plotter::DISTANCE || useDataCompression() == Plotter::BOTH ) 00439 { 00440 calcMergeRadius(); 00441 //d->plotterCompressor.setMergeRadiusPercentage( d->mergeRadiusPercentage ); 00442 } 00443 } 00444 00445 void Plotter::calcMergeRadius() 00446 { 00447 CartesianCoordinatePlane *plane = dynamic_cast< CartesianCoordinatePlane* >( coordinatePlane() ); 00448 Q_ASSERT( plane ); 00449 //Q_ASSERT( plane->translate( plane->translateBack( plane->visibleDiagramArea().topLeft() ) ) == plane->visibleDiagramArea().topLeft() ); 00450 QRectF range = plane->visibleDataRange(); 00451 //qDebug() << range; 00452 const qreal radius = std::sqrt( ( range.x() + range.width() ) * ( range.y() + range.height() ) ); 00453 //qDebug() << radius; 00454 //qDebug() << radius * d->mergeRadiusPercentage; 00455 //qDebug() << d->mergeRadiusPercentage; 00456 d->plotterCompressor.setMergeRadius( radius * d->mergeRadiusPercentage ); 00457 } 00458 00459 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE) 00460 const 00461 #endif 00462 int Plotter::numberOfAbscissaSegments () const 00463 { 00464 return d->attributesModel->rowCount( attributesModelRootIndex() ); 00465 } 00466 00467 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE) 00468 const 00469 #endif 00470 int Plotter::numberOfOrdinateSegments () const 00471 { 00472 return d->attributesModel->columnCount( attributesModelRootIndex() ); 00473 }