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 painter->drawText( infosKDD.x , infosKDD.y ,
00784 infosKDD.width, infosKDD.height,
00785 Qt::AlignHCenter | Qt::AlignVCenter | Qt::SingleLine,
00786 region->text );
00787
00788 }
00789
00790
00791 }
00792
00793 } else {
00794
00795
00796 painter->rotate( -oldRotation );
00797 oldRotation = 0;
00798 QFontMetrics & fm = region->chart ? fm1 : fm0;
00799 int boundingRectWidth = fm.boundingRect( region->text ).width();
00800 int leftBearing = fm.leftBearing( region->text[ 0 ] );
00801 const QChar c = region->text.at( region->text.length() - 1 );
00802 int rightBearing = fm.rightBearing( c );
00803 int w = boundingRectWidth + leftBearing + rightBearing + 1;
00804 int h = fm.height();
00805 int dx = 0;
00806 int dy = 0;
00807 switch( align & ( Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter ) ) {
00808 case Qt::AlignRight:
00809 dx = -w+1;
00810 break;
00811 case Qt::AlignHCenter:
00812
00813
00814 dx = -( ( boundingRectWidth / 2 ) + leftBearing );
00815 break;
00816 }
00817 switch( align & ( Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter ) ) {
00818 case Qt::AlignBottom:
00819 dy = -h+1;
00820 break;
00821 case Qt::AlignVCenter:
00822 dy = -h / 2;
00823 break;
00824 }
00825
00826 QRegion thisRegion(
00827 QRect( anchor.x() + dx, anchor.y() + dy, w, h ) );
00828 if( allowOverlapping )
00829 drawThisOne = true;
00830 else {
00831 QRegion sectReg( thisRegion.intersect( lastRegionDone ) );
00832 drawThisOne = sectReg.isEmpty();
00833 }
00834 if( drawThisOne ) {
00835 lastRegionDone = lastRegionDone.unite( thisRegion );
00836 region->pTextRegion = new QRegion( thisRegion );
00837 #ifdef DEBUG_TEXT_PAINTING
00838
00839 QRect rect( region->pTextRegion->boundingRect() );
00840 painter->drawRect( rect );
00841 painter->setPen( Qt::red );
00842 rect.setLeft( rect.left() + leftBearing );
00843 rect.setTop( rect.top() + ( fm.height()-fm.boundingRect( region->text ).height() ) /2 );
00844 rect.setWidth( fm.boundingRect( region->text ).width() );
00845 rect.setHeight( fm.boundingRect( region->text ).height() );
00846 painter->drawRect( rect );
00847 painter->setPen( Qt::black );
00848 #endif
00849
00850
00851
00852
00853
00854
00855 QRect textRect( region->pTextRegion->boundingRect() );
00856 if( bIsAreaChart ){
00857 QBrush brush( params()->dataValuesBackground( region->chart ) );
00858 painter->setBrush( brush );
00859 painter->setPen( Qt::NoPen );
00860 QRect rect( textRect );
00861 rect.moveBy( -2, 0 );
00862 rect.setWidth( rect.width() + 4 );
00863 painter->drawRect( rect );
00864 }
00865 painter->setFont( region->chart ? font1 : font0 );
00866 if( params()->dataValuesAutoColor( region->chart ) ) {
00867 if( bIsAreaChart ){
00868 QColor color( params()->dataColor( region->row ) );
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878 painter->setPen( color.dark() );
00879 }else{
00880 if( zero )
00881 painter->setPen( Qt::black );
00882 else {
00883 QColor color( params()->dataColor(
00884 ( KDChartParams::Pie == params()->chartType()
00885 || KDChartParams::Ring == params()->chartType() )
00886 ? region->col
00887 : region->row ) );
00888 painter->setPen( QColor( static_cast < int > ( 255- color.red() ),
00889 static_cast < int > ( 255- color.green() ),
00890 static_cast < int > ( 255- color.blue() ) ) );
00891 }
00892 }
00893 }else{
00894 painter->setPen( params()->dataValuesColor( region->chart ) );
00895 }
00896 painter->drawText( textRect.left(), textRect.top(),
00897 textRect.width()+1, textRect.height()+1,
00898 Qt::AlignLeft | Qt::AlignTop, region->text );
00899 }
00900
00901
00902 }
00903 }
00904
00905 painter->restore();
00906
00907 }
00908 painter->restore();
00909 }
00910
00911 }
00912
00913
00917 void KDChartPainter::paintCustomBoxes( QPainter* painter,
00918 KDChartDataRegionList* regions )
00919 {
00920
00921 bool bGlobalFound;
00922 const KDChartParams::KDChartFrameSettings* globalFrameSettings
00923 = params()->frameSettings( KDChartEnums::AreasCustomBoxes, bGlobalFound );
00924
00925 uint idx;
00926 for( idx = 0; idx <= params()->maxCustomBoxIdx(); ++idx ) {
00927 const KDChartCustomBox * box = params()->customBox( idx );
00928 if( box ) {
00929
00930 paintArea( painter,
00931 KDChartEnums::AreaCustomBoxesBASE + idx,
00932 regions,
00933 box->dataRow(),
00934 box->dataCol(),
00935 box->data3rd() );
00936
00937 bool bIndividualFound;
00938 const KDChartParams::KDChartFrameSettings * individualFrameSettings
00939 = params()->frameSettings( KDChartEnums::AreaCustomBoxesBASE + idx,
00940 bIndividualFound );
00941 const KDChartParams::KDChartFrameSettings * settings
00942 = bIndividualFound ? individualFrameSettings
00943 : bGlobalFound ? globalFrameSettings : 0;
00944
00945 const QPoint anchor( calculateAnchor( *box, regions ) );
00946 box->paint( painter,
00947 anchor,
00948 _areaWidthP1000,
00949 _areaHeightP1000,
00950 settings ? settings->framePtr() : 0,
00951 trueFrameRect( box->trueRect( anchor, _areaWidthP1000, _areaHeightP1000 ),
00952 settings ) );
00953 }
00954 }
00955 }
00956
00957
00961 QPoint KDChartPainter::calculateAnchor( const KDChartCustomBox & box,
00962 KDChartDataRegionList* regions ) const
00963 {
00964 QPoint pt(0,0);
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981 if( !box.anchorBeingCalculated() ) {
00982
00983 box.setInternalFlagAnchorBeingCalculated( true );
00984
00985 bool allCustomBoxes;
00986 QRect rect( calculateAreaRect( allCustomBoxes,
00987 box.anchorArea(),
00988 box.dataRow(),
00989 box.dataCol(),
00990 box.data3rd(),
00991 regions ) );
00992 if( allCustomBoxes ) {
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008 }
01009 pt = KDChartEnums::positionFlagToPoint( rect, box.anchorPosition() );
01010
01011 box.setInternalFlagAnchorBeingCalculated( false );
01012 }
01013
01014 return pt;
01015 }
01016
01017
01022 QRect KDChartPainter::calculateAreaRect( bool & allCustomBoxes,
01023 uint area,
01024 uint dataRow,
01025 uint dataCol,
01026 uint ,
01027 KDChartDataRegionList* regions ) const
01028 {
01029 QRect rect(0,0, 0,0);
01030 allCustomBoxes = false;
01031 uint pos;
01032 switch( area ) {
01033 case KDChartEnums::AreaData:
01034 rect = _dataRect;
01035 break;
01036 case KDChartEnums::AreaAxes:
01037 break;
01038 case KDChartEnums::AreaLegend:
01039 rect = _legendRect;
01040 break;
01041 case KDChartEnums::AreaDataAxes:
01042 rect = _axesRect;
01043 break;
01044 case KDChartEnums::AreaDataAxesLegend:
01045 rect = _axesRect;
01046 if( _legendRect.isValid() ) {
01047 if( rect.isValid() )
01048 rect = rect.unite( _legendRect );
01049 else
01050 rect = _legendRect;
01051 }
01052 break;
01053 case KDChartEnums::AreaHeaders: {
01054 bool bStart = true;
01055 for( pos = KDChartParams::HdFtPosHeadersSTART;
01056 KDChartParams::HdFtPosHeadersEND >= pos;
01057 ++pos ) {
01058 const QRect& r = params()->headerFooterRect( pos );
01059 if( r.isValid() ) {
01060 if( bStart )
01061 rect = r;
01062 else
01063 rect = rect.unite( r );
01064 bStart = false;
01065 }
01066 }
01067 }
01068 break;
01069 case KDChartEnums::AreaFooters: {
01070 bool bStart = true;
01071 for( pos = KDChartParams::HdFtPosFootersSTART;
01072 KDChartParams::HdFtPosFootersEND >= pos;
01073 ++pos ) {
01074 const QRect& r = params()->headerFooterRect( pos );
01075 if( r.isValid() ) {
01076 if( bStart )
01077 rect = r;
01078 else
01079 rect = rect.unite( r );
01080 bStart = false;
01081 }
01082 }
01083 }
01084 break;
01085 case KDChartEnums::AreaDataAxesLegendHeadersFooters: {
01086 rect = _axesRect;
01087 bool bStart = !rect.isValid();
01088 if( _legendRect.isValid() ) {
01089 if( bStart )
01090 rect = _legendRect;
01091 else
01092 rect = rect.unite( _legendRect );
01093 bStart = false;
01094 }
01095 for( pos = KDChartParams::HdFtPosSTART;
01096 KDChartParams::HdFtPosEND >= pos;
01097 ++pos ) {
01098 const QRect& r = params()->headerFooterRect( pos );
01099 if( r.isValid() ) {
01100 if( bStart )
01101 rect = r;
01102 else
01103 rect = rect.unite( r );
01104 bStart = false;
01105 }
01106 }
01107 }
01108 break;
01109 case KDChartEnums::AreaOutermost:
01110 rect = _outermostRect;
01111 break;
01112 case KDChartEnums::AreaInnermost:
01113 rect = _innermostRect;
01114 break;
01115 case KDChartEnums::AreasCustomBoxes:
01116 allCustomBoxes = true;
01117 break;
01118 case KDChartEnums::AreaChartDataRegion:
01119 if( regions ) {
01120 KDChartDataRegion* current;
01121 for ( current = regions->first();
01122 current != 0;
01123 current = regions->next() ) {
01124 if ( current->row == dataRow
01125 && current->col == dataCol
01126
01127
01128
01129 ) {
01130 rect = current->rect();
01131 break;
01132 }
01133 }
01134 }
01135 break;
01136 case KDChartEnums::AreaUNKNOWN:
01137 break;
01138
01139 default: {
01140 uint maskBASE = KDChartEnums::AreaBASEMask & area;
01141 pos = area - maskBASE;
01142 if ( KDChartEnums::AreaAxisBASE == maskBASE ) {
01143 rect = params()->axisParams( pos ).axisTrueAreaRect();
01144 } else if ( KDChartEnums::AreaHdFtBASE == maskBASE ) {
01145 rect = params()->headerFooterRect( pos );
01146 } else if ( KDChartEnums::AreaCustomBoxesBASE == maskBASE ) {
01147 const KDChartCustomBox * box = params()->customBox( pos );
01148 if( box ) {
01149 rect = box->trueRect( calculateAnchor( *box, regions ),
01150 _areaWidthP1000,
01151 _areaHeightP1000 );
01152 }
01153 }
01154 }
01155 }
01156 return rect;
01157 }
01158
01159
01160 QPoint KDChartPainter::pointOnCircle( const QRect& rect, double angle )
01161 {
01162
01163
01164
01165
01166
01167
01168
01169 double normAngle = angle / 16.0;
01170 double normAngleRad = DEGTORAD( normAngle );
01171 double cosAngle = cos( normAngleRad );
01172 double sinAngle = -sin( normAngleRad );
01173 double posX = floor( cosAngle * ( double ) rect.width() / 2.0 + 0.5 );
01174 double posY = floor( sinAngle * ( double ) rect.height() / 2.0 + 0.5 );
01175 return QPoint( static_cast<int>(posX) + rect.center().x(),
01176 static_cast<int>(posY) + rect.center().y() );
01177
01178 }
01179
01180 void KDChartPainter::makeArc( QPointArray& points,
01181 const QRect& rect,
01182 double startAngle, double angles )
01183 {
01184 double endAngle = startAngle + angles;
01185 int rCX = rect.center().x();
01186 int rCY = rect.center().y();
01187 double rWid2 = ( double ) rect.width() / 2.0;
01188 double rHig2 = ( double ) rect.height() / 2.0;
01189 int numSteps = static_cast<int>(angles);
01190 if( floor( angles ) < angles )
01191 ++numSteps;
01192 points.resize( numSteps );
01193 double angle = startAngle;
01194 if( angle < 0.0 )
01195 angle += 5760.0;
01196 else if( angle >= 5760.0 )
01197 angle -= 5760.0;
01198 for(int i = 0; i < numSteps; ++i){
01199 double normAngle = angle / 16.0;
01200 double normAngleRad = DEGTORAD( normAngle );
01201 double cosAngle = cos( normAngleRad );
01202 double sinAngle = -sin( normAngleRad );
01203 double posX = floor( cosAngle * rWid2 + 0.5 );
01204 double posY = floor( sinAngle * rHig2 + 0.5 );
01205 points[i] = QPoint( ( int ) posX + rCX,
01206 ( int ) posY + rCY );
01207 if( i+1 >= numSteps-1 )
01208 angle = endAngle;
01209 else
01210 angle += 1.0;
01211 if( angle >= 5760.0 )
01212 angle -= 5760.0;
01213 }
01214 }
01215
01225 void KDChartPainter::paintAxes( QPainter* , KDChartTableDataBase* )
01226 {
01227
01228 }
01229
01230
01231 int KDChartPainter::legendTitleVertGap() const
01232 {
01233 return _legendTitleHeight
01234 + static_cast < int > ( _legendTitleMetricsHeight * 0.20 );
01235 }
01236
01237
01238 QFont KDChartPainter::trueLegendFont() const
01239 {
01240 QFont trueFont = params()->legendFont();
01241 if ( params()->legendFontUseRelSize() ) {
01242 const double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);
01243 trueFont.setPixelSize(
01244 static_cast < int > ( params()->legendFontRelSize() * averageValueP1000 ) );
01245 }
01246 return trueFont;
01247 }
01248
01249
01255 void KDChartPainter::calculateHorizontalLegendSize( QPainter* painter,
01256 QSize& size,
01257 bool& legendNewLinesStartAtLeft ) const
01258 {
01259
01260 legendNewLinesStartAtLeft = false;
01261 QRect legendRect( _legendRect );
01262
01263
01264
01265
01266
01267
01268
01269 legendRect.setLeft( _innermostRect.left() );
01270
01271 const int em2 = 2 * _legendEMSpace;
01272 const int em4 = 4 * _legendEMSpace;
01273 const int emDiv2 = static_cast < int > ( _legendEMSpace / 2.0 );
01274
01275 const int xposHori0 = legendRect.left() + _legendEMSpace;
01276
01277 int xpos = xposHori0;
01278
01279 int ypos = legendRect.top() + emDiv2;
01280
01281
01282 if( _legendTitle )
01283 xpos += _legendTitleWidth + em4;
01284
01285 int maxX = _legendTitleWidth + _legendEMSpace;
01286
01287
01288 int xposHori1 = xpos;
01289
01290
01291 int x2 = xpos + em2;
01292
01293
01294
01295
01296 const int rightEdge = _innermostRect.right()-_legendEMSpace;
01297 bool bFirstLFWithTitle = _legendTitle;
01298 painter->setFont( trueLegendFont() );
01299 QFontMetrics txtMetrics( painter->fontMetrics() );
01300 int dataset;
01301 for ( dataset = 0; dataset < _numLegendTexts; ++dataset ) {
01302
01303
01304
01305 if( !_legendTexts[ dataset ].isEmpty() ){
01306 int txtWidth = txtMetrics.width( _legendTexts[ dataset ] ) + 1;
01307 if( x2 + txtWidth > rightEdge ){
01308 if( xposHori1 + em2 + txtWidth > rightEdge){
01309 xposHori1 = xposHori0;
01310 legendNewLinesStartAtLeft = true;
01311 }
01312 xpos = xposHori1;
01313 x2 = xpos + em2;
01314 ypos += bFirstLFWithTitle ? legendTitleVertGap() : _legendSpacing;
01315 bFirstLFWithTitle = false;
01316 }
01317 maxX = QMAX(maxX, x2+txtWidth+_legendEMSpace);
01318
01319 xpos += txtWidth + em4;
01320 x2 += txtWidth + em4;
01321 }
01322 }
01323 if( bFirstLFWithTitle )
01324 ypos += _legendTitleHeight;
01325 else
01326 ypos += txtMetrics.height();
01327
01328 size.setWidth( maxX - legendRect.left() );
01329 size.setHeight( ypos + emDiv2 - _legendRect.top() );
01330 }
01331
01332
01333 bool KDChartPainter::mustDrawVerticalLegend() const
01334 {
01335 return
01336 params()->legendOrientation() == Qt::Vertical ||
01337 params()->legendPosition() == KDChartParams::LegendLeft ||
01338 params()->legendPosition() == KDChartParams::LegendRight ||
01339 params()->legendPosition() == KDChartParams::LegendTopLeft ||
01340 params()->legendPosition() == KDChartParams::LegendTopLeftLeft ||
01341 params()->legendPosition() == KDChartParams::LegendTopRight ||
01342 params()->legendPosition() == KDChartParams::LegendTopRightRight ||
01343 params()->legendPosition() == KDChartParams::LegendBottomLeft ||
01344 params()->legendPosition() == KDChartParams::LegendBottomLeftLeft ||
01345 params()->legendPosition() == KDChartParams::LegendBottomRight ||
01346 params()->legendPosition() == KDChartParams::LegendBottomRightRight;
01347 }
01348
01349
01358 void KDChartPainter::paintLegend( QPainter* painter,
01359 KDChartTableDataBase* )
01360 {
01361 if ( params()->legendPosition() == KDChartParams::NoLegend )
01362 return ;
01363
01364 const bool bVertical = mustDrawVerticalLegend();
01365 painter->save();
01366
01367
01368 bool bFrameFound;
01369 params()->frameSettings( KDChartEnums::AreaLegend, bFrameFound );
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384 const int em2 = 2 * _legendEMSpace;
01385 const int em4 = 4 * _legendEMSpace;
01386 const int emDiv2 = static_cast < int > ( _legendEMSpace / 2.0 );
01387
01388 const int xposHori0 = _legendRect.left() + _legendEMSpace;
01389
01390 int xpos = xposHori0;
01391
01392 int ypos = _legendRect.top() + emDiv2;
01393
01394
01395
01396
01397
01398 if( _legendTitle ) {
01399 painter->setFont( params()->legendTitleFont() );
01400 _legendTitle->draw( painter,
01401 xpos,
01402 ypos,
01403 QRegion( xpos,
01404 ypos ,
01405 _legendTitleWidth,
01406 _legendTitleHeight ),
01407 params()->legendTitleTextColor() );
01408 if( bVertical )
01409 ypos += legendTitleVertGap();
01410
01411 else
01412 xpos += _legendTitleWidth + em4;
01413
01414 }
01415
01416
01417 const int xposHori1 = _legendNewLinesStartAtLeft ? xposHori0 : xpos;
01418
01419
01420 int x2 = xpos + em2;
01421
01422
01423
01424
01425 const int rightEdge = _legendRect.right();
01426 bool bFirstLF = true;
01427 painter->setFont( trueLegendFont() );
01428 QFontMetrics txtMetrics( painter->fontMetrics() );
01429 int dataset;
01430 for ( dataset = 0; dataset < _numLegendTexts; ++dataset ) {
01431
01432
01433
01434 if( !_legendTexts[ dataset ].isEmpty() ){
01435 int txtWidth = txtMetrics.width( _legendTexts[ dataset ] ) + 1;
01436
01437
01438
01439
01440 int legHeight = static_cast <int>((txtMetrics.height() - (int)(txtMetrics.height() * 0.1))*0.85);
01441
01442
01443
01444 if( !bVertical && x2 + txtWidth >= rightEdge ){
01445 _legendRect.setHeight( _legendRect.height() + _legendSpacing );
01446 xpos = xposHori1;
01447 x2 = xpos + em2;
01448 ypos += bFirstLF ? legendTitleVertGap() : _legendSpacing;
01449 bFirstLF = false;
01450 }
01451 painter->setBrush( QBrush( params()->dataColor( dataset ),
01452 QBrush::SolidPattern ) );
01453
01454 if( params()->legendShowLines() ){
01455 painter->setPen( QPen( params()->dataColor( dataset ), 2,
01456 params()->lineStyle( dataset ) ) );
01457 painter->drawLine(
01458 xpos - emDiv2,
01459 ypos + emDiv2 + 1,
01460 xpos + static_cast < int > ( _legendEMSpace * 1.5 ),
01461 ypos + emDiv2 + 1);
01462 }
01463
01464
01465
01466
01467
01468 drawMarker( painter,
01469 params(),
01470 _areaWidthP1000, _areaHeightP1000,
01471 _dataRect.x(), _dataRect.y(),
01472 params()->lineMarker()
01473 ? params()->lineMarkerStyle( dataset )
01474 : KDChartParams::LineMarkerSquare,
01475 params()->dataColor(dataset),
01476 QPoint(xpos + emDiv2,
01477 bVertical? ypos + emDiv2: !bFirstLF ?ypos + _legendSpacing:_legendRect.center().y() - (legHeight / 2 )) ,
01478 0, 0, 0, NULL,
01479 &legHeight , &legHeight ,
01480 bVertical ? Qt::AlignCenter : (Qt::AlignTop | Qt::AlignHCenter) );
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493 painter->setPen( params()->legendTextColor() );
01494 painter->drawText( x2,
01495 bVertical ? ypos : !bFirstLF ? ypos + _legendSpacing : _legendRect.center().y() - (legHeight / 2 ),
01496 txtWidth,
01497 legHeight,
01498 Qt::AlignLeft | Qt::AlignVCenter,
01499 _legendTexts[ dataset ] );
01500
01501 if( bVertical )
01502 ypos += _legendSpacing;
01503 else {
01504 xpos += txtWidth + em4;
01505 x2 += txtWidth + em4;
01506 }
01507 }
01508 }
01509
01510 painter->setPen( QPen( Qt::black, 1 ) );
01511 painter->setBrush( QBrush::NoBrush );
01512 if( !bFrameFound )
01513 painter->drawRect( _legendRect );
01514
01515
01516 painter->restore();
01517 }
01518
01519
01520 void adjustFromTo(int& from, int& to)
01521 {
01522 if( abs(from) > abs(to) ){
01523 int n = from;
01524 from = to;
01525 to = n;
01526 }
01527 }
01528
01529
01530 bool KDChartPainter::axesOverlapping( int axis1, int axis2 )
01531 {
01532 KDChartAxisParams::AxisPos basicPos = KDChartAxisParams::basicAxisPos( axis1 );
01533 if( basicPos != KDChartAxisParams::basicAxisPos( axis2 ) )
01534
01535 return false;
01536
01537 if( KDChartAxisParams::AxisPosLeft != basicPos &&
01538 KDChartAxisParams::AxisPosRight != basicPos )
01539
01540 return false;
01541
01542 int f1 = params()->axisParams( axis1 ).axisUseAvailableSpaceFrom();
01543 int t1 = params()->axisParams( axis1 ).axisUseAvailableSpaceTo();
01544 int f2 = params()->axisParams( axis2 ).axisUseAvailableSpaceFrom();
01545 int t2 = params()->axisParams( axis2 ).axisUseAvailableSpaceTo();
01546 adjustFromTo(f1,t1);
01547 adjustFromTo(f2,t2);
01548
01549
01550 const double guessedAxisHeightP1000 = _areaHeightP1000 * 80.0 / 100.0;
01551 if(f1 < 0) f1 = static_cast < int > ( f1 * -guessedAxisHeightP1000 );
01552 if(t1 < 0) t1 = static_cast < int > ( t1 * -guessedAxisHeightP1000 );
01553 if(f2 < 0) f2 = static_cast < int > ( f2 * -guessedAxisHeightP1000 );
01554 if(t2 < 0) t2 = static_cast < int > ( t2 * -guessedAxisHeightP1000 );
01555 const bool res = (f1 >= f2 && f1 < t2) || (f2 >= f1 && f2 < t1);
01556 return res;
01557 }
01558
01559
01560 void internSetAxisArea( KDChartParams* params, int axis,
01561 int x0, int y0, int w0, int h0 )
01562 {
01563
01564 int nFrom = QMAX(-1000, params->axisParams( axis ).axisUseAvailableSpaceFrom());
01565 int nTo = QMAX(-1000, params->axisParams( axis ).axisUseAvailableSpaceTo());
01566 adjustFromTo(nFrom,nTo);
01567
01568 KDChartAxisParams::AxisPos basicPos = KDChartAxisParams::basicAxisPos( axis );
01569 int x, y, w, h;
01570 if( KDChartAxisParams::AxisPosBottom == basicPos ||
01571 KDChartAxisParams::AxisPosTop == basicPos ){
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586 x = x0;
01587 y = y0;
01588 w = w0;
01589 h = h0;
01590
01591 }else{
01592 x = x0;
01593 if( nTo < 0 )
01594 y = y0 + h0 - h0*nTo/-1000;
01595 else
01596 y = y0 + h0 - nTo;
01597 w = w0;
01598 if( nFrom < 0 )
01599 h = y0 + h0 - h0*nFrom/-1000 - y;
01600 else
01601 h = y0 + h0 - nFrom - y;
01602 }
01603
01604 params->setAxisArea( axis,
01605 QRect( x,
01606 y,
01607 w,
01608 h ) );
01609 }
01610
01611
01620 void KDChartPainter::paintHeaderFooter( QPainter* painter,
01621 KDChartTableDataBase* )
01622 {
01623 const double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);
01624
01625 painter->save();
01626
01627 for( int iHdFt = KDChartParams::HdFtPosSTART;
01628 iHdFt <= KDChartParams::HdFtPosEND; ++iHdFt ){
01629 QString txt( params()->headerFooterText( iHdFt ) );
01630 if ( !txt.isEmpty() ) {
01631 QFont actFont( params()->headerFooterFont( iHdFt ) );
01632 if ( params()->headerFooterFontUseRelSize( iHdFt ) )
01633 actFont.setPixelSize( static_cast < int > (
01634 params()->headerFooterFontRelSize( iHdFt ) * averageValueP1000 ) );
01635 painter->setPen( params()->headerFooterColor( iHdFt ) );
01636 painter->setFont( actFont );
01637
01638
01639
01640
01641
01642 QRect rect( params()->headerFooterRect( iHdFt ) );
01643 int dXY = iHdFt < KDChartParams::HdFtPosFootersSTART
01644 ? _hdLeading/3
01645 : _ftLeading/3;
01646 rect.moveBy(dXY, dXY);
01647 rect.setWidth( rect.width() -2*dXY +1 );
01648 rect.setHeight( rect.height()-2*dXY +1 );
01649 painter->drawText( rect,
01650 Qt::AlignLeft | Qt::AlignTop | Qt::SingleLine,
01651 txt );
01652 }
01653 }
01654 painter->restore();
01655 }
01656
01657
01658 int KDChartPainter::calculateHdFtRects(
01659 QPainter* painter,
01660 double averageValueP1000,
01661 int xposLeft,
01662 int xposRight,
01663 bool bHeader,
01664 int& yposTop,
01665 int& yposBottom )
01666 {
01667 int& leading = (bHeader ? _hdLeading : _ftLeading);
01668 leading = 0;
01669
01670
01671 const int rangesCnt = 3;
01672 const int ranges[ rangesCnt ]
01673 = { bHeader ? KDChartParams::HdFtPosHeaders0START : KDChartParams::HdFtPosFooters0START,
01674 bHeader ? KDChartParams::HdFtPosHeaders1START : KDChartParams::HdFtPosFooters1START,
01675 bHeader ? KDChartParams::HdFtPosHeaders2START : KDChartParams::HdFtPosFooters2START };
01676 const int rangeSize = 3;
01677 QFontMetrics* metrics[rangesCnt * rangeSize];
01678
01679 int i;
01680 for( i = 0; i < rangesCnt*rangeSize; ++i )
01681 metrics[ i ] = 0;
01682
01683 int iRange;
01684 int iHdFt;
01685 for( iRange = 0; iRange < rangesCnt; ++iRange ){
01686 for( i = 0; i < rangeSize; ++i ){
01687 iHdFt = ranges[iRange] + i;
01688 QString txt( params()->headerFooterText( iHdFt ) );
01689 if ( !txt.isEmpty() ) {
01690 QFont actFont( params()->headerFooterFont( iHdFt ) );
01691 if ( params()->headerFooterFontUseRelSize( iHdFt ) ) {
01692 actFont.setPixelSize( static_cast < int > (
01693 params()->headerFooterFontRelSize( iHdFt ) * averageValueP1000 ) );
01694 }
01695 painter->setFont( actFont );
01696 metrics[ iRange*rangeSize + i ] = new QFontMetrics( painter->fontMetrics() );
01697 leading = QMAX( leading, metrics[ iRange*rangeSize + i ]->lineSpacing() / 2 );
01698 }
01699 }
01700 }
01701
01702 if( bHeader )
01703 ++yposTop;
01704
01705
01706
01707 int leading23 = leading*2/3 +1;
01708
01709 for( iRange =
01710 bHeader ? 0 : rangesCnt-1;
01711 bHeader ? iRange < rangesCnt : iRange >= 0;
01712 bHeader ? ++iRange : --iRange ){
01713
01714
01715 int ascents[rangeSize];
01716 int heights[rangeSize];
01717 int widths[ rangeSize];
01718 int maxAscent = 0;
01719 int maxHeight = 0;
01720 for( i = 0; i < rangeSize; ++i ){
01721 iHdFt = ranges[iRange] + i;
01722 if ( metrics[ iRange*rangeSize + i ] ) {
01723 QFontMetrics& m = *metrics[ iRange*rangeSize + i ];
01724 ascents[i] = m.ascent();
01725 heights[i] = m.height() + leading23;
01726
01727
01728
01729 widths[ i] = m.boundingRect( params()->headerFooterText( iHdFt )+" " ).width() + leading23;
01730
01731 maxAscent = QMAX( maxAscent, ascents[i] );
01732 maxHeight = QMAX( maxHeight, heights[i] );
01733 }else{
01734 heights[i] = 0;
01735 }
01736 }
01737
01738 if( !bHeader )
01739 yposBottom -= maxHeight;
01740
01741 for( i = 0; i < rangeSize; ++i ){
01742 if( heights[i] ){
01743 iHdFt = ranges[iRange] + i;
01744 int x1;
01745 switch( i ){
01746 case 1: x1 = xposLeft+1;
01747 break;
01748 case 2: x1 = xposRight-widths[i]-1;
01749 break;
01750 default: x1 = xposLeft + (xposRight-xposLeft-widths[i]) / 2;
01751 }
01752 ((KDChartParams*)params())->__internalStoreHdFtRect( iHdFt,
01753 QRect( x1,
01754 bHeader
01755 ? yposTop + maxAscent - ascents[i]
01756 : yposBottom + maxAscent - ascents[i],
01757 widths[ i],
01758 heights[i] - 1 ) );
01759 }
01760 }
01761 if( bHeader )
01762 yposTop += leading + maxHeight;
01763 else
01764 yposBottom -= leading;
01765 }
01766 for( i = 0; i < rangesCnt*rangeSize; ++i )
01767 if( metrics[ i ] )
01768 delete metrics[ i ];
01769 return leading;
01770 }
01771
01772
01773
01774 void KDChartPainter::findChartDatasets( KDChartTableDataBase* data,
01775 bool paint2nd,
01776 uint chart,
01777 uint& chartDatasetStart,
01778 uint& chartDatasetEnd )
01779 {
01780 if( params()->neverUsedSetChartSourceMode()
01781 || !params()->findDatasets( KDChartParams::DataEntry,
01782 KDChartParams::ExtraLinesAnchor,
01783 chartDatasetStart,
01784 chartDatasetEnd,
01785 chart ) ) {
01786 uint maxRow, maxRowMinus1;
01787 switch ( data->usedRows() ) {
01788 case 0:
01789 return ;
01790 case 1:
01791 maxRow = 0;
01792 maxRowMinus1 = 0;
01793 break;
01794 default:
01795 maxRow = data->usedRows() - 1;
01796 maxRowMinus1 = maxRow;
01797 }
01798 chartDatasetStart = paint2nd ? maxRow : 0;
01799 chartDatasetEnd = paint2nd
01800 ? maxRow
01801 : ( ( KDChartParams::NoType == params()->additionalChartType() )
01802 ? maxRow
01803 : maxRowMinus1 );
01804
01805 }
01806 }
01807
01808
01809 void KDChartPainter::calculateAllAxesRects(
01810 QPainter* painter,
01811 bool finalPrecision,
01812 KDChartTableDataBase* data
01813 )
01814 {
01815 const bool bIsAreaChart = KDChartParams::Area == params()->chartType();
01816 const bool bMultiRows = KDChartParams::Bar == params()->chartType() &&
01817 KDChartParams::BarMultiRows == params()->barChartSubType();
01818
01819 const int trueWidth = _outermostRect.width();
01820 const int trueHeight = _outermostRect.height();
01821 const double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);
01822
01823
01824 int nAxesLeft0 = _axesRect.left() - _outermostRect.left();
01825 int nAxesRight0 = _outermostRect.right() - _axesRect.right();
01826 int nAxesTop0 = _axesRect.top() - _outermostRect.top();
01827 int nAxesBottom0 = _outermostRect.bottom() - _axesRect.bottom();
01828 if( bMultiRows ){
01829 uint chartDatasetStart, chartDatasetEnd;
01830 findChartDatasets( data, false, 0, chartDatasetStart, chartDatasetEnd );
01831 const int datasets = chartDatasetEnd - chartDatasetStart + 1;
01832 int numValues = 0;
01833 if ( params()->numValues() != -1 )
01834 numValues = params()->numValues();
01835 else
01836 numValues = data->usedCols();
01837 if( datasets ){
01838 const int additionalGapWidth = static_cast < int > ( 1.0 * _axesRect.width() / (9.75*numValues + 4.0*datasets) * 4.0*datasets );
01839 nAxesRight0 += additionalGapWidth;
01840 nAxesTop0 += static_cast < int > ( additionalGapWidth * 0.52 );
01841
01842
01843 }
01844 }
01845
01846 int nAxesLeftADD =0;
01847 int nAxesRightADD =0;
01848 int nAxesTopADD =0;
01849 int nAxesBottomADD=0;
01850
01851
01852
01853 bool bAddLeft = axesOverlapping( KDChartAxisParams::AxisPosLeft,
01854 KDChartAxisParams::AxisPosLeft2 );
01855 bool bAddRight = axesOverlapping( KDChartAxisParams::AxisPosRight,
01856 KDChartAxisParams::AxisPosRight2 );
01857 bool bAddTop = axesOverlapping( KDChartAxisParams::AxisPosTop,
01858 KDChartAxisParams::AxisPosTop2 );
01859 bool bAddBottom = axesOverlapping( KDChartAxisParams::AxisPosBottom,
01860 KDChartAxisParams::AxisPosBottom2 );
01861
01862 uint iAxis;
01863 for ( iAxis = 0; iAxis < KDCHART_MAX_AXES; ++iAxis ) {
01864
01865 const KDChartAxisParams& para = params()->axisParams( iAxis );
01866 int areaSize = 0;
01867
01868 if ( para.axisVisible()
01869 && KDChartAxisParams::AxisTypeUnknown != para.axisType() ) {
01870
01871 const KDChartAxisParams::AxisPos
01872 basicPos( KDChartAxisParams::basicAxisPos( iAxis ) );
01873
01874 int areaMin = para.axisAreaMin();
01875 int areaMax = para.axisAreaMax();
01876 if ( 0 > areaMin )
01877 areaMin = static_cast < int > ( -1.0 * averageValueP1000 * areaMin );
01878 if ( 0 > areaMax )
01879 areaMax = static_cast < int > ( -1.0 * averageValueP1000 * areaMax );
01880
01881
01882
01883 switch ( basicPos ) {
01884 case KDChartAxisParams::AxisPosBottom:
01885 case KDChartAxisParams::AxisPosTop:
01886 if ( para.axisLabelsVisible() ) {
01887 int fntHeight;
01888 if ( para.axisLabelsFontUseRelSize() )
01889 fntHeight = static_cast < int > (
01890 para.axisLabelsFontRelSize()
01891 * averageValueP1000 );
01892 else {
01893 painter->setFont( para.axisLabelsFont() );
01894 QFontMetrics metrics( painter->fontMetrics() );
01895 fntHeight = metrics.height();
01896 }
01897
01898 uint dataDataset, dataDataset2;
01899 if( !params()->findDataset( KDChartParams::DataEntry,
01900 dataDataset,
01901 dataDataset2,
01902 KDCHART_ALL_CHARTS ) ) {
01903 qDebug( "IMPLEMENTATION ERROR: findDataset( DataEntry, ... ) should *always* return true. (a)" );
01904 dataDataset = KDCHART_ALL_DATASETS;
01905 }
01906 QVariant::Type valType = QVariant::Invalid;
01907 const bool dataCellsHaveSeveralCoordinates =
01908 (KDCHART_ALL_DATASETS == dataDataset)
01909 ? data->cellsHaveSeveralCoordinates( &valType )
01910 : data->cellsHaveSeveralCoordinates( dataDataset, dataDataset2, &valType );
01911 QString format( para.axisLabelsDateTimeFormat() );
01912 if( dataCellsHaveSeveralCoordinates
01913 && QVariant::DateTime == valType ){
01914 if( KDCHART_AXIS_LABELS_AUTO_DATETIME_FORMAT == format )
01915 areaMin = QMAX( areaMin, static_cast < int > ( fntHeight * 6.75 ) );
01916 else
01917 areaMin = QMAX( areaMin, fntHeight * ( 3 + format.contains("\n") ) );
01918 }
01919 else
01920 areaMin = QMAX( areaMin, fntHeight * 3 );
01921 }
01922 break;
01923 case KDChartAxisParams::AxisPosLeft:
01924 case KDChartAxisParams::AxisPosRight:
01925 default:
01926 break;
01927 }
01928
01929
01930 switch ( para.axisAreaMode() ) {
01931 case KDChartAxisParams::AxisAreaModeAutoSize:
01932 {
01933 areaSize = areaMin;
01934 switch ( basicPos ) {
01935 case KDChartAxisParams::AxisPosBottom:
01936 case KDChartAxisParams::AxisPosTop:
01937 break;
01938 case KDChartAxisParams::AxisPosLeft:
01939 case KDChartAxisParams::AxisPosRight:
01940 if( finalPrecision ){
01941 internal__KDChart__CalcValues& cv = calcVal[iAxis];
01942 const int nUsableAxisWidth = static_cast < int > (cv.pTextsW);
01943 const KDChartAxisParams & para = params()->axisParams( iAxis );
01944 QFont axisLabelsFont( para.axisLabelsFont() );
01945 if ( para.axisLabelsFontUseRelSize() ) {
01946 axisLabelsFont.setPixelSize( static_cast < int > ( cv.nTxtHeight ) );
01947 }
01948 painter->setFont( para.axisLabelsFont() );
01949 QFontMetrics axisLabelsFontMetrics( painter->fontMetrics() );
01950 const int lenEM( axisLabelsFontMetrics.boundingRect("M").width() );
01951 const QStringList* labelTexts = para.axisLabelTexts();
01952 uint nLabels = ( 0 != labelTexts )
01953 ? labelTexts->count()
01954 : 0;
01955 int maxLabelsWidth = 0;
01956 for ( uint i = 0; i < nLabels; ++i )
01957 maxLabelsWidth =
01958 QMAX( maxLabelsWidth,
01959 axisLabelsFontMetrics.boundingRect(*labelTexts->at(i)).width() );
01960 if( nUsableAxisWidth < maxLabelsWidth )
01961 areaSize = maxLabelsWidth
01962 + (para.axisTrueAreaRect().width() - nUsableAxisWidth)
01963 + lenEM;
01964 }
01965 break;
01966 default:
01967 break;
01968 }
01969 }
01970 break;
01971 case KDChartAxisParams::AxisAreaModeMinMaxSize:
01972 {
01973 qDebug( "Sorry, not implemented: AxisAreaModeMinMaxSize" );
01974 }
01975
01976
01977
01978
01979
01980
01981
01982
01983
01984 case KDChartAxisParams::AxisAreaModeFixedSize:
01985 {
01986 areaSize = areaMax ? QMIN( areaMin, areaMax ) : areaMin;
01987 }
01988 break;
01989 }
01990
01991 switch ( basicPos ) {
01992 case KDChartAxisParams::AxisPosBottom:
01993 if( bAddBottom )
01994 nAxesBottomADD += areaSize;
01995 else
01996 nAxesBottomADD = QMAX( nAxesBottomADD, areaSize );
01997 break;
01998 case KDChartAxisParams::AxisPosLeft:
01999 if( bAddLeft )
02000 nAxesLeftADD += areaSize;
02001 else
02002 nAxesLeftADD = QMAX( nAxesLeftADD, areaSize );
02003 break;
02004 case KDChartAxisParams::AxisPosTop:
02005 if( bAddTop )
02006 nAxesTopADD += areaSize;
02007 else
02008 nAxesTopADD = QMAX( nAxesTopADD, areaSize );
02009 break;
02010 case KDChartAxisParams::AxisPosRight:
02011 if( bAddRight )
02012 nAxesRightADD += areaSize;
02013 else
02014 nAxesRightADD = QMAX( nAxesRightADD, areaSize );
02015 break;
02016 default:
02017 break;
02018 }
02019 }
02020
02021
02022
02023
02024 ( ( KDChartAxisParams& ) para ).setAxisTrueAreaSize( areaSize );
02025 }
02026 int nMinDistance = static_cast < int > ( 30.0 * averageValueP1000 );
02027
02028 int nAxesBottom = QMAX( nAxesBottom0 + nAxesBottomADD, nMinDistance );
02029
02030
02031
02032 int nAxesLeft = QMAX( nAxesLeft0 + nAxesLeftADD, nMinDistance )
02033 - (bIsAreaChart ? 0 : 1);
02034
02035 int nAxesTop = QMAX( nAxesTop0 + nAxesTopADD, nMinDistance );
02036
02037 int nAxesRight = QMAX( nAxesRight0 + nAxesRightADD, nMinDistance );
02038
02039 int nBottom = params()->axisParams( KDChartAxisParams::AxisPosBottom ).axisTrueAreaSize();
02040 int nLeft = params()->axisParams( KDChartAxisParams::AxisPosLeft ).axisTrueAreaSize();
02041 int nTop = params()->axisParams( KDChartAxisParams::AxisPosTop ).axisTrueAreaSize();
02042 int nRight = params()->axisParams( KDChartAxisParams::AxisPosRight ).axisTrueAreaSize();
02043 int nBottom2 = params()->axisParams( KDChartAxisParams::AxisPosBottom2 ).axisTrueAreaSize();
02044 int nLeft2 = params()->axisParams( KDChartAxisParams::AxisPosLeft2 ).axisTrueAreaSize();
02045 int nTop2 = params()->axisParams( KDChartAxisParams::AxisPosTop2 ).axisTrueAreaSize();
02046 int nRight2 = params()->axisParams( KDChartAxisParams::AxisPosRight2 ).axisTrueAreaSize();
02047
02048 internSetAxisArea( _params,
02049 KDChartAxisParams::AxisPosBottom,
02050 _outermostRect.left() + nAxesLeft,
02051 _outermostRect.top() + trueHeight - nAxesBottom,
02052 trueWidth - nAxesLeft - nAxesRight + 1,
02053 nBottom );
02054 internSetAxisArea( _params,
02055 KDChartAxisParams::AxisPosLeft,
02056 _outermostRect.left() + (bAddLeft ? nAxesLeft0 + nLeft2 : nAxesLeft0),
02057 _outermostRect.top() + nAxesTop,
02058 nLeft,
02059 trueHeight - nAxesTop - nAxesBottom + 1 );
02060
02061 internSetAxisArea( _params,
02062 KDChartAxisParams::AxisPosTop,
02063 _outermostRect.left() + nAxesLeft,
02064 _outermostRect.top() + (bAddTop ? nAxesTop0 + nTop2 : nAxesTop0),
02065 trueWidth - nAxesLeft - nAxesRight + 1,
02066 nTop );
02067 internSetAxisArea( _params,
02068 KDChartAxisParams::AxisPosRight,
02069 _outermostRect.left() + trueWidth - nAxesRight,
02070 _outermostRect.top() + nAxesTop,
02071 nRight,
02072 trueHeight - nAxesTop - nAxesBottom + 1 );
02073
02074 internSetAxisArea( _params,
02075 KDChartAxisParams::AxisPosBottom2,
02076 _outermostRect.left() + nAxesLeft,
02077 _outermostRect.top() + trueHeight - nAxesBottom + (bAddBottom ? nBottom : 0),
02078 trueWidth - nAxesLeft - nAxesRight + 1,
02079 nBottom2 );
02080 internSetAxisArea( _params,
02081 KDChartAxisParams::AxisPosLeft2,
02082 _outermostRect.left() + nAxesLeft0,
02083 _outermostRect.top() + nAxesTop,
02084 nLeft2,
02085 trueHeight - nAxesTop - nAxesBottom + 1 );
02086
02087 internSetAxisArea( _params,
02088 KDChartAxisParams::AxisPosTop2,
02089 _outermostRect.left() + nAxesLeft,
02090 _outermostRect.top() + nAxesTop0,
02091 trueWidth - nAxesLeft - nAxesRight + 1,
02092 nTop2 );
02093 internSetAxisArea( _params,
02094 KDChartAxisParams::AxisPosRight2,
02095 _outermostRect.left() + trueWidth - nAxesRight + (bAddRight ? nRight : 0),
02096 _outermostRect.top() + nAxesTop,
02097 nRight2,
02098 trueHeight - nAxesTop - nAxesBottom + 1 );
02099
02100 _dataRect = QRect( _outermostRect.left() + nAxesLeft,
02101 _outermostRect.top() + nAxesTop,
02102 trueWidth - nAxesLeft - nAxesRight + 1,
02103 trueHeight - nAxesTop - nAxesBottom + 1 );
02104 }
02105
02106
02107
02120 void KDChartPainter::setupGeometry( QPainter* painter,
02121 KDChartTableDataBase* data,
02122 const QRect& drawRect )
02123 {
02124
02125
02126 const bool oldBlockSignalsState = params()->signalsBlocked();
02127 const_cast < KDChartParams* > ( params() )->blockSignals( true );
02128
02129 _outermostRect = drawRect;
02130
02131 int yposTop = _outermostRect.topLeft().y();
02132 int xposLeft = _outermostRect.topLeft().x();
02133 int yposBottom = _outermostRect.bottomRight().y();
02134 int xposRight = _outermostRect.bottomRight().x();
02135
02136 const int trueWidth = _outermostRect.width();
02137 const int trueHeight = _outermostRect.height();
02138
02139
02140
02141 _areaWidthP1000 = trueWidth / 1000.0;
02142 _areaHeightP1000 = trueHeight / 1000.0;
02143
02144
02145 xposLeft += 0 < params()->globalLeadingLeft()
02146 ? params()->globalLeadingLeft()
02147 : static_cast < int > ( params()->globalLeadingLeft() * -_areaWidthP1000 );
02148 yposTop += 0 < params()->globalLeadingTop()
02149 ? params()->globalLeadingTop()
02150 : static_cast < int > ( params()->globalLeadingTop() * -_areaHeightP1000 );
02151 xposRight -= 0 < params()->globalLeadingRight()
02152 ? params()->globalLeadingRight()
02153 : static_cast < int > ( params()->globalLeadingRight() * -_areaWidthP1000 );
02154 yposBottom -= 0 < params()->globalLeadingBottom()
02155 ? params()->globalLeadingBottom()
02156 : static_cast < int > ( params()->globalLeadingBottom()* -_areaHeightP1000 );
02157
02158 _innermostRect = QRect( QPoint(xposLeft, yposTop),
02159 QPoint(xposRight, yposBottom) );
02160
02161 _logicalWidth = xposRight - xposLeft;
02162 _logicalHeight = yposBottom - yposTop;
02163
02164
02165
02166 _areaWidthP1000 = _logicalWidth / 1000.0;
02167 _areaHeightP1000 = _logicalHeight / 1000.0;
02168
02169 double averageValueP1000 = QMIN(_areaWidthP1000, _areaHeightP1000);
02170
02171
02172
02173
02174
02175
02176
02177 int headerLineLeading = calculateHdFtRects(
02178 painter,
02179 averageValueP1000,
02180 xposLeft, xposRight,
02181 false,
02182 yposTop, yposBottom );
02183 calculateHdFtRects(
02184 painter,
02185 averageValueP1000,
02186 xposLeft, xposRight,
02187 true,
02188 yposTop, yposBottom );
02189
02190
02191
02192 if ( params()->legendPosition() != KDChartParams::NoLegend ) {
02193
02194 findLegendTexts( data );
02195
02196 bool hasLegendTitle = false;
02197 if ( !params()->legendTitleText().isEmpty() )
02198 hasLegendTitle = true;
02199
02200 _legendTitleWidth = 0;
02201 if( _legendTitle )
02202 delete _legendTitle;
02203 _legendTitle = 0;
02204 if ( hasLegendTitle ) {
02205 QFont actLegendTitleFont = params()->legendTitleFont();
02206 if ( params()->legendTitleFontUseRelSize() ) {
02207 int nTxtHeight =
02208 static_cast < int > ( params()->legendTitleFontRelSize()
02209 * averageValueP1000 );
02210 actLegendTitleFont.setPixelSize( nTxtHeight );
02211
02212 const_cast < KDChartParams* > ( params() )->setLegendTitleFont( actLegendTitleFont, false );
02213 }
02214 painter->setFont( actLegendTitleFont );
02215 QFontMetrics legendTitleMetrics( painter->fontMetrics() );
02216 _legendTitleMetricsHeight = legendTitleMetrics.height();
02217
02218 _legendTitle = new KDChartTextPiece( painter,
02219 params()->legendTitleText(),
02220 actLegendTitleFont );
02221 _legendTitleWidth = _legendTitle->width();
02222 _legendTitleHeight = _legendTitle->height();
02223
02224 }
02225
02226 painter->setFont( trueLegendFont() );
02227 QFontMetrics legendMetrics( painter->fontMetrics() );
02228 _legendSpacing = legendMetrics.lineSpacing();
02229 _legendHeight = legendMetrics.height();
02230 _legendLeading = legendMetrics.leading();
02231
02232 _legendEMSpace = legendMetrics.width( 'M' );
02233
02234 int sizeX = 0;
02235 int sizeY = 0;
02236
02237 for ( int dataset = 0; dataset < _numLegendTexts; dataset++ ) {
02238 sizeX = QMAX( sizeX, legendMetrics.width( _legendTexts[ dataset ] ) );
02239 if( !_legendTexts[ dataset ].isEmpty() )
02240 sizeY += _legendSpacing;
02241 }
02242
02243 sizeY += _legendEMSpace - _legendLeading;
02244
02245 if ( hasLegendTitle )
02246 sizeY += legendTitleVertGap();
02247
02248
02249
02250 sizeX += ( _legendEMSpace * 4 );
02251
02252
02253
02254
02255
02256
02257 sizeX = QMAX( sizeX, _legendTitleWidth + _legendEMSpace*2 );
02258
02259
02260
02261
02262 if( !mustDrawVerticalLegend() ){
02263 QSize size;
02264 calculateHorizontalLegendSize( painter,
02265 size,
02266 _legendNewLinesStartAtLeft );
02267 sizeX = size.width();
02268 sizeY = size.height();
02269 }
02270
02271 switch ( params()->legendPosition() ) {
02272 case KDChartParams::LegendTop:
02273 if ( headerLineLeading )
02274 yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02275 _legendRect = QRect( xposLeft + ( (xposRight-xposLeft) - sizeX ) / 2,
02276 yposTop, sizeX, sizeY );
02277 yposTop = _legendRect.bottom() + params()->legendSpacing();
02278
02279 break;
02280 case KDChartParams::LegendBottom:
02281 if ( params()->showGrid() )
02282 yposTop += headerLineLeading;
02283 _legendRect = QRect( xposLeft + ( (xposRight-xposLeft) - sizeX ) / 2,
02284 yposBottom - sizeY,
02285 sizeX, sizeY );
02286 yposBottom = _legendRect.top() - params()->legendSpacing();
02287 break;
02288 case KDChartParams::LegendLeft:
02289 if ( params()->showGrid() )
02290 yposTop += headerLineLeading;
02291 _legendRect = QRect( xposLeft + 1, ( yposBottom - yposTop - sizeY ) / 2 +
02292 yposTop,
02293 sizeX, sizeY );
02294 xposLeft = _legendRect.right() + params()->legendSpacing();
02295 break;
02296 case KDChartParams::LegendRight:
02297 if ( params()->showGrid() )
02298 yposTop += headerLineLeading;
02299 _legendRect = QRect( xposRight - sizeX - 1,
02300 ( yposBottom - yposTop - sizeY ) / 2 + yposTop,
02301 sizeX, sizeY );
02302 xposRight = _legendRect.left() - params()->legendSpacing();
02303 break;
02304 case KDChartParams::LegendTopLeft:
02305 if ( headerLineLeading )
02306 yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02307 _legendRect = QRect( xposLeft + 1, yposTop, sizeX, sizeY );
02308 yposTop = _legendRect.bottom() + params()->legendSpacing();
02309 xposLeft = _legendRect.right() + params()->legendSpacing();
02310 break;
02311 case KDChartParams::LegendTopLeftTop:
02312 if ( headerLineLeading )
02313 yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02314 _legendRect = QRect( xposLeft + 1, yposTop, sizeX, sizeY );
02315 yposTop = _legendRect.bottom() + params()->legendSpacing();
02316 break;
02317 case KDChartParams::LegendTopLeftLeft:
02318 if ( headerLineLeading )
02319 yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02320 _legendRect = QRect( xposLeft + 1, yposTop, sizeX, sizeY );
02321 xposLeft = _legendRect.right() + params()->legendSpacing();
02322 break;
02323 case KDChartParams::LegendTopRight:
02324 if ( headerLineLeading )
02325 yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02326 _legendRect = QRect( xposRight - sizeX - 1,
02327 yposTop, sizeX, sizeY );
02328 yposTop = _legendRect.bottom() + params()->legendSpacing();
02329 xposRight = _legendRect.left() - params()->legendSpacing();
02330 break;
02331 case KDChartParams::LegendTopRightTop:
02332 if ( headerLineLeading )
02333 yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02334 _legendRect = QRect( xposRight - sizeX - 1,
02335 yposTop, sizeX, sizeY );
02336 yposTop = _legendRect.bottom() + params()->legendSpacing();
02337 break;
02338 case KDChartParams::LegendTopRightRight:
02339 if ( headerLineLeading )
02340 yposTop += QMAX( (int)params()->legendSpacing(), headerLineLeading );
02341 _legendRect = QRect( xposRight - sizeX - 1,
02342 yposTop, sizeX, sizeY );
02343 xposRight = _legendRect.left() - params()->legendSpacing();
02344 break;
02345 case KDChartParams::LegendBottomLeft:
02346 if ( params()->showGrid() )
02347 yposTop += headerLineLeading;
02348 _legendRect = QRect( xposLeft + 1, yposBottom - sizeY, sizeX, sizeY );
02349 yposBottom = _legendRect.top() - params()->legendSpacing();
02350 xposLeft = _legendRect.right() + params()->legendSpacing();
02351 break;
02352 case KDChartParams::LegendBottomLeftBottom:
02353 if ( params()->showGrid() )
02354 yposTop += headerLineLeading;
02355 _legendRect = QRect( xposLeft + 1, yposBottom - sizeY, sizeX, sizeY );
02356 yposBottom = _legendRect.top() - params()->legendSpacing();
02357 break;
02358 case KDChartParams::LegendBottomLeftLeft:
02359 if ( params()->showGrid() )
02360 yposTop += headerLineLeading;
02361 _legendRect = QRect( xposLeft + 1, yposBottom - sizeY, sizeX, sizeY );
02362 xposLeft = _legendRect.right() + params()->legendSpacing();
02363 break;
02364 case KDChartParams::LegendBottomRight:
02365 if ( params()->showGrid() )
02366 yposTop += headerLineLeading;
02367 _legendRect = QRect( xposRight - sizeX - 1,
02368 yposBottom - sizeY, sizeX, sizeY );
02369 yposBottom = _legendRect.top() - params()->legendSpacing();
02370 xposRight = _legendRect.left() - params()->legendSpacing();
02371 break;
02372 case KDChartParams::LegendBottomRightBottom:
02373 if ( params()->showGrid() )
02374 yposTop += headerLineLeading;
02375 _legendRect = QRect( xposRight - sizeX - 1,
02376 yposBottom - sizeY, sizeX, sizeY );
02377 yposBottom = _legendRect.top() - params()->legendSpacing();
02378 break;
02379 case KDChartParams::LegendBottomRightRight:
02380 if ( params()->showGrid() )
02381 yposTop += headerLineLeading;
02382 _legendRect = QRect( xposRight - sizeX - 1,
02383 yposBottom - sizeY, sizeX, sizeY );
02384 xposRight = _legendRect.left() - params()->legendSpacing();
02385 break;
02386 default:
02387
02388 qDebug( "KDChart: Unknown legend position" );
02389 }
02390 _params->setLegendArea( _legendRect );
02391
02392 }else{
02393 _params->setLegendArea( QRect(QPoint(0,0), QSize(0,0)) );
02394 }
02395
02396
02397 _axesRect = QRect( QPoint(xposLeft, yposTop), QPoint(xposRight, yposBottom) );
02398
02399
02400
02401 if( KDChartParams::Polar == params()->chartType() ) {
02402 _dataRect = _axesRect;
02403 } else {
02404
02405
02406 calculateAllAxesRects( painter, false, data );
02407
02408
02409
02410 double dblDummy;
02411 if( calculateAllAxesLabelTextsAndCalcValues(
02412 painter,
02413 data,
02414 _areaWidthP1000,
02415 _areaHeightP1000,
02416 dblDummy ) )
02417
02418
02419 calculateAllAxesRects( painter, true, data );
02420 }
02421 _params->setDataArea( _dataRect );
02422
02423 const_cast < KDChartParams* > ( params() )->blockSignals( oldBlockSignalsState );
02424 }
02425
02426
02430 void KDChartPainter::findLegendTexts( KDChartTableDataBase* data )
02431 {
02432 uint dataset;
02433 QVariant vValY;
02434 switch ( params()->legendSource() ) {
02435 case KDChartParams::LegendManual: {
02436
02437
02438 _numLegendTexts = numLegendFallbackTexts( data );
02439 for ( dataset = 0; dataset < static_cast<uint>(_numLegendTexts); dataset++ )
02440 _legendTexts[ dataset ] = params()->legendText( dataset );
02441 break;
02442 }
02443 case KDChartParams::LegendFirstColumn: {
02444
02445 for ( dataset = 0; dataset < data->usedRows(); dataset++ ){
02446 if( data->cellCoord( dataset, 0, vValY, 1 ) ){
02447 if( QVariant::String == vValY.type() )
02448 _legendTexts[ dataset ] = vValY.toString();
02449 else
02450 _legendTexts[ dataset ] = "";
02451 }
02452 }
02453 _numLegendTexts = data->usedRows();
02454 break;
02455 }
02456 case KDChartParams::LegendAutomatic: {
02457
02458 bool notfound = false;
02459 _numLegendTexts = numLegendFallbackTexts( data );
02460
02461 for ( dataset = 0; dataset < data->usedRows(); dataset++ ) {
02462 if( data->cellCoord( dataset, 0, vValY, 1 ) ){
02463 if( QVariant::String == vValY.type() )
02464 _legendTexts[ dataset ] = vValY.toString();
02465 else
02466 _legendTexts[ dataset ] = "";
02467 if( _legendTexts[ dataset ].isEmpty() ){
02468 notfound = true;
02469 break;
02470 }
02471 }
02472 }
02473
02474
02475
02476
02477 if ( notfound ) {
02478 for ( dataset = 0; dataset < numLegendFallbackTexts( data );
02479 dataset++ ) {
02480 _legendTexts[ dataset ] = params()->legendText( dataset );
02481 if ( _legendTexts[ dataset ].isEmpty() || _legendTexts[ dataset ].isNull() ) {
02482 _legendTexts[ dataset ] = fallbackLegendText( dataset );
02483
02484 _numLegendTexts = numLegendFallbackTexts( data );
02485 }
02486 }
02487 }
02488 break;
02489 }
02490 default:
02491
02492 qDebug( "KDChart: Unknown legend source" );
02493 }
02494 }
02495
02496
02512 QString KDChartPainter::fallbackLegendText( uint dataset ) const
02513 {
02514 return QObject::tr( "Series " ) + QString::number( dataset + 1 );
02515 }
02516
02517
02530 uint KDChartPainter::numLegendFallbackTexts( KDChartTableDataBase* data ) const
02531 {
02532 return data->usedRows();
02533 }
02534
02535
02545 void KDChartPainter::drawMarker( QPainter* painter,
02546 int style,
02547 const QColor& color,
02548 const QPoint& p,
02549 const QSize& size,
02550 uint align )
02551 {
02552 int width = size.width();
02553 int height = size.height();
02554 drawMarker( painter,
02555 0,
02556 0.0, 0.0,
02557 0,0,
02558 style,
02559 color,
02560 p,
02561 0,0,0,
02562 0,
02563 &width,
02564 &height,
02565 align );
02566 }
02567
02568
02584 KDChartDataRegion* KDChartPainter::drawMarker( QPainter* painter,
02585 const KDChartParams* params,
02586 double areaWidthP1000,
02587 double areaHeightP1000,
02588 int deltaX,
02589 int deltaY,
02590 int style,
02591 const QColor& color,
02592 const QPoint& _p,
02593 uint dataset, uint value, uint chart,
02594 KDChartDataRegionList* regions,
02595 int* width,
02596 int* height,
02597 uint align )
02598 {
02599 KDChartDataRegion* datReg = 0;
02600 const double areaSizeP1000 = QMIN(areaWidthP1000, areaHeightP1000);
02601 int xsize = width ? *width : (params ? params->lineMarkerSize().width() : 12);
02602 if( 0 > xsize )
02603 xsize = static_cast < int > (xsize * -areaSizeP1000);
02604 int ysize = height ? *height : (params ? params->lineMarkerSize().height() : 12);
02605 if( 0 > ysize )
02606 ysize = static_cast < int > (ysize * -areaSizeP1000);
02607 if( KDChartParams::LineMarkerCross != style ){
02608 xsize = QMAX( xsize, 4 );
02609 ysize = QMAX( ysize, 4 );
02610 }
02611 uint xsize2 = xsize / 2;
02612 uint ysize2 = ysize / 2;
02613 uint xsize4 = xsize / 4;
02614 uint ysize4 = ysize / 4;
02615 uint xsize6 = xsize / 6;
02616 uint ysize6 = ysize / 6;
02617 painter->setPen( color );
02618 const uint xysize2 = QMIN( xsize2, ysize2 );
02619
02620 int x = _p.x();
02621 int y = _p.y();
02622 if( align & Qt::AlignLeft )
02623 x += xsize2;
02624 else if( align & Qt::AlignRight )
02625 x -= xsize2;
02626 if( align & Qt::AlignTop )
02627 y += ysize2;
02628 else if( align & Qt::AlignBottom )
02629 y -= ysize2;
02630 const QPoint p(x, y);
02631
02632 switch ( style ) {
02633 case KDChartParams::LineMarkerSquare: {
02634 const QPen oldPen( painter->pen() );
02635 const QBrush oldBrush( painter->brush() );
02636 painter->setBrush( color );
02637 painter->setPen( color );
02638 QRect rect( QPoint( p.x() - xsize2, p.y() - ysize2 ), QPoint( p.x() + xsize2, p.y() + ysize2 ) );
02639 painter->drawRect( rect );
02640
02641 rect.moveBy( deltaX, deltaY );
02642 if ( regions ){
02643 datReg =
02644 new KDChartDataRegion(
02645 dataset, value,
02646 chart, rect );
02647 regions->append( datReg );
02648 }
02649 painter->setPen( oldPen );
02650 painter->setBrush( oldBrush );
02651 break;
02652 }
02653 case KDChartParams::LineMarkerDiamond:{
02654 const QBrush oldBrush( painter->brush() );
02655 painter->setBrush( color );
02656 QPointArray points( 4 );
02657 points.setPoint( 0, p.x() - xsize2, p.y() );
02658 points.setPoint( 1, p.x(), p.y() - ysize2 );
02659 points.setPoint( 2, p.x() + xsize2, p.y() );
02660 points.setPoint( 3, p.x(), p.y() + ysize2 );
02661 painter->drawPolygon( points );
02662
02663 points.translate( deltaX, deltaY );
02664 if ( regions ){
02665 datReg = new KDChartDataRegion(
02666 dataset, value,
02667 chart, points );
02668 regions->append( datReg );
02669 }
02670 painter->setBrush( oldBrush );
02671 break;
02672 }
02673 case KDChartParams::LineMarker1Pixel: {
02674 QRect rect( p, p );
02675 painter->drawRect( rect );
02676
02677 rect.moveBy( deltaX, deltaY );
02678 if ( regions ){
02679 datReg = new KDChartDataRegion(
02680 dataset, value,
02681 chart, rect );
02682 regions->append( datReg );
02683 }
02684 break;
02685 }
02686 case KDChartParams::LineMarker4Pixels:{
02687 QRect rect( p, QPoint( p.x()+1, p.y()+1 ) );
02688 painter->drawRect( rect );
02689
02690 rect.moveBy( deltaX, deltaY );
02691 if ( regions ){
02692 datReg = new KDChartDataRegion(
02693 dataset, value,
02694 chart, rect );
02695 regions->append( datReg );
02696 }
02697 break;
02698 }
02699 case KDChartParams::LineMarkerRing: {
02700 const QPen oldPen( painter->pen() );
02701 painter->setPen( QPen( color, QMIN(xsize4, ysize4) ) );
02702 const QBrush oldBrush( painter->brush() );
02703 painter->setBrush( Qt::NoBrush );
02704 painter->drawEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
02705 if ( regions ) {
02706 QPointArray points;
02707 points.makeEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
02708
02709 points.translate( deltaX, deltaY );
02710 if( points.size() > 0 ){
02711 datReg = new KDChartDataRegion(
02712 dataset, value,
02713 chart, points );
02714 regions->append( datReg );
02715 }
02716 }
02717 painter->setBrush( oldBrush );
02718 painter->setPen( oldPen );
02719 break;
02720 }
02721 case KDChartParams::LineMarkerCross: {
02722 const QPen oldPen( painter->pen() );
02723 painter->setPen( color );
02724 const QBrush oldBrush( painter->brush() );
02725 painter->setBrush( color );
02726 int numPoints = (ysize && xsize) ? 12 : 4;
02727 QPointArray points( numPoints );
02728 if( ysize && xsize ){
02729 points.setPoint( 0, p.x() - xsize6, p.y() - ysize6 );
02730 points.setPoint( 1, p.x() - xsize6, p.y() - ysize2 );
02731 points.setPoint( 2, p.x() + xsize6, p.y() - ysize2 );
02732 points.setPoint( 3, p.x() + xsize6, p.y() - ysize6 );
02733 points.setPoint( 4, p.x() + xsize2, p.y() - ysize6 );
02734 points.setPoint( 5, p.x() + xsize2, p.y() + ysize6 );
02735 points.setPoint( 6, p.x() + xsize6, p.y() + ysize6 );
02736 points.setPoint( 7, p.x() + xsize6, p.y() + ysize2 );
02737 points.setPoint( 8, p.x() - xsize6, p.y() + ysize2 );
02738 points.setPoint( 9, p.x() - xsize6, p.y() + ysize6 );
02739 points.setPoint(10, p.x() - xsize2, p.y() + ysize6 );
02740 points.setPoint(11, p.x() - xsize2, p.y() - ysize6 );
02741 }else if( ysize ){
02742 points.setPoint( 0, p.x() - ysize6, p.y() - ysize2 );
02743 points.setPoint( 1, p.x() + ysize6, p.y() - ysize2 );
02744 points.setPoint( 2, p.x() + ysize6, p.y() + ysize2 );
02745 points.setPoint( 3, p.x() - ysize6, p.y() + ysize2 );
02746 }else{
02747 points.setPoint( 0, p.x() - xsize2, p.y() - xsize6 );
02748 points.setPoint( 1, p.x() + xsize2, p.y() - xsize6 );
02749 points.setPoint( 2, p.x() + xsize2, p.y() + xsize6 );
02750 points.setPoint( 3, p.x() - xsize2, p.y() + xsize6 );
02751 }
02752 painter->drawPolygon( points );
02753
02754 points.translate( deltaX, deltaY );
02755 if( regions ){
02756 datReg = new KDChartDataRegion(
02757 dataset, value,
02758 chart, points );
02759 regions->append( datReg );
02760 }
02761 painter->setBrush( oldBrush );
02762 painter->setPen( oldPen );
02763 break;
02764 }
02765 case KDChartParams::LineMarkerFastCross: {
02766 const QPen oldPen( painter->pen() );
02767 painter->setPen( color );
02768 painter->drawLine( QPoint(p.x() - xysize2, p.y()),
02769 QPoint(p.x() + xysize2, p.y()) );
02770 painter->drawLine( QPoint(p.x(), p.y() - xysize2),
02771 QPoint(p.x(), p.y() + xysize2) );
02772 QRect rect( QPoint( p.x() - 2, p.y() - 2 ),
02773 QPoint( p.x() + 2, p.y() + 2 ) );
02774
02775 rect.moveBy( deltaX, deltaY );
02776 if ( regions ){
02777 datReg =
02778 new KDChartDataRegion(
02779 dataset, value,
02780 chart, rect );
02781 regions->append( datReg );
02782 }
02783 painter->setPen( oldPen );
02784 break;
02785 }
02786 case KDChartParams::LineMarkerCircle:
02787 default: {
02788 const QBrush oldBrush( painter->brush() );
02789 painter->setBrush( color );
02790 painter->drawEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
02791 if ( regions ) {
02792 QPointArray points;
02793 points.makeEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
02794
02795 points.translate( deltaX, deltaY );
02796 if( points.size() > 0 ){
02797 datReg = new KDChartDataRegion(
02798 dataset, value,
02799 chart, points );
02800 regions->append( datReg );
02801 }
02802 }
02803 painter->setBrush( oldBrush );
02804 }
02805 }
02806 return datReg;
02807 }
02808
02809
02810 void KDChartPainter::drawExtraLinesAndMarkers(
02811 KDChartPropertySet& propSet,
02812 const QPen& defaultPen,
02813 const KDChartParams::LineMarkerStyle& defaultMarkerStyle,
02814 int myPointX,
02815 int myPointY,
02816 QPainter* painter,
02817 const KDChartAxisParams* abscissaPara,
02818 const KDChartAxisParams* ordinatePara,
02819 const double areaWidthP1000,
02820 const double areaHeightP1000,
02821 bool bDrawInFront )
02822 {
02823
02824
02825
02826
02827 int iDummy;
02828 uint extraLinesAlign = 0;
02829 if( propSet.hasOwnExtraLinesAlign( iDummy, extraLinesAlign )
02830 && ( extraLinesAlign
02831 & ( Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter |
02832 Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter ) ) ){
02833 bool extraLinesInFront = false;
02834 propSet.hasOwnExtraLinesInFront( iDummy, extraLinesInFront );
02835 if( bDrawInFront == extraLinesInFront ){
02836 const double areaSizeP1000 = QMIN(areaWidthP1000, areaHeightP1000);
02837 int extraLinesLength = -20;
02838 int extraLinesWidth = defaultPen.width();
02839 QColor extraLinesColor = defaultPen.color();
02840 Qt::PenStyle extraLinesStyle = defaultPen.style();
02841 uint extraMarkersAlign = 0;
02842 propSet.hasOwnExtraLinesLength( iDummy, extraLinesLength );
02843 propSet.hasOwnExtraLinesWidth( iDummy, extraLinesWidth );
02844 propSet.hasOwnExtraLinesColor( iDummy, extraLinesColor );
02845 propSet.hasOwnExtraLinesStyle( iDummy, extraLinesStyle );
02846 const int horiLenP2 = (0 > extraLinesLength)
02847 ? static_cast<int>(areaWidthP1000 * extraLinesLength) / 2
02848 : extraLinesLength / 2;
02849 const int vertLenP2 = (0 > extraLinesLength)
02850 ? static_cast<int>(areaHeightP1000 * extraLinesLength) / 2
02851 : extraLinesLength / 2;
02852
02853 QPoint pL( (Qt::AlignLeft == (extraLinesAlign & Qt::AlignLeft))
02854 ? 0
02855 : (Qt::AlignHCenter == (extraLinesAlign & Qt::AlignHCenter))
02856 ? myPointX - horiLenP2
02857 : myPointX,
02858 myPointY );
02859 QPoint pR( (Qt::AlignRight == (extraLinesAlign & Qt::AlignRight))
02860 ? abscissaPara->axisTrueAreaRect().width()
02861 : (Qt::AlignHCenter == (extraLinesAlign & Qt::AlignHCenter))
02862 ? myPointX + horiLenP2
02863 : myPointX,
02864 myPointY );
02865 QPoint pT( myPointX,
02866 (Qt::AlignTop == (extraLinesAlign & Qt::AlignTop))
02867 ? 0
02868 : (Qt::AlignVCenter == (extraLinesAlign & Qt::AlignVCenter))
02869 ? myPointY - vertLenP2
02870 : myPointY );
02871 QPoint pB( myPointX,
02872 (Qt::AlignBottom == (extraLinesAlign & Qt::AlignBottom))
02873 ? ordinatePara->axisTrueAreaRect().height()
02874 : (Qt::AlignVCenter == (extraLinesAlign & Qt::AlignVCenter))
02875 ? myPointY + vertLenP2
02876 : myPointY );
02877 const QPen extraPen( extraLinesColor,
02878 0 > extraLinesWidth
02879 ? static_cast < int > ( areaSizeP1000 * -extraLinesWidth )
02880 : extraLinesWidth,
02881 extraLinesStyle );
02882 const QPen oldPen( painter->pen() );
02883 painter->setPen( extraPen );
02884 if( extraLinesAlign & ( Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter ) )
02885 painter->drawLine( pL, pR );
02886 if( extraLinesAlign & ( Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter ) )
02887 painter->drawLine( pT, pB );
02888 painter->setPen( oldPen );
02889
02890 propSet.hasOwnExtraMarkersAlign( iDummy, extraMarkersAlign );
02891 if( extraMarkersAlign
02892 & ( Qt::AlignLeft | Qt::AlignRight |
02893 Qt::AlignTop | Qt::AlignBottom ) ){
02894 QSize extraMarkersSize = params()->lineMarkerSize();
02895 QColor extraMarkersColor = extraLinesColor;
02896 int extraMarkersStyle = defaultMarkerStyle;
02897 propSet.hasOwnExtraMarkersSize( iDummy, extraMarkersSize );
02898 propSet.hasOwnExtraMarkersColor( iDummy, extraMarkersColor );
02899 propSet.hasOwnExtraMarkersStyle( iDummy, extraMarkersStyle );
02900
02901 int w = extraMarkersSize.width();
02902 int h = extraMarkersSize.height();
02903 if( w < 0 )
02904 w = static_cast < int > (w * -areaSizeP1000);
02905 if( h < 0 )
02906 h = static_cast < int > (h * -areaSizeP1000);
02907 if( extraMarkersAlign & Qt::AlignLeft )
02908 drawMarker( painter,
02909 params(),
02910 _areaWidthP1000, _areaHeightP1000,
02911 _dataRect.x(), _dataRect.y(),
02912 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
02913 extraMarkersColor,
02914 pL,
02915 0, 0, 0, 0,
02916 &w, &h,
02917 Qt::AlignCenter );
02918 if( extraMarkersAlign & Qt::AlignRight )
02919 drawMarker( painter,
02920 params(),
02921 _areaWidthP1000, _areaHeightP1000,
02922 _dataRect.x(), _dataRect.y(),
02923 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
02924 extraMarkersColor,
02925 pR,
02926 0, 0, 0, 0,
02927 &w, &h,
02928 Qt::AlignCenter );
02929 if( extraMarkersAlign & Qt::AlignTop )
02930 drawMarker( painter,
02931 params(),
02932 _areaWidthP1000, _areaHeightP1000,
02933 _dataRect.x(), _dataRect.y(),
02934 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
02935 extraMarkersColor,
02936 pT,
02937 0, 0, 0, 0,
02938 &w, &h,
02939 Qt::AlignCenter );
02940 if( extraMarkersAlign & Qt::AlignBottom )
02941 drawMarker( painter,
02942 params(),
02943 _areaWidthP1000, _areaHeightP1000,
02944 _dataRect.x(), _dataRect.y(),
02945 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
02946 extraMarkersColor,
02947 pB,
02948 0, 0, 0, 0,
02949 &w, &h,
02950 Qt::AlignCenter );
02951 }
02952 }
02953 }
02954 }
02955
02956