KD Chart 2  [rev.2.5]
KDChartPolarDiagram.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 "KDChartPolarDiagram.h"
00024 #include "KDChartPolarDiagram_p.h"
00025 
00026 #include <QPainter>
00027 #include "KDChartAttributesModel.h"
00028 #include "KDChartPaintContext.h"
00029 #include "KDChartPainterSaver_p.h"
00030 #include "KDChartDataValueAttributes.h"
00031 
00032 #include <KDABLibFakes>
00033 
00034 using namespace KDChart;
00035 
00036 PolarDiagram::Private::Private() :
00037     rotateCircularLabels( false ),
00038     closeDatasets( false )
00039 {
00040 }
00041 
00042 PolarDiagram::Private::~Private() {}
00043 
00044 #define d d_func()
00045 
00046 PolarDiagram::PolarDiagram( QWidget* parent, PolarCoordinatePlane* plane ) :
00047     AbstractPolarDiagram( new Private( ), parent, plane )
00048 {
00049     //init();
00050 }
00051 
00052 PolarDiagram::~PolarDiagram()
00053 {
00054 }
00055 
00056 
00057 void PolarDiagram::init()
00058 {
00059     setShowDelimitersAtPosition( Position::Unknown, false );
00060     setShowDelimitersAtPosition( Position::Center, false );
00061     setShowDelimitersAtPosition( Position::NorthWest, false );
00062     setShowDelimitersAtPosition( Position::North, true );
00063     setShowDelimitersAtPosition( Position::NorthEast, false );
00064     setShowDelimitersAtPosition( Position::West, false );
00065     setShowDelimitersAtPosition( Position::East, false );
00066     setShowDelimitersAtPosition( Position::SouthWest, false );
00067     setShowDelimitersAtPosition( Position::South, true );
00068     setShowDelimitersAtPosition( Position::SouthEast, false );
00069     setShowDelimitersAtPosition( Position::Floating, false );
00070 
00071     setShowLabelsAtPosition( Position::Unknown, false );
00072     setShowLabelsAtPosition( Position::Center, false );
00073     setShowLabelsAtPosition( Position::NorthWest, false );
00074     setShowLabelsAtPosition( Position::North, true );
00075     setShowLabelsAtPosition( Position::NorthEast, false );
00076     setShowLabelsAtPosition( Position::West, false );
00077     setShowLabelsAtPosition( Position::East, false );
00078     setShowLabelsAtPosition( Position::SouthWest, false );
00079     setShowLabelsAtPosition( Position::South, true );
00080     setShowLabelsAtPosition( Position::SouthEast, false );
00081     setShowLabelsAtPosition( Position::Floating, false );
00082 }
00083 
00087 PolarDiagram * PolarDiagram::clone() const
00088 {
00089     PolarDiagram* newDiagram = new PolarDiagram( new Private( *d ) );
00090     // This needs to be copied after the fact
00091     newDiagram->d->showDelimitersAtPosition = d->showDelimitersAtPosition;
00092     newDiagram->d->showLabelsAtPosition = d->showLabelsAtPosition;
00093     newDiagram->d->rotateCircularLabels = d->rotateCircularLabels;
00094     newDiagram->d->closeDatasets = d->closeDatasets;
00095     return newDiagram;
00096 }
00097 
00098 const QPair<QPointF, QPointF> PolarDiagram::calculateDataBoundaries () const
00099 {
00100     if ( !checkInvariants(true) ) return QPair<QPointF, QPointF>( QPointF( 0, 0 ), QPointF( 0, 0 ) );
00101     const int rowCount = model()->rowCount(rootIndex());
00102     const int colCount = model()->columnCount(rootIndex());
00103     qreal xMin = 0.0;
00104     qreal xMax = colCount;
00105     qreal yMin = 0, yMax = 0;
00106     for ( int iCol=0; iCol<colCount; ++iCol ) {
00107         for ( int iRow=0; iRow< rowCount; ++iRow ) {
00108             qreal value = model()->data( model()->index( iRow, iCol, rootIndex() ) ).toReal(); // checked
00109             yMax = qMax( yMax, value );
00110             yMin = qMin( yMin, value );
00111         }
00112     }
00113     QPointF bottomLeft ( QPointF( xMin, yMin ) );
00114     QPointF topRight ( QPointF( xMax, yMax ) );
00115     return QPair<QPointF, QPointF> ( bottomLeft,  topRight );
00116 }
00117 
00118 
00119 
00120 void PolarDiagram::paintEvent ( QPaintEvent*)
00121 {
00122     QPainter painter ( viewport() );
00123     PaintContext ctx;
00124     ctx.setPainter ( &painter );
00125     ctx.setRectangle( QRectF ( 0, 0, width(), height() ) );
00126     paint ( &ctx );
00127 }
00128 
00129 void PolarDiagram::resizeEvent ( QResizeEvent*)
00130 {
00131 }
00132 
00133 void PolarDiagram::paintPolarMarkers( PaintContext* ctx, const QPolygonF& polygon )
00134 {
00135     Q_UNUSED(ctx);
00136     Q_UNUSED(polygon);
00137     // obsolete, since we are using real markers now!
00138 }
00139 
00140 void PolarDiagram::paint( PaintContext* ctx )
00141 {
00142     qreal dummy1, dummy2;
00143     paint( ctx, true,  dummy1, dummy2 );
00144     paint( ctx, false, dummy1, dummy2 );
00145 }
00146 
00147 void PolarDiagram::paint( PaintContext* ctx,
00148                           bool calculateListAndReturnScale,
00149                           qreal& newZoomX, qreal& newZoomY )
00150 {
00151     // note: Not having any data model assigned is no bug
00152     //       but we can not draw a diagram then either.
00153     if ( !checkInvariants(true) )
00154         return;
00155     d->reverseMapper.clear();
00156 
00157     const int rowCount = model()->rowCount( rootIndex() );
00158     const int colCount = model()->columnCount( rootIndex() );
00159 
00160     if( calculateListAndReturnScale ){
00161         // Check if all of the data value texts / data comments fit into the available space...
00162         d->labelPaintCache.clear();
00163 
00164         for ( int iCol = 0; iCol < colCount; ++iCol ) {
00165             for ( int iRow=0; iRow < rowCount; ++iRow ) {
00166                 QModelIndex index = model()->index( iRow, iCol, rootIndex() ); // checked
00167                 const qreal value = model()->data( index ).toReal();
00168                 QPointF point = coordinatePlane()->translate(
00169                         QPointF( value, iRow ) ) + ctx->rectangle().topLeft();
00170                 //qDebug() << point;
00171                 d->addLabel( &d->labelPaintCache, index, 0, PositionPoints( point ),
00172                              Position::Center, Position::Center, value );
00173             }
00174         }
00175 
00176         newZoomX = coordinatePlane()->zoomFactorX();
00177         newZoomY = coordinatePlane()->zoomFactorY();
00178 
00179         if ( d->labelPaintCache.paintReplay.count() ) {
00180             // ...and zoom out if necessary
00181             const qreal oldZoomX = newZoomX;
00182             const qreal oldZoomY = newZoomY;
00183 
00184             QRectF txtRectF;
00185             d->paintDataValueTextsAndMarkers( ctx, d->labelPaintCache, true, true, &txtRectF );
00186             const QRect txtRect = txtRectF.toRect();
00187             const QRect curRect = coordinatePlane()->geometry();
00188             const qreal gapX = qMin( txtRect.left() - curRect.left(), curRect.right()  - txtRect.right() );
00189             const qreal gapY = qMin( txtRect.top()  - curRect.top(),  curRect.bottom() - txtRect.bottom() );
00190             if ( gapX < 0.0 ) {
00191                 newZoomX = oldZoomX * ( 1.0 + ( gapX - 1.0 ) / curRect.width() );
00192             }
00193             if ( gapY < 0.0 ) {
00194                 newZoomY = oldZoomY * ( 1.0 + ( gapY - 1.0 ) / curRect.height() );
00195             }
00196         }
00197     } else {
00198         // Paint the data sets
00199         for ( int iCol = 0; iCol < colCount; ++iCol ) {
00200             //TODO(khz): As of yet PolarDiagram can not show per-segment line attributes
00201             //           but it draws every polyline in one go - using one color.
00202             //           This needs to be enhanced to allow for cell-specific settings
00203             //           in the same way as LineDiagram does it.
00204             QBrush brush = qVariantValue<QBrush>( d->datasetAttrs( iCol, KDChart::DatasetBrushRole ) );
00205             QPolygonF polygon;
00206             for ( int iRow = 0; iRow < rowCount; ++iRow ) {
00207                 QModelIndex index = model()->index( iRow, iCol, rootIndex() ); // checked
00208                 const qreal value = model()->data( index ).toReal();
00209                 QPointF point = coordinatePlane()->translate( QPointF( value, iRow ) )
00210                                 + ctx->rectangle().topLeft();
00211                 polygon.append( point );
00212                 //qDebug() << point;
00213             }
00214             if ( closeDatasets() && !polygon.isEmpty() ) {
00215                 // close the circle by connecting the last data point to the first
00216                 polygon.append( polygon.first() );
00217             }
00218 
00219             PainterSaver painterSaver( ctx->painter() );
00220             ctx->painter()->setRenderHint ( QPainter::Antialiasing );
00221             ctx->painter()->setBrush( brush );
00222             QPen p( model()->headerData( iCol, Qt::Horizontal, KDChart::DatasetPenRole ).value< QPen >() );
00223             if ( p.style() != Qt::NoPen )
00224             {
00225                 ctx->painter()->setPen( PrintingParameters::scalePen( p ) );
00226                 ctx->painter()->drawPolyline( polygon );
00227             }
00228         }
00229         d->paintDataValueTextsAndMarkers( ctx, d->labelPaintCache, true );
00230     }
00231 }
00232 
00233 void PolarDiagram::resize ( const QSizeF& )
00234 {
00235 }
00236 
00237 /*virtual*/
00238 qreal PolarDiagram::valueTotals () const
00239 {
00240     return model()->rowCount(rootIndex());
00241 }
00242 
00243 /*virtual*/
00244 qreal PolarDiagram::numberOfValuesPerDataset() const
00245 {
00246     return model() ? model()->rowCount(rootIndex()) : 0.0;
00247 }
00248 
00249 /*virtual*/
00250 qreal PolarDiagram::numberOfGridRings() const
00251 {
00252     return 5; // FIXME
00253 }
00254 
00255 void PolarDiagram::setZeroDegreePosition( int degrees )
00256 {
00257     Q_UNUSED( degrees );
00258     qWarning() << "Deprecated PolarDiagram::setZeroDegreePosition() called, setting ignored.";
00259 }
00260 
00261 int PolarDiagram::zeroDegreePosition() const
00262 {
00263     qWarning() << "Deprecated PolarDiagram::zeroDegreePosition() called.";
00264     return 0;
00265 }
00266 
00267 void PolarDiagram::setRotateCircularLabels( bool rotateCircularLabels )
00268 {
00269     d->rotateCircularLabels = rotateCircularLabels;
00270 }
00271 
00272 bool PolarDiagram::rotateCircularLabels() const
00273 {
00274     return d->rotateCircularLabels;
00275 }
00276 
00277 void PolarDiagram::setCloseDatasets( bool closeDatasets )
00278 {
00279     d->closeDatasets = closeDatasets;
00280 }
00281 
00282 bool PolarDiagram::closeDatasets() const
00283 {
00284     return d->closeDatasets;
00285 }
00286 
00287 void PolarDiagram::setShowDelimitersAtPosition( Position position,
00288                                                        bool showDelimiters )
00289 {
00290     d->showDelimitersAtPosition[position.value()] = showDelimiters;
00291 }
00292 
00293 void PolarDiagram::setShowLabelsAtPosition( Position position,
00294                                                    bool showLabels )
00295 {
00296     d->showLabelsAtPosition[position.value()] = showLabels;
00297 }
00298 
00299 bool PolarDiagram::showDelimitersAtPosition( Position position ) const
00300 {
00301     return d->showDelimitersAtPosition[position.value()];
00302 }
00303 
00304 bool PolarDiagram::showLabelsAtPosition( Position position ) const
00305 {
00306     return d->showLabelsAtPosition[position.value()];
00307 }
00308 
00309 
00310 
 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/