KD Chart 2  [rev.2.5]
KDChartPlotter.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/