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 "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