# KDChartBarDiagram.cpp

Go to the documentation of this file.

    00001 /****************************************************************************
    00002  ** Copyright (C) 2006 Klar�vdalens Datakonsult AB.  All rights reserved.
    00003  **
    00004  ** This file is part of the KD Chart library.
    00005  **
    00006  ** This file may be distributed and/or modified under the terms of the
    00007  ** GNU General Public License version 2 as published by the Free Software
    00008  ** Foundation and appearing in the file LICENSE.GPL included in the
    00009  ** packaging of this file.
    00010  **
    00011  ** Licensees holding valid commercial KD Chart licenses may use this file in
    00012  ** accordance with the KD Chart Commercial License Agreement provided with
    00013  ** the Software.
    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  ** See http://www.kdab.net/kdchart for
    00019  **   information about KDChart Commercial License Agreements.
    00020  **
    00021  ** Contact info@kdab.net if any conditions of this
    00022  ** licensing are not clear to you.
    00023  **
    00024  **********************************************************************/
    00025
    00026 #include <QPainter>
    00027 #include <QDebug>
    00028
    00029 #include "KDChartBarDiagram.h"
    00030 #include "KDChartBarDiagram_p.h"
    00031 #include "KDChartThreeDBarAttributes.h"
    00032 #include "KDChartPosition.h"
    00033 #include "KDChartAttributesModel.h"
    00034 #include "KDChartAbstractGrid.h"
    00035
    00036 #include <KDABLibFakes>
    00037
    00038
    00039 using namespace KDChart;
    00040
    00041 BarDiagram::Private::Private()
    00042     : barType( Normal )
    00043     , maxDepth ( 0 )
    00044 {
    00045 }
    00046
    00047 BarDiagram::Private::~Private() {}
    00048
    00049 #define d d_func()
    00050
    00051
    00052 BarDiagram::BarDiagram( QWidget* parent, CartesianCoordinatePlane* plane ) :
    00053     AbstractCartesianDiagram( new Private(), parent, plane )
    00054 {
    00055     init();
    00056 }
    00057
    00058 void BarDiagram::init()
    00059 {
    00060 }
    00061
    00062 BarDiagram::~BarDiagram()
    00063 {
    00064 }
    00065
    00066 BarDiagram * BarDiagram::clone() const
    00067 {
    00068     return new BarDiagram( new Private( *d ) );
    00069 }
    00070
    00071 void BarDiagram::setType( const BarType type )
    00072 {
    00073     if ( type == d->barType ) return;
    00074
    00075     d->barType = type;
    00076     // AbstractAxis settings - see AbstractDiagram and CartesianAxis
    00077     setPercentMode( type == BarDiagram::Percent );
    00078     setDataBoundariesDirty();
    00079     emit layoutChanged( this );
    00080 }
    00081
    00082 BarDiagram::BarType BarDiagram::type() const
    00083 {
    00084    return d->barType;
    00085 }
    00086
    00087 void BarDiagram::setBarAttributes( const BarAttributes & ta )
    00088 {
    00089     d->attributesModel->setModelData( qVariantFromValue( ta ), BarAttributesRole );
    00090 }
    00091
    00092 void BarDiagram::setBarAttributes( int column, const BarAttributes & ta )
    00093 {
    00094     d->attributesModel->setHeaderData(
    00095         column, Qt::Vertical,
    00096         qVariantFromValue( ta ),
    00097         BarAttributesRole );
    00098 }
    00099
    00100 void BarDiagram::setBarAttributes( const QModelIndex & index, const BarAttributes & ta )
    00101 {
    00102     attributesModel()->setData(
    00103         d->attributesModel->mapFromSource( index ),
    00104         qVariantFromValue( ta ),
    00105         BarAttributesRole );
    00106 }
    00107
    00108 BarAttributes BarDiagram::barAttributes() const
    00109 {
    00110     return qVariantValue<BarAttributes>(
    00111         d->attributesModel->data( KDChart::BarAttributesRole ) );
    00112 }
    00113
    00114 BarAttributes BarDiagram::barAttributes( int column ) const
    00115 {
    00116     return qVariantValue<BarAttributes>(
    00117         d->attributesModel->data(
    00118             d->attributesModel->mapFromSource( columnToIndex( column ) ),
    00119             KDChart::BarAttributesRole ) );
    00120 }
    00121
    00122 BarAttributes BarDiagram::barAttributes( const QModelIndex & index ) const
    00123 {
    00124     return qVariantValue<BarAttributes>(
    00125         d->attributesModel->data(
    00126             d->attributesModel->mapFromSource( index ),
    00127             KDChart::BarAttributesRole ) );
    00128 }
    00129
    00130 void BarDiagram::setThreeDBarAttributes( const ThreeDBarAttributes & threeDAttrs )
    00131 {
    00132     setDataBoundariesDirty();
    00133     d->attributesModel->setModelData( qVariantFromValue( threeDAttrs ), ThreeDBarAttributesRole );
    00134     emit layoutChanged( this );
    00135 }
    00136
    00137 void BarDiagram::setThreeDBarAttributes( int column, const ThreeDBarAttributes & threeDAttrs )
    00138 {
    00139     setDataBoundariesDirty();
    00140     d->attributesModel->setHeaderData(
    00141         column, Qt::Vertical,
    00142         qVariantFromValue( threeDAttrs ),
    00143         ThreeDBarAttributesRole );
    00144     emit layoutChanged( this );
    00145 }
    00146
    00147 void BarDiagram::setThreeDBarAttributes( const QModelIndex & index, const ThreeDBarAttributes & threeDAttrs )
    00148 {
    00149     setDataBoundariesDirty();
    00150     d->attributesModel->setData(
    00151         d->attributesModel->mapFromSource(index),
    00152         qVariantFromValue( threeDAttrs ),
    00153         ThreeDBarAttributesRole );
    00154     emit layoutChanged( this );
    00155 }
    00156
    00157 ThreeDBarAttributes BarDiagram::threeDBarAttributes() const
    00158 {
    00159     return qVariantValue<ThreeDBarAttributes>(
    00160         d->attributesModel->data( KDChart::ThreeDBarAttributesRole ) );
    00161 }
    00162
    00163 ThreeDBarAttributes BarDiagram::threeDBarAttributes( int column ) const
    00164 {
    00165     return qVariantValue<ThreeDBarAttributes>(
    00166         d->attributesModel->data(
    00167             d->attributesModel->mapFromSource( columnToIndex( column ) ),
    00168             KDChart::ThreeDBarAttributesRole ) );
    00169 }
    00170
    00171 ThreeDBarAttributes BarDiagram::threeDBarAttributes( const QModelIndex & index ) const
    00172 {
    00173     return qVariantValue<ThreeDBarAttributes>(
    00174         d->attributesModel->data(
    00175             d->attributesModel->mapFromSource(index),
    00176             KDChart::ThreeDBarAttributesRole ) );
    00177 }
    00178
    00179 double BarDiagram::threeDItemDepth( const QModelIndex & index ) const
    00180 {
    00181     return threeDBarAttributes( index ).validDepth();
    00182 }
    00183
    00184 double BarDiagram::threeDItemDepth( int column ) const
    00185 {
    00186     return qVariantValue<ThreeDBarAttributes>(
    00187         d->attributesModel->headerData (
    00188             column,
    00189             Qt::Vertical,
    00190             KDChart::ThreeDBarAttributesRole ) ).validDepth();
    00191 }
    00192
    00193 void BarDiagram::resizeEvent ( QResizeEvent*)
    00194 {
    00195
    00196 }
    00197
    00198 const QPair<QPointF, QPointF> BarDiagram::calculateDataBoundaries() const
    00199 {
    00200     if ( !checkInvariants(true) ) return QPair<QPointF, QPointF>( QPointF( 0, 0 ), QPointF( 0, 0 ) );
    00201     const int rowCount = d->attributesModel->rowCount(attributesModelRootIndex());
    00202     const int colCount = d->attributesModel->columnCount(attributesModelRootIndex());
    00203
    00204     double xMin = 0;
    00205     double xMax = rowCount;
    00206     double yMin = 0, yMax = 0;
    00207     //double maxThreeDDepth   = 0.0;
    00208
    00209
    00210     // calculate boundaries for  different line types Normal - Stacked - Percent - Default Normal
    00211     switch ( type() ){
    00212         case BarDiagram::Normal:
    00213         {
    00214             bool bStarting = true;
    00215             for ( int i=0; i<colCount; ++i ) {
    00216                 for ( int j=0; j< rowCount; ++j ) {
    00217                     const double value = d->attributesModel->data( d->attributesModel->index( j, i, attributesModelRootIndex() ) ).toDouble();
    00218                     // this is always true yMin can be 0 in case all values
    00219                     // are the same
    00220                     // same for yMax it can be zero if all values are negative
    00221                     if( bStarting ){
    00222                         yMin = value;
    00223                         yMax = value;
    00224                         bStarting = false;
    00225                     }else{
    00226                         yMin = qMin( yMin, value );
    00227                         yMax = qMax( yMax, value );
    00228                     }
    00229                 }
    00230             }
    00231         }
    00232             break;
    00233         case BarDiagram::Stacked:
    00234         {
    00235             bool bStarting = true;
    00236             for ( int j=0; j< rowCount; ++j ) {
    00237                 // calculate sum of values per column - Find out stacked Min/Max
    00238                 double stackedValues = 0;
    00239                 for ( int i=0; i<colCount ; ++i ) {
    00240                     QModelIndex idx = model()->index( j, i, rootIndex() );
    00241                     stackedValues +=  model()->data( idx ).toDouble();
    00242                     // this is always true yMin can be 0 in case all values
    00243                     // are the same
    00244                     // same for yMax it can be zero if all values are negative
    00245                     if( bStarting ){
    00246                         yMin = stackedValues;
    00247                         yMax = stackedValues;
    00248                         bStarting = false;
    00249                     }else{
    00250                         yMin = qMin( yMin, stackedValues );
    00251                         yMax = qMax( yMax, stackedValues );
    00252                     }
    00253                 }
    00254             }
    00255         }
    00256             break;
    00257         case BarDiagram::Percent:
    00258         {
    00259             for ( int i=0; i<colCount; ++i ) {
    00260                 for ( int j=0; j< rowCount; ++j ) {
    00261                     // Ordinate should begin at 0 the max value being the 100% pos
    00262                     QModelIndex idx = model()->index( j, i, rootIndex() );
    00263                     // only positive values are handled
    00264                     double value = model()->data( idx ).toDouble();
    00265                     if ( value > 0 )
    00266                         yMax = qMax( yMax, value );
    00267                 }
    00268             }
    00269         }
    00270             break;
    00271         case BarDiagram::Rows:
    00272         {
    00273             qDebug()<< "KDChartBarDiagram::calculateDataBoundaries"
    00274                     << "Sorry Type Rows not implemented yet";
    00275             break;
    00276         }
    00277
    00278
    00279         default:
    00280              Q_ASSERT_X ( false, "calculateDataBoundaries()",
    00281                          "Type item does not match a defined bar chart Type." );
    00282     }
    00283
    00284     // special cases
    00285     if (  yMax == yMin ) {
    00286         if ( yMin == 0.0 )
    00287             yMax = 0.1; //we need at list a range
    00288         else
    00289             yMax = 0.0; // they are the same but negative
    00290     }
    00291     QPointF bottomLeft ( QPointF( xMin, yMin ) );
    00292     QPointF topRight ( QPointF( xMax, yMax ) );
    00293
    00294     //qDebug() << "BarDiagram::calculateDataBoundaries () returns ( " << bottomLeft << topRight <<")";
    00295     return QPair<QPointF, QPointF> ( bottomLeft,  topRight );
    00296 }
    00297
    00298 /*
    00299 void BarDiagram::paintEvent ( QPaintEvent*)
    00300 {
    00301     qDebug() << "BarDiagram::paintEvent";
    00302     QPainter painter ( viewport() );
    00303     PaintContext ctx;
    00304     ctx.setPainter ( &painter );
    00305     ctx.setRectangle( QRectF ( 0, 0, width(), height() ) );
    00306     paint ( &ctx );
    00307 }*/
    00308
    00309
    00310 void BarDiagram::calculateValueAndGapWidths( int rowCount,int colCount,
    00311                                              double groupWidth,
    00312                                              double& outBarWidth,
    00313                                              double& outSpaceBetweenBars,
    00314                                              double& outSpaceBetweenGroups )
    00315 {
    00316     Q_UNUSED( rowCount );
    00317
    00318     BarAttributes ba = barAttributes( model()->index( 0, 0, rootIndex() ) );
    00319
    00320     // Pending Michel Fixme
    00321     /* We are colCount groups to paint. Each group is centered around the
    00322      * horizontal point position on the grid. The full area covers the
    00323      * values -1 to colCount + 1. A bar has a relative width of one unit,
    00324      * the gaps between bars are 0.5 wide, and the gap between groups is
    00325      * also one unit, by default. */
    00326
    00327     const double units = colCount // number of bars in group * 1.0
    00328         + (colCount-1) * ba.barGapFactor() // number of bar gaps
    00329         + 1 * ba.groupGapFactor(); // number of group gaps
    00330
    00331     double unitWidth = groupWidth / units;
    00332     outBarWidth = unitWidth;
    00333     outSpaceBetweenBars += unitWidth * ba.barGapFactor();
    00334     // Pending Michel - minLimit: allow space between bars to be reduced until the bars are displayed next to each other.
    00335     // is that what we want?
    00336     if ( outSpaceBetweenBars < 0 )
    00337         outSpaceBetweenBars = 0;
    00338     outSpaceBetweenGroups += unitWidth * ba.groupGapFactor();
    00339 }
    00340
    00341 void BarDiagram::paint( PaintContext* ctx )
    00342 {
    00343     // note: Not having any data model assigned is no bug
    00344     //       but we can not draw a diagram then either.
    00345     if ( !checkInvariants(true) )
    00346         return;
    00347
    00348     // Calculate width
    00349     QPointF boundLeft, boundRight;
    00350     QPair<QPointF,QPointF> boundaries = dataBoundaries();
    00351     if( !AbstractGrid::isBoundariesValid(boundaries) ) return;
    00352
    00353     CartesianCoordinatePlane* plane = dynamic_cast<KDChart::CartesianCoordinatePlane*>( coordinatePlane() );
    00354     if( ! plane ) return;
    00355
    00356     boundLeft = plane->translate( boundaries.first );
    00357     boundRight = plane->translate( boundaries.second );
    00358     double width = boundRight.x() - boundLeft.x();
    00359     //calculates and stores the values
    00360     const int rowCount = d->attributesModel->rowCount(attributesModelRootIndex());
    00361     const int colCount = d->attributesModel->columnCount(attributesModelRootIndex());
    00362     DataValueTextInfoList list;
    00363     BarAttributes ba = barAttributes( model()->index( 0, 0, rootIndex() ) );
    00364     double barWidth = 0;
    00365     double maxDepth = 0;
    00366     double spaceBetweenBars = 0;
    00367     double spaceBetweenGroups = 0;
    00368     double groupWidth =  /*ctx->rectangle().width() / ( rowCount + 2 )*/ width/ (rowCount + 2);
    00369
    00370
    00371     if ( ba.useFixedBarWidth() ) {
    00372         barWidth = ba.fixedBarWidth();
    00373         groupWidth += barWidth;
    00374
    00375         // Pending Michel set a min and max value for the groupWidth related to the area.width
    00376         // FixMe
    00377         if ( groupWidth < 0 )
    00378             groupWidth = 0;
    00379
    00380         if ( groupWidth  * rowCount > ctx->rectangle().width() )
    00381             groupWidth = ctx->rectangle().width() / rowCount;
    00382     }
    00383
    00384     // maxLimit: allow the space between bars to be larger until area.width() is covered by the groups.
    00385     double maxLimit = rowCount * (groupWidth + ((colCount-1) * ba.fixedDataValueGap()) );
    00386
    00387     //Pending Michel: FixMe
    00388     if ( ba.useFixedDataValueGap() ) {
    00389         if ( ctx->rectangle().width() > maxLimit )
    00390             spaceBetweenBars += ba.fixedDataValueGap();
    00391         else
    00392             spaceBetweenBars = ((ctx->rectangle().width()/rowCount) - groupWidth)/(colCount-1);
    00393    }
    00394
    00395     //Pending Michel: FixMe
    00396     if ( ba.useFixedValueBlockGap() )
    00397         spaceBetweenGroups += ba.fixedValueBlockGap();
    00398
    00399     calculateValueAndGapWidths( rowCount, colCount,groupWidth,
    00400                                 barWidth, spaceBetweenBars, spaceBetweenGroups );
    00401
    00402     // paint different bar types: Normal - Stacked - Percent
    00403     switch ( type() )
    00404         {
    00405         case BarDiagram::Normal:
    00406         {
    00407             // we paint the bars for all series next to each other, then move to the next value
    00408             for ( int i=0; i<rowCount; ++i ) {
    00409                 double offset = -groupWidth/2 + spaceBetweenGroups/2;
    00410                 // case fixed data value gap - handles max and min limits as well
    00411                 if ( ba.useFixedDataValueGap() ) {
    00412                     if ( spaceBetweenBars > 0 ) {
    00413                       if ( ctx->rectangle().width() > maxLimit )
    00414                             offset -= ba.fixedDataValueGap();
    00415                       else
    00416                         offset -= ((ctx->rectangle().width()/rowCount) - groupWidth)/(colCount-1);
    00417
    00418                     } else {
    00419                         //allow reducing the gap until the bars are displayed next to each other - null gap
    00420                         offset += barWidth/2;
    00421                     }
    00422                 }
    00423
    00424                 for ( int j=0; j< colCount; ++j ) {
    00425                     // paint one group
    00426                     const qreal value = d->attributesModel->data( d->attributesModel->index( i, j, attributesModelRootIndex() ) ).toDouble();
    00427                     QPointF topPoint = plane->translate( QPointF( i + 0.5, value ) );
    00428                     QPointF bottomPoint = plane->translate( QPointF( i, 0 ) );
    00429                     const double barHeight = bottomPoint.y() - topPoint.y();
    00430                     topPoint.setX( topPoint.x() + offset );
    00431
    00432                     const QModelIndex index = model()->index( i, j, rootIndex() );
    00433
    00434                     //PENDING Michel: FIXME barWidth
    00435                     const QRectF rect( topPoint, QSizeF( barWidth, barHeight ) );
    00436                     d->appendDataValueTextInfoToList( this, list, index, PositionPoints( rect ),
    00437                             Position::NorthWest, Position::SouthEast,
    00438                             value );
    00439                     paintBars( ctx, index, rect, maxDepth );
    00440
    00441                     offset += barWidth + spaceBetweenBars;
    00442                 }
    00443             }
    00444         }
    00445             break;
    00446         case BarDiagram::Stacked:
    00447         {
    00448            for ( int i = 0; i<colCount; ++i ) {
    00449                double offset = spaceBetweenGroups;
    00450                for ( int j = 0; j< rowCount; ++j ) {
    00451                    QModelIndex index = model()->index( j, i, rootIndex() );
    00452                    ThreeDBarAttributes threeDAttrs = threeDBarAttributes( index );
    00453                    double value = 0, stackedValues = 0;
    00454                    QPointF point, previousPoint;
    00455
    00456                    if ( threeDAttrs.isEnabled() ) {
    00457                        if ( barWidth > 0 )
    00458                            barWidth =  (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount;
    00459                        if ( barWidth <= 0 ) {
    00460                            barWidth = 0;
    00461                            maxDepth = offset - (width/rowCount);
    00462                        }
    00463                    } else
    00464                        barWidth =  (ctx->rectangle().width() - (offset*rowCount))/ rowCount ;
    00465
    00466                    value = model()->data( index ).toDouble();
    00467                    for ( int k = i; k >= 0 ; --k )
    00468                        stackedValues += model()->data( model()->index( j, k, rootIndex() ) ).toDouble();
    00469                    point = plane->translate( QPointF( j, stackedValues ) );
    00470                    point.setX( point.x() + offset/2 );
    00471                    previousPoint = plane->translate( QPointF( j, stackedValues - value ) );
    00472                    const double barHeight = previousPoint.y() - point.y();
    00473
    00474                    const QRectF rect( point, QSizeF( barWidth , barHeight ) );
    00475                    d->appendDataValueTextInfoToList( this, list, index, PositionPoints( rect ),
    00476                            Position::NorthWest, Position::SouthEast,
    00477                            value );
    00478                    paintBars( ctx, index, rect, maxDepth );
    00479                }
    00480
    00481            }
    00482         }
    00483            break;
    00484         case BarDiagram::Percent:
    00485         {
    00486             double maxValue = 100; // always 100 %
    00487             double sumValues = 0;
    00488             QVector <double > sumValuesVector;
    00489
    00490             //calculate sum of values for each column and store
    00491             for ( int j=0; j<rowCount; ++j ) {
    00492                 for ( int i=0; i<colCount; ++i ) {
    00493                     double tmpValue = model()->data( model()->index( j, i, rootIndex() ) ).toDouble();
    00494                     if ( tmpValue > 0 )
    00495                         sumValues += tmpValue;
    00496                     if ( i == colCount-1 ) {
    00497                         sumValuesVector <<  sumValues ;
    00498                         sumValues = 0;
    00499                     }
    00500                 }
    00501             }
    00502
    00503             // calculate stacked percent value
    00504             for ( int i = 0; i<colCount; ++i ) {
    00505                 double offset = spaceBetweenGroups;
    00506                 for ( int j=0; j<rowCount ; ++j ) {
    00507                     double value = 0, stackedValues = 0;
    00508                     QPointF point, previousPoint;
    00509                     QModelIndex index = model()->index( j, i, rootIndex() );
    00510                     ThreeDBarAttributes threeDAttrs = threeDBarAttributes( index );
    00511
    00512                     if ( threeDAttrs.isEnabled() ){
    00513                         if ( barWidth > 0 )
    00514                             barWidth =  (width - ((offset+(threeDAttrs.depth()))*rowCount))/ rowCount;
    00515                         if ( barWidth <= 0 ) {
    00516                             barWidth = 0;
    00517                             maxDepth = offset - ( width/rowCount);
    00518                         }
    00519                     }else{
    00520                         barWidth = (ctx->rectangle().width() - (offset*rowCount))/ rowCount;
    00521                     }
    00522
    00523                     value = model()->data( index ).toDouble();
    00524
    00525                     // calculate stacked percent value
    00526                     // we only take in account positives values for now.
    00527                     for ( int k = i; k >= 0 ; --k ) {
    00528                         double val = model()->data( model()->index( j, k, rootIndex() ) ).toDouble();
    00529                         if ( val > 0)
    00530                             stackedValues += val;
    00531                     }
    00532
    00533                     if (  sumValuesVector.at( j ) != 0 && value > 0 ) {
    00534                       point = plane->translate( QPointF( j,  stackedValues/sumValuesVector.at(j)* maxValue ) );
    00535
    00536                         point.setX( point.x() + offset/2 );
    00537
    00538                         previousPoint = plane->translate( QPointF( j, (stackedValues - value)/sumValuesVector.at(j)* maxValue ) );
    00539                     }
    00540                     const double barHeight = previousPoint.y() - point.y();
    00541
    00542                     const QRectF rect( point, QSizeF( barWidth, barHeight ) );
    00543                     d->appendDataValueTextInfoToList( this, list, index, PositionPoints( rect ),
    00544                             Position::NorthWest, Position::SouthEast,
    00545                             value );
    00546                     paintBars( ctx, index, rect, maxDepth );
    00547
    00548                 }
    00549             }
    00550         }
    00551         break;
    00552         default:
    00553             Q_ASSERT_X ( false, "paint()",
    00554                          "Type item does not match a defined bar chart Type." );
    00555         }
    00556
    00557     // paint all data value texts, but no point markers
    00558     d->paintDataValueTextsAndMarkers( this, ctx, list, false );
    00559 }
    00560
    00561 void BarDiagram::paintBars( PaintContext* ctx, const QModelIndex& index, const QRectF& bar, double& maxDepth )
    00562 {
    00563     QRectF isoRect;
    00564     QPolygonF topPoints, sidePoints;
    00565     ThreeDBarAttributes threeDAttrs = threeDBarAttributes( index );
    00566     double usedDepth;
    00567
    00568     //Pending Michel: configure threeDBrush settings - shadowColor etc...
    00569     QBrush indexBrush ( brush( index ) );
    00570     QPen indexPen( pen( index ) );
    00571     PainterSaver painterSaver( ctx->painter() );
    00572     if ( antiAliasing() )
    00573         ctx->painter()->setRenderHint ( QPainter::Antialiasing );
    00574     ctx->painter()->setBrush( indexBrush );
    00575     ctx->painter()->setPen( indexPen );
    00576     if ( threeDAttrs.isEnabled() ) {
    00577         bool stackedMode = false;
    00578         bool percentMode = false;
    00579         bool paintTop = true;
    00580         if ( maxDepth )
    00581             threeDAttrs.setDepth( -maxDepth );
    00582         QPointF boundRight = coordinatePlane()->translate( dataBoundaries().second );
    00583         //fixme adjust the painting to reasonable depth value
    00584         switch ( type() )
    00585         {
    00586         case BarDiagram::Normal:
    00587             usedDepth = threeDAttrs.depth()/4;
    00588             stackedMode = false;
    00589             percentMode = false;
    00590             break;
    00591         case BarDiagram::Stacked:
    00592             usedDepth = threeDAttrs.depth();
    00593             stackedMode = true;
    00594             percentMode = false;
    00595             break;
    00596         case BarDiagram::Percent:
    00597             usedDepth = threeDAttrs.depth();
    00598             stackedMode = false;
    00599             percentMode = true;
    00600             break;
    00601         default:
    00602             Q_ASSERT_X ( false, "dataBoundaries()",
    00603                          "Type item does not match a defined bar chart Type." );
    00604         }
    00605         isoRect =  bar.translated( usedDepth, -usedDepth );
    00606         // we need to find out if the height is negative
    00607         // and in this case paint it up and down
    00608         //qDebug() << isoRect.height();
    00609         if (  isoRect.height() < 0 ) {
    00610           topPoints << isoRect.bottomLeft() << isoRect.bottomRight()
    00611                     << bar.bottomRight() << bar.bottomLeft();
    00612           if ( stackedMode ) {
    00613               // fix it when several negative stacked values
    00614               if (  index.column() == 0 ) {
    00615                   paintTop = true;
    00616               }
    00617               else
    00618                   paintTop = false;
    00619           }
    00620
    00621         } else {
    00622             ctx->painter()->drawRect( isoRect );
    00623             topPoints << bar.topLeft() << bar.topRight() << isoRect.topRight() << isoRect.topLeft();
    00624         }
    00625
    00626         if ( percentMode && isoRect.height() == 0 )
    00627             paintTop = false;
    00628
    00629         bool needToSetClippingOffForTop = false;
    00630         if ( paintTop ){
    00631             // Draw the top, if at least one of the top's points is
    00632             // either inside or near at the edge of the coordinate plane:
    00633             bool drawIt = false;
    00634             bool hasPointOutside = false;
    00635             const QRectF r( ctx->rectangle().adjusted(0,-1,1,0) );
    00636             KDAB_FOREACH( QPointF pt, topPoints ) {
    00637                 if( r.contains( pt ) )
    00638                     drawIt = true;
    00639                 else
    00640                     hasPointOutside = true;
    00641             }
    00642             if( drawIt ){
    00643                 needToSetClippingOffForTop = hasPointOutside && ctx->painter()->hasClipping();
    00644                 if( needToSetClippingOffForTop )
    00645                     ctx->painter()->setClipping( false );
    00646                 ctx->painter()->drawPolygon( topPoints );
    00647                 if( needToSetClippingOffForTop )
    00648                     ctx->painter()->setClipping( true );
    00649             }
    00650         }
    00651
    00652
    00653
    00654         sidePoints << bar.topRight() << isoRect.topRight() << isoRect.bottomRight() << bar.bottomRight();
    00655         if (  bar.height() != 0 ){
    00656             if( needToSetClippingOffForTop )
    00657                 ctx->painter()->setClipping( false );
    00658             ctx->painter()->drawPolygon( sidePoints );
    00659             if( needToSetClippingOffForTop )
    00660                 ctx->painter()->setClipping( true );
    00661         }
    00662     }
    00663
    00664     if (  bar.height() != 0 )
    00665         ctx->painter()->drawRect( bar );
    00666     // reset
    00667     d->maxDepth = threeDAttrs.depth();
    00668 }
    00669
    00670 void BarDiagram::resize ( const QSizeF& )
    00671 {
    00672 }
    00673
    00674 const int BarDiagram::numberOfAbscissaSegments () const
    00675 {
    00676     return d->attributesModel->rowCount(attributesModelRootIndex());
    00677 }
    00678
    00679 const int BarDiagram::numberOfOrdinateSegments () const
    00680 {
    00681     return d->attributesModel->columnCount(attributesModelRootIndex());
    00682 }
    00683
    00684 #undef d