kchart

KDChartBarPainter.cpp

00001 /* -*- Mode: C++ -*-
00002    KDChart - a multi-platform charting engine
00003 */
00004 
00005 /****************************************************************************
00006  ** Copyright (C) 2001-2003 Klarälvdalens Datakonsult AB.  All rights reserved.
00007  **
00008  ** This file is part of the KDChart library.
00009  **
00010  ** This file may be distributed and/or modified under the terms of the
00011  ** GNU General Public License version 2 as published by the Free Software
00012  ** Foundation and appearing in the file LICENSE.GPL included in the
00013  ** packaging of this file.
00014  **
00015  ** Licensees holding valid commercial KDChart licenses may use this file in
00016  ** accordance with the KDChart Commercial License Agreement provided with
00017  ** the Software.
00018  **
00019  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021  **
00022  ** See http://www.klaralvdalens-datakonsult.se/?page=products for
00023  **   information about KDChart Commercial License Agreements.
00024  **
00025  ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
00026  ** licensing are not clear to you.
00027  **
00028  **********************************************************************/
00029 #include "KDChartBarPainter.h"
00030 #include <KDChartParams.h>
00031 
00032 #include <qpainter.h>
00033 
00034 #include <stdlib.h>
00035 
00047 KDChartBarPainter::KDChartBarPainter( KDChartParams* params ) :
00048     KDChartAxesPainter( params )
00049 {
00050     // This constructor intentionally left blank so far; we cannot setup the
00051     // geometry yet since we do not know the size of the painter.
00052 }
00053 
00054 
00058 KDChartBarPainter::~KDChartBarPainter()
00059 {
00060     // intentionally left blank
00061 }
00062 
00063 bool KDChartBarPainter::isNormalMode() const
00064 {
00065 
00066     return KDChartParams::BarNormal == params()->barChartSubType();
00067 }
00068 
00069 int KDChartBarPainter::clipShiftUp( bool normalMode, double areaWidthP1000 ) const
00070 {
00071 
00072     const bool bThreeDBars = params()->threeDBars() || (KDChartParams::BarMultiRows == params()->barChartSubType());
00073     return   ( normalMode && !bThreeDBars )
00074         ? static_cast < int > ( areaWidthP1000 * 16.0 )
00075         : 0;
00076 }
00077 
00078 
00079 void KDChartBarPainter::initMyPainter( QPainter* painter )
00080 {
00081     _myPainter = painter;
00082     _painterDX = 0.0;
00083     _painterDY = 0.0;
00084 }
00085 
00086 void KDChartBarPainter::shiftMyPainter( double dx, double dy )
00087 {
00088     if( dx != 0.0 || dy != 0.0 ){
00089         _myPainter->translate(dx, dy);
00090         _painterDX += dx;
00091         _painterDY += dy;
00092     }
00093 }
00094 
00095 void KDChartBarPainter::shiftMyPainterBack()
00096 {
00097     if( _painterDX != 0.0 || _painterDY != 0.0 ){
00098         _myPainter->translate(-_painterDX, -_painterDY);
00099         _painterDX = 0.0;
00100         _painterDY = 0.0;
00101     }
00102 }
00103 
00104 
00105 void KDChartBarPainter::calculateXFront1_2( bool bNormalMode, bool bIsVeryFirstBar, bool bIsFirstDataset, bool _bThreeDBars,
00106                                             double xpos, double valueBlockGap, double datasetGap, double frontBarWidth,
00107                                             int& frontX1, int& frontX2, int& prevFrontX2 ){
00108 
00109     if( _bThreeDBars || bIsVeryFirstBar || !bNormalMode )
00110         frontX1 = static_cast<int>( xpos );
00111     else if( bIsFirstDataset )
00112         frontX1 = prevFrontX2 +  static_cast <int> ( valueBlockGap ) + 1;
00113     else
00114         frontX1 = prevFrontX2 + static_cast < int > ( datasetGap ) + 1;
00115 
00116     // Note: frontX2 is calculated by using xpos but NOT by using frontX1.
00117     //       So we make sure that (a) the gaps between all bars of one dataset
00118     //       are exactly the same size, and that (b) the bars are automatically
00119     //       adjusted in their width: to match their very position within the abscissa range.
00120     //       Adjusting will result in them being ONE pixel wider sometimes.
00121     frontX2 = static_cast < int > ( xpos + frontBarWidth );
00122     prevFrontX2 = frontX2;
00123 }
00124 
00125 
00126 QPointArray rectToPointArray( const QRect& r )
00127 {
00128     QPointArray a(4);
00129     a.putPoints( 0, 4, r.left(),r.top(), r.right(),r.top(), r.right(),r.bottom(), r.left(),r.bottom() );
00130     return a;
00131 }
00132 
00133 
00134 void KDChartBarPainter::specificPaintData( QPainter* painter,
00135                                            const QRect& ourClipRect,
00136                                            KDChartTableDataBase* data,
00137                                            KDChartDataRegionList* regions,
00138                                            const KDChartAxisParams* ordinatePara,
00139                                            bool bNormalMode,
00140                                            uint chart,
00141                                            double logWidth,
00142                                            double areaWidthP1000,
00143                                            double logHeight,
00144                                            double axisYOffset,
00145                                            double minColumnValue,
00146                                            double maxColumnValue,
00147                                            double columnValueDistance,
00148                                            uint chartDatasetStart,
00149                                            uint chartDatasetEnd,
00150                                            uint datasetStart,
00151                                            uint datasetEnd )
00152 {
00153     /****************Pending Michel***********************
00154      *Rectangles are painted in the following order:     *
00155      *front , right side, top.                           *
00156      *Store the painted rectangles in order to paint     *
00157      *them in relation to each other for more precision. *
00158      ****************************************************/
00159     QRect frontRectPositive,frontRectNegative,
00160         rightRectPositive, rightRectNegative,
00161         excessRectPositive,excessRectNegative;
00162 
00163     _areaP1000 = areaWidthP1000;
00164 
00165 
00166 
00167     if( !data ) return;
00168     // qDebug("datasetStart: %i    datasetEnd: %i", datasetStart, datasetEnd);
00169     const QPen defaultOutlinePen( params()->outlineDataColor(),
00170                                   params()->outlineDataLineWidth(),
00171                                   params()->outlineDataLineStyle() );
00172     abscissaInfos ai;
00173     ai.bCenterThePoints = true;
00174     calculateAbscissaInfos( *params(), *data,
00175                             datasetStart, datasetEnd,
00176                             logWidth, _dataRect,
00177                             ai );
00178 
00179     const QRect devRect( painter->window() );
00180 
00181     initMyPainter( painter );
00182 
00183     const bool ordinateIsLogarithmic
00184         = KDChartAxisParams::AxisCalcLogarithmic == ordinatePara->axisCalcMode();
00185 
00186     const bool bMultiRows = KDChartParams::BarMultiRows == params()->barChartSubType();
00187     _bThreeDBars = params()->threeDBars() || bMultiRows;
00188     int numChartDataEntryDatasets = 0;
00189     uint myLastDataEntryDataset = 0;
00190     for( uint iD = chartDatasetStart; iD <= chartDatasetEnd; ++iD ){
00191         if( params()->chartSourceMode( iD ) == KDChartParams::DataEntry ){
00192             ++numChartDataEntryDatasets;
00193             myLastDataEntryDataset = iD;
00194         }
00195     }
00196 
00197     const bool bHadClipping = painter->hasClipping();
00198 
00199     //this allow the height/size of the bar to be painted fully
00200     if( bMultiRows ) {
00201         painter->setClipping( false );
00202     }
00203     // Number of columns in one dataset: If -1, use all values,
00204     // otherwise use the specified number of values.
00205     int numValues = 0;
00206     if ( params()->numValues() != -1 )
00207         numValues = params()->numValues();
00208     else
00209         numValues = data->usedCols();
00210 
00211     double datasetGap = bMultiRows
00212                         ? 0.0
00213                         : params()->datasetGap()
00214                         * (   params()->datasetGapIsRelative()
00215                               ? areaWidthP1000
00216                               : 1.0 );
00217     double valueBlockGap = bMultiRows
00218                            ? 0.0
00219                            : params()->valueBlockGap()
00220                            * (   params()->valueBlockGapIsRelative()
00221                                  ? areaWidthP1000
00222                                  : 1.0 );
00223 
00224     // This is the same for all three bar types except for multi-bar Surface charts.
00225     double spaceBetweenValueBlocks = bMultiRows
00226                                      ? 0.0
00227                                      : static_cast<int>( valueBlockGap ) * numValues;
00228 
00229     // Set some geometry values that apply to bar charts only
00230     double totalNumberOfBars = 0.0;
00231     double spaceBetweenDatasets = 0.0;
00232     switch ( params()->barChartSubType() ) {
00233     case KDChartParams::BarNormal: {
00234         totalNumberOfBars = numChartDataEntryDatasets * numValues;
00235         spaceBetweenDatasets = datasetGap
00236                                * ( totalNumberOfBars - numValues );
00237         break;
00238     }
00239     case KDChartParams::BarStacked:
00240     case KDChartParams::BarPercent:
00241     case KDChartParams::BarMultiRows:
00242         totalNumberOfBars = numValues;
00243         spaceBetweenDatasets = 0; // always 0 when stacked/percent/multi-rows
00244         break;
00245     default:
00246         qFatal( "Unsupported bar chart type" );
00247     };
00248 
00249     double barWidth = 0.0;
00250     if( params()->barWidth() == KDCHART_AUTO_SIZE ) {
00251 
00252         //Default auto calc. to optimize when many bars datasetGap ==  blockGap/2 == barWidth/2
00253         //unless valueBlockGap or datasetGap are different from default values == users value
00254         barWidth = logWidth / totalNumberOfBars;
00255         do {
00256             barWidth -= 0.1;
00257             params()->valueBlockGap() != 24 ? spaceBetweenValueBlocks = params()->valueBlockGap() * numValues
00258                                             : spaceBetweenValueBlocks = ( barWidth/2 ) * numValues;
00259             if  ( spaceBetweenDatasets != 0 )
00260                 params()->datasetGap()!= 6 ? spaceBetweenDatasets = params()->datasetGap() * ( totalNumberOfBars - numValues )
00261                                            : spaceBetweenDatasets = ( barWidth/4 ) * ( totalNumberOfBars - numValues );
00262         }
00263         while (  barWidth*totalNumberOfBars + spaceBetweenValueBlocks + spaceBetweenDatasets > logWidth );
00264 
00265         valueBlockGap = ( spaceBetweenValueBlocks )/ numValues;
00266         if ( spaceBetweenDatasets != 0 )
00267             datasetGap = spaceBetweenDatasets /  ( totalNumberOfBars - numValues );
00268 
00269         barWidth = (logWidth - ( valueBlockGap * numValues ) - ( datasetGap * ( totalNumberOfBars - numValues ) ) ) / totalNumberOfBars;
00270         ;
00271 
00272         /* Debug space available
00273            qDebug (  " logWidth %f" ,  logWidth );
00274            qDebug (  "compare value %f",  barWidth*totalNumberOfBars + spaceBetweenValueBlocks + datasetGap * ( totalNumberOfBars - numValues ) );
00275         */
00276     } else if( 0 > params()->barWidth() )
00277         barWidth = params()->barWidth() * -areaWidthP1000;
00278     else
00279         barWidth = params()->barWidth();
00280 
00281     //sideBarWidth: pre-calculate in order to have a reference
00282     //we will correct according to the available space later.
00283     //This in order to center the labels in relation to the front width
00284     //when painting 3DBars
00285     double sideBarWidth = _bThreeDBars
00286                           ? ( barWidth - barWidth / (1.0 + params()->cosThreeDBarAngle()) ) *
00287                           params()->threeDBarDepth()
00288                           : 0.0;
00289 
00290     const double frontBarWidth = _bThreeDBars && !bMultiRows
00291                                  ? barWidth - sideBarWidth
00292                                  : barWidth;
00293 
00294     //correct the width for the side of the bar
00295     double totalThreeDBarWidth = totalNumberOfBars*barWidth + sideBarWidth;
00296     double totalSpaceOccupied = totalThreeDBarWidth + spaceBetweenDatasets + spaceBetweenValueBlocks;
00297     if ( logWidth < totalSpaceOccupied) {
00298         sideBarWidth -= (totalSpaceOccupied /*+  spaceBetweenDatasets + spaceBetweenValueBlocks*/ - logWidth)/totalNumberOfBars;
00299 
00300         //qDebug ( "logWidth %f", logWidth );
00301         //qDebug ( "totalSpaceOccupied %f", totalSpaceOccupied );
00302     }
00303 
00304     const double sideBarHeight = sideBarWidth;
00305 
00306 
00307     double pixelsPerUnit = 0.0;
00308 
00309     if ( params()->barChartSubType() != KDChartParams::BarPercent )  // not used for percent
00310         pixelsPerUnit = logHeight / ( columnValueDistance ? columnValueDistance : 10 );
00311 
00312     //qDebug("\nordinatePara->trueAxisLow()  = %f", ordinatePara->trueAxisLow());
00313     //qDebug(  "ordinatePara->trueAxisHigh() = %f", ordinatePara->trueAxisHigh());
00314     //qDebug(  "sideBarHeight            = %f", sideBarHeight);
00315     //qDebug(  "pixelsPerUnit            = %f", pixelsPerUnit);
00316 
00317     double zeroXAxisI;
00318     if ( params()->barChartSubType() == KDChartParams::BarPercent ) {
00319         if ( minColumnValue == 0.0 )
00320             zeroXAxisI = 0.0;
00321         else if ( maxColumnValue == 0.0 )
00322             zeroXAxisI = logHeight - sideBarHeight;
00323         else
00324             zeroXAxisI = ( logHeight - sideBarHeight ) / 2.0;
00325 
00326     } else {
00327         zeroXAxisI = logHeight
00328                      - ordinatePara->axisZeroLineStartY()
00329                      + _dataRect.y();
00330     }
00331 
00332     double shiftUpperBars =    (params()->barChartSubType() != KDChartParams::BarPercent)
00333                                && (ordinatePara->axisTrueLineWidth() % 2)
00334                                ? 1.0
00335                                : 0.0;
00336 
00337     // Initializing drawing positions
00338     double yposPositivesStart = logHeight;
00339     double yposNegativesStart = logHeight;
00340     if( params()->barChartSubType() == KDChartParams::BarPercent ){
00341         yposPositivesStart += axisYOffset;
00342         yposNegativesStart += axisYOffset;
00343     }
00344 
00345     for ( int iPaintExtraLinesOrTheData = 0;
00346           iPaintExtraLinesOrTheData < 3;
00347           ++iPaintExtraLinesOrTheData )
00348     {
00349 
00350         const bool bDrawExtraLines        = (1 != iPaintExtraLinesOrTheData);
00351         const bool bDrawExtraLinesInFront = (2 == iPaintExtraLinesOrTheData);
00352 
00353         double xpos = 0.0;
00354 
00355         if ( _bThreeDBars && !bMultiRows  )
00356             xpos = 0.0 + (barWidth/2) + (valueBlockGap/2) - (frontBarWidth/2);
00357         else
00358             xpos = 0.0 + (valueBlockGap / 2.0);
00359 
00360         double yposPositives = yposPositivesStart;
00361         double yposNegatives = yposNegativesStart;
00362 
00363         /* Pending Michel: no need for this anymore */
00364         //double totalThreeDBarWidth = bMultiRows
00365         //? barWidth + sideBarWidth
00366         //  : barWidth;
00367 
00368         double nShiftX = bMultiRows
00369                          ? sideBarWidth
00370                          : 0.0;
00371         double nShiftY = bMultiRows
00372                          ? sideBarHeight
00373                          : 0.0;
00374 
00375         double valueTotal = 0.0; // valueTotal is used for percent bars only
00376 
00377         // iterate over all columns: item1, item2, item3 ...
00378         int prevFrontX2 = 0;
00379         bool bIsVeryFirstBar = true;
00380         for ( int value = 0; value < numValues; ++value ) {
00381 
00382             bool bFirstValidValueUnknown = true;
00383             uint firstValidValue = 0;
00384             uint lastValidPositiveValue  = 0;
00385             double maxValueInThisColumn = 0.0, minValueInThisColumn = 0.0;
00386             if ( params()->barChartSubType() == KDChartParams::BarStacked ||
00387                  params()->barChartSubType() == KDChartParams::BarPercent) {
00388                 valueTotal = 0.0;
00389                 // iterate over datasets of this axis only:
00390                 for ( uint dataset  = datasetStart;
00391                       dataset <= datasetEnd;
00392                       ++dataset ) {
00393 
00394                     QVariant vVal;
00395                     if( data->cellCoord( dataset, value, vVal, 1 )
00396                         && params()->chartSourceMode( dataset ) == KDChartParams::DataEntry
00397                         && QVariant::Double == vVal.type() ){
00398 
00399                         const double cellValue
00400                             = ordinateIsLogarithmic
00401                             ? log10( vVal.toDouble() )
00402                             : vVal.toDouble();
00403                         //qDebug("value   %u    dataset   %u   logHeight %f", value,dataset,logHeight);
00404 
00405                         if( bFirstValidValueUnknown ){
00406                             firstValidValue = dataset;
00407                             bFirstValidValueUnknown = false;
00408                         }
00409                         if( 0.0 <= cellValue )
00410                             lastValidPositiveValue = dataset;
00411 
00412                         maxValueInThisColumn = QMAX( maxValueInThisColumn, cellValue );
00413                         minValueInThisColumn = QMIN( minValueInThisColumn, cellValue );
00414                         if( params()->barChartSubType() == KDChartParams::BarPercent /*||
00415                                                                                        params()->barChartSubType() == KDChartParams::BarStacked*/ )
00416                             valueTotal += cellValue;
00417                     }
00418                 }
00419             }
00420 
00421             //qDebug("shiftMyPainter( (numChartDataEntryDatasets-1)*nShiftX, (numChartDataEntryDatasets-1)*-nShiftY );");
00422             shiftMyPainter( (numChartDataEntryDatasets-1)*nShiftX, (numChartDataEntryDatasets-1)*-nShiftY );
00423 
00424             // iterate over all datasets of this chart:
00425             // (but draw only the bars of this axis)
00426             bool bIsFirstDataset = true;
00427             for ( uint dataset = bMultiRows
00428                                  ? chartDatasetEnd
00429                                  : chartDatasetStart;
00430                   dataset >= chartDatasetStart && dataset <= chartDatasetEnd;
00431                   bMultiRows
00432                                  ? --dataset
00433                                  : ++dataset ) {
00434                 //qDebug("value   %u    dataset   %u   logHeight %f", value,dataset,logHeight);
00435 
00436                 const bool bDataEntrySourceMode
00437                     = (params()->chartSourceMode( dataset ) == KDChartParams::DataEntry);
00438 
00439 
00440                 QVariant coord1;
00441                 QVariant coord2;
00442                 int propID;
00443                 if( data->cellContent( dataset, value, coord1, coord2, propID )
00444                     && QVariant::Double == coord1.type() ){
00445 
00446                     const double cellValue
00447                         = ordinateIsLogarithmic
00448                         ? log10( coord1.toDouble() )
00449                         : coord1.toDouble();
00450                     //qDebug("b");
00451                     // there is a numeric value
00452 
00453                     double barHeight;
00454 
00455                     if ( params()->barChartSubType() == KDChartParams::BarPercent )
00456                         barHeight = ( cellValue / valueTotal ) * fabs(zeroXAxisI - logHeight );
00457                     else {
00458                         barHeight = pixelsPerUnit * cellValue;
00459 
00460                         if( 0.0 <= barHeight )
00461                             //barHeight = QMAX(0.0, barHeight - sideBarHeight);
00462                             barHeight = barHeight - sideBarHeight;
00463                         else
00464                             barHeight -= sideBarHeight;
00465                     }
00466 
00467                     // This little adjustment avoids a crash when trying
00468                     // to retrieve the bounding rect of a zero size region...
00469                     if( 0 == barHeight || 0.0 == barHeight ) {
00470 
00471                         barHeight = 1.0; // makes sense to have a min size anyway
00472                     }
00473 
00474                     // draw only the bars belonging to the axis
00475                     // which we are processing currently
00476                     if( dataset >= datasetStart && dataset <= datasetEnd ) {
00477                         //qDebug("b2");
00478 
00479                         // calculate Abscissa axis value, if there are X coordinates
00480                         // ---------------------------------------------------------
00481                         bool skipMe = false;
00482                         if( ai.bCellsHaveSeveralCoordinates ){
00483                             skipMe = !calculateAbscissaAxisValue( coord2,
00484                                                                   ai, 0, xpos );
00485                             // adjust bar position to have it horizontally centered to the point
00486                             if( ai.bAbscissaHasTrueAxisDtValues &&
00487                                 QVariant::DateTime == coord2.type() )
00488                                 xpos -= frontBarWidth / 2.0;
00489                         }
00490 
00491                         if( !skipMe ){
00492                             // Configure colors
00493                             QColor myBarColor(     params()->dataColor(        dataset ) );
00494                             QColor myShadow1Color( params()->dataShadow1Color( dataset ) );
00495                             QColor myShadow2Color( params()->dataShadow2Color( dataset ) );
00496 
00497                             // Get default values for extra lines and their markers
00498                             const KDChartParams::LineMarkerStyle
00499                                 defaultMarkerStyle = params()->lineMarkerStyle( dataset );
00500                             const QPen defaultPen(   params()->lineColor().isValid()
00501                                                      ? params()->lineColor()
00502                                                      : params()->dataColor( dataset ),
00503                                                      params()->lineWidth(),
00504                                                      params()->lineStyle( dataset ) );
00505 
00506                             // --------------------------------------------------------
00507                             // determine any 'extra' properties assigned to this cell
00508                             // by traversing the property set chain (if necessary)
00509                             // --------------------------------------------------------
00510                             KDChartPropertySet propSet;
00511                             bool bCellPropertiesFound =
00512                                 params()->calculateProperties( propID,
00513                                                                propSet );
00514                             bool bShowThisBar = bDataEntrySourceMode;
00515                             if( bCellPropertiesFound ){
00516                                 if( bShowThisBar && !bDrawExtraLines ){
00517                                     int  iDummy;
00518                                     if( propSet.hasOwnShowBar( iDummy, bShowThisBar ) ){
00519                                         // NOP
00520                                     }
00521                                     if( propSet.hasOwnBarColor( iDummy, myBarColor ) ){
00522                                         // adjust the shadow colors
00523                                         params()->calculateShadowColors( myBarColor,
00524                                                                          myShadow1Color,
00525                                                                          myShadow2Color );
00526                                     }
00527                                 }
00528                             }
00529 
00530                             if( !bDrawExtraLines || bCellPropertiesFound ){
00531 
00532                                 //QRegion* region = 0;
00533                                 KDChartDataRegion::PointArrayList * pointArrayList = 0;
00534                                 if( bDataEntrySourceMode && !bDrawExtraLines ){
00535                                     painter->setPen( defaultOutlinePen );
00536                                     if ( myBarColor.isValid() )
00537                                         painter->setBrush( myBarColor );
00538                                     else
00539                                         painter->setBrush( NoBrush );
00540 
00541                                     // Prepare region for detection of mouse clicks
00542                                     // and for finding anchor positions of data value texts
00543                                     if ( regions )
00544                                         pointArrayList = new KDChartDataRegion::PointArrayList();
00545                                 }
00546 
00547                                 // Start drawing
00548                                 int frontX1 = 0;
00549                                 int frontX2 = 0;
00550                                 bool tooLow = false;
00551                                 bool tooHigh = false;
00552 
00553                                 if ( cellValue < 0 || cellValue < minColumnValue ) {
00554                                     double maxValueYPos = maxColumnValue * pixelsPerUnit;
00555                                     double yZero = yposNegatives - zeroXAxisI - sideBarHeight;
00556 
00557                                     tooLow = (barHeight - yZero + logHeight + axisYOffset) < 0;
00558 
00559                                     /*we need to handle those values in case we have a negative view*/
00560                                     if ( cellValue <= 0 && cellValue > maxColumnValue && minColumnValue < 0 && maxColumnValue < 0 )
00561                                         tooLow = true;
00562 
00563                                     if ( tooLow && ( bNormalMode || bMultiRows) ) {
00564                                         double delta   = 0.0125 * logHeight;
00565                                         double height  = -1*(-1.0 * (yZero  + sideBarHeight) - 2 * delta);
00566                                         double height1 = height - 3.0 * delta;
00567 
00568                                         int yArrowGap = static_cast < int > ( 2.5 * delta );
00569                                         calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
00570                                                             xpos, valueBlockGap, datasetGap, frontBarWidth,
00571                                                             frontX1, frontX2, prevFrontX2 );
00572 
00573                                         const int xm = static_cast < int > ( (frontX1 + frontX2) / 2.0 );
00574                                         QRect rect( ourClipRect );
00575 
00576                                         rect.setHeight( static_cast<int>( rect.height() + 3.0 * delta ) );
00577                                         painter->setClipRect( rect );
00578 
00579                                         //Pending Michel: Make sure the point of the arrow is always at the same distance
00580                                         //from the X axis reference to the point of the arrow.
00581                                         int arrowXAxisGap;
00582                                         QPoint arrowTop(  xm,static_cast<int>( yZero + height1 + 2 * yArrowGap) );
00583 
00584                                         if ( arrowTop.y()== yposNegatives )
00585                                             arrowXAxisGap = -2;
00586                                         else
00587                                             arrowXAxisGap = static_cast <int> (yposNegatives - arrowTop.y() - 2);
00588 
00589                                         if( bDrawExtraLines ){
00590                                             drawExtraLinesAndMarkers(
00591                                                 propSet,
00592                                                 defaultPen,
00593                                                 defaultMarkerStyle,
00594                                                 xm, static_cast<int>( yZero + height1 ),
00595                                                 painter,
00596                                                 ai.abscissaPara,
00597                                                 ordinatePara,
00598                                                 areaWidthP1000,
00599                                                 logHeight/1000.0,
00600                                                 bDrawExtraLinesInFront );
00601                                         }else if( bShowThisBar ){
00602                                             if( params()->drawSolidExcessArrows() ) {
00603 
00604                                                 /* PENDING Michel:
00605                                                  * Here we have two situations.
00606                                                  * The value is too low because over the Min negative value
00607                                                  * or it is not within the configured view.
00608                                                  */
00609                                                 // Draw solid excess arrows negatives
00610 
00611                                                 QPointArray points( 5 );
00612                                                 /*this works in a positive view -> 200 500*/
00613                                                 points.setPoint( 0, frontX1, cellValue < 0  ?
00614                                                                                static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
00615                                                                  static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap);
00616                                                 points.setPoint( 1, frontX2, cellValue < 0 ?
00617                                                                               static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
00618                                                                  static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap );
00619                                                 points.setPoint( 2, frontX2, cellValue < 0 ?
00620                                                                                static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
00621                                                                  static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap);
00622                                                 points.setPoint( 3, xm, cellValue < 0 ?
00623                                                                           static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap:
00624                                                                  static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap);
00625                                                 points.setPoint( 4, frontX1, cellValue < 0  ?
00626                                                                                static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
00627                                                                  static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap);
00628 
00629                                                 /* 0 between start and end -> -500 500*/
00630                                                 if ( minColumnValue < 0 && maxColumnValue > 0 ) {
00631                                                     points.setPoint(0, points.point(0).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
00632                                                     points.setPoint(1, points.point(1).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
00633                                                 }
00634 
00635                                                 /* negative view -> -200 -500 */
00636                                                 if ( minColumnValue < 0 && maxColumnValue < 0 ) {
00637                                                     /*value negative or zero > maxColumnValue*/
00638                                                     if ( cellValue > maxColumnValue ) {
00639                                                         // the view is under Yaxis 0 level
00640                                                         // we need to show a symbol for the bars which are over the Yaxis.
00641                                                         // calculate the coordinate and direction for the arrow.
00642                                                         // arrow downward for negative values and upward for positives value
00643                                                         int diffArrowBase = points.point(2).y() - points.point(3).y();
00644                                                         double maxValueYPos = maxColumnValue * pixelsPerUnit;
00645                                                         double minValueYPos = minColumnValue * pixelsPerUnit;
00646                                                         double adjustedArrow = (cellValue == 0 ? minValueYPos - maxValueYPos + diffArrowBase + 2:
00647                                                                                 minValueYPos - maxValueYPos - diffArrowBase + 1);
00648                                                         points.setPoint( 0, frontX1, points.point(0).y() + static_cast <int> (adjustedArrow));
00649                                                         points.setPoint( 1, frontX2, points.point(1).y() + static_cast <int> (adjustedArrow ));
00650                                                         points.setPoint( 2, frontX2, points.point(2).y() + static_cast <int> (adjustedArrow));
00651                                                         points.setPoint( 3, xm, points.point(3).y() + static_cast <int> (adjustedArrow));
00652                                                         points.setPoint( 4, frontX1, points.point(4).y() + static_cast <int> (adjustedArrow));
00653                                                     }
00654                                                     /*value < mincolumn value*/
00655                                                     if ( cellValue < minColumnValue ) {
00656                                                         points.setPoint( 0, frontX1, static_cast <int> ( yZero - maxValueYPos ) );
00657                                                         points.setPoint( 1, frontX2, static_cast <int> ( yZero - maxValueYPos ) );
00658                                                     }
00659 
00660                                                 }
00661 
00662                                                 /*Pending Michel: case setbarWidth */
00663                                                 //adjust the painting in case we have a user given Width allow it
00664                                                 //to be larger than the auto calculated width in case we want to overlap
00665 
00666                                                 if ( params()->userWidth() != 0 ) {
00667                                                     int userwidth = 0;
00668                                                     if ( params()->userWidth() < 0 )
00669                                                         userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
00670                                                     else
00671                                                         userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
00672                                                     //if ( userwidth < frontBarWidth ) {
00673                                                     QRect tmpRect ( points.point(0), points.point(2));
00674                                                     points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
00675                                                                     points.point(0).y());
00676                                                     points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
00677                                                                     points.point(1).y());
00678                                                     points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
00679                                                                     points.point(2).y());
00680                                                     points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
00681                                                                     points.point(4).y());
00682                                                     //}
00683                                                 }
00684                                                 if ( bMultiRows )painter->setClipping(  false );
00685                                                 painter->drawPolygon( points );
00686 
00687                                                 //correct the y position: displaying position for the value label
00688                                                   QPoint tpLeft (points.point(4).x(), points.point(4).y() - 2 * yArrowGap );
00689                                                   QPoint tpRight(points.point(2).x(), points.point(2).y() - 2 * yArrowGap );
00690 
00691                                                 //store the front rectangle
00692                                                 excessRectNegative.setTopLeft(tpLeft);
00693                                                 excessRectNegative.setTopRight(tpRight);
00694                                                 excessRectNegative.setBottomRight(points.point(1));
00695                                                 excessRectNegative.setBottomLeft(points.point(0));
00696 
00697                                                 // Don't use points for drawing after this!
00698                                                 if ( pointArrayList ) {
00699                                                     if (  cellValue < 0 ) {
00700                                                         //correction for labels vertical position
00701                                                         int size = static_cast <int> ( ( points.point( 3 ).y() - tpRight.y() + excessRectNegative.width() )/2 );
00702                                                         points.setPoint( 4 ,tpLeft );
00703                                                         points.setPoint( 2, tpRight );
00704                                                         if (  cellValue < maxColumnValue )
00705                                                             points.translate( _dataRect.x(), -_dataRect.y() - size );
00706                                                         else
00707                                                             points.translate( _dataRect.x(), _dataRect.y() );
00708                                                     } else
00709                                                         points.translate(  _dataRect.x(),  _dataRect.y() );
00710 
00711                                                     pointArrayList->append( points );
00712                                                 }
00713 
00714                                             } else {
00715                                                 // Draw split excess arrows negatives
00716 
00717                                                 /* PENDING Michel:
00718                                                  * Here we have two situations.
00719                                                  * The value is too low because over the Min negative value
00720                                                  * The value is not within the configured view..
00721                                                  */
00722                                                 QPointArray points( 5 );
00723                                                 /*this works in a positive view -> 200 500*/
00724                                                 points.setPoint( 0, frontX1, cellValue < 0  ?
00725                                                                                static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
00726                                                                  static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
00727                                                 points.setPoint( 1, frontX2, cellValue < 0 ?
00728                                                                               static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
00729                                                                  static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
00730                                                 points.setPoint( 2, frontX2, cellValue < 0 ?
00731                                                                                static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
00732                                                                  static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
00733                                                 points.setPoint( 3, xm, cellValue < 0 ?
00734                                                                           static_cast<int>( yZero + height1) + arrowXAxisGap:
00735                                                                  static_cast<int>(yZero+height1 - 3.0*delta)+(2 * yArrowGap)+ arrowXAxisGap);
00736                                                 points.setPoint( 4, frontX1, cellValue < 0  ?
00737                                                                  static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
00738                                                                  static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
00739 
00740                                                 /* 0 between start and end -> -500 500*/
00741                                                 if ( minColumnValue < 0 && maxColumnValue > 0 ) {
00742                                                     points.setPoint(0, points.point(0).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
00743                                                     points.setPoint(1, points.point(1).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
00744                                                 }
00745 
00746                                                 /* negative view -> -200 -500 */
00747                                                 if ( minColumnValue < 0 && maxColumnValue < 0 ) {
00748                                                     /*value negative or zero > maxColumnValue*/
00749                                                     if ( cellValue > maxColumnValue ) {
00750                                                         // the view is under Yaxis 0 level
00751                                                         // we need to show a symbol for the bars which are over the Yaxis.
00752                                                         // calculate the coordinate and direction for the arrow.
00753                                                         // arrow downward for negative values and upward for positives value
00754                                                         int diffArrowBase = points.point(2).y() - points.point(3).y();
00755                                                         double maxValueYPos = maxColumnValue * pixelsPerUnit;
00756 
00757                                                         points.setPoint( 0, frontX1, static_cast <int> ( yZero - maxValueYPos) );
00758                                                         points.setPoint( 1, frontX2, static_cast <int> ( yZero - maxValueYPos) );
00759                                                         points.setPoint( 2, frontX2, static_cast <int> ( yZero - maxValueYPos) );
00760                                                         points.setPoint( 3, xm, static_cast <int> ( yZero - maxValueYPos - diffArrowBase ) );
00761                                                         points.setPoint( 4, frontX1, static_cast <int> ( yZero - maxValueYPos) );
00762                                                     }
00763                                                     /*value < mincolumn value*/
00764                                                     if ( cellValue < minColumnValue ) {
00765                                                         points.setPoint( 0, frontX1, static_cast <int> ( yZero - maxValueYPos) );
00766                                                         points.setPoint( 1, frontX2, static_cast <int> ( yZero - maxValueYPos) );
00767                                                     }
00768                                                 }
00769 
00770                                                 //Pending Michel adjust the painting in case we have a user given Width
00771                                                 //allow it to be larger than the auto calculated width in case we want
00772                                                 //to overlap
00773                                                 if ( params()->userWidth() != 0 ) {
00774                                                     int userwidth = 0;
00775                                                     if ( params()->userWidth() < 0 )
00776                                                         userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
00777                                                     else
00778                                                         userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
00779                                                     //if ( userwidth < frontBarWidth ) {
00780                                                     QRect tmpRect ( points.point(0), points.point(2));
00781                                                     points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
00782                                                                     points.point(0).y());
00783                                                     points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
00784                                                                     points.point(1).y());
00785                                                     points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
00786                                                                     points.point(2).y());
00787                                                     points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
00788                                                                     points.point(4).y());
00789                                                 }
00790                                                 if ( bMultiRows )painter->setClipping(  false );
00791                                                  painter->drawPolygon( points );
00792 
00793                                                  //correct the y position: displaying position for the value label
00794                                                  QPoint tpLeft (points.point(4).x(), points.point(4).y() - 2 * yArrowGap );
00795                                                  QPoint tpRight(points.point(2).x(), points.point(2).y() - 2 * yArrowGap );
00796 
00797                                                 //store the excess front rectangle
00798                                                 excessRectNegative.setTopLeft(tpLeft);
00799                                                 excessRectNegative.setTopRight(tpRight);
00800                                                 excessRectNegative.setBottomRight(points.point(1));
00801                                                 excessRectNegative.setBottomLeft(points.point(0));
00802 
00803                                                 // Don't use points for drawing after this!
00804                                                 if ( pointArrayList ) {
00805                                                     if (  cellValue < 0 ) {
00806                                                         //calculate correction for labels vertical position
00807                                                         int size = static_cast <int> ( ( points.point( 3 ).y() - tpRight.y() + excessRectNegative.width() )/2 );
00808                                                         if (  cellValue < maxColumnValue )
00809                                                         points.translate( _dataRect.x(), -_dataRect.y() - size );
00810                                                         else
00811                                                             points.translate( _dataRect.x(), _dataRect.y() + ( 2 * yArrowGap ) );
00812                                                     } else
00813                                                         points.translate(  _dataRect.x(),  -_dataRect.y() );
00814 
00815                                                     pointArrayList->append( points );
00816                                                 }
00817 
00818                                                 QPointArray points2( 6 );
00819                                                 points2.setPoint( 0, frontX1, cellValue < 0 ?
00820                                                                                 static_cast<int>( yZero + height1 - 3.0 * delta ) + arrowXAxisGap:
00821                                                                   static_cast<int>(yZero + height1) + arrowXAxisGap);
00822                                                 points2.setPoint( 1, xm,      cellValue < 0 ?
00823                                                                   static_cast<int>(yZero + height1) + arrowXAxisGap:
00824                                                                   static_cast<int>( yZero + height1 - 3.0 * delta ) + arrowXAxisGap);
00825                                                 points2.setPoint( 2, frontX2, cellValue < 0 ?
00826                                                                   static_cast<int>(yZero + height1 - 3.0 * delta) + arrowXAxisGap:
00827                                                                   static_cast<int>(yZero + height1) + arrowXAxisGap);
00828                                                 points2.setPoint( 3, frontX2, cellValue < 0 ?
00829                                                                   static_cast<int>(yZero + height1 - 3.75 * delta) + arrowXAxisGap :
00830                                                                   static_cast<int>(yZero + height1 - 0.75 * delta)  + arrowXAxisGap);
00831                                                 points2.setPoint( 4, xm,      cellValue < 0 ?
00832                                                                   static_cast<int>(yZero + height1 - 0.75 * delta)  + arrowXAxisGap:
00833                                                                   static_cast<int>(yZero + height1 - 3.75 * delta) + arrowXAxisGap);
00834                                                 points2.setPoint( 5, frontX1, cellValue < 0 ?
00835                                                                   static_cast<int>(yZero + height1 - 3.75 * delta)  + arrowXAxisGap:
00836                                                                   static_cast<int>(yZero + height1 - 0.75 * delta)  + arrowXAxisGap);
00837                                                 points2.translate( 0, yArrowGap );
00838 
00839                                                 if ( minColumnValue < 0 && maxColumnValue < 0 &&  cellValue > maxColumnValue ) {
00840                                                     // the view is under Yaxis 0 level
00841                                                     // we need to show a symbol for the bars which are over the Yaxis.
00842                                                     // calculate the coordinate and direction for the arrow.
00843                                                     // arrow downward for negative values and upward for positives value
00844                                                     int diffArrowBase = points.point(2).y() - points.point(3).y();
00845                                                     double maxValueYPos = maxColumnValue * pixelsPerUnit;
00846                                                     double minValueYPos = minColumnValue * pixelsPerUnit;
00847                                                     double adjustedArrow = cellValue == 0 ? minValueYPos - maxValueYPos + diffArrowBase:
00848                                                                            minValueYPos - maxValueYPos - diffArrowBase + 1;
00849 
00850                                                     points2.setPoint( 0, frontX1, points2.point(0).y()
00851                                                                       + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
00852                                                     points2.setPoint( 1, xm,  points2.point(1).y()
00853                                                                       + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
00854                                                     points2.setPoint( 2, frontX2, points2.point(2).y()
00855                                                                       +  static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
00856                                                     points2.setPoint( 3, frontX2, points2.point(3).y()
00857                                                                       + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
00858                                                     points2.setPoint( 4, xm, points2.point(4).y()
00859                                                                       + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
00860                                                     points2.setPoint( 5, frontX1, points2.point(5).y()
00861                                                                       + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
00862                                                 }
00863 
00864                                                 //Pending Michel adjust the painting in case we have a user given Width
00865                                                 //allow it to be larger than the auto calculated width in case we want
00866                                                 //to overlap
00867                                                 if ( params()->userWidth() != 0 ) {
00868                                                     int userwidth = 0;
00869                                                     if ( params()->userWidth() < 0 )
00870                                                         userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
00871                                                     else
00872                                                         userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
00873                                                     //if ( userwidth < frontBarWidth ) {
00874 
00875                                                     points2.setPoint(0, excessRectNegative.topLeft().x(),points2.point(0).y());
00876                                                     points2.setPoint(2, excessRectNegative.topRight().x(),points2.point(2).y());
00877                                                     points2.setPoint(3, excessRectNegative.topRight().x(),points2.point(3).y());
00878                                                     points2.setPoint(5, excessRectNegative.topLeft().x(),points2.point(5).y());
00879                                                 }
00880 
00881                                                 painter->drawPolygon( points2 );
00882 
00883                                                 /*
00884                                                   NOTE:  We do NOT want to store the region here, but
00885                                                   we use the front rectangle above in order to display the
00886                                                   data value labels inside the front rectangle.
00887                                                   Disadvantage: clicking onto these excess arrows, will not
00888                                                   result in a signal being sent, because KDChartWidget will
00889                                                   not notice, that the user has clicked onto the bar.
00890                                                   That's a minor drawback, compared to the gain of being
00891                                                   able to position the labels correctly.
00892                                                 */
00893 
00894                                                 if ( cellValue < 0  )
00895                                                     points2.translate( 0, yArrowGap );
00896                                                 else
00897                                                     points2.translate( 0, -yArrowGap );
00898 
00899                                                 painter->drawPolygon( points2 );
00900 
00901 
00902                                                 /*
00903                                                   NOTE:  We do NOT want to store the region here
00904                                                   (see comment above)
00905                                                 */
00906                                             }
00907                                         }
00908                                         painter->setClipRect( ourClipRect );
00909                                     } /*if (tooLow && bNormalMode)*/
00910                                     else {
00911                                         //
00912                                         // old code (sometimes not touching the grid):
00913                                         //QRect rec( xpos, yZero, frontBarWidth, -barHeight );
00914                                         //painter->drawRect( rec );
00915                                         //
00916 
00917                                         int pt1Y = static_cast < int > ( yZero - barHeight /*- sideBarsHeight*/ );
00918 
00919                                         /*
00920                                           if ( cellValue != 0 ) {
00921                                           pt1Y = static_cast <int> (cellValue * pixelsPerUnit * -2);
00922                                           qDebug( "value %s",QString::number(static_cast <int> (cellValue)).latin1());
00923                                           qDebug( "pt1Y %s", QString::number(static_cast <int> (cellValue * pixelsPerUnit * -2)).latin1());
00924                                           }
00925                                           else
00926                                           pt1Y = static_cast < int > ( yZero - barHeight);
00927                                         */
00928                                         calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
00929                                                             xpos, valueBlockGap, datasetGap, frontBarWidth,
00930                                                             frontX1, frontX2, prevFrontX2 );
00931 
00932                                         QPoint pt1( frontX1, pt1Y );
00933                                         QPoint pt2( frontX2,
00934                                                     static_cast < int > ( yZero + sideBarHeight) );
00935 
00936                                         if( 0.0 > maxColumnValue ){
00937                                             pt2.setY(pt2.y() - static_cast < int > (pixelsPerUnit * maxColumnValue));
00938                                         }
00939                                         if( pt2.y() < pt1Y ) {
00940                                             pt1.setY( pt2.y() );
00941                                             pt2.setY( pt1Y );
00942                                         }
00943                                         if( pt2.x() < frontX1 ) {
00944                                             pt1.setX( frontX2 );
00945                                             pt2.setX( frontX1 );
00946                                         }
00947                                         if( bDrawExtraLines ){
00948                                             int y = pt2.y();
00949                                             if( _bThreeDBars )
00950                                                 y -= static_cast < int > ( sideBarHeight );
00951                                             drawExtraLinesAndMarkers(
00952                                                 propSet,
00953                                                 defaultPen,
00954                                                 defaultMarkerStyle,
00955                                                 (frontX1+frontX2)/2, y,
00956                                                 painter,
00957                                                 ai.abscissaPara,
00958                                                 ordinatePara,
00959                                                 areaWidthP1000,
00960                                                 logHeight/1000.0,
00961                                                 bDrawExtraLinesInFront );
00962                                         }else if( bShowThisBar ){
00963 
00964                                             QSize siz( pt2.x() - pt1.x(),
00965                                                        pt2.y() - pt1.y() );
00966                                             QRect rect( pt1, siz );
00967 
00968                                             if( 1.5 > frontBarWidth ){
00969                                                 QPen oldPen( painter->pen() );
00970                                                 painter->setPen( QPen(painter->brush().color(), 0) );
00971                                                 painter->drawLine(pt1, QPoint(pt1.x(),pt2.y()));
00972                                                 painter->setPen( oldPen );
00973                                             }else{
00974                                                 // store the front rect negative
00975                                                 if ( tooLow || cellValue < minColumnValue) {
00976                                                     frontRectNegative.setTopLeft(excessRectNegative.bottomLeft());
00977                                                     frontRectNegative.setTopRight(excessRectNegative.bottomRight());
00978                                                     frontRectNegative.setBottomRight(excessRectNegative.topRight());
00979                                                     frontRectNegative.setBottomLeft(excessRectNegative.topLeft());
00980 
00981                                                 } else {
00982                                                     frontRectNegative.setTopLeft(rect.topLeft());
00983                                                     frontRectNegative.setTopRight(rect.topRight());
00984                                                     frontRectNegative.setBottomRight(rect.bottomRight());
00985                                                     frontRectNegative.setBottomLeft(rect.bottomLeft());
00986 
00987                                                     if ( cellValue == 0 && params()->barChartSubType() == KDChartParams::BarPercent)
00988                                                         rect.setTop( rect.bottom());
00989                                                 }
00990 
00991                                                 //debug  lines and points
00992                                                 /*
00993                                                   painter->drawLine( rect.topLeft(), rect.topRight());
00994                                                   painter->drawLine( rect.topRight(), rect.bottomRight());
00995                                                   painter->drawLine( rect.bottomRight(), rect.bottomLeft());
00996                                                   painter->drawLine( rect.bottomLeft(), rect.topLeft());
00997 
00998                                                   painter->drawText( frontRectNegative.topLeft(), "0f");
00999                                                   painter->drawText( frontRectNegative.topRight(), "1f");
01000                                                   painter->drawText( frontRectNegative.bottomRight(), "2f");
01001                                                   painter->drawText( frontRectNegative.bottomLeft(), "3f");
01002                                                 */
01003 
01004                                                 //Pending Michel adjust the painting in case we have a user given Width
01005                                                 //and it is not larger than the auto calculated width
01006 
01007                                                 if ( params()->userWidth() != 0 ) {
01008                                                     int userwidth = 0;
01009                                                     if ( params()->userWidth() < 0 )
01010                                                         userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
01011                                                     else
01012                                                         userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
01013                                                     //if ( userwidth < frontBarWidth ) {
01014                                                     rect.setLeft( static_cast <int> (rect.center().x() - (userwidth/2)));
01015                                                     rect.setRight( static_cast <int> (rect.center().x() + (userwidth/2)));
01016                                                     rect.setWidth( static_cast <int> (userwidth) );
01017                                                     frontRectNegative.setLeft( tooLow || cellValue < minColumnValue ?
01018                                                                                static_cast <int> (excessRectNegative.center().x() - (userwidth/2)):rect.left());
01019                                                     frontRectNegative.setRight( tooHigh ? static_cast <int> (excessRectNegative.center().x() + (userwidth/2)):rect.right());
01020                                                 }
01021                                                 //drawing the front size negative values
01022                                                 if ( cellValue != 0 && params()->barChartSubType() != KDChartParams::BarPercent) {
01023                                                     painter->setClipping( false );
01024                                                     painter->drawRect( rect );
01025                                                 }
01026                                             }
01027                                             // Don't use rect for drawing after this!
01028                                             if ( pointArrayList ) {
01029                                                 rect.moveBy( _dataRect.x(), _dataRect.y() );
01030                                                 pointArrayList->append( rectToPointArray( rect ) );
01031                                             }
01032                                         }
01033                                     }
01034                                 } else {
01035                                     //
01036                                     //  Positive values:
01037                                     //
01038                                     /*Pending Michel: all values under the min value are handled as negative*/
01039 
01040                                     double maxValueYPos = maxColumnValue * pixelsPerUnit;
01041                                     double minValueYPos = minColumnValue * pixelsPerUnit;
01042                                     double minDataValueYPos = maxValueYPos - minValueYPos;
01043                                     double yZero = yposPositives - zeroXAxisI;
01044                                     //qDebug( "yposPositives %f - zeroXAxisI %f = %f" ,  yposPositives,  zeroXAxisI,  yZero );
01045                                     //qDebug( "yZero %s", QString::number( yZero ).latin1());
01046                                     //qDebug( "minDataValueYPos = %s",  QString::number( minDataValueYPos).latin1());
01047                                     //qDebug( "positive value %s",  QString::number( cellValue).latin1());
01048                                     //Pending Michel: draw the default split excess arrows
01049                                     //when the front top of the 3d chart reach the max Y value
01050 
01051                                     if(!_bThreeDBars)
01052                                         tooHigh =  ( barHeight > maxValueYPos*1.001 ) || ( cellValue < minColumnValue );
01053                                     else {
01054                                         //calculate the Y position for the top front line
01055                                         //if it is over the max height pos - tooHigh becomes true
01056                                         if ( params()->barChartSubType()!= KDChartParams::BarStacked ) {
01057                                             int dataValueYPos = static_cast <int>( ( cellValue * pixelsPerUnit ) );
01058                                             tooHigh = dataValueYPos > maxValueYPos;
01059                                         } else {
01060                                             tooHigh = maxValueInThisColumn > maxColumnValue;
01061                                         }
01062                                     }
01063 
01064                                     if ( tooHigh && bNormalMode ||
01065                                          tooHigh && params()->barChartSubType()== KDChartParams::BarStacked
01066                                          || tooHigh && bMultiRows ) {
01067 
01068                                         double delta   = -0.0125 * logHeight;
01069                                         double height  = -1.0 * yZero
01070                                                          - 2.0 * delta;
01071                                         double height1 = height + -3.0 * delta;
01072 
01073                                         int yArrowGap = static_cast < int > ( 2.5 * delta );
01074                                         calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
01075                                                             xpos, valueBlockGap, datasetGap, frontBarWidth,
01076                                                             frontX1, frontX2, prevFrontX2 );
01077 
01078                                         const int xm = static_cast < int > ( ( frontX1 + frontX2 ) / 2.0 );
01079                                         QRect rect( ourClipRect );
01080 
01081                                         rect.setTop( static_cast<int>( rect.top() + 3 * delta ) );
01082                                         rect.setHeight( static_cast<int>( rect.height() - 3 * delta ) );
01083                                         painter->setClipRect( rect );
01084 
01085                                         if( bDrawExtraLines ){
01086                                             drawExtraLinesAndMarkers(
01087                                                 propSet,
01088                                                 defaultPen,
01089                                                 defaultMarkerStyle,
01090                                                 xm, static_cast<int>( yZero + height1 ),
01091                                                 painter,
01092                                                 ai.abscissaPara,
01093                                                 ordinatePara,
01094                                                 areaWidthP1000,
01095                                                 logHeight/1000.0,
01096                                                 bDrawExtraLinesInFront );
01097                                         }else if( bShowThisBar ){
01098                                             if( params()->drawSolidExcessArrows() ) {
01099                                                 // Draw solid excess arrows
01100                                                 QPointArray points( 5 );
01101                                                 /*this works for positive config and 0 include config*/
01102                                                 points.setPoint( 0, frontX1,
01103                                                                  (minDataValueYPos < static_cast <int> (yZero))?
01104                                                                  static_cast <int> (minDataValueYPos-1):static_cast <int>(yZero));
01105                                                 points.setPoint( 1, frontX2,
01106                                                                  (minDataValueYPos < static_cast <int> (yZero))?
01107                                                                  static_cast <int> (minDataValueYPos-1):static_cast <int>(yZero));
01108                                                 points.setPoint( 2, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta )
01109                                                                  + 2 * yArrowGap );
01110                                                 points.setPoint( 3, xm,      static_cast<int>( yZero + height1 )
01111                                                                  + 2 * yArrowGap );
01112                                                 points.setPoint( 4, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta )
01113                                                                  + 2 * yArrowGap );
01114 
01115                                                 /*case where start and end value are negatives */
01116                                                 if ( cellValue > maxColumnValue && 0 >= maxColumnValue ) {
01117                                                     points.setPoint( 0, frontX1,static_cast<int>( yZero + height1 - 3.0 * delta ) + 2 * yArrowGap);
01118                                                     points.setPoint( 1, frontX2,static_cast<int>( yZero + height1 - 3.0 * delta ) + 2 * yArrowGap);
01119                                                 }
01120 
01121                                                 //Pending Michel adjust the painting in case we have a user given Width
01122                                                 //allow it to be larger than the auto calculated width in case we want
01123                                                 //to overlap
01124                                                 if ( params()->userWidth() != 0 ) {
01125                                                     int userwidth = 0;
01126                                                     if ( params()->userWidth() < 0 )
01127                                                         userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
01128                                                     else
01129                                                         userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
01130                                                     //if ( userwidth < frontBarWidth ) {
01131                                                     QRect tmpRect ( points.point(0), points.point(2));
01132                                                     points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
01133                                                                     points.point(0).y());
01134                                                     points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
01135                                                                     points.point(1).y());
01136                                                     points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
01137                                                                     points.point(2).y());
01138                                                     points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
01139                                                                     points.point(4).y());
01140                                                     //}
01141                                                 }
01142                                                 if ( params()->barChartSubType() != KDChartParams::BarStacked ||
01143                                                      params()->barChartSubType() == KDChartParams::BarStacked && dataset != datasetEnd ) {
01144                                                     //drawing a single front in case it is too high
01145                                                     painter->setClipping(  false );
01146                                                     painter->drawPolygon( points );
01147                                                 }
01148                                                 //correct the y position: displaying position for the value label
01149                                                 QPoint tpLeft (points.point(4).x(), static_cast <int> (points.point(4).y() -  yArrowGap));
01150                                                 QPoint tpRight(points.point(2).x(), static_cast <int> (points.point(2).y() -  yArrowGap));
01151 
01152                                                 //debugging points
01153                                                 /*
01154                                                   painter->drawText( points.point(0), "p0");
01155                                                   painter->drawText( points.point(1), "p1");
01156                                                   painter->drawText( points.point(2), "p2");
01157                                                   painter->drawText( points.point(3), "p3");
01158                                                 */
01159                                                 //store the front rectangle
01160                                                 excessRectPositive.setTopLeft(tpLeft);
01161                                                 excessRectPositive.setTopRight(tpRight);
01162                                                 excessRectPositive.setBottomRight(points.point(1));
01163                                                 excessRectPositive.setBottomLeft(points.point(0));
01164 
01165                                                 // Don't use points for drawing after this!
01166                                                 if ( pointArrayList && params()->barChartSubType() != KDChartParams::BarStacked ) {
01167                                                     points.translate( _dataRect.x(), _dataRect.y()  + excessRectPositive.top() - yArrowGap );
01168                                                     pointArrayList->append( points );
01169                                                 } else if ( params()->barChartSubType() == KDChartParams::BarStacked )  {
01170                                                     if ( dataset != datasetEnd ) {
01171                                                         points.translate( _dataRect.x(), _dataRect.y()  + excessRectPositive.top() );
01172                                                         pointArrayList->append( points );
01173                                                     } else {
01174                                                         //adjust the display of the value label under Y  max value level
01175                                                         points.translate( _dataRect.x(), _dataRect.y() - excessRectPositive.bottom() - yArrowGap);
01176                                                         pointArrayList->append( points );
01177                                                     }
01178                                                 }
01179                                             } else {
01180 
01181                                                 // Draw split excess arrows (default)
01182                                                 /* PENDING Michel:
01183                                                  * Here we have two situations.
01184                                                  * The value is too high because over the Max positive value
01185                                                  * or it is not within the configured view.
01186                                                  */
01187                                                 QPointArray points( 5 );
01188                                                 /*this works for positive config and 0 include config*/
01189                                                 points.setPoint( 0, frontX1,
01190                                                                  (minDataValueYPos < static_cast <int> (yZero))?
01191                                                                  static_cast <int> (minDataValueYPos - 1) : static_cast <int>(yZero));
01192                                                 points.setPoint( 1, frontX2,
01193                                                                  (minDataValueYPos < static_cast <int> (yZero))?
01194                                                                  static_cast<int> ( minDataValueYPos - 1) : static_cast <int>(yZero));
01195                                                 points.setPoint( 2, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta ) );
01196                                                 points.setPoint( 3, xm,      static_cast<int>( yZero + height1 ) );
01197                                                 points.setPoint( 4, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta ) );
01198 
01199                                                 /*case where start and end value are negatives */
01200                                                 if ( cellValue > maxColumnValue && 0 >= maxColumnValue || cellValue == 0) {
01201                                                     points.setPoint( 0, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta ));
01202                                                     points.setPoint( 1, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta ));
01203                                                 }
01204 
01205                                                 //Pending Michel adjust the painting in case we have a user given Width
01206                                                 //allow it to be larger than the auto calculated width in case we want
01207                                                 //to overlap
01208                                                 if ( params()->userWidth() != 0 ) {
01209                                                     int userwidth = 0;
01210                                                     if ( params()->userWidth() < 0 )
01211                                                         userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
01212                                                     else
01213                                                         userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
01214                                                     //if ( userwidth < frontBarWidth ) {
01215                                                     QRect tmpRect ( points.point(0), points.point(2));
01216                                                     points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
01217                                                                     points.point(0).y());
01218                                                     points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
01219                                                                     points.point(1).y());
01220                                                     points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
01221                                                                     points.point(2).y());
01222                                                     points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
01223                                                                     points.point(4).y());
01224                                                     //}
01225                                                 }
01226                                                 if ( params()->barChartSubType() != KDChartParams::BarStacked ||
01227                                                      params()->barChartSubType() == KDChartParams::BarStacked && dataset != datasetEnd ) {
01228                                                     painter->setClipping(  false );
01229                                                     painter->drawPolygon( points );
01230                                                 }
01231 
01232                                                 //store the front rectangle
01233                                                 excessRectPositive.setTopLeft(points.point(4));
01234                                                 excessRectPositive.setTopRight(points.point(2));
01235                                                 excessRectPositive.setBottomRight(points.point(1));
01236                                                 excessRectPositive.setBottomLeft(points.point(0));
01237 
01238                                                 // Don't use points for drawing after this!
01239                                                 if ( pointArrayList && params()->barChartSubType() != KDChartParams::BarStacked ) {
01240                                                     points.translate( _dataRect.x(), _dataRect.y()  + excessRectPositive.top() );
01241                                                     pointArrayList->append( points );
01242                                                 } else if ( params()->barChartSubType() == KDChartParams::BarStacked )  {
01243                                                     if ( dataset != datasetEnd ) {
01244                                                         points.translate( _dataRect.x(), _dataRect.y()  + excessRectPositive.top() );
01245                                                         pointArrayList->append( points );
01246                                                     } else {
01247                                                         //adjust the display of the value label under Y  max value level
01248                                                         points.translate( _dataRect.x(), _dataRect.y() - excessRectPositive.bottom() - yArrowGap);
01249                                                         pointArrayList->append( points );
01250                                                     }
01251                                                 }
01252 
01253                                                 QPointArray points2( 6 );
01254                                                 points2.setPoint( 0, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta ) );
01255                                                 points2.setPoint( 1, xm,      static_cast<int>( yZero + height1 ) );
01256                                                 points2.setPoint( 2, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta ) );
01257                                                 points2.setPoint( 3, frontX2, static_cast<int>( yZero + height1 - 3.75 * delta ) );
01258                                                 points2.setPoint( 4, xm,      static_cast<int>( yZero + height1 - 0.75 * delta ) );
01259                                                 points2.setPoint( 5, frontX1, static_cast<int>( yZero + height1 - 3.75 * delta ) );
01260                                                 points2.translate( 0, yArrowGap );
01261 
01262                                                 //Pending Michel adjust the painting in case we have a user given Width
01263                                                 //allow it to be larger than the auto calculated width in case we want
01264                                                 //to overlap
01265                                                 if ( params()->userWidth() != 0 ) {
01266                                                     int userwidth = 0;
01267                                                     if ( params()->userWidth() < 0 )
01268                                                         userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
01269                                                     else
01270                                                         userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
01271                                                     //if ( userwidth < frontBarWidth ) {
01272                                                     points2.setPoint(0, excessRectPositive.topLeft().x(),points2.point(0).y());
01273                                                     points2.setPoint(2, excessRectPositive.topRight().x(),points2.point(2).y());
01274                                                     points2.setPoint(3, excessRectPositive.topRight().x(),points2.point(3).y());
01275                                                     points2.setPoint(5, excessRectPositive.topLeft().x(),points2.point(5).y());
01276                                                     //}
01277                                                 }
01278 
01279                                                 painter->drawPolygon( points2 );
01280                                                 /*
01281                                                   NOTE:  We do NOT want to store the region here, but
01282                                                   we use the front rectangle above in order to display the
01283                                                   data value labels inside the front rectangle.
01284                                                   Disadvantage: clicking onto these excess arrows, will not
01285                                                   result in a signal being sent, because KDChartWidget will
01286                                                   not notice, that the user has clicked onto the bar.
01287                                                   That's a minor drawback, compared to the gain of being
01288                                                   able to position the labels correctly.
01289                                                 */
01290                                                 points2.translate( 0, yArrowGap );
01291                                                 painter->drawPolygon( points2 );
01292                                                 /*
01293                                                   NOTE:  We do NOT want to store the region here
01294                                                   (see comment above)
01295                                                 */
01296                                             } // draw split excess arrow
01297                                         } //if( bShowThisBar )
01298 
01299                                         painter->setClipRect( ourClipRect );
01300                                     } // not tooLow  && bNormalMode )
01301                                     else {
01302                                         //bool fromBottom = bNormalMode && !_bThreeDBars;
01303                                         double y0 = yposPositives - zeroXAxisI;
01304 
01305                                         int pt1Y = static_cast < int > ( y0 - barHeight - sideBarHeight);
01306 
01307                                         calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
01308                                                             xpos, valueBlockGap, datasetGap, frontBarWidth,
01309                                                             frontX1, frontX2, prevFrontX2 );
01310 
01311                                         QPoint pt1( frontX1, pt1Y );
01312                                         QPoint pt2( frontX2,
01313                                                     static_cast < int > ( y0 + shiftUpperBars ) );
01314 
01315                                         if( 0.0 < minColumnValue )
01316                                             pt2.setY(pt2.y() - static_cast < int > ( pixelsPerUnit * minColumnValue ));
01317 
01318                                         if( pt2.y() < pt1Y ) {
01319                                             pt1.setY( pt2.y() );
01320                                             pt2.setY( pt1Y );
01321                                         }
01322                                         if( pt2.x() < frontX1 ) {
01323                                             pt1.setX( frontX2 );
01324                                             pt2.setX( frontX1 );
01325                                         }
01326                                         if( bDrawExtraLines ){
01327                                             int y = pt1.y();
01328                                             if( _bThreeDBars )
01329                                                 y -= static_cast < int > ( sideBarHeight );
01330 
01331                                             drawExtraLinesAndMarkers(
01332                                                 propSet,
01333                                                 defaultPen,
01334                                                 defaultMarkerStyle,
01335                                                 (frontX1+frontX2)/2, y,
01336                                                 painter,
01337                                                 ai.abscissaPara,
01338                                                 ordinatePara,
01339                                                 areaWidthP1000,
01340                                                 logHeight/1000.0,
01341                                                 bDrawExtraLinesInFront );
01342                                         }else if( bShowThisBar ){
01343 
01344                                             QSize siz( pt2.x() - pt1.x(),
01345                                                        pt2.y() - pt1.y());
01346 
01347                                             QRect rect(  pt1, siz );
01348 
01349                                             //adjust display for the 3d percent bars - last dataset.
01350                                             if ( params()->barChartSubType() == KDChartParams::BarPercent && cellValue != 0)
01351                                                 rect.setTop( rect.top() + static_cast <int> (sideBarHeight) - 1);
01352 
01353                                             // store the front rect
01354                                             if( tooHigh  ) {
01355                                                 frontRectPositive.setTopLeft(excessRectPositive.topLeft());
01356                                                 frontRectPositive.setTopRight(excessRectPositive.topRight());
01357                                                 frontRectPositive.setBottomRight(excessRectPositive.bottomRight());
01358                                                 frontRectPositive.setBottomLeft(excessRectPositive.bottomLeft());
01359                                             } else {
01360                                                 frontRectPositive.setTopLeft(rect.topLeft());
01361                                                 frontRectPositive.setTopRight(rect.topRight());
01362                                                 frontRectPositive.setBottomRight(rect.bottomRight());
01363                                                 frontRectPositive.setBottomLeft(rect.bottomLeft());
01364                                                 if( _bThreeDBars && cellValue == 0 )
01365                                                     frontRectNegative = frontRectPositive;
01366                                             }
01367 
01368                                             if( 1.5 > frontBarWidth ){
01369                                                 //qDebug("1.5 > frontBarWidth ");
01370                                                 QPen oldPen( painter->pen() );
01371                                                 painter->setPen( QPen(painter->brush().color(), 0) );
01372                                                 painter->drawLine(pt1, QPoint(pt1.x(),pt2.y()));
01373                                                 painter->setPen( oldPen );
01374                                             }else{
01375                                                 //debugging points and lines
01376                                                 /*
01377                                                   painter->drawText( rect.topLeft(), QString::number(cellValue).latin1());
01378                                                   painter->drawText( rect.topRight(), "1f");
01379                                                   painter->drawText( rect.bottomRight(), "2f");
01380                                                   painter->drawText( rect.bottomLeft(), "3f");
01381                                                   painter->drawLine( rect.topLeft(), rect.topRight());
01382                                                   painter->drawLine( rect.topRight(), rect.bottomRight());
01383                                                   painter->drawLine( rect.bottomRight(), rect.bottomLeft());
01384                                                   painter->drawLine( rect.bottomLeft(), rect.topLeft());
01385                                                 */
01386 
01387                                                 //Pending Michel adjust the painting in case we have a user given Width
01388                                                 //allow it to be larger than the auto calculated width in case we want
01389                                                 //to overlap
01390                                                 if ( params()->userWidth() != 0 ) {
01391                                                     int userwidth = 0;
01392                                                     if ( params()->userWidth() < 0 )
01393                                                         userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
01394                                                     else
01395                                                         userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
01396                                                     //if ( userwidth < frontBarWidth ) {
01397                                                     rect.setLeft( static_cast <int> (rect.center().x() - (userwidth/2)));
01398                                                     rect.setRight( static_cast <int> (rect.center().x() + (userwidth/2)));
01399                                                     rect.setWidth( static_cast <int> (userwidth) );
01400                                                     //adjust the front rect
01401                                                     frontRectPositive.setLeft( tooHigh ? static_cast <int> (excessRectPositive.center().x() - (userwidth/2)):rect.left());
01402                                                     frontRectPositive.setRight( tooHigh ? static_cast <int> (excessRectPositive.center().x() + (userwidth/2)):rect.right());
01403                                                 }
01404 
01405                                                 // drawing the front side
01406                                                 if (!tooHigh && !tooLow || params()->barChartSubType() == KDChartParams::BarPercent ) {
01407                                                     if ( bMultiRows )
01408                                                         painter->setClipping( false );
01409                                                     else
01410                                                         painter->setClipping( true );
01411                                                     painter->drawRect( rect );
01412                                                 }
01413                                                 // Don't use rect for drawing after this
01414                                                 if ( pointArrayList ) {
01415                                                     rect.moveBy( _dataRect.x(), _dataRect.y());
01416                                                     pointArrayList->append( rectToPointArray( rect ) );
01417                                                 }
01418                                             }
01419                                         } // bShowThisBar
01420                                     } // positive values
01421                                 }
01422                                 if ( bShowThisBar && _bThreeDBars &&  !bDrawExtraLines ) {
01423                                     //Pending Michel: no need to use that anymore
01424                                     //const int maxY = 2*devRect.height();
01425                                     QPointArray points( 4 );
01426                                     if (cellValue <= 0 || cellValue < minColumnValue) {
01427                                         if ( tooLow || cellValue < minColumnValue ) {
01428                                             points.setPoint(0, excessRectNegative.topRight());
01429                                             points.setPoint(1, excessRectNegative.topRight().x() +  static_cast<int>(sideBarHeight),
01430                                                             excessRectNegative.top() - static_cast<int>(sideBarHeight));
01431                                             points.setPoint(2, excessRectNegative.bottomRight().x() + static_cast<int>(sideBarHeight),
01432                                                             excessRectNegative.bottom() - static_cast<int>(sideBarHeight));
01433                                             points.setPoint(3, excessRectNegative.bottomRight());
01434                                         } else {
01435                                             points.setPoint( 0, frontRectNegative.bottomRight());
01436                                             points.setPoint( 1, frontRectNegative.bottomRight().x() +  static_cast<int>(sideBarHeight),
01437                                                              frontRectNegative.bottom() -  static_cast<int>(sideBarHeight) );
01438                                             points.setPoint(2,  frontRectNegative.bottomRight().x() +  static_cast<int>(sideBarHeight),
01439                                                             frontRectNegative.top() - static_cast<int>(sideBarHeight));
01440                                             points.setPoint(3, frontRectNegative.topRight() );
01441                                         }
01442 
01443                                         rightRectNegative.setTopLeft( points.point(0));
01444                                         rightRectNegative.setTopRight( points.point(2));
01445                                         rightRectNegative.setBottomRight(points.point(1));
01446                                         rightRectNegative.setBottomLeft(points.point(3));
01447 
01448                                     } else {
01449                                         // Pending Michel
01450                                         // Make sure to align the right side top and bottom points
01451                                         // to the front side points
01452                                         if ( tooHigh ) {
01453                                             points.setPoint(0, excessRectPositive.topRight());
01454                                             points.setPoint(1, excessRectPositive.topRight().x() + static_cast <int> (sideBarHeight),
01455                                                             excessRectPositive.top() - static_cast <int> (sideBarHeight) );
01456                                             points.setPoint(2, excessRectPositive.bottomRight().x() + static_cast <int> (sideBarHeight),
01457                                                             excessRectPositive.bottom() - static_cast <int> (sideBarHeight));
01458                                             points.setPoint(3, excessRectPositive.bottomRight());
01459                                         } else {
01460                                             points.setPoint(0, frontRectPositive.topRight());
01461                                             points.setPoint(1, frontRectPositive.topRight().x() + static_cast <int> (sideBarHeight),
01462                                                             frontRectPositive.top() - static_cast<int>(sideBarHeight));
01463                                             points.setPoint(2, frontRectPositive.bottomRight().x() + static_cast <int> (sideBarHeight),
01464                                                             frontRectPositive.bottom() - static_cast<int>(sideBarHeight));
01465                                             points.setPoint(3, frontRectPositive.bottomRight());
01466                                         }
01467                                         //register the right rect
01468                                         rightRectPositive.setTopLeft( points.point(0));
01469                                         rightRectPositive.setTopRight( points.point(1));
01470                                         rightRectPositive.setBottomLeft( points.point(3));
01471                                         rightRectPositive.setBottomRight(points.point(2));
01472                                     }
01473 
01474                                     if ( myShadow2Color.isValid() )
01475                                         painter->setBrush( QBrush( myShadow2Color, params()->shadowPattern() ) );
01476                                     else
01477                                         painter->setBrush( NoBrush );
01478 
01479                                     //debug points and lines
01480                                     /*
01481                                       painter->drawText( points.point(0), "0r");
01482                                       painter->drawText( points.point(1), "1r");
01483                                       painter->drawText( points.point(2), "2r");
01484                                       painter->drawText( points.point(3), "3r");
01485 
01486                                       painter->drawLine( points.point(0), points.point(1));
01487                                       painter->drawLine( points.point(1), points.point(2));
01488                                       painter->drawLine( points.point(2), points.point(3));
01489                                       painter->drawLine( points.point(3), points.point(0));
01490                                     */
01491 
01492                                     //drawing the right side
01493                                     if( (!tooHigh  && !tooLow)  || (tooHigh && cellValue <= 0 ) ) {
01494                                         if (( cellValue != 0 && params()->barChartSubType() == KDChartParams::BarPercent ) ||
01495                                             ( cellValue != 0 && params()->barChartSubType() == KDChartParams::BarStacked ) ||
01496                                             ( cellValue != 0 && bNormalMode ||
01497                                               cellValue != 0 && bMultiRows)) {
01498                                             painter->setClipping( false );
01499                                             painter->drawPolygon( points );
01500                                         }
01501                                     }
01502 
01503                                     // Dont override the region stored in case of excess values or barPercent this in order to display
01504                                     // the value labels closer to the corner of the front bar.
01505                                     if ( pointArrayList  && !tooHigh && !tooLow && params()->barChartSubType() != KDChartParams::BarPercent ) {
01506                                         QPointArray points2cpy( points.copy() );
01507                                         //qDebug("g2");
01508                                         points2cpy.translate( _dataRect.x(), _dataRect.y());
01509                                         //qDebug("g3");
01510                                         pointArrayList->append( points2cpy );
01511                                         //qDebug("g4");
01512                                     }
01513 
01514                                     // drawing the top, but only for the topmost piece for stacked and percent
01515                                     if ( bNormalMode || bMultiRows ||
01516                                          // For stacked and percent bars, there are three ways to determine
01517                                          // the top:
01518                                          // 1. all values are negative: the top is the one in the first dataset
01519                                          ( maxValueInThisColumn <= 0.0 && dataset == firstValidValue ) ||
01520                                          // 2. all values are positive: the top is the one in the last dataset
01521                                          ( minValueInThisColumn >= 0.0 && dataset == lastValidPositiveValue ) ||
01522                                          // 3. some values are positive, some negative:
01523                                          // the top is the one in the last positive
01524                                          // dataset value
01525                                          ( dataset == lastValidPositiveValue ) ) {
01526                                         if (cellValue <= 0  || cellValue < minColumnValue) {
01527                                             if ( tooLow ) {
01528                                                 points.setPoint(0,excessRectNegative.bottomLeft());
01529                                                 points.setPoint(1,excessRectNegative.topLeft().x() + static_cast <int> (sideBarHeight),
01530                                                                 excessRectNegative.bottom() - static_cast <int> (sideBarHeight));
01531                                                 points.setPoint(2,excessRectNegative.bottomRight().x() + static_cast <int> (sideBarHeight),
01532                                                                 excessRectNegative.bottom() - static_cast <int> (sideBarHeight));
01533                                                 points.setPoint(3,excessRectNegative.bottomRight());
01534                                             }else {
01535                                                 // Align the top to the front and the right side
01536                                                 points.setPoint(0,frontRectNegative.topLeft() );
01537                                                 points.setPoint(1,frontRectNegative.topLeft().x() + static_cast <int> (sideBarHeight),                                                          rightRectNegative.top());
01538                                                 points.setPoint(2,rightRectNegative.topRight() );
01539                                                 points.setPoint(3,rightRectNegative.topRight().x() - static_cast <int> (sideBarHeight),
01540                                                                 frontRectNegative.topRight().y() );
01541                                                 //make sure the top rect color is the right one - barStacked - Noll values
01542                                                 if ( (params()->barChartSubType() == KDChartParams::BarStacked && cellValue == 0 && maxValueInThisColumn != 0 ) )
01543                                                     points.translate(0,  maxValueInThisColumn <= 0?-(static_cast <int> (1*pixelsPerUnit) + 1):
01544                                                                      -static_cast<int>(maxValueInThisColumn*pixelsPerUnit));
01545 
01546                                                 if ( params()->barChartSubType() == KDChartParams::BarPercent && cellValue == 0 ) {
01547                                                     if ( dataset == datasetEnd && maxValueInThisColumn != 0)
01548                                                         points.translate(0,  -static_cast<int>( logHeight - sideBarHeight ));
01549                                                     else if ( maxValueInThisColumn == 0)
01550                                                         points.translate(0, static_cast <int> (logHeight + (sideBarHeight - sideBarWidth)));
01551                                                 }
01552                                             }
01553                                         } else {
01554                                             if ( tooHigh ) {
01555                                                 points.setPoint(0, excessRectPositive.topLeft());
01556                                                 points.setPoint(1, excessRectPositive.topLeft().x() + static_cast <int> (sideBarHeight),
01557                                                                 excessRectPositive.top() - static_cast <int> (sideBarHeight) );
01558                                                 points.setPoint(2, excessRectPositive.topRight().x() +  static_cast <int> (sideBarHeight),
01559                                                                 excessRectPositive.top() - static_cast <int> (sideBarHeight));
01560                                                 points.setPoint(3, excessRectPositive.topRight());
01561                                             } else {
01562                                                 // Pending Michel
01563                                                 // Align the top to the front and the right side
01564                                                 points.setPoint(0, frontRectPositive.topLeft());
01565                                                 points.setPoint(1, frontRectPositive.topLeft().x() + static_cast <int> (sideBarHeight),
01566                                                                 rightRectPositive.top() );
01567                                                 points.setPoint(2, rightRectPositive.topRight());
01568                                                 points.setPoint(3, rightRectPositive.topRight().x() - static_cast <int> (sideBarHeight),
01569                                                                 frontRectPositive.topRight().y());
01570                                             }
01571                                         }
01572 
01573                                         if (cellValue < 0.0 && maxValueInThisColumn < 0)
01574                                             painter->setBrush( bMultiRows ? myBarColor : black );
01575                                         else
01576                                             painter->setBrush( QBrush( myShadow1Color, params()->shadowPattern() ) );
01577 
01578                                         if ( !myShadow1Color.isValid() )
01579                                             painter->setBrush( NoBrush ); // override prev. setting
01580                                         // debug points and lines
01581                                         /*
01582                                           painter->drawText( points.point(0), "0t");
01583                                           painter->drawText( points.point(1), "1t");
01584                                           painter->drawText( points.point(2), "2t");
01585                                           painter->drawText( points.point(3), "3t");
01586 
01587                                           painter->drawLine( points.point(0), points.point(1) );
01588                                           painter->drawLine( points.point(1),points.point(2) );
01589                                           painter->drawLine( points.point(2),points.point(3) );
01590                                           painter->drawLine( points.point(3),points.point(0) );
01591                                         */
01592 
01593                                         // drawing the top side
01594                                         if (!tooHigh && !tooLow  || (tooHigh && cellValue <= 0) )
01595                                             painter->drawPolygon( points );
01596 
01597                                         // dont override the region stored in case of excess values.
01598                                         if (pointArrayList && !tooHigh && !tooLow
01599                                             && params()->barChartSubType() != KDChartParams::BarPercent
01600                                             && params()->barChartSubType() != KDChartParams::BarStacked) {
01601                                             points.translate(  _dataRect.x(), _dataRect.y());
01602                                             pointArrayList->append( points );
01603                                         }
01604                                     }
01605                                 }//if ( _bThreeDBars )
01606 
01607                                 if( regions && pointArrayList && ! pointArrayList->empty() ) {
01608                                     if( bShowThisBar && !bDrawExtraLines ){
01609                                         KDChartDataRegion * region;
01610                                         if( _bThreeDBars ){
01611                                             region = new KDChartDataRegion( dataset, value, chart,
01612                                                                             pointArrayList, true );
01613                                         } else {
01614                                             // just store a rectangle if NOT in 3-D bar mode
01615                                             region = new KDChartDataRegion( dataset, value, chart,
01616                                                                             pointArrayList->first().boundingRect() );
01617                                             delete pointArrayList;
01618                                         }
01619                                         /*qDebug("KDChartDataRegion stored!  x: %i  y: %i  w: %i  h: %i",
01620                                           region->rect().x(),region->rect().y(),
01621                                           region->rect().width(),region->rect().height());*/
01622                                         regions->append( region );
01623                                     } else {
01624                                         delete pointArrayList;
01625                                     }
01626                                 }
01627                             }// if( !bDrawExtraLines || bCellPropertiesFound )
01628                         }// if( !skipMe )
01629                     }else{
01630                         // Do not paint a bar, but update the position
01631                         // variable: to find the exact x1 position for
01632                         // the next bar that will be drawn.
01633                         int iDummy1, iDummy2;
01634                         calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
01635                                             xpos, valueBlockGap, datasetGap, frontBarWidth,
01636                                             iDummy1, iDummy2, prevFrontX2 );
01637                     }// if( dataset >= datasetStart && dataset <= datasetEnd )
01638 
01639                     // Vertical advancement in stacked or percent only if there was a value
01640                     // Pending Michel add sideBarHeight in case we are in 3D mode but not for Percent
01641                     // where we need to display the top rect but cant resize the YAxis.
01642                     if ( params()->barChartSubType() == KDChartParams::BarStacked ||
01643                          params()->barChartSubType() == KDChartParams::BarPercent )
01644                         if ( /*barHeight*/ cellValue < 0 )
01645                             (_bThreeDBars && params()->barChartSubType() != KDChartParams::BarPercent)?yposNegatives -= sideBarHeight + barHeight:
01646                                                                                                        yposNegatives -= barHeight;
01647                         else
01648                             (_bThreeDBars && params()->barChartSubType() != KDChartParams::BarPercent)?yposPositives -= sideBarHeight + barHeight:
01649                                                                                                        yposPositives -= barHeight;
01650 
01651                 } else {
01652                     // Do not paint a bar, but update the position
01653                     // variable: to find the exact x1 position for
01654                     // the next bar that will be drawn.
01655                     int iDummy1, iDummy2;
01656                     calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
01657                                         xpos, valueBlockGap, datasetGap, frontBarWidth,
01658                                         iDummy1, iDummy2, prevFrontX2 );
01659                 }
01660 
01661 
01662                 // advance only if the next dataset has DataEntry mode
01663                 bool bAdvanceToNextValue =
01664                     (    bMultiRows ? (dataset == chartDatasetStart) : (dataset == chartDatasetEnd)
01665                          || (    params()->chartSourceMode( bMultiRows ? dataset-1 : dataset+1 )
01666                                  == KDChartParams::DataEntry ) );
01667                 // Advance to next value; only for normal bars
01668                 if ( bNormalMode ) {
01669                     if( bAdvanceToNextValue )
01670                         xpos += barWidth;
01671                     // skip gap between datasets, unless last dataset
01672                     if ( dataset < myLastDataEntryDataset )
01673                         xpos += datasetGap;
01674                 }
01675                 if( bAdvanceToNextValue || bMultiRows  ){
01676                     //qDebug("shiftMyPainter( -nShiftX, nShiftY );");
01677                     shiftMyPainter( -nShiftX, nShiftY );
01678                 }
01679                 bIsVeryFirstBar = false;
01680                 bIsFirstDataset = false;
01681             }
01682 
01683 
01684             // Advancement between value blocks
01685             if ( bNormalMode ){
01686                 // skip gap between value blocks, don't worry about last one here
01687                 xpos += valueBlockGap;
01688                 //qDebug("**************************** xpos: %f  +  valueBlockGap: %f  =  %f", xpos, valueBlockGap, xpos+valueBlockGap);
01689             }else{
01690                 // skip gap between value blocks
01691                 xpos += valueBlockGap + barWidth;
01692                 //qDebug ( "2/ barWidth %f", barWidth );
01693                 //qDebug ( " valueBlockGap %f", valueBlockGap );
01694                 // start at bottom with next value group
01695                 yposPositives = yposPositivesStart;
01696                 yposNegatives = yposNegativesStart;
01697             }
01698             //qDebug("shiftMyPainterBack");
01699             shiftMyPainterBack();
01700         }
01701 
01702     }
01703 
01704 
01705     if( bMultiRows )
01706         painter->setClipping( bHadClipping );
01707 }
KDE Home | KDE Accessibility Home | Description of Access Keys