KDChartPercentBarDiagram_p.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (C) 2001-2010 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 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 "KDChartPercentBarDiagram_p.h"
00024 
00025 #include <QModelIndex>
00026 
00027 #include "KDChartBarDiagram.h"
00028 #include "KDChartTextAttributes.h"
00029 #include "KDChartAttributesModel.h"
00030 #include "KDChartAbstractCartesianDiagram.h"
00031 
00032 using namespace KDChart;
00033 
00034 PercentBarDiagram::PercentBarDiagram( BarDiagram* d )
00035     : BarDiagramType( d )
00036 {
00037 }
00038 
00039 BarDiagram::BarType PercentBarDiagram::type() const
00040 {
00041     return BarDiagram::Percent;
00042 }
00043 
00044 const QPair<QPointF, QPointF> PercentBarDiagram::calculateDataBoundaries() const
00045 {
00046     const double xMin = 0.0;
00047     const double xMax = diagram()->model() ? diagram()->model()->rowCount( diagram()->rootIndex() ) : 0;
00048     const double yMin = 0.0;
00049     const double yMax = 100.0;
00050 
00051     const QPointF bottomLeft( QPointF( xMin, yMin ) );
00052     const QPointF topRight( QPointF( xMax, yMax ) );
00053 
00054     //qDebug() << "BarDiagram::calculateDataBoundaries () returns ( " << bottomLeft << topRight <<")";
00055     return QPair< QPointF, QPointF >( bottomLeft,  topRight );
00056 }
00057 
00058 void PercentBarDiagram::paint( PaintContext* ctx )
00059 {
00060     reverseMapper().clear();
00061 
00062     const QPair<QPointF,QPointF> boundaries = diagram()->dataBoundaries(); // cached
00063 
00064     const QPointF boundLeft = ctx->coordinatePlane()->translate( boundaries.first ) ;
00065     const QPointF boundRight = ctx->coordinatePlane()->translate( boundaries.second );
00066 
00067     const int rowCount = compressor().modelDataRows();
00068     const int colCount = compressor().modelDataColumns();
00069 
00070     BarAttributes ba = diagram()->barAttributes( diagram()->model()->index( 0, 0, diagram()->rootIndex() ) );
00071     double barWidth = 0;
00072     double maxDepth = 0;
00073     double width = boundRight.x() - boundLeft.x();
00074     double groupWidth = width/ (rowCount + 2);
00075     double spaceBetweenBars = 0;
00076     double spaceBetweenGroups = 0;
00077 
00078     if ( ba.useFixedBarWidth() ) {
00079         barWidth = ba.fixedBarWidth();
00080         groupWidth += barWidth;
00081 
00082         // Pending Michel set a min and max value for the groupWidth
00083         // related to the area.width
00084         if ( groupWidth < 0 )
00085             groupWidth = 0;
00086 
00087         if ( groupWidth  * rowCount > width )
00088             groupWidth = width / rowCount;
00089     }
00090 
00091     // maxLimit: allow the space between bars to be larger until area.width()
00092     // is covered by the groups.
00093     double maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) );
00094 
00095 
00096     //Pending Michel: FixMe
00097     if ( ba.useFixedDataValueGap() ) {
00098         if ( width > maxLimit )
00099             spaceBetweenBars += ba.fixedDataValueGap();
00100         else
00101             spaceBetweenBars = ((width/rowCount) - groupWidth)/(colCount-1);
00102     }
00103 
00104     if ( ba.useFixedValueBlockGap() )
00105         spaceBetweenGroups += ba.fixedValueBlockGap();
00106 
00107     calculateValueAndGapWidths( rowCount, colCount,groupWidth,
00108                                 barWidth, spaceBetweenBars, spaceBetweenGroups );
00109 
00110     DataValueTextInfoList list;
00111     const double maxValue = 100; // always 100 %
00112     double sumValues = 0;
00113     QVector <double > sumValuesVector;
00114 
00115     //calculate sum of values for each column and store
00116     for( int row = 0; row < rowCount; ++row )
00117     {
00118         for( int col = 0; col < colCount; ++col )
00119         {
00120             const CartesianDiagramDataCompressor::CachePosition position( row, col );
00121             const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00122             //if ( point.value > 0 )
00123             sumValues += qMax( point.value, -point.value );
00124             if ( col == colCount - 1 ) {
00125                 sumValuesVector <<  sumValues ;
00126                 sumValues = 0;
00127             }
00128         }
00129     }
00130 
00131     // calculate stacked percent value
00132     for( int col = 0; col < colCount; ++col )
00133     {
00134         double offset = spaceBetweenGroups;
00135         if( ba.useFixedBarWidth() )
00136             offset -= ba.fixedBarWidth();
00137         
00138         if( offset < 0 )
00139             offset = 0;
00140 
00141         for( int row = 0; row < rowCount ; ++row )
00142         {
00143             const CartesianDiagramDataCompressor::CachePosition position( row, col );
00144             const CartesianDiagramDataCompressor::DataPoint p = compressor().data( position );
00145             QModelIndex sourceIndex = attributesModel()->mapToSource( p.index );
00146             ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( sourceIndex );
00147 
00148             if ( threeDAttrs.isEnabled() ){
00149                 if ( barWidth > 0 )
00150                     barWidth =  (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount;
00151                 if ( barWidth <= 0 ) {
00152                     barWidth = 0;
00153                     maxDepth = offset - ( width/rowCount);
00154                 }
00155             }else{
00156                 barWidth = (width - (offset*rowCount))/ rowCount;
00157             }
00158 
00159             const double value = qMax( p.value, -p.value );
00160             double stackedValues = 0.0;
00161             double key = 0.0;
00162             
00163             // calculate stacked percent value
00164             // we only take in account positives values for now.
00165             for( int k = col; k >= 0 ; --k )
00166             {
00167                 const CartesianDiagramDataCompressor::CachePosition position( row, k );
00168                 const CartesianDiagramDataCompressor::DataPoint point = compressor().data( position );
00169                 stackedValues += qMax( point.value, -point.value );
00170                 key = point.key;
00171             }
00172 
00173             QPointF point, previousPoint;
00174             if(  sumValuesVector.at( row ) != 0 && value > 0 ) {
00175                 point = ctx->coordinatePlane()->translate( QPointF( key,  stackedValues / sumValuesVector.at( row ) * maxValue ) );
00176                 point.rx() += offset / 2;
00177 
00178                 previousPoint = ctx->coordinatePlane()->translate( QPointF( key, ( stackedValues - value)/sumValuesVector.at(row)* maxValue ) );
00179             }
00180             const double barHeight = previousPoint.y() - point.y();
00181 
00182             const QRectF rect( point, QSizeF( barWidth, barHeight ) );
00183             appendDataValueTextInfoToList( diagram(), list, sourceIndex, PositionPoints( rect ),
00184                                               Position::NorthWest, Position::SouthEast,
00185                                               value );
00186             paintBars( ctx, sourceIndex, rect, maxDepth );
00187         }
00188     }
00189     paintDataValueTextsAndMarkers(  diagram(),  ctx,  list,  false );
00190 }