kchart

KDChartPainter.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 <KDChartParams.h>
00030 #if defined ( SUN7 ) || defined (_SGIAPI) || defined ( Q_WS_WIN)
00031   #include <math.h>
00032 #else
00033   #include <cmath>
00034   #include <stdlib.h>
00035 #endif
00036 
00037 #include <KDDrawText.h>
00038 #include <KDChartPainter.h>
00039 #include <KDChartEnums.h>
00040 #include <KDChartParams.h>
00041 #include <KDChartCustomBox.h>
00042 #include <KDChartTableBase.h>
00043 #include <KDChartDataRegion.h>
00044 #include <KDChartUnknownTypeException.h>
00045 #include <KDChartNotEnoughSpaceException.h>
00046 #include <KDChartBarPainter.h>
00047 #include <KDChartAreaPainter.h>
00048 #include <KDChartLinesPainter.h>
00049 #include <KDChartPiePainter.h>
00050 #include <KDChartPolarPainter.h>
00051 #include <KDChartRingPainter.h>
00052 #include <KDChartHiLoPainter.h>
00053 #include <KDChartBWPainter.h>
00054 #include <KDChartTextPiece.h>
00055 
00056 #include <KDChart.h>  // for static method KDChart::painterToDrawRect()
00057 
00058 #include <qpainter.h>
00059 #include <qpaintdevice.h>
00060 #include <qpaintdevicemetrics.h>
00061 
00062 #define DEGTORAD(d) (d)*M_PI/180
00063 
00064 
00096 KDChartPainter::KDChartPainter( KDChartParams* params ) :
00097 _outermostRect( QRect(QPoint(0,0), QSize(0,0))),
00098 _legendTitle( 0 ),
00099 _params( params ),
00100 _legendNewLinesStartAtLeft( true ),
00101 _legendTitleHeight( 0 ),
00102 _legendTitleWidth( 0 ),
00103 _legendTitleMetricsHeight( 0 )
00104 {
00105     // This constructor intentionally left blank so far; we cannot setup the
00106     // geometry yet since we do not know the size of the painter.
00107 }
00108 
00113 KDChartPainter::~KDChartPainter()
00114 {
00115     delete _legendTitle;
00116 }
00117 
00118 bool KDChartPainter::calculateAllAxesLabelTextsAndCalcValues(
00119         QPainter*,
00120         KDChartTableDataBase*,
00121         double,
00122         double,
00123         double& )
00124 {
00125     // This function intentionally returning false; it is implemented
00126     // by the KDChartAxesPainter class only.
00127     return false;
00128 }
00129 
00145 KDChartPainter* KDChartPainter::create( KDChartParams* params, bool make2nd )
00146 {
00147     KDChartParams::ChartType cType = make2nd
00148         ? params->additionalChartType()
00149         : params->chartType();
00150     switch ( cType )
00151     {
00152         case KDChartParams::Bar:
00153             return new KDChartBarPainter( params );
00154         case KDChartParams::Line:
00155             return new KDChartLinesPainter( params );
00156         case KDChartParams::Area:
00157             return new KDChartAreaPainter( params );
00158         case KDChartParams::Pie:
00159             return new KDChartPiePainter( params );
00160         case KDChartParams::Ring:
00161             return new KDChartRingPainter( params );
00162         case KDChartParams::HiLo:
00163             return new KDChartHiLoPainter( params );
00164         case KDChartParams::BoxWhisker:
00165             return new KDChartBWPainter( params );
00166         case KDChartParams::Polar:
00167             return new KDChartPolarPainter( params );
00168         case KDChartParams::NoType:
00169         default:
00170             return 0;
00171     }
00172 }
00173 
00174 
00191 void KDChartPainter::registerPainter( const QString& /*painterName*/,
00192         KDChartPainter* /*painter*/ )
00193 {
00194     // PENDING(kalle) Implement this
00195     qDebug( "Sorry, not implemented:  KDChartPainter::registerPainter()" );
00196 }
00197 
00198 
00208 void KDChartPainter::unregisterPainter( const QString& /*painterName*/ )
00209 {
00210     // PENDING(kalle) Implement this
00211     qDebug( "Sorry, not implemented:  KDChartPainter::unregisterPainter()" );
00212 }
00213 
00214 
00227 void KDChartPainter::paint( QPainter* painter,
00228                             KDChartTableDataBase* data,
00229                             bool paintFirst,
00230                             bool paintLast,
00231                             KDChartDataRegionList* regions,
00232                             const QRect* rect,
00233                             bool mustCalculateGeometry )
00234 {
00235 
00236 
00237   if( paintFirst && regions )
00238         regions->clear();
00239 
00240     // Protect against non-existing data
00241     if( data->usedCols() == 0 && data->usedRows() == 0 )
00242         return ;
00243 
00244     QRect drawRect;
00245     //Pending Michel: at this point we have to setupGeometry
00246     if( mustCalculateGeometry || _outermostRect.isNull() ){
00247       if( rect )
00248             drawRect = *rect;
00249         else if( !KDChart::painterToDrawRect( painter, drawRect ) ){
00250             qDebug("ERROR: KDChartPainter::paint() could not calculate the drawing area.");
00251             return;
00252         }
00253       setupGeometry( painter, data, drawRect );
00254     }
00255     else
00256         drawRect = _outermostRect;
00257 
00258     //qDebug("A2: _legendRect:\n%i,%i\n%i,%i", _legendRect.left(),_legendRect.top(),_legendRect.right(),_legendRect.bottom() );
00259 
00260 
00261     // Note: In addition to the below paintArea calls there might be several
00262     //       other paintArea calls regarding to the BASE areas (AreaAxisBASE,
00263     //       AreaHdFtBASE, AreaCustomBoxesBASE).
00264     //       These additional calls result in smaller areas being drawn inside
00265     //       on the larger ones specifies here.
00266     if ( paintFirst ) {
00267         paintArea( painter, KDChartEnums::AreaOutermost );
00268         paintArea( painter, KDChartEnums::AreaInnermost );
00269 
00270         paintArea( painter, KDChartEnums::AreaDataAxesLegendHeadersFooters );
00271 
00272         paintArea( painter, KDChartEnums::AreaHeaders );
00273         paintArea( painter, KDChartEnums::AreaFooters );
00274         // header areas are drawn in the following order:
00275         //   1st center: main header, left main header, right main header
00276         //   2nd above:  header #0,   left header #0,   right header #0
00277         //   3rd below:  header #2,   left header #2,   right header #2
00278         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader  );
00279         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeaderL );
00280         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeaderR );
00281         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader0  );
00282         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader0L );
00283         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader0R );
00284         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader2  );
00285         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader2L );
00286         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader2R );
00287         // footer areas are drawn in the same order as the header areas:
00288         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter  );
00289         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooterL );
00290         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooterR );
00291         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter0  );
00292         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter0L );
00293         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter0R );
00294         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter2  );
00295         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter2L );
00296         paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter2R );
00297 
00298         paintHeaderFooter( painter, data );
00299 
00300         paintArea( painter, KDChartEnums::AreaDataAxesLegend );
00301         paintArea( painter, KDChartEnums::AreaDataAxes );
00302         paintArea( painter, KDChartEnums::AreaAxes );
00303         for( int axis = KDChartAxisParams::AxisPosSTART;
00304              KDChartAxisParams::AxisPosEND >= axis; ++axis )
00305             paintArea( painter, KDChartEnums::AreaAxisBASE + axis );
00306         paintArea( painter, KDChartEnums::AreaData );
00307         paintAxes( painter, data );
00308     }
00309 
00310     painter->save();
00311     paintData( painter, data, !paintFirst, regions );
00312     painter->restore();
00313 
00314     if ( paintLast ) {
00315         // paint the frame lines of all little data region areas
00316         // on top of all data representations
00317         paintDataRegionAreas( painter, regions );
00318         if( KDChartParams::Bar          != params()->chartType() ||
00319             KDChartParams::BarMultiRows != params()->barChartSubType() )
00320             paintDataValues( painter, data, regions );
00321         if (params()->legendPosition()!=KDChartParams::NoLegend)
00322             paintArea(   painter, KDChartEnums::AreaLegend );
00323         paintLegend( painter, data );
00324         paintCustomBoxes( painter, regions );
00325     }
00326 }
00327 
00328 
00332 void KDChartPainter::paintArea( QPainter* painter,
00333         uint area,
00334         KDChartDataRegionList* regions,
00335         uint dataRow,
00336         uint dataCol,
00337         uint data3rd )
00338 {
00339     if( KDChartEnums::AreaCustomBoxesBASE != (KDChartEnums::AreaBASEMask & area) ){
00340         bool bFound;
00341         const KDChartParams::KDChartFrameSettings* settings =
00342             params()->frameSettings( area, bFound );
00343         if( bFound ) {
00344             bool allCustomBoxes;
00345             QRect rect( calculateAreaRect( allCustomBoxes,
00346                                            area,
00347                                            dataRow, dataCol, data3rd, regions ) );
00348 
00349             if( !allCustomBoxes )
00350                 paintAreaWithGap( painter, rect, *settings );
00351         }
00352     }
00353 }
00354 
00355 
00356 void KDChartPainter::paintDataRegionAreas( QPainter* painter,
00357                                            KDChartDataRegionList* regions )
00358 {
00359     if( regions ){
00360         int iterIdx;
00361         bool bFound;
00362         const KDChartParams::KDChartFrameSettings* settings =
00363             params()->frameSettings( KDChartEnums::AreaChartDataRegion, bFound, &iterIdx );
00364         while( bFound ) {
00365             bool bDummy;
00366             QRect rect( calculateAreaRect( bDummy,
00367                                            KDChartEnums::AreaChartDataRegion,
00368                                            settings->dataRow(),
00369                                            settings->dataCol(),
00370                                            settings->data3rd(),
00371                                            regions ) );
00372             // NOTE: we can *not* draw any background behind the
00373             //       data representations.
00374             // reason: for being able to do that we would have to
00375             //         know the respective regions _before_ the
00376             //         data representations are drawn; since that
00377             //         is impossible, we just draw the borders only
00378             //         ( == the corners and the edges ) and ignore the background
00379             //
00380             // (actually: Since the respective interface function does not allow
00381             //            specifying a background there is nothing to be ignored anyway.)
00382             settings->frame().paint( painter,
00383                                      KDFrame::PaintBorder,
00384                                      trueFrameRect( rect, settings ) );
00385             settings = params()->nextFrameSettings( bFound, &iterIdx );
00386         }
00387     }
00388 }
00389 
00390 
00391 QRect KDChartPainter::trueFrameRect( const QRect& orgRect,
00392                                      const KDChartParams::KDChartFrameSettings* settings ) const
00393 {
00394     QRect rect( orgRect );
00395     if( settings ){
00396         rect.moveBy( -settings->innerGapX(), -settings->innerGapY() );
00397         rect.setWidth(  rect.width()  + 2*settings->innerGapX() );
00398         rect.setHeight( rect.height() + 2*settings->innerGapY() );
00399     }
00400     return rect;
00401 }
00402 
00403 
00410 void KDChartPainter::paintAreaWithGap( QPainter* painter,
00411                                        QRect rect,
00412                                        const KDChartParams::KDChartFrameSettings& settings )
00413 {
00414     if( painter && rect.isValid() )
00415         settings.frame().paint( painter,
00416                                 KDFrame::PaintAll,
00417                                 trueFrameRect( rect, &settings ) );
00418 }
00419 
00420 
00424 void KDChartPainter::paintDataValues( QPainter* painter,
00425         KDChartTableDataBase* data,
00426         KDChartDataRegionList* regions )
00427 {
00428     KDChartDataRegion* region;
00429     if (    painter
00430             && data
00431             && regions
00432             && regions->count()
00433             && params()
00434             && (    params()->printDataValues( 0 )
00435                 || params()->printDataValues( 1 ) ) ) {
00436 
00437         // out of loop status saving
00438         painter->save();
00439 
00440         QFont font0( params()->dataValuesFont( 0 ) );
00441 
00442         if( params()->dataValuesUseFontRelSize(  0 ) ) {
00443             float size = QMIN(_areaWidthP1000, _areaHeightP1000) * abs(params()->dataValuesFontRelSize( 0 ));
00444             if ( 9.0 > size )
00445                 size = 9.0;
00446             font0.setPixelSize( static_cast < int > ( size ) );
00447         }
00448         painter->setFont( font0 );
00449         QFontMetrics fm0( painter->fontMetrics() );
00450         double fm0HeightP100( fm0.height() / 100.0 );
00451         QFont font1( params()->dataValuesFont( 1 ) );
00452 
00453         if( params()->dataValuesUseFontRelSize(  1 ) ) {
00454             float size = QMIN(_areaWidthP1000, _areaHeightP1000) * abs(params()->dataValuesFontRelSize( 1 ));
00455             if ( 9.0 > size )
00456                 size = 9.0;
00457             font1.setPixelSize( static_cast < int > ( size ) );
00458         } else
00459       font1.setPixelSize( font0.pixelSize());
00460         painter->setFont( font1 );
00461         QFontMetrics fm1( painter->fontMetrics() );
00462         double fm1HeightP100( fm1.height() / 100.0 );
00463 
00464         bool lastDigitIrrelevant0 = true;
00465         bool lastDigitIrrelevant1 = true;
00466         // get and format the texts
00467         for ( region=regions->first();
00468                 region != 0;
00469                 region = regions->next() ) {
00470             QVariant vValY;
00471             if( data->cellCoord( region->row, region->col, vValY, 1 ) ){
00472                 if( QVariant::String == vValY.type() ){
00473                     const QString sVal( vValY.toString() );
00474                     if( !sVal.isEmpty() )
00475                         region->text = sVal;
00476                 }else if( QVariant::Double == vValY.type() ){
00477                     double value( vValY.toDouble() );
00478                     region->negative = 0.0 > value;
00479                     double divi( pow( 10.0, params()->dataValuesDivPow10( region->chart ) ) );
00480                     if ( 1.0 != divi )
00481                         value /= divi;
00482                     int digits( params()->dataValuesDigitsBehindComma( region->chart ) );
00483                     bool autoDigits( KDCHART_DATA_VALUE_AUTO_DIGITS == digits );
00484                     if( autoDigits ) {
00485                         if( 10 < digits )
00486                             digits = 10;
00487                     } else
00488                         (   region->chart
00489                             ? lastDigitIrrelevant1
00490                             : lastDigitIrrelevant0 ) = false;
00491                     if( value == KDCHART_NEG_INFINITE )
00492                         region->text = "-LEMNISKATE";
00493                     else if( value == KDCHART_POS_INFINITE )
00494                         region->text = "+LEMNISKATE";
00495                     else {
00496                         region->text.setNum( value, 'f', digits );
00497                         if ( autoDigits && region->text.contains( '.' ) ) {
00498                             int len = region->text.length();
00499                             while (    3 < len
00500                                     && '0' == region->text[ len-1 ]
00501                                     && '.' != region->text[ len-2 ] ) {
00502                                 --len;
00503                                 region->text.truncate( len );
00504                             }
00505                             if( '0' != region->text[ len-1 ] )
00506                                 (   region->chart
00507                                     ? lastDigitIrrelevant1
00508                                     : lastDigitIrrelevant0 ) = false;
00509                         }
00510                     }
00511                 }
00512             }
00513         }
00514 
00515         if ( lastDigitIrrelevant0 || lastDigitIrrelevant1 )
00516             for ( region=regions->first();
00517                     region != 0;
00518                     region = regions->next() )
00519                 if (   (     ( lastDigitIrrelevant0 && !region->chart )
00520                             || ( lastDigitIrrelevant1 &&  region->chart ) )
00521                         && region->text.contains( '.' )
00522                         && ( 2 < region->text.length() ) )
00523                     region->text.truncate ( region->text.length() - 2 );
00524 
00525 
00526         // draw the Data Value Texts and calculate the text regions
00527         painter->setPen( Qt::black );
00528 
00529         bool allowOverlapping = params()->allowOverlappingDataValueTexts();
00530         bool drawThisOne;
00531         QRegion lastRegionDone;
00532 
00533         QFontMetrics actFM( painter->fontMetrics() );
00534 
00535         QFont* oldFont = 0;
00536         int oldRotation = 0;
00537         uint oldChart = UINT_MAX;
00538         uint oldDatacolorNo = UINT_MAX;
00539         for ( region=regions->first();
00540                 region != 0;
00541                 region = regions->next() ) {
00542 
00543             // in loop status saving
00544             painter->save();
00545 
00546             if ( region->text.length() ) {
00547 
00548                 QVariant vValY;
00549                 bool zero =
00550                     data->cellCoord( region->row, region->col, vValY, 1 ) &&
00551                     QVariant::Double == vValY.type() &&
00552                     ( 0.0 == vValY.toDouble() || 0 == vValY.toDouble() );
00553                 uint align( params()->dataValuesAnchorAlign( region->chart,
00554                             region->negative ) );
00555                 KDChartParams::ChartType cType = region->chart
00556                     ? params()->additionalChartType()
00557                     : params()->chartType();
00558 
00559 
00560                 // these use the bounding rect of region-region:
00561                 bool bIsAreaChart = KDChartParams::Area == cType;
00562                 bool rectangular = (    KDChartParams::Bar        == cType
00563                                      || KDChartParams::Line       == cType
00564                                      || bIsAreaChart
00565                                      || KDChartParams::HiLo       == cType
00566                                      || KDChartParams::BoxWhisker == cType );
00567 
00568                 // these use the nine anchor points stored in region->points
00569                 bool circular    = (    KDChartParams::Pie        == cType
00570                                      || KDChartParams::Ring       == cType
00571                                      || KDChartParams::Polar      == cType );
00572 
00573 
00574                 KDChartEnums::PositionFlag anchorPos(
00575                     params()->dataValuesAnchorPosition( region->chart, region->negative ) );
00576 
00577                 QPoint anchor(
00578                         rectangular
00579                         ? KDChartEnums::positionFlagToPoint( region->rect(), anchorPos )
00580                         : KDChartEnums::positionFlagToPoint( region->points, anchorPos ) );
00581 
00582                 double & fmHeightP100 = region->chart ? fm1HeightP100 : fm0HeightP100;
00583 
00584                 int angle = region->startAngle;
00585                 switch ( anchorPos ) {
00586                     case KDChartEnums::PosTopLeft:
00587                     case KDChartEnums::PosCenterLeft:
00588                     case KDChartEnums::PosBottomLeft:
00589                         angle += region->angleLen;
00590                         break;
00591                     case KDChartEnums::PosTopCenter:
00592                     case KDChartEnums::PosCenter:
00593                     case KDChartEnums::PosBottomCenter:
00594                         angle += region->angleLen / 2;
00595                         break;
00596                         /*
00597                            case KDChartEnums::PosTopRight:
00598                            case KDChartEnums::PosCenterRight:
00599                            case KDChartEnums::PosBottomRight:
00600                            angle += 0;
00601                            break;
00602                            */
00603                     default:
00604                         break;
00605                 }
00606                  double anchorDX( params()->dataValuesAnchorDeltaX( region->chart, region->negative )
00607                         * fmHeightP100 );
00608                  double anchorDY( params()->dataValuesAnchorDeltaY( region->chart, region->negative )
00609                         * fmHeightP100 );
00610                  if ( circular ) {
00611                      if ( 0.0 != anchorDY ) {
00612                         double normAngle = angle / 16;
00613                         double normAngleRad = DEGTORAD( normAngle );
00614                         double sinAngle = sin( normAngleRad );
00615                         QPoint& pM = region->points[ KDChartEnums::PosCenter ];
00616                         double dX( pM.x() - anchor.x() );
00617                         double dY( pM.y() - anchor.y() );
00618                         double radialLen( sinAngle ? dY / sinAngle : dY );
00619                         double radialFactor( ( radialLen == 0.0 ) ? 0.0 : ( ( radialLen - anchorDY ) / radialLen ) );
00620                         anchor.setX( static_cast < int > ( pM.x() - dX * radialFactor ) );
00621                         anchor.setY( static_cast < int > ( pM.y() - dY * radialFactor ) );
00622                      }
00623                 } else {
00624                     anchor.setX( anchor.x() + static_cast < int > ( anchorDX ) );
00625                     anchor.setY( anchor.y() + static_cast < int > ( anchorDY ) );
00626                 }
00627 
00628 
00629                 if(anchor.x() < -250){
00630                     anchor.setX(-250);
00631                     //qDebug("!! bad negative x position in KDChartPainter::paintDataValues() !!");
00632                 }
00633                 if(anchor.y() < -2500){
00634                     anchor.setY(-2500);
00635                     //qDebug("!! bad negative y position in KDChartPainter::paintDataValues() !!");
00636                 }
00637 
00638                 int rotation( params()->dataValuesRotation( region->chart,
00639                                                             region->negative ) );
00640                 bool incRotationBy90 = false;
00641                 if( region->text == "-LEMNISKATE" ||
00642                         region->text == "+LEMNISKATE" ){
00643                     if( params()->dataValuesShowInfinite( region->chart ) ){
00644                         //bool bIsLineChart = KDChartParams::Line == cType;
00645                         if( region->text == "-LEMNISKATE" )
00646                             align = Qt::AlignRight + Qt::AlignVCenter;
00647                         else
00648                             align = Qt::AlignLeft  + Qt::AlignVCenter;
00649                         if( !rotation )
00650                             rotation = 90;
00651                         else
00652                             incRotationBy90 = true;
00653                         region->text = " 8 ";
00654                     }else{
00655                         region->text = "";
00656                     }
00657                 }
00658 
00659                 if ( rotation ) {
00660           anchor = painter->worldMatrix().map( anchor );
00661 
00662                     //   Temporary solution for fixing the data labels size
00663                     // bug when in QPrinter::HighResolution mode:
00664                     //   There seem to be no backdraws by acting like this,
00665                     // but further investigation is required to detect the
00666                     // real error in the previous code/
00667                     if (    KDCHART_SAGGITAL_ROTATION   == rotation
00668                          || KDCHART_TANGENTIAL_ROTATION == rotation ) {
00669                         rotation = (   KDCHART_TANGENTIAL_ROTATION == rotation
00670                                      ? -1440
00671                                      : 0 )
00672                                  + angle;
00673                         rotation /= 16;
00674                         if( incRotationBy90 )
00675                             rotation += 90;
00676                         if ( 360 <= rotation )
00677                             rotation -= 360;
00678                         else if ( 0 > rotation )
00679                             rotation += 360;
00680                         rotation = 360 - rotation;
00681                     }else if( incRotationBy90 )
00682                         rotation = (rotation + 90) % 360;
00683 
00684 
00685              if( rotation != oldRotation ) {
00686               painter->rotate( rotation - oldRotation );
00687                       // Comment this out - zooming and scrolling
00688               // oldRotation = rotation;
00689              }
00690 
00691                     QFont* actFont = region->chart ? &font1 : &font0;
00692                     if( oldFont != actFont ) {
00693                         painter->setFont( *actFont );
00694                         actFM = QFontMetrics( painter->fontMetrics() );
00695             // Comment this out - zooming and scrolling
00696                         //oldFont = actFont;
00697                     }
00698 
00699                     KDDrawTextRegionAndTrueRect infosKDD =
00700                         KDDrawText::measureRotatedText( painter,
00701                                                         rotation,
00702                                                         anchor,
00703                                                         region->text,
00704                                                         0,
00705                                                         align,
00706                                                         &actFM,
00707                                                         true,
00708                                                         true,
00709                                                         5 );
00710                     //anchor = painter->worldMatrix().map( anchor );
00711 
00712                     if( allowOverlapping ) {
00713                         drawThisOne = true;
00714                     }else {
00715                         QRegion sectReg( infosKDD.region.intersect( lastRegionDone ) );
00716                         drawThisOne = sectReg.isEmpty();
00717                     }
00718                     if( drawThisOne ) {
00719                         lastRegionDone     = lastRegionDone.unite( infosKDD.region );
00720                         region->pTextRegion = new QRegion( infosKDD.region );
00721 
00722                         if( params()->dataValuesAutoColor( region->chart ) ) {
00723                             if( bIsAreaChart ){
00724                                 QColor color( params()->dataColor( region->row ) );
00725                                 /*
00726                                 if(    ( (0.0 > anchorDY) &&  region->negative )
00727                                     || ( (0.0 < anchorDY) && !region->negative ) )
00728                                     painter->setPen(
00729                                         QColor( static_cast < int > ( 255- color.red() ),
00730                                                 static_cast < int > ( 255- color.green() ),
00731                                                 static_cast < int > ( 255- color.blue() ) ) );
00732                                 else
00733                                 */
00734                                     painter->setPen( color.dark() );
00735                             }else{
00736                                 if( zero ) {
00737                                     if( oldDatacolorNo != UINT_MAX ) {
00738                                         painter->setPen( Qt::black );
00739                                         oldDatacolorNo = UINT_MAX;
00740                                     }
00741                                 }
00742                                 else {
00743                                     uint datacolorNo = (    KDChartParams::Pie   == cType
00744                                                         || KDChartParams::Ring  == cType )
00745                                         ? region->col
00746                                         : region->row;
00747                                     if(  oldDatacolorNo != datacolorNo ) {
00748                                         oldDatacolorNo = datacolorNo;
00749                                         QColor color( params()->dataColor( datacolorNo ) );
00750                                         painter->setPen( QColor(
00751                                                         static_cast < int > (255-color.red()  ),
00752                                                         static_cast < int > (255-color.green()),
00753                                                         static_cast < int > (255-color.blue() )));
00754                                     }
00755                                 }
00756                             }
00757                         }
00758                         else if( oldChart != region->chart ) {
00759                             oldChart = region->chart;
00760                             painter->setPen( params()->dataValuesColor( region->chart ) );
00761                         }
00762 
00763                         if( params()->optimizeOutputForScreen() ){
00764                             painter->rotate( -oldRotation );
00765                             oldRotation = 0;
00766                             if ( anchor.y() < 0 )
00767                   anchor.setY( -anchor.y() );
00768 
00769                             KDDrawText::drawRotatedText( painter,
00770                                                          rotation,
00771                                                          anchor,
00772                                                          region->text,
00773                                                          region->chart ? &font1 : &font0,
00774                                                          align,
00775                                                          false,   // bool showAnchor
00776                                                          0,       // const QFontMetrics* fontMet
00777                                                          false,   // bool noFirstrotate
00778                                                          false,   // bool noBackrotate
00779                                                          0,       // KDDrawTextRegionAndTrueRect* infos
00780                                                          true );  // bool optimizeOutputForScreen
00781                         }else{
00782                            painter->setPen( params()->dataValuesColor( region->chart ) );
00783                            //Pending Michel Painting data value labels rotated.
00784                            painter->drawText( infosKDD.x , infosKDD.y ,
00785                                                infosKDD.width, infosKDD.height,
00786                                                Qt::AlignHCenter | Qt::AlignVCenter | Qt::SingleLine,
00787                                                region->text );
00788 
00789                         }
00790 
00791 
00792                     } // if not intersect
00793 
00794                 } else {
00795 
00796                     // no rotation:
00797                     painter->rotate( -oldRotation );
00798                     oldRotation = 0;
00799                     QFontMetrics & fm = region->chart ? fm1 : fm0;
00800                     int boundingRectWidth = fm.boundingRect( region->text ).width();
00801                     int leftBearing = fm.leftBearing( region->text[ 0 ] );
00802                     const QChar c =  region->text.at( region->text.length() - 1 );
00803                     int rightBearing = fm.rightBearing( c );
00804                     int w =  boundingRectWidth + leftBearing + rightBearing + 1;
00805                     int h = fm.height(); // ascent + descent + 1
00806                     int dx = 0;
00807                     int dy = 0;
00808                     switch( align & ( Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter ) ) {
00809                         case Qt::AlignRight:
00810                             dx = -w+1;
00811                             break;
00812                         case Qt::AlignHCenter:
00813                             // Center on the middle of the bounding rect, not
00814                             // the painted area, because numbers appear centered then
00815                             dx = -( ( boundingRectWidth / 2 ) + leftBearing );
00816                             break;
00817                     }
00818                     switch( align & ( Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter ) ) {
00819                         case Qt::AlignBottom:
00820                             dy = -h+1;
00821                             break;
00822                         case Qt::AlignVCenter:
00823                             dy = -h / 2;
00824                             break;
00825                     }
00826 
00827                     QRegion thisRegion(
00828                             QRect( anchor.x() + dx, anchor.y() + dy, w, h ) );
00829                     if( allowOverlapping )
00830                         drawThisOne = true;
00831                     else {
00832                         QRegion sectReg( thisRegion.intersect( lastRegionDone ) );
00833                         drawThisOne = sectReg.isEmpty();
00834                     }
00835                     if( drawThisOne ) {
00836                         lastRegionDone      = lastRegionDone.unite( thisRegion );
00837                         region->pTextRegion = new QRegion( thisRegion );
00838 #ifdef DEBUG_TEXT_PAINTING
00839                         // for testing:
00840                         QRect rect( region->pTextRegion->boundingRect() );
00841                         painter->drawRect( rect );
00842                         painter->setPen( Qt::red );
00843                         rect.setLeft( rect.left() + leftBearing );
00844                         rect.setTop( rect.top() + ( fm.height()-fm.boundingRect( region->text ).height() ) /2 );
00845                         rect.setWidth( fm.boundingRect( region->text ).width() );
00846                         rect.setHeight( fm.boundingRect( region->text ).height() );
00847                         painter->drawRect( rect );
00848                         painter->setPen( Qt::black );
00849 #endif
00850                         /*
00851 
00852 NOTE: The following will be REMOVED again once
00853 the layout policy feature is implemented !!!
00854 
00855 */
00856                         QRect textRect( region->pTextRegion->boundingRect() );
00857                         if( bIsAreaChart ){
00858                             QBrush brush( params()->dataValuesBackground( region->chart ) );
00859                             painter->setBrush( brush );
00860                             painter->setPen(   Qt::NoPen );
00861                             QRect rect( textRect );
00862                             rect.moveBy( -2, 0 );
00863                             rect.setWidth( rect.width() + 4 );
00864                             painter->drawRect( rect );
00865                         }
00866                         painter->setFont( region->chart ? font1 : font0 );
00867                         if( params()->dataValuesAutoColor( region->chart ) ) {
00868                             if( bIsAreaChart ){
00869                                 QColor color( params()->dataColor( region->row ) );
00870                                 /*
00871                                 if(    ( (0.0 > anchorDY) &&  region->negative )
00872                                     || ( (0.0 < anchorDY) && !region->negative ) )
00873                                     painter->setPen(
00874                                         QColor( static_cast < int > ( 255- color.red() ),
00875                                                 static_cast < int > ( 255- color.green() ),
00876                                                 static_cast < int > ( 255- color.blue() ) ) );
00877                                 else
00878                                 */
00879                                     painter->setPen( color.dark() );
00880                             }else{
00881                                 if( zero )
00882                                     painter->setPen( Qt::black );
00883                                 else {
00884                                     QColor color( params()->dataColor(
00885                                                 (    KDChartParams::Pie   == params()->chartType()
00886                                                     || KDChartParams::Ring  == params()->chartType() )
00887                                                 ? region->col
00888                                                 : region->row ) );
00889                                     painter->setPen( QColor( static_cast < int > ( 255- color.red() ),
00890                                                 static_cast < int > ( 255- color.green() ),
00891                                                 static_cast < int > ( 255- color.blue() ) ) );
00892                                 }
00893                             }
00894                         }else{
00895                             painter->setPen( params()->dataValuesColor( region->chart ) );
00896                         }
00897 
00898                         painter->drawText( textRect.left(),    textRect.top(),
00899                                            textRect.width()+1, textRect.height()+1,
00900                                            Qt::AlignLeft | Qt::AlignTop, region->text );
00901 
00902                     }
00903 
00904 
00905                 }
00906             }
00907             //
00908           painter->restore();
00909 
00910         }
00911     painter->restore();
00912     }
00913 
00914 }
00915 
00916 
00920 void KDChartPainter::paintCustomBoxes( QPainter* painter,
00921                                        KDChartDataRegionList* regions )
00922 {
00923     // paint all of the custom boxes AND their surrounding frames+background (if any)
00924     bool bGlobalFound;
00925     const KDChartParams::KDChartFrameSettings* globalFrameSettings
00926         = params()->frameSettings( KDChartEnums::AreasCustomBoxes, bGlobalFound );
00927 
00928     uint idx;
00929     for( idx = 0; idx <= params()->maxCustomBoxIdx(); ++idx ) {
00930         const KDChartCustomBox * box = params()->customBox( idx );
00931         if( box ) {
00932             // paint border and background
00933             paintArea( painter,
00934                        KDChartEnums::AreaCustomBoxesBASE + idx,
00935                        regions,
00936                        box->dataRow(),
00937                        box->dataCol(),
00938                        box->data3rd() );
00939             // retrieve frame information
00940             bool bIndividualFound;
00941             const KDChartParams::KDChartFrameSettings * individualFrameSettings
00942                 = params()->frameSettings( KDChartEnums::AreaCustomBoxesBASE + idx,
00943                                            bIndividualFound );
00944             const KDChartParams::KDChartFrameSettings * settings
00945                 = bIndividualFound ? individualFrameSettings
00946                                    : bGlobalFound ? globalFrameSettings : 0;
00947             // paint content
00948             const QPoint anchor( calculateAnchor( *box, regions ) );
00949             box->paint( painter,
00950                         anchor,
00951                         _areaWidthP1000,
00952                         _areaHeightP1000,
00953                         settings ? settings->framePtr() : 0,
00954                         trueFrameRect( box->trueRect( anchor, _areaWidthP1000, _areaHeightP1000 ),
00955                                        settings ) );
00956         }
00957     }
00958 }
00959 
00960 
00964 QPoint KDChartPainter::calculateAnchor( const KDChartCustomBox & box,
00965         KDChartDataRegionList* regions ) const
00966 {
00967     QPoint pt(0,0);
00968 
00969     // Recursion handling:
00970     //
00971     //    *  calculateAnchor() normally calls calculateAreaRect()
00972     //
00973     //    *  calculateAreaRect() will in turn calls calculateAnchor() in case of
00974     //       box.anchorArea() being based on KDChartEnums::AreaCustomBoxesBASE
00975     //
00976     //    This is Ok as long as the recursive call of calculateAnchor() is NOT
00977     //    intend examination the same box as a previous call.
00978     //
00979     // Rule:
00980     //
00981     //    A box may be aligned to another box (and the 2nd box may again be
00982     //    aligned to a 3rd box and so on) but NO CIRCULAR alignment is allowed.
00983     //
00984     if( !box.anchorBeingCalculated() ) {
00985 
00986         box.setInternalFlagAnchorBeingCalculated( true );
00987 
00988         bool allCustomBoxes;
00989         QRect rect( calculateAreaRect( allCustomBoxes,
00990                                        box.anchorArea(),
00991                                        box.dataRow(),
00992                                        box.dataCol(),
00993                                        box.data3rd(),
00994                                        regions ) );
00995         if( allCustomBoxes ) {
00996             //
00997             //  Dear user of this library.
00998             //
00999             //  You faced the above error during program runtime?
01000             //
01001             //  The reason for this is that you may NOT use  AreasCustomBoxes
01002             //  as a value for the KDChartCustomBox anchor area.
01003             //
01004             //  This is due to the fact that an anchor area allways must specify one AREA
01005             //  or some contiguous areas that form an area when combined.
01006             //  The flag  AreasCustomBoxes  however specifies a list of custom boxes
01007             //  that normally do not form a contiguos ares, so they cannot be used as anchor area.
01008             //
01009             //  In order to specify a SINGLE custom box please use AreaCustomBoxBASE+boxId.
01010             //
01011         }
01012         pt = KDChartEnums::positionFlagToPoint( rect, box.anchorPosition() );
01013 
01014         box.setInternalFlagAnchorBeingCalculated( false );
01015     }
01016 
01017     return pt;
01018 }
01019 
01020 
01025 QRect KDChartPainter::calculateAreaRect( bool & allCustomBoxes,
01026                                          uint area,
01027                                          uint dataRow,
01028                                          uint dataCol,
01029                                          uint /*data3rd*/,
01030                                          KDChartDataRegionList* regions ) const
01031 {
01032     QRect rect(0,0, 0,0);
01033     allCustomBoxes = false;
01034     uint pos;
01035     switch( area ) {
01036         case KDChartEnums::AreaData:
01037             rect = _dataRect;
01038             break;
01039         case KDChartEnums::AreaAxes:
01040             break;
01041         case KDChartEnums::AreaLegend:
01042             rect = _legendRect;
01043             break;
01044         case KDChartEnums::AreaDataAxes:
01045             rect = _axesRect;
01046             break;
01047         case KDChartEnums::AreaDataAxesLegend:
01048             rect = _axesRect;
01049             if( _legendRect.isValid() ) {
01050                 if( rect.isValid() )
01051                     rect = rect.unite( _legendRect );
01052                 else
01053                     rect = _legendRect;
01054             }
01055             break;
01056         case KDChartEnums::AreaHeaders: {
01057                                             bool bStart = true;
01058                                             for( pos = KDChartParams::HdFtPosHeadersSTART;
01059                                                     KDChartParams::HdFtPosHeadersEND >= pos;
01060                                                     ++pos ) {
01061                                                 const QRect& r = params()->headerFooterRect( pos );
01062                                                 if( r.isValid() ) {
01063                                                     if( bStart )
01064                                                         rect = r;
01065                                                     else
01066                                                         rect = rect.unite( r );
01067                                                     bStart = false;
01068                                                 }
01069                                             }
01070                                         }
01071                                         break;
01072         case KDChartEnums::AreaFooters: {
01073                                             bool bStart = true;
01074                                             for( pos = KDChartParams::HdFtPosFootersSTART;
01075                                                     KDChartParams::HdFtPosFootersEND >= pos;
01076                                                     ++pos ) {
01077                                                 const QRect& r = params()->headerFooterRect( pos );
01078                                                 if( r.isValid() ) {
01079                                                     if( bStart )
01080                                                         rect = r;
01081                                                     else
01082                                                         rect = rect.unite( r );
01083                                                     bStart = false;
01084                                                 }
01085                                             }
01086                                         }
01087                                         break;
01088         case KDChartEnums::AreaDataAxesLegendHeadersFooters: {
01089                                                                  rect = _axesRect;
01090                                                                  bool bStart = !rect.isValid();
01091                                                                  if( _legendRect.isValid() ) {
01092                                                                      if( bStart )
01093                                                                          rect = _legendRect;
01094                                                                      else
01095                                                                          rect = rect.unite( _legendRect );
01096                                                                      bStart = false;
01097                                                                  }
01098                                                                  for( pos = KDChartParams::HdFtPosSTART;
01099                                                                          KDChartParams::HdFtPosEND >= pos;
01100                                                                          ++pos ) {
01101                                                                      const QRect& r = params()->headerFooterRect( pos );
01102                                                                      if( r.isValid() ) {
01103                                                                          if( bStart )
01104                                                                              rect = r;
01105                                                                          else
01106                                                                              rect = rect.unite( r );
01107                                                                          bStart = false;
01108                                                                      }
01109                                                                  }
01110                                                              }
01111                                                              break;
01112         case KDChartEnums::AreaOutermost:
01113                                                              rect = _outermostRect;
01114                                                              break;
01115         case KDChartEnums::AreaInnermost:
01116                                                              rect = _innermostRect;
01117                                                              break;
01118         case KDChartEnums::AreasCustomBoxes:
01119                                                              allCustomBoxes = true;
01120                                                              break;
01121         case KDChartEnums::AreaChartDataRegion:
01122                                                              if( regions ) {
01123                                                                  KDChartDataRegion* current;
01124                                                                  for ( current = regions->first();
01125                                                                          current != 0;
01126                                                                          current =  regions->next() ) {
01127                                                                      if (    current->row == dataRow
01128                                                                              && current->col == dataCol
01129                                                                              //
01130                                                                              // the line below prepared for true 3-dimensional data charts
01131                                                                              //
01132                                                                              /* && current->region.thirdDimension == data3rd */ ) {
01133                                                                          rect = current->rect();
01134                                                                          break;
01135                                                                      }
01136                                                                  }
01137                                                              }
01138                                                              break;
01139         case KDChartEnums::AreaUNKNOWN:
01140                                                              break;
01141 
01142         default: {
01143                      uint maskBASE = KDChartEnums::AreaBASEMask & area;
01144                      pos = area - maskBASE;
01145                      if ( KDChartEnums::AreaAxisBASE == maskBASE ) {
01146                          rect = params()->axisParams( pos ).axisTrueAreaRect();
01147                      } else if ( KDChartEnums::AreaHdFtBASE == maskBASE ) {
01148                          rect = params()->headerFooterRect( pos );
01149                      } else if ( KDChartEnums::AreaCustomBoxesBASE == maskBASE ) {
01150                          const KDChartCustomBox * box = params()->customBox( pos );
01151                          if( box ) {
01152                              rect = box->trueRect( calculateAnchor( *box, regions ),
01153                                      _areaWidthP1000,
01154                                      _areaHeightP1000 );
01155                          }
01156                      }
01157                  }
01158     }
01159     return rect;
01160 }
01161 
01162 
01163 QPoint KDChartPainter::pointOnCircle( const QRect& rect, double angle )
01164 {
01165     // There are two ways of computing this: The simple, but slow one
01166     // is to use QPointArray.makeArc() and take the first point. The
01167     // more advanced, but faster one is to do the trigonometric
01168     // computionations ourselves. Since the comments in
01169     // QPointArray::makeArc() very often say that the code there is
01170     // "poor", we'd better do it outselves...
01171 
01172     double normAngle = angle / 16.0;
01173     double normAngleRad = DEGTORAD( normAngle );
01174     double cosAngle = cos( normAngleRad );
01175     double sinAngle = -sin( normAngleRad );
01176     double posX = floor( cosAngle * ( double ) rect.width() / 2.0 + 0.5 );
01177     double posY = floor( sinAngle * ( double ) rect.height() / 2.0 + 0.5 );
01178     return QPoint( static_cast<int>(posX) + rect.center().x(),
01179                    static_cast<int>(posY) + rect.center().y() );
01180 
01181 }
01182 
01183 void KDChartPainter::makeArc( QPointArray& points,
01184                               const QRect& rect,
01185                               double startAngle, double angles )
01186 {
01187     double endAngle = startAngle + angles;
01188     int rCX = rect.center().x();
01189     int rCY = rect.center().y();
01190     double rWid2 = ( double ) rect.width() / 2.0;
01191     double rHig2 = ( double ) rect.height() / 2.0;
01192     int numSteps = static_cast<int>(angles);
01193     if( floor( angles ) < angles )
01194         ++numSteps;
01195     points.resize( numSteps );
01196     double angle = startAngle;
01197     if( angle < 0.0 )
01198         angle += 5760.0;
01199     else if( angle >= 5760.0 )
01200         angle -= 5760.0;
01201     for(int i = 0; i < numSteps; ++i){
01202         double normAngle = angle / 16.0;
01203         double normAngleRad = DEGTORAD( normAngle );
01204         double cosAngle = cos( normAngleRad );
01205         double sinAngle = -sin( normAngleRad );
01206         double posX = floor( cosAngle * rWid2 + 0.5 );
01207         double posY = floor( sinAngle * rHig2 + 0.5 );
01208         points[i] = QPoint( ( int ) posX + rCX,
01209                             ( int ) posY + rCY );
01210         if( i+1 >= numSteps-1 )
01211             angle = endAngle; // the very last step width may be smaller than 1.0
01212         else
01213             angle += 1.0;
01214         if( angle >= 5760.0 )
01215             angle -= 5760.0;
01216     }
01217 }
01218 
01228 void KDChartPainter::paintAxes( QPainter* /*painter*/, KDChartTableDataBase* /*data*/ )
01229 {
01230     // This method intentionally left blank.
01231 }
01232 
01233 
01234 int KDChartPainter::legendTitleVertGap() const
01235 {
01236     return _legendTitleHeight
01237            + static_cast < int > ( _legendTitleMetricsHeight * 0.20 );
01238 }
01239 
01240 
01241 QFont KDChartPainter::trueLegendFont() const
01242 {
01243     QFont trueFont = params()->legendFont();
01244     if ( params()->legendFontUseRelSize() ) {
01245         const double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);//( _areaWidthP1000 + _areaHeightP1000 ) / 2.0;
01246         trueFont.setPixelSize(
01247             static_cast < int > ( params()->legendFontRelSize() * averageValueP1000 ) );
01248     }
01249     return trueFont;
01250 }
01251 
01252 
01258 void KDChartPainter::calculateHorizontalLegendSize( QPainter* painter,
01259                                                     QSize& size,
01260                                                     bool& legendNewLinesStartAtLeft ) const
01261 {
01262 
01263   legendNewLinesStartAtLeft = false;
01264   QRect legendRect( _legendRect );
01265   /*
01266    * Pending Michel reset the left side before calculating
01267    *the new legend position calculation
01268    *otherwise we occasionally reach the edge and get a wrong
01269    *result
01270    */
01271 
01272   legendRect.setLeft( _innermostRect.left() );
01273 
01274     const int em2 = 2 * _legendEMSpace;
01275     const int em4 = 4 * _legendEMSpace;
01276     const int emDiv2 = static_cast < int > ( _legendEMSpace / 2.0 );
01277 
01278     const int xposHori0 = legendRect.left() + _legendEMSpace;
01279 
01280     int xpos = xposHori0;
01281 
01282     int ypos = legendRect.top() + emDiv2;
01283 
01284     // first paint the title, if any
01285     if( _legendTitle )
01286         xpos += _legendTitleWidth + em4;
01287 
01288     int maxX = _legendTitleWidth + _legendEMSpace;
01289 
01290     // save the x position: here start the item texts if in horizontal mode
01291     int xposHori1 = xpos;
01292 
01293     // add the space of the box plus the space between the box and the text
01294     int x2 = xpos + em2;
01295 
01296     // loop over all the datasets, each one has one row in the legend
01297     // if its data are to be used in at least one of the charts drawn
01298     // *but* only if there is a legend text for it!
01299     const int rightEdge = _innermostRect.right()-_legendEMSpace;
01300     bool bFirstLFWithTitle = _legendTitle;
01301     painter->setFont( trueLegendFont() );
01302     QFontMetrics txtMetrics( painter->fontMetrics() );
01303     int dataset;
01304     for ( dataset = 0; dataset < _numLegendTexts; ++dataset ) {
01305         /*
01306            if( KDChartParams::DataEntry == params()->chartSourceMode( dataset ) ) {
01307            */
01308         if( !_legendTexts[ dataset ].isEmpty() ){
01309             int txtWidth = txtMetrics.width( _legendTexts[ dataset ] ) + 1;
01310             if( x2 + txtWidth > rightEdge ){
01311                 if( xposHori1 + em2 + txtWidth > rightEdge){
01312                     xposHori1 = xposHori0;
01313                     legendNewLinesStartAtLeft = true;
01314                 }
01315                 xpos = xposHori1;
01316                 x2   = xpos + em2;
01317                 ypos += bFirstLFWithTitle ? legendTitleVertGap() : _legendSpacing;
01318                 bFirstLFWithTitle = false;
01319             }
01320             maxX = QMAX(maxX, x2+txtWidth+_legendEMSpace);
01321 
01322             xpos += txtWidth + em4;
01323             x2   += txtWidth + em4;
01324         }
01325     }
01326     if( bFirstLFWithTitle )
01327         ypos += _legendTitleHeight;
01328     else
01329         ypos += txtMetrics.height();
01330 
01331     size.setWidth(  maxX - legendRect.left() );
01332     size.setHeight( ypos + emDiv2 - _legendRect.top()  );
01333 }
01334 
01335 
01336 bool KDChartPainter::mustDrawVerticalLegend() const
01337 {
01338     return
01339         params()->legendOrientation() == Qt::Vertical ||
01340         params()->legendPosition() == KDChartParams::LegendLeft ||
01341         params()->legendPosition() == KDChartParams::LegendRight ||
01342         params()->legendPosition() == KDChartParams::LegendTopLeft ||
01343         params()->legendPosition() == KDChartParams::LegendTopLeftLeft ||
01344         params()->legendPosition() == KDChartParams::LegendTopRight ||
01345         params()->legendPosition() == KDChartParams::LegendTopRightRight ||
01346         params()->legendPosition() == KDChartParams::LegendBottomLeft ||
01347         params()->legendPosition() == KDChartParams::LegendBottomLeftLeft ||
01348         params()->legendPosition() == KDChartParams::LegendBottomRight ||
01349         params()->legendPosition() == KDChartParams::LegendBottomRightRight;
01350 }
01351 
01352 QFont KDChartPainter::trueLegendTitleFont() const
01353 {
01354     const double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);//( _areaWidthP1000 + _areaHeightP1000 ) / 2.0;
01355     QFont font( params()->legendTitleFont() );
01356     if ( params()->legendTitleFontUseRelSize() ) {
01357         int nTxtHeight =
01358             static_cast < int > ( params()->legendTitleFontRelSize()
01359             * averageValueP1000 );
01360         font.setPixelSize( nTxtHeight );
01361           // qDebug("l-t-height %i",nTxtHeight);
01362     }
01363     return font;
01364 }
01365 
01374 void KDChartPainter::paintLegend( QPainter* painter,
01375         KDChartTableDataBase* /*data*/ )
01376 {
01377     if ( params()->legendPosition() == KDChartParams::NoLegend )
01378         return ; // do not draw legend
01379 
01380     const bool bVertical = mustDrawVerticalLegend();
01381     painter->save();
01382 
01383 
01384     bool bFrameFound;
01385     params()->frameSettings( KDChartEnums::AreaLegend, bFrameFound );
01386 
01387     // start out with a rectangle around the legend
01388     //painter->setPen( QPen( Qt::black, 1 ) );
01389     //painter->setBrush( QBrush::NoBrush );
01390     //Pending Michel: let us paint the frame at the end of the drawmarker
01391     //and draw text process, in case we need to resize it then
01392     /*
01393     if( !bFrameFound ) {
01394       painter->drawRect( _legendRect );
01395     }
01396     */
01397     //qDebug("B:  _legendRect:\n          %i,%i\n          %i,%i", _legendRect.left(),_legendRect.top(),_legendRect.right(),_legendRect.bottom() );
01398     //qDebug("B: legendArea():\n          %i,%i\n          %i,%i\n", _params->legendArea().left(),_params->legendArea().top(),_params->legendArea().right(),_params->legendArea().bottom() );
01399 
01400     const int em2 = 2 * _legendEMSpace;
01401     const int em4 = 4 * _legendEMSpace;
01402     const int emDiv2 = static_cast < int > ( _legendEMSpace / 2.0 );
01403 
01404     const int xposHori0 = _legendRect.left() + _legendEMSpace;
01405 
01406     int xpos = xposHori0;
01407 
01408     int ypos = _legendRect.top() + emDiv2;
01409 
01410 
01411 
01412 
01413     // first paint the title, if any
01414     if( _legendTitle ) {
01415         painter->setFont( trueLegendTitleFont() );
01416         _legendTitle->draw( painter,
01417                             xpos,
01418                             ypos,
01419                             QRegion( xpos,
01420                                      ypos ,
01421                                      _legendTitleWidth,
01422                                      _legendTitleHeight ),
01423                             params()->legendTitleTextColor() );
01424         if( bVertical )
01425             ypos += legendTitleVertGap();
01426 
01427         else
01428             xpos += _legendTitleWidth + em4;
01429 
01430     }
01431 
01432     // save the x position: here start the item texts if in horizontal mode
01433     const int xposHori1 = _legendNewLinesStartAtLeft ? xposHori0 : xpos;
01434 
01435     // add the space of the box plus the space between the box and the text
01436     int x2 = xpos + em2;
01437 
01438     // loop over all the datasets, each one has one row in the legend
01439     // if its data are to be used in at least one of the charts drawn
01440     // *but* only if there is a legend text for it!
01441     const int rightEdge = _legendRect.right();
01442     bool bFirstLF = true;
01443     painter->setFont( trueLegendFont() );
01444     QFontMetrics txtMetrics( painter->fontMetrics() );
01445     int dataset;
01446     for ( dataset = 0; dataset < _numLegendTexts; ++dataset ) {
01447         /*
01448            if( KDChartParams::DataEntry == params()->chartSourceMode( dataset ) ) {
01449            */
01450         if( !_legendTexts[ dataset ].isEmpty() ){
01451             int txtWidth = txtMetrics.width( _legendTexts[ dataset ] ) + 1;
01452 
01453             // calculate the width and height for the marker, relative to the font height
01454             // we need the legend text to be aligned to the marker
01455             // substract a gap.
01456         int legHeight = static_cast <int>((txtMetrics.height() - (int)(txtMetrics.height() * 0.1))*0.85);
01457 
01458         //int legHeight = static_cast <int> (_legendRect.height()*0.8);
01459 
01460             if( !bVertical && x2 + txtWidth >= rightEdge ){
01461           _legendRect.setHeight( _legendRect.height() + _legendSpacing );
01462                 xpos = xposHori1;
01463                 x2   = xpos + em2;
01464                 ypos += bFirstLF ? legendTitleVertGap() : _legendSpacing;
01465                 bFirstLF = false;
01466             }
01467             painter->setBrush( QBrush( params()->dataColor( dataset ),
01468                                QBrush::SolidPattern ) );
01469 
01470             if( params()->legendShowLines() ){
01471                 painter->setPen( QPen( params()->dataColor( dataset ), 2,
01472                                  params()->lineStyle( dataset ) ) );
01473                 painter->drawLine(
01474                     xpos - emDiv2,
01475                     ypos + emDiv2 + 1,
01476                     xpos + static_cast < int > ( _legendEMSpace * 1.5 ),
01477                     ypos + emDiv2 + 1);
01478          }
01479 
01480             /*
01481             // draw marker if we have a marker, OR we have no marker and no line
01482             if ( params()->lineMarker() ||
01483                  params()->lineStyle( dataset ) == Qt::NoPen )*/
01484         drawMarker( painter,
01485             params(),
01486             _areaWidthP1000, _areaHeightP1000,
01487             _dataRect.x(), _dataRect.y(),
01488             params()->lineMarker()
01489             ? params()->lineMarkerStyle( dataset )
01490             : KDChartParams::LineMarkerSquare,
01491             params()->dataColor(dataset),
01492             QPoint(xpos + emDiv2,
01493                    bVertical? ypos + emDiv2: !bFirstLF ?ypos + _legendSpacing:_legendRect.center().y() - (legHeight / 2 ))/*ypos + emDiv2*/ ,
01494             0, 0, 0, NULL,  // these params are deadweight here. TODO
01495                 &legHeight /*&_legendEMSpace*/, &legHeight /*&_legendEMSpace*/,
01496             bVertical ? Qt::AlignCenter : (Qt::AlignTop | Qt::AlignHCenter) );
01497         /*
01498         painter->drawText(_legendRect.topLeft(), "topLeft" );
01499             painter->drawText(_legendRect.topLeft().x(), _legendRect.center().y(), "center" );
01500            painter->drawText(_legendRect.bottomLeft(), "bottomLeft" );
01501         */
01502             /* old:
01503             painter->setPen( Qt::black );
01504             painter->drawRect( xpos,
01505                                ypos + ( _legendHeight - _legendEMSpace ) / 2,
01506                                _legendEMSpace,
01507                                _legendEMSpace );
01508             */
01509             painter->setPen( params()->legendTextColor() );
01510             painter->drawText( x2,
01511                                bVertical ?  ypos : !bFirstLF ? ypos + _legendSpacing : _legendRect.center().y() - (legHeight / 2 ),
01512                                txtWidth,
01513                                legHeight,
01514                                Qt::AlignLeft | Qt::AlignVCenter,
01515                                _legendTexts[ dataset ] );
01516 
01517             if( bVertical )
01518                 ypos += _legendSpacing;
01519             else {
01520                 xpos += txtWidth + em4;
01521                 x2   += txtWidth + em4;
01522             }
01523         }
01524     }
01525 
01526     painter->setPen( QPen( Qt::black, 1 ) );
01527     painter->setBrush( QBrush::NoBrush );
01528     if( !bFrameFound )
01529       painter->drawRect( _legendRect );
01530 
01531 
01532     painter->restore();
01533 }
01534 
01535 
01536 void adjustFromTo(int& from, int& to)
01537 {
01538     if( abs(from) > abs(to) ){
01539         int n = from;
01540         from = to;
01541         to = n;
01542     }
01543 }
01544 
01545 
01546 bool KDChartPainter::axesOverlapping( int axis1, int axis2 )
01547 {
01548     KDChartAxisParams::AxisPos basicPos = KDChartAxisParams::basicAxisPos( axis1 );
01549     if( basicPos != KDChartAxisParams::basicAxisPos( axis2 ) )
01550         // Only axes of the same position can be compared. (e.g. 2 left axes)
01551         return false;
01552 
01553     if( KDChartAxisParams::AxisPosLeft  != basicPos &&
01554             KDChartAxisParams::AxisPosRight != basicPos )
01555         // Available space usage only possible for (vertical) ordinate axes.
01556         return false;
01557 
01558     int f1 = params()->axisParams( axis1 ).axisUseAvailableSpaceFrom();
01559     int t1 = params()->axisParams( axis1 ).axisUseAvailableSpaceTo();
01560     int f2 = params()->axisParams( axis2 ).axisUseAvailableSpaceFrom();
01561     int t2 = params()->axisParams( axis2 ).axisUseAvailableSpaceTo();
01562     adjustFromTo(f1,t1);
01563     adjustFromTo(f2,t2);
01564     // give these values some meaning
01565     // to be able to compare mixed fixed and/or relative figures:
01566     const double guessedAxisHeightP1000 = _areaHeightP1000 * 80.0 / 100.0;
01567     if(f1 < 0) f1 = static_cast < int > ( f1 * -guessedAxisHeightP1000 );
01568     if(t1 < 0) t1 = static_cast < int > ( t1 * -guessedAxisHeightP1000 );
01569     if(f2 < 0) f2 = static_cast < int > ( f2 * -guessedAxisHeightP1000 );
01570     if(t2 < 0) t2 = static_cast < int > ( t2 * -guessedAxisHeightP1000 );
01571     const bool res = (f1 >= f2 && f1 < t2) || (f2 >= f1 && f2 < t1);
01572     return res;
01573 }
01574 
01575 
01576 void internSetAxisArea( KDChartParams* params, int axis,
01577         int x0, int y0, int w0, int h0 )
01578 {
01579     // axis may never occupy more than 1000 per mille of the available space
01580     int nFrom = QMAX(-1000, params->axisParams( axis ).axisUseAvailableSpaceFrom());
01581     int nTo   = QMAX(-1000, params->axisParams( axis ).axisUseAvailableSpaceTo());
01582     adjustFromTo(nFrom,nTo);
01583 
01584     KDChartAxisParams::AxisPos basicPos = KDChartAxisParams::basicAxisPos( axis );
01585     int x, y, w, h;
01586     if( KDChartAxisParams::AxisPosBottom == basicPos ||
01587             KDChartAxisParams::AxisPosTop    == basicPos ){
01588 
01589         // Note: available space usage is ignored for abscissa axes!
01590         //
01591         //if( nFrom < 0 )
01592         //  x = x0 + w0*nFrom/-1000;
01593         //else
01594         //  x = x0 +    nFrom;
01595         //y = y0;
01596         //if( nTo < 0 )
01597         //  w = x0 + w0*nTo/-1000 - x;
01598         //else
01599         //  w = x0 +    nTo       - x;
01600         //h = h0;
01601 
01602         x = x0;
01603         y = y0;
01604         w = w0;
01605         h = h0;
01606 
01607     }else{
01608         x = x0;
01609         if( nTo < 0 )
01610             y = y0 + h0 - h0*nTo/-1000;
01611         else
01612             y = y0 + h0 -    nTo;
01613         w = w0;
01614         if( nFrom < 0 )
01615             h = y0 + h0 - h0*nFrom/-1000 - y;
01616         else
01617             h = y0 + h0 -    nFrom       - y;
01618     }
01619 
01620     params->setAxisArea( axis,
01621             QRect( x,
01622                 y,
01623                 w,
01624                 h ) );
01625 }
01626 
01627 
01636 void KDChartPainter::paintHeaderFooter( QPainter* painter,
01637         KDChartTableDataBase* /*data*/ )
01638 {
01639     const double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);//( _areaWidthP1000 + _areaHeightP1000 ) / 2.0;
01640 
01641     painter->save();
01642 
01643     for( int iHdFt  = KDChartParams::HdFtPosSTART;
01644             iHdFt <= KDChartParams::HdFtPosEND;  ++iHdFt ){
01645         QString txt( params()->headerFooterText( iHdFt ) );
01646         if ( !txt.isEmpty() ) {
01647             QFont actFont( params()->headerFooterFont( iHdFt ) );
01648             if ( params()->headerFooterFontUseRelSize( iHdFt ) )
01649                 actFont.setPixelSize( static_cast < int > (
01650                     params()->headerFooterFontRelSize( iHdFt ) * averageValueP1000 ) );
01651             painter->setPen( params()->headerFooterColor( iHdFt ) );
01652             painter->setFont( actFont );
01653             // Note: The alignment flags used here match the rect calculation
01654             //       done in KDChartPainter::setupGeometry().
01655             //       AlignTop is done to ensure that the hd/ft texts of the same
01656             //       group (e.g. Hd2L and Hd2 and Hd2R) have the same baselines.
01657 
01658             QRect rect( params()->headerFooterRect( iHdFt ) );
01659             int dXY = iHdFt < KDChartParams::HdFtPosFootersSTART
01660                 ? _hdLeading/3
01661                 : _ftLeading/3;
01662             rect.moveBy(dXY, dXY);
01663             rect.setWidth(  rect.width() -2*dXY +1 );
01664             rect.setHeight( rect.height()-2*dXY +1 );
01665             painter->drawText( rect,
01666                     Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine,
01667                     txt );
01668         }
01669     }
01670     painter->restore();
01671 }
01672 
01673 
01674 int KDChartPainter::calculateHdFtRects(
01675         QPainter* painter,
01676         double averageValueP1000,
01677         int  xposLeft,
01678         int  xposRight,
01679         bool bHeader,
01680         int& yposTop,
01681         int& yposBottom )
01682 {
01683     int& leading = (bHeader ? _hdLeading : _ftLeading);
01684     leading = 0; // pixels between the header (or footer, resp.) text
01685     // and the border of the respective Hd/Ft area
01686 
01687     const int rangesCnt = 3;
01688     const int ranges[ rangesCnt ]
01689         = { bHeader ? KDChartParams::HdFtPosHeaders0START : KDChartParams::HdFtPosFooters0START,
01690             bHeader ? KDChartParams::HdFtPosHeaders1START : KDChartParams::HdFtPosFooters1START,
01691             bHeader ? KDChartParams::HdFtPosHeaders2START : KDChartParams::HdFtPosFooters2START };
01692     const int rangeSize = 3;
01693     QFontMetrics* metrics[rangesCnt * rangeSize];
01694 
01695     int i;
01696     for( i = 0; i < rangesCnt*rangeSize; ++i )
01697         metrics[ i ] = 0;
01698 
01699     int iRange;
01700     int iHdFt;
01701     for( iRange = 0; iRange < rangesCnt; ++iRange ){
01702         for( i = 0; i < rangeSize; ++i ){
01703             iHdFt = ranges[iRange] + i;
01704             QString txt( params()->headerFooterText( iHdFt ) );
01705             if ( !txt.isEmpty() ) {
01706                 QFont actFont( params()->headerFooterFont( iHdFt ) );
01707                 if ( params()->headerFooterFontUseRelSize( iHdFt ) ) {
01708                     actFont.setPixelSize( static_cast < int > (
01709                             params()->headerFooterFontRelSize( iHdFt ) * averageValueP1000 ) );
01710                 }
01711                 painter->setFont( actFont );
01712                 metrics[ iRange*rangeSize + i ] = new QFontMetrics( painter->fontMetrics() );
01713                 leading = QMAX( leading, metrics[ iRange*rangeSize + i ]->lineSpacing() / 2 );
01714             }
01715         }
01716     }
01717 
01718     if( bHeader )
01719         ++yposTop;//yposTop += leading/3;
01720     //else
01721     //--yposBottom;//yposBottom -= leading/3;
01722 
01723     int leading23 = leading*2/3 +1;
01724 
01725     for( iRange =
01726             bHeader ? 0                  : rangesCnt-1;
01727             bHeader ? iRange < rangesCnt : iRange >= 0;
01728             bHeader ? ++iRange           : --iRange ){
01729         // Ascents and heights must be looked at to ensure that the hd/ft texts
01730         // of the same group (e.g. Hd2L and Hd2 and Hd2R) have equal baselines.
01731         int ascents[rangeSize];
01732         int heights[rangeSize];
01733         int widths[ rangeSize];
01734         int maxAscent = 0;
01735         int maxHeight = 0;
01736         for( i = 0; i < rangeSize; ++i ){
01737             iHdFt = ranges[iRange] + i;
01738             if ( metrics[ iRange*rangeSize + i ] ) {
01739                 QFontMetrics& m = *metrics[ iRange*rangeSize + i ];
01740                 ascents[i] = m.ascent();
01741                 heights[i] = m.height() + leading23;
01742 
01743                 // the following adds two spaces to work around a bug in Qt:
01744                 // bounding rect sometimes is too small, if using italicized fonts
01745                 widths[ i] = m.boundingRect( params()->headerFooterText( iHdFt )+"  " ).width() + leading23;
01746 
01747                 maxAscent = QMAX( maxAscent, ascents[i] );
01748                 maxHeight = QMAX( maxHeight, heights[i] );
01749             }else{
01750                 heights[i] = 0;
01751             }
01752         }
01753 
01754         if( !bHeader )
01755             yposBottom -= maxHeight;
01756 
01757         for( i = 0; i < rangeSize; ++i ){
01758             if( heights[i] ){
01759                 iHdFt = ranges[iRange] + i;
01760                 int x1;
01761                 switch( i ){
01762                     case 1:  x1 = xposLeft+1;
01763                             break;
01764                     case 2:  x1 = xposRight-widths[i]-1;
01765                             break;
01766                     default: x1 = xposLeft + (xposRight-xposLeft-widths[i]) / 2;
01767                 }
01768                 ((KDChartParams*)params())->__internalStoreHdFtRect( iHdFt,
01769                                                                     QRect( x1,
01770                                                                         bHeader
01771                                                                         ? yposTop    + maxAscent - ascents[i]
01772                                                                         : yposBottom + maxAscent - ascents[i],
01773                                                                         widths[ i],
01774                                                                         heights[i] - 1 ) );
01775             }
01776         }
01777         if( bHeader )
01778             yposTop    += leading + maxHeight;
01779         else
01780             yposBottom -= leading;
01781     }
01782     for( i = 0; i < rangesCnt*rangeSize; ++i )
01783         if( metrics[ i ] )
01784             delete metrics[ i ];
01785     return leading;
01786 }
01787 
01788 
01789 
01790 void KDChartPainter::findChartDatasets( KDChartTableDataBase* data,
01791                                         bool paint2nd,
01792                                         uint chart,
01793                                         uint& chartDatasetStart,
01794                                         uint& chartDatasetEnd )
01795 {
01796     chartDatasetStart = 0;
01797     chartDatasetEnd   = 0;
01798     if(    params()->neverUsedSetChartSourceMode()
01799         || !params()->findDatasets( KDChartParams::DataEntry,
01800                                     KDChartParams::ExtraLinesAnchor,
01801                                     chartDatasetStart,
01802                                     chartDatasetEnd,
01803                                     chart ) ) {
01804         uint maxRow, maxRowMinus1;
01805         switch ( data->usedRows() ) {
01806             case 0:
01807                 return ;
01808             case 1:
01809                 maxRow = 0;
01810                 maxRowMinus1 = 0;
01811                 break;
01812             default:
01813                 maxRow = data->usedRows() - 1;
01814                 maxRowMinus1 = maxRow;
01815         }
01816         chartDatasetStart = paint2nd ? maxRow : 0;
01817         chartDatasetEnd = paint2nd
01818                         ? maxRow
01819                         : (   ( KDChartParams::NoType == params()->additionalChartType() )
01820                             ? maxRow
01821                             : maxRowMinus1 );
01822 
01823     }
01824 }
01825 
01826 
01827 void KDChartPainter::calculateAllAxesRects(
01828         QPainter* painter,
01829         bool finalPrecision,
01830         KDChartTableDataBase* data
01831         )
01832 {
01833     const bool bIsAreaChart = KDChartParams::Area == params()->chartType();
01834     const bool bMultiRows = KDChartParams::Bar == params()->chartType() &&
01835         KDChartParams::BarMultiRows == params()->barChartSubType();
01836 
01837     const int trueWidth  = _outermostRect.width();
01838     const int trueHeight = _outermostRect.height();
01839     const double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);//( _areaWidthP1000 + _areaHeightP1000 ) / 2.0;
01840 
01841     // store the axes' 0 offsets
01842     int nAxesLeft0   = _axesRect.left() - _outermostRect.left();
01843     int nAxesRight0  = _outermostRect.right() - _axesRect.right();
01844     int nAxesTop0    = _axesRect.top() - _outermostRect.top();
01845     int nAxesBottom0 = _outermostRect.bottom() - _axesRect.bottom();
01846     if( bMultiRows ){
01847         uint chartDatasetStart, chartDatasetEnd;
01848         findChartDatasets( data, false, 0, chartDatasetStart, chartDatasetEnd );
01849         const int datasets = chartDatasetEnd - chartDatasetStart + 1;
01850         int numValues = 0;
01851         if ( params()->numValues() != -1 )
01852             numValues = params()->numValues();
01853         else
01854             numValues = data->usedCols();
01855         if( datasets ){
01856             const int additionalGapWidth = static_cast < int > ( 1.0 * _axesRect.width() / (9.75*numValues + 4.0*datasets) * 4.0*datasets );
01857             nAxesRight0 += additionalGapWidth;
01858             nAxesTop0   += static_cast < int > ( additionalGapWidth * 0.52 );
01859             //const double widthFactor = additionalGapWidth*1.0 / _axesRect.width();
01860             //nAxesTop0   += static_cast < int > ( _axesRect.height() * widthFactor );
01861         }
01862     }
01863     // store the distances to be added to the axes' 0 offsets
01864     int nAxesLeftADD  =0;
01865     int nAxesRightADD =0;
01866     int nAxesTopADD   =0;
01867     int nAxesBottomADD=0;
01868 
01869     // determine whether the axes widths of one side should be added
01870     // or their maximum should be used
01871     bool bAddLeft = axesOverlapping( KDChartAxisParams::AxisPosLeft,
01872             KDChartAxisParams::AxisPosLeft2 );
01873     bool bAddRight = axesOverlapping( KDChartAxisParams::AxisPosRight,
01874             KDChartAxisParams::AxisPosRight2 );
01875     bool bAddTop = axesOverlapping( KDChartAxisParams::AxisPosTop,
01876             KDChartAxisParams::AxisPosTop2 );
01877     bool bAddBottom = axesOverlapping( KDChartAxisParams::AxisPosBottom,
01878             KDChartAxisParams::AxisPosBottom2 );
01879     // iterate over all axes
01880     uint iAxis;
01881     for ( iAxis = 0; iAxis < KDCHART_MAX_AXES; ++iAxis ) {
01882         //qDebug(  "iAxis %i",  iAxis );
01883         const KDChartAxisParams& para = params()->axisParams( iAxis );
01884         int areaSize = 0;
01885 
01886         if ( para.axisVisible()
01887                 && KDChartAxisParams::AxisTypeUnknown != para.axisType() ) {
01888 
01889             const KDChartAxisParams::AxisPos
01890                 basicPos( KDChartAxisParams::basicAxisPos( iAxis ) );
01891 
01892             int areaMin = para.axisAreaMin();
01893             int areaMax = para.axisAreaMax();
01894             if ( 0 > areaMin )
01895                 areaMin = static_cast < int > ( -1.0 * averageValueP1000 * areaMin );
01896             if ( 0 > areaMax )
01897                 areaMax = static_cast < int > ( -1.0 * averageValueP1000 * areaMax );
01898 
01899             // make sure areaMin will not be too small
01900             // for the label texts and check if there is an axis Title
01901             switch ( basicPos ) {
01902                 case KDChartAxisParams::AxisPosBottom:
01903                 case KDChartAxisParams::AxisPosTop:
01904                     if ( para.axisLabelsVisible() ) {
01905                         int fntHeight;
01906                         if ( para.axisLabelsFontUseRelSize() )
01907                             fntHeight = QMAX(static_cast < int > ( para.axisLabelsFontRelSize() * averageValueP1000 ),
01908                                              para.axisLabelsFontMinSize() );
01909                         else {
01910                             painter->setFont( para.axisLabelsFont() );
01911                             QFontMetrics metrics( painter->fontMetrics() );
01912                             fntHeight = metrics.height();
01913                         }
01914                         // adjust text height in case of formatted Date/Time values
01915                         uint dataDataset, dataDataset2;
01916                         if( !params()->findDataset( KDChartParams::DataEntry,
01917                                                     dataDataset,
01918                                                     dataDataset2,
01919                                                     KDCHART_ALL_CHARTS ) ) {
01920                             qDebug( "IMPLEMENTATION ERROR: findDataset( DataEntry, ... ) should *always* return true. (a)" );
01921                             dataDataset = KDCHART_ALL_DATASETS;
01922                         }
01923                         QVariant::Type valType = QVariant::Invalid;
01924                         const bool dataCellsHaveSeveralCoordinates =
01925                             (KDCHART_ALL_DATASETS == dataDataset)
01926                             ? data->cellsHaveSeveralCoordinates( &valType )
01927                             : data->cellsHaveSeveralCoordinates( dataDataset, dataDataset2, &valType );
01928                         QString format( para.axisLabelsDateTimeFormat() );
01929                         if(    dataCellsHaveSeveralCoordinates
01930                             && QVariant::DateTime == valType ){
01931                             if( KDCHART_AXIS_LABELS_AUTO_DATETIME_FORMAT == format )
01932                                 areaMin = QMAX( areaMin, static_cast < int > ( fntHeight * 6.75 ) );
01933                             else
01934                                 areaMin = QMAX( areaMin, fntHeight * ( 3 + format.contains("\n") ) );
01935                         }
01936                         else
01937                             areaMin = QMAX( areaMin, fntHeight * 3 );
01938                     }
01939                     break;
01940                 case KDChartAxisParams::AxisPosLeft:
01941                 case KDChartAxisParams::AxisPosRight:
01942                 default:
01943                     break;
01944             }
01945 
01946 
01947             switch ( para.axisAreaMode() ) {
01948                 case KDChartAxisParams::AxisAreaModeAutoSize:
01949                 {
01950                     areaSize = areaMin;
01951                     switch ( basicPos ) {
01952                         case KDChartAxisParams::AxisPosBottom:
01953                         case KDChartAxisParams::AxisPosTop:
01954                             break;
01955                         case KDChartAxisParams::AxisPosLeft:
01956                         case KDChartAxisParams::AxisPosRight:
01957                             if( finalPrecision ){
01958                                 internal__KDChart__CalcValues& cv = calcVal[iAxis];
01959                                 const int nUsableAxisWidth = static_cast < int > (cv.pTextsW);
01960                                 const KDChartAxisParams & para = params()->axisParams( iAxis );
01961                                 QFont axisLabelsFont( para.axisLabelsFont() );
01962                                 if ( para.axisLabelsFontUseRelSize() ) {
01963                                     axisLabelsFont.setPixelSize( static_cast < int > ( cv.nTxtHeight ) );
01964                                 }
01965                                 painter->setFont( para.axisLabelsFont() );
01966                                 QFontMetrics axisLabelsFontMetrics( painter->fontMetrics() );
01967                                 const int lenEM( axisLabelsFontMetrics.boundingRect("M").width() );
01968                                 const QStringList* labelTexts = para.axisLabelTexts();
01969                                 uint nLabels = ( 0 != labelTexts )
01970                                             ? labelTexts->count()
01971                                             : 0;
01972                                 int maxLabelsWidth = 0;
01973                                 for ( uint i = 0; i < nLabels; ++i )
01974                                     maxLabelsWidth =
01975                                         QMAX( maxLabelsWidth,
01976                                               axisLabelsFontMetrics.boundingRect(*labelTexts->at(i)).width() );
01977                                 if( nUsableAxisWidth < maxLabelsWidth )
01978                                     areaSize = maxLabelsWidth
01979                                              + (para.axisTrueAreaRect().width() - nUsableAxisWidth)
01980                                              + lenEM;
01981                             }
01982                             break;
01983                         default:
01984                             break;
01985                     }
01986                 }
01987                 break;
01988                 case KDChartAxisParams::AxisAreaModeMinMaxSize:
01989                 {
01990                     qDebug( "Sorry, not implemented: AxisAreaModeMinMaxSize" );
01991                 }
01992 
01993                 //
01994                 //
01995                 //   F E A T U R E   P L A N N E D   F O R   F U T U R E . . .
01996                 //
01997                 //
01998 
01999                 // break;
02000 
02001                 case KDChartAxisParams::AxisAreaModeFixedSize:
02002                 {
02003                     areaSize = areaMax ? QMIN( areaMin, areaMax ) : areaMin;
02004                 }
02005                 break;
02006             }
02007 
02008             //find out if there is a title box
02009              uint idx;
02010              int boxSize = 0;
02011              for( idx = 0; idx <= params()->maxCustomBoxIdx(); ++idx ) {
02012                  const KDChartCustomBox * box = params()->customBox( idx );
02013                  if (  box )
02014                      if ( box->parentAxisArea() == KDChartAxisParams::AxisPosBottom
02015                           || box->parentAxisArea() == KDChartAxisParams::AxisPosLeft
02016                           || box->parentAxisArea() == KDChartAxisParams::AxisPosTop
02017                           || box->parentAxisArea() == KDChartAxisParams::AxisPosRight )
02018                       boxSize = box->trueRect(QPoint( 0,0 ), _areaWidthP1000, _areaHeightP1000 ).height();
02019              }
02020 
02021              areaSize += boxSize;
02022 
02023              switch ( basicPos ) {
02024              case KDChartAxisParams::AxisPosBottom:
02025                  if( bAddBottom ) {
02026                      //areaSize += boxSize;
02027                         nAxesBottomADD += areaSize;
02028                     }
02029                     else{
02030                         // areaSize += boxSize;
02031                         nAxesBottomADD = QMAX( nAxesBottomADD + boxSize, areaSize );
02032                     }
02033                     break;
02034                 case KDChartAxisParams::AxisPosLeft:
02035                     if( bAddLeft )
02036                         nAxesLeftADD += areaSize;
02037                     else
02038                         nAxesLeftADD = QMAX( nAxesLeftADD + boxSize, areaSize );
02039                     break;
02040                 case KDChartAxisParams::AxisPosTop:
02041                     if( bAddTop )
02042                         nAxesTopADD += areaSize;
02043                     else
02044                         nAxesTopADD = QMAX( nAxesTopADD + boxSize, areaSize );
02045                     break;
02046                 case KDChartAxisParams::AxisPosRight:
02047                     if( bAddRight )
02048                         nAxesRightADD += areaSize;
02049                     else
02050                         nAxesRightADD = QMAX( nAxesRightADD + boxSize, areaSize );
02051                     break;
02052                 default:
02053                     break;
02054             }
02055         }
02056         // Note: to prevent users from erroneously calling this
02057         //       function we do *not* provide a wrapper for it
02058         //       in the KDChartParams class but rather call it
02059         //       *directly* using a dirty typecast.
02060         ( ( KDChartAxisParams& ) para ).setAxisTrueAreaSize( areaSize );
02061     }
02062     int nMinDistance = static_cast < int > ( 30.0 * averageValueP1000 );
02063 
02064     int nAxesBottom = QMAX( nAxesBottom0 + nAxesBottomADD, nMinDistance );
02065 
02066     // for micro alignment with the X axis, we adjust the Y axis - but not for Area Charts:
02067     // otherwise the areas drawn would overwrite the Y axis line.
02068     int nAxesLeft   = QMAX( nAxesLeft0   + nAxesLeftADD,   nMinDistance )
02069                       - (bIsAreaChart ? 0 : 1);
02070 
02071     int nAxesTop    = QMAX( nAxesTop0    + nAxesTopADD,    nMinDistance );
02072 
02073     int nAxesRight  = QMAX( nAxesRight0  + nAxesRightADD,  nMinDistance );
02074 
02075     int nBottom  = params()->axisParams( KDChartAxisParams::AxisPosBottom ).axisTrueAreaSize();
02076     int nLeft    = params()->axisParams( KDChartAxisParams::AxisPosLeft ).axisTrueAreaSize();
02077     int nTop     = params()->axisParams( KDChartAxisParams::AxisPosTop ).axisTrueAreaSize();
02078     int nRight   = params()->axisParams( KDChartAxisParams::AxisPosRight ).axisTrueAreaSize();
02079     int nBottom2 = params()->axisParams( KDChartAxisParams::AxisPosBottom2 ).axisTrueAreaSize();
02080     int nLeft2   = params()->axisParams( KDChartAxisParams::AxisPosLeft2 ).axisTrueAreaSize();
02081     int nTop2    = params()->axisParams( KDChartAxisParams::AxisPosTop2 ).axisTrueAreaSize();
02082     int nRight2  = params()->axisParams( KDChartAxisParams::AxisPosRight2 ).axisTrueAreaSize();
02083 
02084     internSetAxisArea( _params,
02085             KDChartAxisParams::AxisPosBottom,
02086             _outermostRect.left() + nAxesLeft,
02087             _outermostRect.top()  + trueHeight - nAxesBottom,
02088             trueWidth - nAxesLeft - nAxesRight + 1,
02089             nBottom );
02090     internSetAxisArea( _params,
02091             KDChartAxisParams::AxisPosLeft,
02092             _outermostRect.left() + (bAddLeft ? nAxesLeft0 + nLeft2 : nAxesLeft0),
02093             _outermostRect.top()  + nAxesTop,
02094             nLeft,
02095             trueHeight - nAxesTop - nAxesBottom + 1 );
02096 
02097     internSetAxisArea( _params,
02098             KDChartAxisParams::AxisPosTop,
02099             _outermostRect.left() + nAxesLeft,
02100             _outermostRect.top()  + (bAddTop ? nAxesTop0 + nTop2 : nAxesTop0),
02101             trueWidth - nAxesLeft - nAxesRight + 1,
02102             nTop );
02103     internSetAxisArea( _params,
02104             KDChartAxisParams::AxisPosRight,
02105             _outermostRect.left() + trueWidth - nAxesRight,
02106             _outermostRect.top()  + nAxesTop,
02107             nRight,
02108             trueHeight - nAxesTop - nAxesBottom + 1 );
02109 
02110     internSetAxisArea( _params,
02111             KDChartAxisParams::AxisPosBottom2,
02112             _outermostRect.left() + nAxesLeft,
02113             _outermostRect.top()  + trueHeight - nAxesBottom + (bAddBottom ? nBottom : 0),
02114             trueWidth - nAxesLeft - nAxesRight + 1,
02115             nBottom2 );
02116     internSetAxisArea( _params,
02117             KDChartAxisParams::AxisPosLeft2,
02118             _outermostRect.left() + nAxesLeft0,
02119             _outermostRect.top()  + nAxesTop,
02120             nLeft2,
02121             trueHeight - nAxesTop - nAxesBottom + 1 );
02122 
02123     internSetAxisArea( _params,
02124             KDChartAxisParams::AxisPosTop2,
02125             _outermostRect.left() + nAxesLeft,
02126             _outermostRect.top()  + nAxesTop0,
02127             trueWidth - nAxesLeft - nAxesRight + 1,
02128             nTop2 );
02129     internSetAxisArea( _params,
02130             KDChartAxisParams::AxisPosRight2,
02131             _outermostRect.left() + trueWidth - nAxesRight + (bAddRight ? nRight : 0),
02132             _outermostRect.top()  + nAxesTop,
02133             nRight2,
02134             trueHeight - nAxesTop - nAxesBottom + 1 );
02135 
02136     _dataRect = QRect( _outermostRect.left() + nAxesLeft,
02137                        _outermostRect.top()  + nAxesTop,
02138                        trueWidth - nAxesLeft - nAxesRight + 1,
02139                        trueHeight - nAxesTop - nAxesBottom + 1 );
02140 }
02141 
02142 
02143 
02156 void KDChartPainter::setupGeometry( QPainter* painter,
02157                                     KDChartTableDataBase* data,
02158                                     const QRect& drawRect )
02159 {
02160   //qDebug("INVOKING: KDChartPainter::setupGeometry()");
02161     // avoid recursion from repaint() being called due to params() changed signals...
02162     const bool oldBlockSignalsState = params()->signalsBlocked();
02163     const_cast < KDChartParams* > ( params() )->blockSignals( true );
02164 
02165     _outermostRect = drawRect;
02166 
02167     int yposTop    = _outermostRect.topLeft().y();
02168     int xposLeft   = _outermostRect.topLeft().x();
02169     int yposBottom = _outermostRect.bottomRight().y();
02170     int xposRight  = _outermostRect.bottomRight().x();
02171 
02172     const int trueWidth  = _outermostRect.width();
02173     const int trueHeight = _outermostRect.height();
02174 
02175     // Temporary values used to calculate start values xposLeft, yposTop, xposRight, yposBottom.
02176     // They will be replaced immediately after these calculations.
02177     _areaWidthP1000    = trueWidth / 1000.0;
02178     _areaHeightP1000   = trueHeight / 1000.0;
02179 
02180 
02181     xposLeft   +=   0 < params()->globalLeadingLeft()
02182         ? params()->globalLeadingLeft()
02183         : static_cast < int > ( params()->globalLeadingLeft()  * -_areaWidthP1000 );
02184     yposTop    +=   0 < params()->globalLeadingTop()
02185         ? params()->globalLeadingTop()
02186         : static_cast < int > ( params()->globalLeadingTop()   * -_areaHeightP1000 );
02187     xposRight  -=   0 < params()->globalLeadingRight()
02188         ? params()->globalLeadingRight()
02189         : static_cast < int > ( params()->globalLeadingRight() * -_areaWidthP1000 );
02190     yposBottom -=   0 < params()->globalLeadingBottom()
02191         ? params()->globalLeadingBottom()
02192         : static_cast < int > ( params()->globalLeadingBottom()* -_areaHeightP1000 );
02193 
02194     _innermostRect = QRect( QPoint(xposLeft,  yposTop),
02195                             QPoint(xposRight, yposBottom) );
02196 
02197     _logicalWidth  = xposRight  - xposLeft;
02198     _logicalHeight = yposBottom - yposTop;
02199 
02200     // true values (having taken the global leadings into account)
02201     // to be used by all following functions
02202     _areaWidthP1000 =  _logicalWidth  / 1000.0;
02203     _areaHeightP1000 = _logicalHeight / 1000.0;
02204 
02205     double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);//( _areaWidthP1000 + _areaHeightP1000 ) / 2.0;
02206 
02207     // new code design:
02208     //        1. now min-header-leading is text height/2
02209     //        2. leading or legendSpacing (whichever is larger)
02210     //           will be added if legend is below the header(s)
02211     //        3. leading will be added between header and data area
02212     //           in case there is no top legend but grid is to be shown.
02213     int headerLineLeading = calculateHdFtRects(
02214             painter,
02215             averageValueP1000,
02216             xposLeft, xposRight,
02217             false,
02218             yposTop, yposBottom );
02219     calculateHdFtRects(
02220             painter,
02221             averageValueP1000,
02222             xposLeft, xposRight,
02223             true,
02224             yposTop, yposBottom );
02225 
02226     // Calculate legend position. First check whether there is going
02227     // to be a legend at all:
02228     if ( params()->legendPosition() != KDChartParams::NoLegend ) {
02229         // Now calculate the size needed for the legend
02230         findLegendTexts( data );
02231 
02232         bool hasLegendTitle = false;
02233         if ( !params()->legendTitleText().isEmpty() )
02234             hasLegendTitle = true;
02235 
02236         _legendTitleWidth = 0;
02237         if( _legendTitle )
02238             delete _legendTitle;
02239         _legendTitle = 0;
02240         if ( hasLegendTitle ) {
02241             const QFont font( trueLegendTitleFont() );
02242             painter->setFont( font );
02243             QFontMetrics legendTitleMetrics( painter->fontMetrics() );
02244             _legendTitleMetricsHeight = legendTitleMetrics.height();
02245 
02246             _legendTitle = new KDChartTextPiece( painter,
02247                                                  params()->legendTitleText(),
02248                                                  font );
02249             _legendTitleWidth = _legendTitle->width();
02250             _legendTitleHeight = _legendTitle->height();
02251             // qDebug("1. _legendTitleHeight %i",_legendTitleHeight);
02252         }
02253 
02254         painter->setFont( trueLegendFont() );
02255         QFontMetrics legendMetrics( painter->fontMetrics() );
02256         _legendSpacing = legendMetrics.lineSpacing();
02257         _legendHeight = legendMetrics.height();
02258         _legendLeading = legendMetrics.leading();
02259 
02260         _legendEMSpace = legendMetrics.width( 'M' );
02261 
02262         int sizeX = 0;
02263         int sizeY = 0;
02264 
02265         for ( int dataset = 0; dataset < _numLegendTexts; dataset++ ) {
02266             sizeX = QMAX( sizeX, legendMetrics.width( _legendTexts[ dataset ] ) );
02267             if( !_legendTexts[ dataset ].isEmpty() )
02268                 sizeY += _legendSpacing;
02269         }
02270         // add space below the legend's bottom line
02271         sizeY += _legendEMSpace - _legendLeading;
02272         // add space for the legend title if any was set
02273         if ( hasLegendTitle )
02274             sizeY += legendTitleVertGap();
02275 
02276         // assume 4 em spaces: before the color box, the color box, after the
02277         // color box and after the legend text
02278         sizeX += ( _legendEMSpace * 4 );
02279 
02280         // We cannot setup the title width earlier as the title does
02281         // not have a color box. The two em spaces are before the
02282         // color box (where the title does not start yet, it is
02283         // left-aligned with the color boxes) and after the title (to
02284         // have some space before the boundary line comes).
02285         sizeX = QMAX( sizeX, _legendTitleWidth + _legendEMSpace*2 );
02286 
02287     //qDebug("setupGeometry  mustDrawVerticalLegend: %s", mustDrawVerticalLegend() ? "YES":"NO ");
02288 
02289     //     PENDING Michel: do that after having calculated the position
02290         if( !mustDrawVerticalLegend() ){
02291             QSize size;
02292             calculateHorizontalLegendSize( painter,
02293                                            size,
02294                                            _legendNewLinesStartAtLeft );
02295             sizeX = size.width();
02296             sizeY = size.height();
02297         }
02298 
02299         switch ( params()->legendPosition() ) {
02300             case KDChartParams::LegendTop:
02301                 if ( headerLineLeading )
02302                     yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02303                 _legendRect = QRect( xposLeft + ( (xposRight-xposLeft) - sizeX ) / 2,
02304                                      yposTop, sizeX, sizeY );
02305                 yposTop = _legendRect.bottom() + params()->legendSpacing();
02306                 //qDebug("A:  _legendRect:\n%i,%i\n%i,%i", _legendRect.left(),_legendRect.top(),_legendRect.right(),_legendRect.bottom() );
02307                 break;
02308             case KDChartParams::LegendBottom:
02309                 if ( params()->showGrid() )
02310                     yposTop += headerLineLeading;
02311                 _legendRect = QRect( xposLeft + ( (xposRight-xposLeft) - sizeX ) / 2,
02312                                      yposBottom - sizeY,
02313                                      sizeX, sizeY );
02314                 yposBottom = _legendRect.top() - params()->legendSpacing();
02315                 break;
02316             case KDChartParams::LegendLeft:
02317                 if ( params()->showGrid() )
02318                     yposTop += headerLineLeading;
02319                 _legendRect = QRect( xposLeft + 1, ( yposBottom - yposTop - sizeY ) / 2 +
02320                                      yposTop,
02321                                      sizeX, sizeY );
02322                 xposLeft = _legendRect.right() + params()->legendSpacing();
02323                 break;
02324             case KDChartParams::LegendRight:
02325                 if ( params()->showGrid() )
02326                     yposTop += headerLineLeading;
02327                 _legendRect = QRect( xposRight - sizeX - 1,
02328                         ( yposBottom - yposTop - sizeY ) / 2 + yposTop,
02329                         sizeX, sizeY );
02330                 xposRight = _legendRect.left() - params()->legendSpacing();
02331                 break;
02332             case KDChartParams::LegendTopLeft:
02333                 if ( headerLineLeading )
02334                     yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02335                 _legendRect = QRect( xposLeft + 1, yposTop, sizeX, sizeY );
02336                 yposTop = _legendRect.bottom() + params()->legendSpacing();
02337                 xposLeft = _legendRect.right() + params()->legendSpacing();
02338                 break;
02339             case KDChartParams::LegendTopLeftTop:
02340                 if ( headerLineLeading )
02341                     yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02342                 _legendRect = QRect( xposLeft + 1, yposTop, sizeX, sizeY );
02343                 yposTop = _legendRect.bottom() + params()->legendSpacing();
02344                 break;
02345             case KDChartParams::LegendTopLeftLeft:
02346                 if ( headerLineLeading )
02347                     yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02348                 _legendRect = QRect( xposLeft + 1, yposTop, sizeX, sizeY );
02349                 xposLeft = _legendRect.right() + params()->legendSpacing();
02350                 break;
02351             case KDChartParams::LegendTopRight:
02352                 if ( headerLineLeading )
02353                     yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02354                 _legendRect = QRect( xposRight - sizeX - 1,
02355                         yposTop, sizeX, sizeY );
02356                 yposTop = _legendRect.bottom() + params()->legendSpacing();
02357                 xposRight = _legendRect.left() - params()->legendSpacing();
02358                 break;
02359             case KDChartParams::LegendTopRightTop:
02360                 if ( headerLineLeading )
02361                     yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02362                 _legendRect = QRect( xposRight - sizeX - 1,
02363                         yposTop, sizeX, sizeY );
02364                 yposTop = _legendRect.bottom() + params()->legendSpacing();
02365                 break;
02366             case KDChartParams::LegendTopRightRight:
02367                 if ( headerLineLeading )
02368                     yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02369                 _legendRect = QRect( xposRight - sizeX - 1,
02370                         yposTop, sizeX, sizeY );
02371                 xposRight = _legendRect.left() - params()->legendSpacing();
02372                 break;
02373             case KDChartParams::LegendBottomLeft:
02374                 if ( params()->showGrid() )
02375                     yposTop += headerLineLeading;
02376                 _legendRect = QRect( xposLeft + 1, yposBottom - sizeY, sizeX, sizeY );
02377                 yposBottom = _legendRect.top() - params()->legendSpacing();
02378                 xposLeft = _legendRect.right() + params()->legendSpacing();
02379                 break;
02380             case KDChartParams::LegendBottomLeftBottom:
02381                 if ( params()->showGrid() )
02382                     yposTop += headerLineLeading;
02383                 _legendRect = QRect( xposLeft + 1, yposBottom - sizeY, sizeX, sizeY );
02384                 yposBottom = _legendRect.top() - params()->legendSpacing();
02385                 break;
02386             case KDChartParams::LegendBottomLeftLeft:
02387                 if ( params()->showGrid() )
02388                     yposTop += headerLineLeading;
02389                 _legendRect = QRect( xposLeft + 1, yposBottom - sizeY, sizeX, sizeY );
02390                 xposLeft = _legendRect.right() + params()->legendSpacing();
02391                 break;
02392             case KDChartParams::LegendBottomRight:
02393                 if ( params()->showGrid() )
02394                     yposTop += headerLineLeading;
02395                 _legendRect = QRect( xposRight - sizeX - 1,
02396                         yposBottom - sizeY, sizeX, sizeY );
02397                 yposBottom = _legendRect.top() - params()->legendSpacing();
02398                 xposRight = _legendRect.left() - params()->legendSpacing();
02399                 break;
02400             case KDChartParams::LegendBottomRightBottom:
02401                 if ( params()->showGrid() )
02402                     yposTop += headerLineLeading;
02403                 _legendRect = QRect( xposRight - sizeX - 1,
02404                         yposBottom - sizeY, sizeX, sizeY );
02405                 yposBottom = _legendRect.top() - params()->legendSpacing();
02406                 break;
02407             case KDChartParams::LegendBottomRightRight:
02408                 if ( params()->showGrid() )
02409                     yposTop += headerLineLeading;
02410                 _legendRect = QRect( xposRight - sizeX - 1,
02411                         yposBottom - sizeY, sizeX, sizeY );
02412                 xposRight = _legendRect.left() - params()->legendSpacing();
02413                 break;
02414             default:
02415                 // Should not be able to happen
02416                 qDebug( "KDChart: Unknown legend position" );
02417         }
02418         _params->setLegendArea( _legendRect );
02419 
02420     }else{
02421       _params->setLegendArea( QRect(QPoint(0,0), QSize(0,0)) );
02422     }
02423 
02424 
02425     _axesRect = QRect( QPoint(xposLeft, yposTop), QPoint(xposRight, yposBottom) );
02426 
02427     // important rule: do *not* calculate axes areas for Polar charts!
02428     //                 (even if left and bottom axes might be set active)
02429     if( KDChartParams::Polar == params()->chartType() ) {
02430         _dataRect = _axesRect;
02431     } else {
02432         // 1st step: make a preliminary approximation of the axes sizes,
02433         //           as a basis of following label texts calculation
02434         calculateAllAxesRects( painter, false, data );
02435         // 2nd step: calculate all labels (preliminary data, will be
02436         //           overwritten by KDChartAxesPainter)
02437         //           to find out the longest possible axis labels
02438         double dblDummy;
02439         if( calculateAllAxesLabelTextsAndCalcValues(
02440                 painter,
02441                 data,
02442                 _areaWidthP1000,
02443                 _areaHeightP1000,
02444                 dblDummy ) )
02445             // 3rd step: calculate the _true_ axes rects based upon
02446             //           the preliminary axes labels
02447             calculateAllAxesRects( painter, true, data );
02448     }
02449     _params->setDataArea( _dataRect );
02450 
02451     const_cast < KDChartParams* > ( params() )->blockSignals( oldBlockSignalsState );
02452 }
02453 
02454 
02458 void KDChartPainter::findLegendTexts( KDChartTableDataBase* data )
02459 {
02460     uint dataset;
02461     QVariant vValY;
02462     switch ( params()->legendSource() ) {
02463         case KDChartParams::LegendManual: {
02464             // The easiest case: Take manually set strings, no matter whether any
02465             // have been set.
02466             _numLegendTexts = numLegendFallbackTexts( data );
02467             for ( dataset = 0; dataset < static_cast<uint>(_numLegendTexts); dataset++ )
02468                 _legendTexts[ dataset ] = params()->legendText( dataset );
02469             break;
02470         }
02471         case KDChartParams::LegendFirstColumn: {
02472             // Take whatever is in the first column
02473             for ( dataset = 0; dataset < data->usedRows(); dataset++ ){
02474                 if( data->cellCoord( dataset, 0, vValY, 1 ) ){
02475                     if( QVariant::String == vValY.type() )
02476                         _legendTexts[ dataset ] = vValY.toString();
02477                     else
02478                         _legendTexts[ dataset ] = "";
02479                 }
02480             }
02481             _numLegendTexts = data->usedRows();
02482             break;
02483         }
02484         case KDChartParams::LegendAutomatic: {
02485             // First, try the first row
02486             bool notfound = false;
02487             _numLegendTexts = numLegendFallbackTexts( data ); // assume this for cleaner
02488             // code below
02489             for ( dataset = 0; dataset < data->usedRows(); dataset++ ) {
02490                 if( data->cellCoord( dataset, 0, vValY, 1 ) ){
02491                     if( QVariant::String == vValY.type() )
02492                         _legendTexts[ dataset ] = vValY.toString();
02493                     else
02494                         _legendTexts[ dataset ] = "";
02495                     if( _legendTexts[ dataset ].isEmpty() ){
02496                         notfound = true;
02497                         break;
02498                     }
02499                 }
02500             }
02501 
02502             // If there were no entries for all the datasets, use the manually set
02503             // texts, and resort to Series 1, Series 2, ... where nothing has been
02504             // set.
02505             if ( notfound ) {
02506                 for ( dataset = 0; dataset < numLegendFallbackTexts( data );
02507                         dataset++ ) {
02508                     _legendTexts[ dataset ] = params()->legendText( dataset );
02509                     if ( _legendTexts[ dataset ].isEmpty() || _legendTexts[ dataset ].isNull() ) {
02510                         _legendTexts[ dataset ] = fallbackLegendText( dataset );
02511                         // there
02512                         _numLegendTexts = numLegendFallbackTexts( data );
02513                     }
02514                 }
02515             }
02516             break;
02517         }
02518         default:
02519             // Should not happen
02520             qDebug( "KDChart: Unknown legend source" );
02521     }
02522 }
02523 
02524 
02540 QString KDChartPainter::fallbackLegendText( uint dataset ) const
02541 {
02542     return QObject::tr( "Series " ) + QString::number( dataset + 1 );
02543 }
02544 
02545 
02558 uint KDChartPainter::numLegendFallbackTexts( KDChartTableDataBase* data ) const
02559 {
02560     return data->usedRows();
02561 }
02562 
02563 
02573 void KDChartPainter::drawMarker( QPainter* painter,
02574                                  int style,
02575                                  const QColor& color,
02576                                  const QPoint& p,
02577                                  const QSize& size,
02578                                  uint align )
02579 {
02580     int width = size.width();
02581     int height = size.height();
02582     drawMarker( painter,
02583                 0,
02584                 0.0, 0.0,
02585                 0,0,
02586                 style,
02587                 color,
02588                 p,
02589                 0,0,0,
02590                 0,
02591                 &width,
02592                 &height,
02593                 align );
02594 }
02595 
02596 
02612 KDChartDataRegion* KDChartPainter::drawMarker( QPainter* painter,
02613                                                const KDChartParams* params,
02614                                                double areaWidthP1000,
02615                                                double areaHeightP1000,
02616                                                int deltaX,
02617                                                int deltaY,
02618                                                int style,
02619                                                const QColor& color,
02620                                                const QPoint& _p,
02621                                                uint dataset, uint value, uint chart,
02622                                                KDChartDataRegionList* regions,
02623                                                int* width,
02624                                                int* height,
02625                                                uint align )
02626 {
02627     KDChartDataRegion* datReg = 0;
02628     const double areaSizeP1000 = QMIN(areaWidthP1000, areaHeightP1000);
02629     int xsize  = width ? *width : (params ? params->lineMarkerSize().width() : 12);
02630     if( 0 > xsize )
02631         xsize = static_cast < int > (xsize * -areaSizeP1000);
02632     int ysize  = height ? *height : (params ? params->lineMarkerSize().height() : 12);
02633     if( 0 > ysize )
02634         ysize = static_cast < int > (ysize * -areaSizeP1000);
02635     if( KDChartParams::LineMarkerCross != style ){
02636         xsize = QMAX( xsize, 4 );
02637         ysize = QMAX( ysize, 4 );
02638     }
02639     uint xsize2 = xsize / 2;
02640     uint ysize2 = ysize / 2;
02641     uint xsize4 = xsize / 4;
02642     uint ysize4 = ysize / 4;
02643     uint xsize6 = xsize / 6;
02644     uint ysize6 = ysize / 6;
02645     painter->setPen( color );
02646     const uint xysize2 = QMIN( xsize2, ysize2 );
02647 
02648     int x = _p.x();
02649     int y = _p.y();
02650     if( align & Qt::AlignLeft )
02651         x += xsize2;
02652     else if( align & Qt::AlignRight )
02653         x -= xsize2;
02654     if( align & Qt::AlignTop )
02655         y += ysize2;
02656     else if( align & Qt::AlignBottom )
02657         y -= ysize2;
02658     const QPoint p(x, y);
02659 
02660     switch ( style ) {
02661         case KDChartParams::LineMarkerSquare: {
02662                                                 const QPen oldPen( painter->pen() );
02663                                                 const QBrush oldBrush( painter->brush() );
02664                                                 painter->setBrush( color );
02665                                                 painter->setPen(   color );
02666                                                 QRect rect( QPoint( p.x() - xsize2, p.y() - ysize2 ), QPoint( p.x() + xsize2, p.y() + ysize2 ) );
02667                                                 painter->drawRect( rect );
02668                                                 // Don't use rect for drawing after this!
02669                                                 rect.moveBy( deltaX, deltaY );
02670                                                 if ( regions ){
02671                                                     datReg =
02672                                                         new KDChartDataRegion(
02673                                                                 dataset, value,
02674                                                                 chart,   rect );
02675                                                     regions->append( datReg );
02676                                                 }
02677                                                 painter->setPen(   oldPen );
02678                                                 painter->setBrush( oldBrush );
02679                                                 break;
02680                                               }
02681         case KDChartParams::LineMarkerDiamond:{
02682                                                 const QBrush oldBrush( painter->brush() );
02683                                                 painter->setBrush( color );
02684                                                 QPointArray points( 4 );
02685                                                 points.setPoint( 0, p.x() - xsize2, p.y() );
02686                                                 points.setPoint( 1, p.x(),          p.y() - ysize2 );
02687                                                 points.setPoint( 2, p.x() + xsize2, p.y() );
02688                                                 points.setPoint( 3, p.x(),          p.y() + ysize2 );
02689                                                 painter->drawPolygon( points );
02690                                                 // Don't use points for drawing after this!
02691                                                 points.translate( deltaX, deltaY );
02692                                                 if ( regions ){
02693                                                     datReg = new KDChartDataRegion(
02694                                                                     dataset, value,
02695                                                                     chart,   points );
02696                                                     regions->append( datReg  );
02697                                                 }
02698                                                 painter->setBrush( oldBrush );
02699                                                 break;
02700                                               }
02701         case KDChartParams::LineMarker1Pixel: {
02702                                                 QRect rect( p, p );
02703                                                 painter->drawRect( rect );
02704                                                 // Don't use rect for drawing after this!
02705                                                 rect.moveBy( deltaX, deltaY );
02706                                                 if ( regions ){
02707                                                     datReg = new KDChartDataRegion(
02708                                                                     dataset, value,
02709                                                                     chart, rect );
02710                                                     regions->append( datReg );
02711                                                 }
02712                                                 break;
02713                                               }
02714         case KDChartParams::LineMarker4Pixels:{
02715                                                 QRect rect( p, QPoint( p.x()+1, p.y()+1 ) );
02716                                                 painter->drawRect( rect );
02717                                                 // Don't use rect for drawing after this!
02718                                                 rect.moveBy( deltaX, deltaY );
02719                                                 if ( regions ){
02720                                                     datReg = new KDChartDataRegion(
02721                                                                     dataset, value,
02722                                                                     chart, rect );
02723                                                     regions->append( datReg );
02724                                                 }
02725                                                 break;
02726                                               }
02727         case KDChartParams::LineMarkerRing:   {
02728                                                 const QPen oldPen( painter->pen() );
02729                                                 painter->setPen( QPen( color, QMIN(xsize4, ysize4) ) );
02730                                                 const QBrush oldBrush( painter->brush() );
02731                                                 painter->setBrush( Qt::NoBrush );
02732                                                 painter->drawEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
02733                                                 if ( regions ) {
02734                                                     QPointArray points;
02735                                                     points.makeEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
02736                                                     // Don't use points for drawing after this!
02737                                                     points.translate( deltaX, deltaY );
02738                                                     if( points.size() > 0 ){
02739                                                         datReg = new KDChartDataRegion(
02740                                                                         dataset, value,
02741                                                                         chart,   points );
02742                                                         regions->append( datReg );
02743                                                     }
02744                                                 }
02745                                                 painter->setBrush( oldBrush );
02746                                                 painter->setPen(   oldPen );
02747                                                 break;
02748                                               }
02749         case KDChartParams::LineMarkerCross:  {
02750                                                 const QPen oldPen( painter->pen() );
02751                                                 painter->setPen( color );
02752                                                 const QBrush oldBrush( painter->brush() );
02753                                                 painter->setBrush( color );
02754                                                 int numPoints = (ysize && xsize) ? 12 : 4;
02755                                                 QPointArray points( numPoints );
02756                                                 if( ysize && xsize ){
02757                                                     points.setPoint( 0, p.x() - xsize6, p.y() - ysize6 );
02758                                                     points.setPoint( 1, p.x() - xsize6, p.y() - ysize2 );
02759                                                     points.setPoint( 2, p.x() + xsize6, p.y() - ysize2 );
02760                                                     points.setPoint( 3, p.x() + xsize6, p.y() - ysize6 );
02761                                                     points.setPoint( 4, p.x() + xsize2, p.y() - ysize6 );
02762                                                     points.setPoint( 5, p.x() + xsize2, p.y() + ysize6 );
02763                                                     points.setPoint( 6, p.x() + xsize6, p.y() + ysize6 );
02764                                                     points.setPoint( 7, p.x() + xsize6, p.y() + ysize2 );
02765                                                     points.setPoint( 8, p.x() - xsize6, p.y() + ysize2 );
02766                                                     points.setPoint( 9, p.x() - xsize6, p.y() + ysize6 );
02767                                                     points.setPoint(10, p.x() - xsize2, p.y() + ysize6 );
02768                                                     points.setPoint(11, p.x() - xsize2, p.y() - ysize6 );
02769                                                 }else if( ysize ){
02770                                                     points.setPoint( 0, p.x() - ysize6, p.y() - ysize2 );
02771                                                     points.setPoint( 1, p.x() + ysize6, p.y() - ysize2 );
02772                                                     points.setPoint( 2, p.x() + ysize6, p.y() + ysize2 );
02773                                                     points.setPoint( 3, p.x() - ysize6, p.y() + ysize2 );
02774                                                 }else{
02775                                                     points.setPoint( 0, p.x() - xsize2, p.y() - xsize6 );
02776                                                     points.setPoint( 1, p.x() + xsize2, p.y() - xsize6 );
02777                                                     points.setPoint( 2, p.x() + xsize2, p.y() + xsize6 );
02778                                                     points.setPoint( 3, p.x() - xsize2, p.y() + xsize6 );
02779                                                 }
02780                                                 painter->drawPolygon( points );
02781                                                 // Don't use points for drawing after this!
02782                                                 points.translate( deltaX, deltaY );
02783                                                 if( regions ){
02784                                                     datReg = new KDChartDataRegion(
02785                                                                     dataset, value,
02786                                                                     chart,   points );
02787                                                     regions->append( datReg );
02788                                                 }
02789                                                 painter->setBrush( oldBrush );
02790                                                 painter->setPen(   oldPen );
02791                                                 break;
02792                                               }
02793         case KDChartParams::LineMarkerFastCross: {
02794                                                 const QPen oldPen( painter->pen() );
02795                                                 painter->setPen( color );
02796                                                 painter->drawLine( QPoint(p.x() - xysize2, p.y()),
02797                                                                    QPoint(p.x() + xysize2, p.y()) );
02798                                                 painter->drawLine( QPoint(p.x(), p.y() - xysize2),
02799                                                                    QPoint(p.x(), p.y() + xysize2) );
02800                                                 QRect rect( QPoint( p.x() - 2, p.y() - 2 ),
02801                                                             QPoint( p.x() + 2, p.y() + 2 ) );
02802                                                 // Don't use rect for drawing after this!
02803                                                 rect.moveBy( deltaX, deltaY );
02804                                                 if ( regions ){
02805                                                     datReg =
02806                                                         new KDChartDataRegion(
02807                                                                 dataset, value,
02808                                                                 chart,   rect );
02809                                                     regions->append( datReg );
02810                                                 }
02811                                                 painter->setPen(   oldPen );
02812                                                 break;
02813                                               }
02814         case KDChartParams::LineMarkerCircle:
02815         default:                              {
02816                                                 const QBrush oldBrush( painter->brush() );
02817                                                 painter->setBrush( color );
02818                                                 painter->drawEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
02819                                                 if ( regions ) {
02820                                                     QPointArray points;
02821                                                     points.makeEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
02822                                                     // Don't use points for drawing after this!
02823                                                     points.translate( deltaX, deltaY );
02824                                                     if( points.size() > 0 ){
02825                                                         datReg = new KDChartDataRegion(
02826                                                                         dataset, value,
02827                                                                         chart,   points );
02828                                                         regions->append( datReg );
02829                                                     }
02830                                                 }
02831                                                 painter->setBrush( oldBrush );
02832                                               }
02833     }
02834     return datReg;
02835 }
02836 
02837 
02838 void KDChartPainter::drawExtraLinesAndMarkers(
02839         KDChartPropertySet& propSet,
02840         const QPen& defaultPen,
02841         const KDChartParams::LineMarkerStyle& defaultMarkerStyle,
02842         int myPointX,
02843         int myPointY,
02844         QPainter* painter,
02845         const KDChartAxisParams* abscissaPara,
02846         const KDChartAxisParams* ordinatePara,
02847         const double areaWidthP1000,
02848         const double areaHeightP1000,
02849         bool bDrawInFront )
02850 {
02851 
02852     // we can safely call the following functions and ignore their
02853     // return values since they will touch the parameters' values
02854     // if the propSet *contains* corresponding own values only.
02855     int  iDummy;
02856     uint extraLinesAlign = 0;
02857     if( propSet.hasOwnExtraLinesAlign( iDummy, extraLinesAlign )
02858         && ( extraLinesAlign
02859             & ( Qt::AlignLeft | Qt::AlignRight  | Qt::AlignHCenter |
02860                 Qt::AlignTop  | Qt::AlignBottom | Qt::AlignVCenter ) ) ){
02861         bool extraLinesInFront = false;
02862         propSet.hasOwnExtraLinesInFront( iDummy, extraLinesInFront );
02863         if( bDrawInFront == extraLinesInFront ){
02864             const double areaSizeP1000 = QMIN(areaWidthP1000, areaHeightP1000);
02865             int          extraLinesLength = -20;
02866             int          extraLinesWidth = defaultPen.width();
02867             QColor       extraLinesColor = defaultPen.color();
02868             Qt::PenStyle extraLinesStyle = defaultPen.style();
02869             uint         extraMarkersAlign = 0;
02870             propSet.hasOwnExtraLinesLength( iDummy, extraLinesLength );
02871             propSet.hasOwnExtraLinesWidth(  iDummy, extraLinesWidth  );
02872             propSet.hasOwnExtraLinesColor(  iDummy, extraLinesColor  );
02873             propSet.hasOwnExtraLinesStyle(  iDummy, extraLinesStyle  );
02874             const int horiLenP2 = (0 > extraLinesLength)
02875                                 ? static_cast<int>(areaWidthP1000  * extraLinesLength) / 2
02876                                 : extraLinesLength / 2;
02877             const int vertLenP2 = (0 > extraLinesLength)
02878                                 ? static_cast<int>(areaHeightP1000 * extraLinesLength) / 2
02879                                 : extraLinesLength / 2;
02880             // draw the extra line(s)
02881             QPoint pL( (Qt::AlignLeft == (extraLinesAlign & Qt::AlignLeft))
02882                     ? 0
02883                     : (Qt::AlignHCenter == (extraLinesAlign & Qt::AlignHCenter))
02884                         ? myPointX - horiLenP2
02885                         : myPointX,
02886                     myPointY );
02887             QPoint pR( (Qt::AlignRight == (extraLinesAlign & Qt::AlignRight))
02888                     ? abscissaPara->axisTrueAreaRect().width()
02889                     : (Qt::AlignHCenter == (extraLinesAlign & Qt::AlignHCenter))
02890                         ? myPointX + horiLenP2
02891                         : myPointX,
02892                     myPointY );
02893             QPoint pT( myPointX,
02894                     (Qt::AlignTop == (extraLinesAlign & Qt::AlignTop))
02895                     ? 0
02896                     : (Qt::AlignVCenter == (extraLinesAlign & Qt::AlignVCenter))
02897                         ? myPointY - vertLenP2
02898                         : myPointY );
02899             QPoint pB( myPointX,
02900                     (Qt::AlignBottom == (extraLinesAlign & Qt::AlignBottom))
02901                     ? ordinatePara->axisTrueAreaRect().height()
02902                     : (Qt::AlignVCenter == (extraLinesAlign & Qt::AlignVCenter))
02903                         ? myPointY + vertLenP2
02904                         : myPointY );
02905             const QPen extraPen( extraLinesColor,
02906                                 0 > extraLinesWidth
02907                                 ? static_cast < int > ( areaSizeP1000 * -extraLinesWidth )
02908                                 : extraLinesWidth,
02909                                 extraLinesStyle );
02910             const QPen oldPen( painter->pen() );
02911             painter->setPen( extraPen );
02912             if( extraLinesAlign & ( Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter ) )
02913                 painter->drawLine( pL, pR );
02914             if( extraLinesAlign & ( Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter ) )
02915                 painter->drawLine( pT, pB );
02916             painter->setPen( oldPen );
02917             // draw the marker(s) of the extra line(s)
02918             propSet.hasOwnExtraMarkersAlign( iDummy, extraMarkersAlign );
02919             if( extraMarkersAlign
02920                     & ( Qt::AlignLeft | Qt::AlignRight |
02921                         Qt::AlignTop  | Qt::AlignBottom ) ){
02922                 QSize  extraMarkersSize  = params()->lineMarkerSize();
02923                 QColor extraMarkersColor = extraLinesColor;
02924                 int    extraMarkersStyle = defaultMarkerStyle;
02925                 propSet.hasOwnExtraMarkersSize(  iDummy, extraMarkersSize );
02926                 propSet.hasOwnExtraMarkersColor( iDummy, extraMarkersColor );
02927                 propSet.hasOwnExtraMarkersStyle( iDummy, extraMarkersStyle );
02928                 // draw the extra marker(s)
02929                 int w = extraMarkersSize.width();
02930                 int h = extraMarkersSize.height();
02931                 if( w < 0 )
02932                     w = static_cast < int > (w * -areaSizeP1000);
02933                 if( h < 0 )
02934                     h = static_cast < int > (h * -areaSizeP1000);
02935                 if( extraMarkersAlign & Qt::AlignLeft )
02936                     drawMarker( painter,
02937                                 params(),
02938                                 _areaWidthP1000, _areaHeightP1000,
02939                                 _dataRect.x(), _dataRect.y(),
02940                                 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
02941                                 extraMarkersColor,
02942                                 pL,
02943                                 0, 0, 0, 0,
02944                                 &w, &h,
02945                                 Qt::AlignCenter );
02946                 if( extraMarkersAlign & Qt::AlignRight )
02947                     drawMarker( painter,
02948                                 params(),
02949                                 _areaWidthP1000, _areaHeightP1000,
02950                                 _dataRect.x(), _dataRect.y(),
02951                                 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
02952                                 extraMarkersColor,
02953                                 pR,
02954                                 0, 0, 0, 0,
02955                                 &w, &h,
02956                                 Qt::AlignCenter );
02957                 if( extraMarkersAlign & Qt::AlignTop )
02958                     drawMarker( painter,
02959                                 params(),
02960                                 _areaWidthP1000, _areaHeightP1000,
02961                                 _dataRect.x(), _dataRect.y(),
02962                                 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
02963                                 extraMarkersColor,
02964                                 pT,
02965                                 0, 0, 0, 0,
02966                                 &w, &h,
02967                                 Qt::AlignCenter );
02968                 if( extraMarkersAlign & Qt::AlignBottom )
02969                     drawMarker( painter,
02970                                 params(),
02971                                 _areaWidthP1000, _areaHeightP1000,
02972                                 _dataRect.x(), _dataRect.y(),
02973                                 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
02974                                 extraMarkersColor,
02975                                 pB,
02976                                 0, 0, 0, 0,
02977                                 &w, &h,
02978                                 Qt::AlignCenter );
02979             }
02980         }
02981     }
02982 }
02983 
02984 
KDE Home | KDE Accessibility Home | Description of Access Keys