00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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>
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
00106
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
00126
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& ,
00192 KDChartPainter* )
00193 {
00194
00195 qDebug( "Sorry, not implemented: KDChartPainter::registerPainter()" );
00196 }
00197
00198
00208 void KDChartPainter::unregisterPainter( const QString& )
00209 {
00210
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
00241 if( data->usedCols() == 0 && data->usedRows() == 0 )
00242 return ;
00243
00244 QRect drawRect;
00245
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
00259
00260
00261
00262
00263
00264
00265
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
00275
00276
00277
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
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
00316
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
00373
00374
00375
00376
00377
00378
00379
00380
00381
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
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
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
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
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
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
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
00598
00599
00600
00601
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
00632 }
00633 if(anchor.y() < -2500){
00634 anchor.setY(-2500);
00635
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
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
00663
00664
00665
00666
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
00688
00689 }
00690
00691 QFont* actFont = region->chart ? &font1 : &font0;
00692 if( oldFont != actFont ) {
00693 painter->setFont( *actFont );
00694 actFM = QFontMetrics( painter->fontMetrics() );
00695
00696
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
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
00727
00728
00729
00730
00731
00732
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,
00776 0,
00777 false,
00778 false,
00779 0,
00780 true );
00781 }else{
00782 painter->setPen( params()->dataValuesColor( region->chart ) );
00783
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 }
00793
00794 } else {
00795
00796
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();
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
00814
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
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
00853
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
00872
00873
00874
00875
00876
00877
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
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
00933 paintArea( painter,
00934 KDChartEnums::AreaCustomBoxesBASE + idx,
00935 regions,
00936 box->dataRow(),
00937 box->dataCol(),
00938 box->data3rd() );
00939
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
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
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
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
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
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 ,
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
01131
01132 ) {
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
01166
01167
01168
01169
01170
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;
01212 else
01213 angle += 1.0;
01214 if( angle >= 5760.0 )
01215 angle -= 5760.0;
01216 }
01217 }
01218
01228 void KDChartPainter::paintAxes( QPainter* , KDChartTableDataBase* )
01229 {
01230
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);
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
01267
01268
01269
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
01285 if( _legendTitle )
01286 xpos += _legendTitleWidth + em4;
01287
01288 int maxX = _legendTitleWidth + _legendEMSpace;
01289
01290
01291 int xposHori1 = xpos;
01292
01293
01294 int x2 = xpos + em2;
01295
01296
01297
01298
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
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);
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
01362 }
01363 return font;
01364 }
01365
01374 void KDChartPainter::paintLegend( QPainter* painter,
01375 KDChartTableDataBase* )
01376 {
01377 if ( params()->legendPosition() == KDChartParams::NoLegend )
01378 return ;
01379
01380 const bool bVertical = mustDrawVerticalLegend();
01381 painter->save();
01382
01383
01384 bool bFrameFound;
01385 params()->frameSettings( KDChartEnums::AreaLegend, bFrameFound );
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
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
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
01433 const int xposHori1 = _legendNewLinesStartAtLeft ? xposHori0 : xpos;
01434
01435
01436 int x2 = xpos + em2;
01437
01438
01439
01440
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
01449
01450 if( !_legendTexts[ dataset ].isEmpty() ){
01451 int txtWidth = txtMetrics.width( _legendTexts[ dataset ] ) + 1;
01452
01453
01454
01455
01456 int legHeight = static_cast <int>((txtMetrics.height() - (int)(txtMetrics.height() * 0.1))*0.85);
01457
01458
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
01482
01483
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 )) ,
01494 0, 0, 0, NULL,
01495 &legHeight , &legHeight ,
01496 bVertical ? Qt::AlignCenter : (Qt::AlignTop | Qt::AlignHCenter) );
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
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
01551 return false;
01552
01553 if( KDChartAxisParams::AxisPosLeft != basicPos &&
01554 KDChartAxisParams::AxisPosRight != basicPos )
01555
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
01565
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
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
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
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* )
01638 {
01639 const double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);
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
01654
01655
01656
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;
01685
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;
01720
01721
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
01730
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
01744
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);
01840
01841
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
01860
01861 }
01862 }
01863
01864 int nAxesLeftADD =0;
01865 int nAxesRightADD =0;
01866 int nAxesTopADD =0;
01867 int nAxesBottomADD=0;
01868
01869
01870
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
01880 uint iAxis;
01881 for ( iAxis = 0; iAxis < KDCHART_MAX_AXES; ++iAxis ) {
01882
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
01900
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
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
01996
01997
01998
01999
02000
02001 case KDChartAxisParams::AxisAreaModeFixedSize:
02002 {
02003 areaSize = areaMax ? QMIN( areaMin, areaMax ) : areaMin;
02004 }
02005 break;
02006 }
02007
02008
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
02027 nAxesBottomADD += areaSize;
02028 }
02029 else{
02030
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
02057
02058
02059
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
02067
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
02161
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
02176
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
02201
02202 _areaWidthP1000 = _logicalWidth / 1000.0;
02203 _areaHeightP1000 = _logicalHeight / 1000.0;
02204
02205 double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);
02206
02207
02208
02209
02210
02211
02212
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
02227
02228 if ( params()->legendPosition() != KDChartParams::NoLegend ) {
02229
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
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
02271 sizeY += _legendEMSpace - _legendLeading;
02272
02273 if ( hasLegendTitle )
02274 sizeY += legendTitleVertGap();
02275
02276
02277
02278 sizeX += ( _legendEMSpace * 4 );
02279
02280
02281
02282
02283
02284
02285 sizeX = QMAX( sizeX, _legendTitleWidth + _legendEMSpace*2 );
02286
02287
02288
02289
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
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
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
02428
02429 if( KDChartParams::Polar == params()->chartType() ) {
02430 _dataRect = _axesRect;
02431 } else {
02432
02433
02434 calculateAllAxesRects( painter, false, data );
02435
02436
02437
02438 double dblDummy;
02439 if( calculateAllAxesLabelTextsAndCalcValues(
02440 painter,
02441 data,
02442 _areaWidthP1000,
02443 _areaHeightP1000,
02444 dblDummy ) )
02445
02446
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
02465
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
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
02486 bool notfound = false;
02487 _numLegendTexts = numLegendFallbackTexts( data );
02488
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
02503
02504
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
02512 _numLegendTexts = numLegendFallbackTexts( data );
02513 }
02514 }
02515 }
02516 break;
02517 }
02518 default:
02519
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
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
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
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
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
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
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
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
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
02853
02854
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
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
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
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