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 <qpainter.h>
00030 #include <qlabel.h>
00031
00032 #include <KDDrawText.h>
00033 #include "KDChartAxesPainter.h"
00034 #include "KDChartAxisParams.h"
00035 #include "KDChartParams.h"
00036
00037 #include <stdlib.h>
00038
00039
00045 int secondsSinceUTCStart( const QDateTime& dt )
00046 {
00047 QDateTime dtStart( QDate( 1970, 1, 1 ) );
00048 return dtStart.secsTo( dt );
00049 }
00050
00051
00064 KDChartAxesPainter::KDChartAxesPainter( KDChartParams* params ) :
00065 KDChartPainter( params )
00066 {
00067
00068
00069
00070 }
00071
00075 KDChartAxesPainter::~KDChartAxesPainter()
00076 {
00077
00078 }
00079
00080
00081 #if COMPAT_QT_VERSION < 0x030000
00082 QDateTime dateTimeFromString( const QString& s )
00083 {
00084 int year( s.mid( 0, 4 ).toInt() );
00085 int month( s.mid( 5, 2 ).toInt() );
00086 int day( s.mid( 8, 2 ).toInt() );
00087 QString t( s.mid( 11 ) );
00088 int hour( t.mid( 0, 2 ).toInt() );
00089 int minute( t.mid( 3, 2 ).toInt() );
00090 int second( t.mid( 6, 2 ).toInt() );
00091 int msec( t.mid( 9, 3 ).toInt() );
00092 if ( year && month && day )
00093 return QDateTime( QDate( year, month, day ),
00094 QTime( hour, minute, second, msec ) );
00095 else
00096 return QDateTime();
00097 }
00098 QString dateTimeToString( const QDateTime& dt )
00099 {
00100 QString date;
00101 QString month(
00102 QString::number( dt.date().month() ).rightJustify( 2, '0' ) );
00103 QString day(
00104 QString::number( dt.date().day() ).rightJustify( 2, '0' ) );
00105 date = QString::number( dt.date().year() ) + "-" + month + "-" + day;
00106 QString time;
00107 time.sprintf( "%.2d:%.2d:%.2d",
00108 dt.time().hour(), dt.time().minute(), dt.time().second() );
00109 return date + "T" + time;
00110 }
00111 #endif
00112
00113
00119 void reCalculateLabelTexts(
00120 QPainter* painter,
00121 const KDChartTableDataBase& data,
00122 const KDChartParams& params,
00123 uint axisNumber,
00124 double averageValueP1000,
00125 double delimLen,
00126 internal__KDChart__CalcValues& cv )
00127 {
00128 KDChartAxesPainter::calculateLabelTexts(
00129 painter,
00130 data,
00131 params,
00132 axisNumber,
00133 averageValueP1000,
00134 delimLen,
00135
00136 cv.basicPos,
00137 cv.orig,
00138 cv.dest,
00139 cv.pXDeltaFactor,
00140 cv.pYDeltaFactor,
00141 cv.pXDelimDeltaFaktor,
00142 cv.pYDelimDeltaFaktor,
00143 cv.nSubDelimFactor,
00144 cv.pDelimDelta,
00145 cv.nTxtHeight,
00146 cv.pTextsX,
00147 cv.pTextsY,
00148 cv.pTextsW,
00149 cv.pTextsH,
00150 cv.textAlign,
00151 cv.bLogarithmic,
00152 cv.isDateTime,
00153 cv.autoDtLabels,
00154 cv.dtLow,
00155 cv.dtHigh,
00156 cv.dtDeltaScale,
00157 true,
00158 cv.nDelta,
00159 cv.nDeltaPix );
00160 const KDChartAxisParams & para = params.axisParams( axisNumber );
00161 cv.bSteadyCalc = para.axisSteadyValueCalc();
00162 cv.bDecreasing = para.axisValuesDecreasing();
00163 cv.nLow = para.trueAxisLow();
00164 cv.nHigh = para.trueAxisHigh();
00165 }
00166
00167
00168 bool KDChartAxesPainter::calculateAllAxesLabelTextsAndCalcValues(
00169 QPainter* painter,
00170 KDChartTableDataBase* data,
00171 double areaWidthP1000,
00172 double areaHeightP1000,
00173 double& delimLen)
00174 {
00175 uint iAxis;
00176
00177 double averageValueP1000 = QMIN(areaWidthP1000, areaHeightP1000);
00178
00179 delimLen = 20.0 * averageValueP1000;
00180
00181
00182
00183
00184 for( iAxis = 0; iAxis < KDCHART_MAX_AXES; ++iAxis )
00185 {
00186 internal__KDChart__CalcValues& cv = calcVal[iAxis];
00187 cv.processThisAxis = ( params()->axisParams( iAxis ).axisVisible()
00188 && KDChartAxisParams::AxisTypeUnknown
00189 != params()->axisParams( iAxis ).axisType() );
00190 if( cv.processThisAxis ){
00191 cv.nSubDelimFactor = 0.0;
00192 cv.pDelimDelta = 0.0;
00193 cv.nTxtHeight = 0.0;
00194 cv.pTextsX = 0.0;
00195 cv.pTextsY = 0.0;
00196 cv.pTextsW = 0.0;
00197 cv.pTextsH = 0.0;
00198 cv.textAlign = Qt::AlignHCenter | Qt::AlignVCenter;
00199 cv.isDateTime = false;
00200 cv.autoDtLabels = false;
00201 calculateLabelTexts( painter,
00202 *data,
00203 *params(),
00204 iAxis,
00205 averageValueP1000,
00206 delimLen,
00207
00208 cv.basicPos,
00209 cv.orig,
00210 cv.dest,
00211 cv.pXDeltaFactor,
00212 cv.pYDeltaFactor,
00213 cv.pXDelimDeltaFaktor,
00214 cv.pYDelimDeltaFaktor,
00215 cv.nSubDelimFactor,
00216 cv.pDelimDelta,
00217 cv.nTxtHeight,
00218 cv.pTextsX,
00219 cv.pTextsY,
00220 cv.pTextsW,
00221 cv.pTextsH,
00222 cv.textAlign,
00223 cv.bLogarithmic,
00224 cv.isDateTime,
00225 cv.autoDtLabels,
00226 cv.dtLow,
00227 cv.dtHigh,
00228 cv.dtDeltaScale );
00229 const KDChartAxisParams & para = params()->axisParams( iAxis );
00230 cv.bSteadyCalc = para.axisSteadyValueCalc();
00231 cv.bDecreasing = para.axisValuesDecreasing();
00232 cv.nLow = para.trueAxisLow();
00233 cv.nHigh = para.trueAxisHigh();
00234 cv.nDelta = para.trueAxisDelta();
00235 cv.nDeltaPix = para.trueAxisDeltaPixels();
00236 cv.pLastX = cv.dest.x();
00237 cv.pLastY = cv.dest.y();
00238 }
00239 }
00240
00241
00242 for ( iAxis = 0; iAxis < KDCHART_MAX_AXES; ++iAxis ){
00243 internal__KDChart__CalcValues& cv = calcVal[iAxis];
00244 if( cv.processThisAxis
00245 && cv.bSteadyCalc ){
00246 const KDChartAxisParams & para = params()->axisParams( iAxis );
00247 const uint isoRef = para.isometricReferenceAxis();
00248 if( KDCHART_NO_AXIS != isoRef
00249 && iAxis != isoRef
00250 && ( KDCHART_MAX_AXES > isoRef
00251 || KDCHART_ALL_AXES == isoRef ) ){
00252 if( KDCHART_ALL_AXES == isoRef ){
00253 uint iAxis2;
00254
00255 double nDelta = cv.nDelta;
00256 double nDeltaPix = cv.nDeltaPix;
00257 double nSubDelimFactor = cv.nSubDelimFactor;
00258 for ( iAxis2 = 0;
00259 iAxis2 < KDCHART_MAX_AXES;
00260 ++iAxis2 ){
00261 internal__KDChart__CalcValues& cv2 = calcVal[iAxis2];
00262 if( cv2.processThisAxis
00263 && cv2.bSteadyCalc
00264 && (0.0 != cv2.nDelta)
00265 && (fabs(cv2.nDeltaPix / cv2.nDelta) < fabs(nDeltaPix / nDelta)) ){
00266 if( (nDelta >= 0.0) == (cv2.nDelta >= 0.0) )
00267 nDelta = cv2.nDelta;
00268 else
00269 nDelta = cv2.nDelta * -1.0;
00270 if( (nDeltaPix >= 0.0) == (cv2.nDeltaPix >= 0.0) )
00271 nDeltaPix = cv2.nDeltaPix;
00272 else
00273 nDeltaPix = cv2.nDeltaPix * -1.0;
00274 if( (nSubDelimFactor >= 0.0) == (cv2.nSubDelimFactor >= 0.0) )
00275 nSubDelimFactor = cv2.nSubDelimFactor;
00276 else
00277 nSubDelimFactor = cv2.nSubDelimFactor * -1.0;
00278 }
00279 }
00280
00281 for ( iAxis2 = 0;
00282 iAxis2 < KDCHART_MAX_AXES;
00283 ++iAxis2 ){
00284 internal__KDChart__CalcValues& cv2 = calcVal[iAxis2];
00285 if( cv2.processThisAxis
00286 && cv2.bSteadyCalc
00287 && ( fabs(cv2.nDelta) != fabs(nDelta)
00288 || fabs(cv2.nDeltaPix) != fabs(nDeltaPix) ) ){
00289
00290
00291
00292 if( (cv2.nDelta >= 0.0) == (nDelta >= 0.0) )
00293 cv2.nDelta = nDelta;
00294 else
00295 cv2.nDelta = nDelta * -1.0;
00296 if( (cv2.nDeltaPix >= 0.0) == (nDeltaPix >= 0.0) )
00297 cv2.nDeltaPix = nDeltaPix;
00298 else
00299 cv2.nDeltaPix = nDeltaPix * -1.0;
00300 reCalculateLabelTexts( painter,
00301 *data,
00302 *params(),
00303 iAxis2,
00304 averageValueP1000,
00305 delimLen,
00306 cv2 );
00307 if( (cv2.nSubDelimFactor >= 0.0) == (nSubDelimFactor >= 0.0) )
00308 cv2.nSubDelimFactor = nSubDelimFactor;
00309 else
00310 cv2.nSubDelimFactor = nSubDelimFactor * -1.0;
00311 }
00312 }
00313 }else{
00314 internal__KDChart__CalcValues& cv2 = calcVal[isoRef];
00315
00316 if( cv2.processThisAxis
00317 && cv2.bSteadyCalc
00318 && ( cv2.nDelta != cv.nDelta
00319 || cv2.nDeltaPix != cv.nDeltaPix ) ){
00320 if( cv2.nDelta > cv.nDelta
00321 || ( cv2.nDelta == cv.nDelta
00322 && cv2.nDeltaPix < cv.nDeltaPix ) ){
00323
00324
00325 cv.nDelta = cv2.nDelta;
00326 cv.nDeltaPix = cv2.nDeltaPix;
00327 reCalculateLabelTexts(
00328 painter,
00329 *data,
00330 *params(),
00331 iAxis,
00332 averageValueP1000,
00333 delimLen,
00334 cv );
00335 cv.nSubDelimFactor = cv2.nSubDelimFactor;
00336 }else{
00337
00338
00339
00340
00341 cv2.nDelta = cv.nDelta;
00342 cv2.nDeltaPix = cv.nDeltaPix;
00343 reCalculateLabelTexts(
00344 painter,
00345 *data,
00346 *params(),
00347 isoRef,
00348 averageValueP1000,
00349 delimLen,
00350 cv2 );
00351 cv2.nSubDelimFactor = cv.nSubDelimFactor;
00352 }
00353 }
00354 }
00355 }
00356 }
00357 }
00358 return true;
00359 }
00360
00361
00368 void KDChartAxesPainter::paintAxes( QPainter* painter,
00369 KDChartTableDataBase* data )
00370 {
00371 if ( !painter || !data || 0 == params() )
00372 return ;
00373
00374 const bool bMultiRowBarChart = KDChartParams::Bar == params()->chartType() &&
00375 KDChartParams::BarMultiRows == params()->barChartSubType();
00376
00377 double areaWidthP1000 = _logicalWidth / 1000.0;
00378 double areaHeightP1000 = _logicalHeight / 1000.0;
00379 double averageValueP1000 = QMIN(areaWidthP1000, areaHeightP1000);
00380
00381 double delimLen;
00382
00383 calculateAllAxesLabelTextsAndCalcValues( painter, data, areaWidthP1000, areaHeightP1000, delimLen );
00384
00385
00386
00387 painter->save();
00388 painter->setPen( Qt::NoPen );
00389
00390 bool screenOutput = params()->optimizeOutputForScreen();
00391 uint iAxis;
00392
00393 for ( iAxis = 0; iAxis < KDCHART_MAX_AXES; ++iAxis ){
00394 internal__KDChart__CalcValues& cv = calcVal[iAxis];
00395 if( cv.processThisAxis ){
00396
00397 const KDChartAxisParams & para = params()->axisParams( iAxis );
00398
00399 internal__KDChart__CalcValues& cv = calcVal[iAxis];
00400
00401 const QColor labelsColor( para.axisLabelsColor() );
00402
00403
00404
00405
00406 uint lineWidth = 0 <= para.axisLineWidth()
00407 ? para.axisLineWidth()
00408 : -1 * static_cast < int > ( para.axisLineWidth()
00409 * averageValueP1000 );
00410 ( ( KDChartAxisParams& ) para ).setAxisTrueLineWidth( lineWidth );
00411
00412 uint gridLineWidth
00413 = ( KDCHART_AXIS_GRID_AUTO_LINEWIDTH
00414 == para.axisGridLineWidth() )
00415 ? lineWidth
00416 : ( ( 0 <= para.axisGridLineWidth() )
00417 ? para.axisGridLineWidth()
00418 : -1 * static_cast < int > ( para.axisGridLineWidth()
00419 * averageValueP1000 ) );
00420
00421 uint gridSubLineWidth
00422 = ( KDCHART_AXIS_GRID_AUTO_LINEWIDTH
00423 == para.axisGridSubLineWidth() )
00424 ? lineWidth
00425 : ( ( 0 <= para.axisGridSubLineWidth() )
00426 ? para.axisGridSubLineWidth()
00427 : -1 * static_cast < int > ( para.axisGridSubLineWidth()
00428 * averageValueP1000 ) );
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 bool bTouchEdges = para.axisLabelsTouchEdges();
00475
00476
00477
00478
00479
00480 if( cv.bLogarithmic )
00481 cv.nSubDelimFactor = 0.1;
00482
00483 const double nUsableAxisHeight = cv.pTextsH;
00484 const double nUsableAxisWidth = cv.pTextsW;
00485
00486 const bool isHorizontalAxis
00487 = (KDChartAxisParams::AxisPosBottom == cv.basicPos) ||
00488 (KDChartAxisParams::AxisPosTop == cv.basicPos);
00489
00490 QStringList* labelTexts = ( QStringList* ) para.axisLabelTexts();
00491 uint nLabels = ( 0 != labelTexts )
00492 ? labelTexts->count()
00493 : 0;
00494
00495 QPoint p1( cv.orig );
00496
00497 QPoint p2( cv.orig );
00498
00499 QPoint p2a( cv.orig );
00500
00501 QPoint pGA( cv.orig );
00502
00503 QPoint pGZ( cv.orig );
00504
00505
00506 double axisZeroLineStartX = p1.x();
00507 double axisZeroLineStartY = p1.y();
00508
00509 p2.setX( p2.x() + static_cast < int > ( cv.pXDelimDeltaFaktor * delimLen ) );
00510 p2.setY( p2.y() + static_cast < int > ( cv.pYDelimDeltaFaktor * delimLen ) );
00511 p2a.setX( p2a.x() + static_cast < int > ( cv.pXDelimDeltaFaktor * delimLen * 2.0 / 3.0 ) );
00512 p2a.setY( p2a.y() + static_cast < int > ( cv.pYDelimDeltaFaktor * delimLen * 2.0 / 3.0 ) );
00513 pGZ.setX( pGZ.x() - static_cast < int > ( cv.pXDelimDeltaFaktor * (_dataRect.width() - 1) ) );
00514 pGZ.setY( pGZ.y() - static_cast < int > ( cv.pYDelimDeltaFaktor * (_dataRect.height() - 1) ) );
00515
00516 if ( nLabels ) {
00517
00518
00519 const bool oldClippingFlag = painter->hasClipping();
00520 painter->setClipping( false );
00521
00522 if( para.hasAxisFirstLabelText() )
00523 labelTexts->first() = para.axisFirstLabelText();
00524 if( para.hasAxisLastLabelText() )
00525 labelTexts->last() = para.axisLastLabelText();
00526
00527 const double pXDelta = cv.pXDeltaFactor * cv.pDelimDelta;
00528 const double pYDelta = cv.pYDeltaFactor * cv.pDelimDelta;
00529
00530
00531 painter->setPen( QPen( para.axisLineColor(),
00532 lineWidth ) );
00533
00534 const QString formatDT = cv.isDateTime
00535 ? para.axisLabelsDateTimeFormat()
00536 : QString();
00537
00538
00539 const double minTextHeight = para.axisLabelsFontMinSize();
00540 if ( minTextHeight > cv.nTxtHeight )
00541 cv.nTxtHeight = minTextHeight;
00542 QFont actFont( para.axisLabelsFont() );
00543 if ( para.axisLabelsFontUseRelSize() ) {
00544 actFont.setPixelSize( static_cast < int > ( cv.nTxtHeight ) );
00545 }
00546 painter->setFont( actFont );
00547 QFontMetrics fm( painter->fontMetrics() );
00548
00549 int nLeaveOut = 0;
00550 int nRotation = 0;
00551
00552
00553
00554 QString commonDtHeader;
00555 if( cv.autoDtLabels ){
00556 cv.textAlign = Qt::AlignCenter;
00557
00558
00559 const QDate& dLow = cv.dtLow.date();
00560 const QTime& tLow = cv.dtLow.time();
00561 const QDate& dHigh = cv.dtHigh.date();
00562 const QTime& tHigh = cv.dtHigh.time();
00563 bool sameYear = dLow.year() == dHigh.year();
00564 bool sameMonth = sameYear && (dLow.month() == dHigh.month() );
00565 bool sameDay = sameMonth && (dLow.day() == dHigh.day() );
00566 bool sameHour = sameDay && (tLow.hour() == tHigh.hour() );
00567 bool sameMinute = sameHour && (tLow.minute() == tHigh.minute());
00568 bool sameSecond = sameMinute && (tLow.second() == tHigh.second());
00569 if( sameDay ){
00570 commonDtHeader = QString::number( dLow.day() )
00571 + ". "
00572 #if COMPAT_QT_VERSION >= 0x030000
00573 + QDate::longMonthName( dLow.month() )
00574 #else
00575 + dLow.monthName( dLow.month() )
00576 #endif
00577 + ' '
00578 + QString::number( dLow.year() );
00579 if( sameHour ){
00580 commonDtHeader += " / "
00581 + QString::number( tLow.hour() )
00582 + ':';
00583 if( sameMinute ){
00584 if( 10 > tLow.minute() )
00585 commonDtHeader += '0';
00586 commonDtHeader += QString::number( tLow.minute() )
00587 + ':';
00588 if( sameSecond ){
00589 if( 10 > tLow.second() )
00590 commonDtHeader += '0';
00591 commonDtHeader += QString::number( tLow.second() );
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 }
00602 else
00603 commonDtHeader += "00";
00604 }
00605 else
00606 commonDtHeader += "00";
00607 }
00608 }else if( sameMonth )
00609 #if COMPAT_QT_VERSION >= 0x030000
00610 commonDtHeader = QDate::longMonthName( dLow.month() )
00611 #else
00612 commonDtHeader = dLow.monthName( dLow.month() )
00613 #endif
00614 + ' '
00615 + QString::number( dLow.year() );
00616 else if( sameYear )
00617 commonDtHeader = QString::number( dLow.year() );
00618
00619
00620 }else{
00621
00622
00623
00624 QRegion unitedRegions;
00625
00626 const bool tryLeavingOut =
00627 ( para.axisValueLeaveOut() == KDCHART_AXIS_LABELS_AUTO_LEAVEOUT )
00628 || ( 0 < para.axisValueLeaveOut() );
00629 if( tryLeavingOut ) {
00630 if( para.axisValueLeaveOut()
00631 == KDCHART_AXIS_LABELS_AUTO_LEAVEOUT )
00632 nLeaveOut = 0;
00633 else
00634 nLeaveOut = para.axisValueLeaveOut();
00635
00636 }
00637 else
00638 nLeaveOut = 0;
00639 int stepWidthLeaveOut = nLeaveOut+1;
00640 int iStepsLeaveOut = 0;
00641
00642 const bool tryShrinking = !para.axisLabelsDontShrinkFont();
00643 const double nInitialTxtHeight = cv.nTxtHeight;
00644
00645 const bool tryRotating = isHorizontalAxis
00646 && !para.axisLabelsDontAutoRotate();
00647 const int nInitialRotation = ( (360 > para.axisLabelsRotation())
00648 && (270 <= para.axisLabelsRotation()) )
00649 ? para.axisLabelsRotation()
00650 : 0;
00651 nRotation = nInitialRotation;
00652
00653 bool textsDontFitIntoArea;
00654 bool textsOverlapping;
00655 bool textsMatching;
00656 do {
00657 textsDontFitIntoArea = false;
00658 textsOverlapping = false;
00659 textsMatching = true;
00660
00661 unitedRegions = QRegion();
00662 int align = nRotation
00663 ? (Qt::AlignRight | Qt::AlignVCenter)
00664 : cv.textAlign;
00665 QPoint anchor(200,200);
00666 int iLeaveOut = 0;
00667 double iLabel=0.0;
00668 for ( QStringList::Iterator it = labelTexts->begin();
00669 it != labelTexts->end();
00670 ++it ) {
00671 iLabel += 1.0;
00672 if( iLeaveOut < nLeaveOut ) {
00673 ++iLeaveOut;
00674 } else {
00675 iLeaveOut = 0;
00676 anchor.setX( p2.x() + static_cast < int > ( pXDelta * (iLabel - 0.5) ) );
00677 anchor.setY( p2.y() + static_cast < int > ( pYDelta * (iLabel - 0.5) ) );
00678
00679
00680 anchor = painter->worldMatrix().map( anchor );
00681
00682 QString text;
00683 if( cv.isDateTime ){
00684 #if COMPAT_QT_VERSION >= 0x030000
00685 QDateTime dt( QDateTime::fromString( *it,
00686 Qt::ISODate ) );
00687 text = dt.toString( formatDT );
00688 #else
00689 QDateTime dt( dateTimeFromString( *it ) );
00690 text = dt.toString();
00691 #endif
00692 }else{
00693 text = *it;
00694 }
00695 KDDrawTextRegionAndTrueRect infosKDD =
00696 KDDrawText::measureRotatedText( painter,
00697 nRotation,
00698 anchor,
00699 text,
00700 0,
00701 align,
00702 &fm,
00703 false,
00704 false,
00705 15 );
00706 if( infosKDD.region.boundingRect().left()
00707 < params()->globalLeadingLeft()+1 ){
00708 textsMatching = false;
00709 textsDontFitIntoArea = true;
00710
00711 break;
00712 }
00713 else{
00714 QRegion sectReg( infosKDD.region.intersect( unitedRegions ) );
00715 if ( sectReg.isEmpty() )
00716 unitedRegions = unitedRegions.unite( infosKDD.region );
00717 else {
00718 textsMatching = false;
00719 textsOverlapping = true;
00720
00721 break;
00722 }
00723 }
00724 }
00725 }
00726
00727
00728
00729
00730 if( isHorizontalAxis ) {
00731 if( nUsableAxisHeight < unitedRegions.boundingRect().height() ){
00732 textsMatching = false;
00733 textsDontFitIntoArea = true;
00734
00735 }
00736 } else {
00737 if( nUsableAxisWidth < unitedRegions.boundingRect().width() ){
00738
00739 textsMatching = false;
00740 textsDontFitIntoArea = true;
00741
00742 }
00743
00744 }
00745
00746
00747
00748
00749
00750 if( !textsMatching ) {
00751 bool rotatingDoesNotHelp = false;
00752
00753
00754
00755
00756 if ( tryRotating ) {
00757
00758
00759
00760
00761 if( textsDontFitIntoArea ){
00762 if( nRotation != nInitialRotation ){
00763 textsDontFitIntoArea = false;
00764 nRotation = nInitialRotation;
00765 }
00766 rotatingDoesNotHelp = true;
00767 }
00768 else{
00769 if( nRotation ) {
00770 if( 270 < nRotation ) {
00771 nRotation -= 5;
00772 if( 270 > nRotation )
00773 nRotation = 270;
00774 } else {
00775 if( nInitialRotation )
00776 nRotation = nInitialRotation;
00777 else
00778 nRotation = 0;
00779 rotatingDoesNotHelp = true;
00780 }
00781 } else {
00782 if( nInitialRotation )
00783 nRotation = nInitialRotation;
00784 else
00785 nRotation = 350;
00786 }
00787 }
00788 }
00789 if ( !tryRotating || rotatingDoesNotHelp ) {
00790
00791
00792
00793
00794 if ( tryShrinking && (minTextHeight < cv.nTxtHeight) ) {
00795 cv.nTxtHeight -= 1.0;
00796 if ( minTextHeight > cv.nTxtHeight )
00797 cv.nTxtHeight = minTextHeight;
00798 } else {
00799
00800
00801
00802
00803 if( tryLeavingOut
00804 && textsOverlapping
00805 && (nLeaveOut+1 < static_cast < int > ( nLabels ) ) ) {
00806 ++iStepsLeaveOut;
00807
00808 nLeaveOut =
00809 iStepsLeaveOut*stepWidthLeaveOut - 1;
00810 if( tryShrinking )
00811 cv.nTxtHeight = nInitialTxtHeight;
00812 }
00813 else
00814 break;
00815 }
00816 if( tryShrinking ) {
00817 actFont.setPixelSize( static_cast < int > ( cv.nTxtHeight ) );
00818
00819 painter->setFont( actFont );
00820 fm = painter->fontMetrics();
00821 }
00822 }
00823 }
00824 } while( !textsMatching );
00825
00826 if( nRotation ){
00827
00828
00829
00830
00831
00832
00833 cv.textAlign = Qt::AlignRight | Qt::AlignVCenter;
00834
00835
00836
00837 double dx = (pXDelta / 2) - (cv.nTxtHeight / 4);
00838 double dy = (cv.nTxtHeight / 2.0);
00839 cv.pTextsX += dx;
00840 cv.pTextsY += dy;
00841 }
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856 }
00857
00858 painter->setFont( actFont );
00859 fm = QFontMetrics( painter->fontMetrics() );
00860
00861
00862 QPen gridPen, leaveOutGridPen;
00863 if( para.axisShowGrid() && !bMultiRowBarChart )
00864 gridPen.setColor( para.axisGridColor() );
00865
00866 const int pXDeltaDiv2 = static_cast < int > ( pXDelta / 2.0 );
00867 const int pYDeltaDiv2 = static_cast < int > ( pYDelta / 2.0 );
00868
00869 bool bDrawAdditionalSubGridLine = false;
00870 double pGXMicroAdjust = 0.0;
00871 double pGYMicroAdjust = 0.0;
00872 if ( !bTouchEdges ) {
00873
00874 p1.setX( p1.x() + pXDeltaDiv2 );
00875 p1.setY( p1.y() + pYDeltaDiv2 );
00876 p2.setX( p2.x() + pXDeltaDiv2 );
00877 p2.setY( p2.y() + pYDeltaDiv2 );
00878
00879 p2a.setX( p2a.x() + pXDeltaDiv2 );
00880 p2a.setY( p2a.y() + pYDeltaDiv2 );
00881
00882 bDrawAdditionalSubGridLine =
00883 isHorizontalAxis && !
00884 params()->axisParams(
00885 KDChartAxisParams::AxisPosRight ).axisVisible() &&
00886 !bMultiRowBarChart;
00887 pGA.setX( pGA.x() + pXDeltaDiv2 );
00888 pGA.setY( pGA.y() + pYDeltaDiv2 );
00889 pGZ.setX( pGZ.x() + pXDeltaDiv2 );
00890 pGZ.setY( pGZ.y() + pYDeltaDiv2 );
00891
00892 if( KDChartAxisParams::AxisTypeNORTH == para.axisType() ) {
00893 pGXMicroAdjust = cv.pXDeltaFactor * lineWidth / 2.0;
00894 pGYMicroAdjust = cv.pYDeltaFactor * lineWidth / 2.0;
00895 }
00896 }
00897 double x1, y1, x2, y2, xGA, yGA, xGZ, yGZ,
00898 p1X, p1Y, p2X, p2Y, pGAX, pGAY, pGZX, pGZY, xT, yT;
00899
00900 double pXSubDelimDelta = pXDelta * cv.nSubDelimFactor;
00901 double pYSubDelimDelta = pYDelta * cv.nSubDelimFactor;
00902
00903 if ( !cv.autoDtLabels
00904 && 0.0 != cv.nSubDelimFactor
00905 && para.axisShowSubDelimiters()
00906 && para.axisLabelsVisible()
00907 && !nLeaveOut ) {
00908 QPen pen( para.axisLineColor(), static_cast < int > ( 0.5 * lineWidth ) );
00909 uint penWidth = pen.width();
00910 bool bOk = true;
00911
00912 if( cv.bLogarithmic )
00913 cv.nSubDelimFactor = 0.1;
00914
00915 while ( fabs( ( pXDelta + pYDelta ) * cv.nSubDelimFactor / 6.0 )
00916 <= 1.0 + penWidth
00917 && bOk ) {
00918 if ( 0 < penWidth ) {
00919 --penWidth;
00920 pen.setWidth( penWidth );
00921 }else{
00922 if( cv.bLogarithmic ){
00923 break;
00924
00925 }else{
00926 if ( 0.5 != cv.nSubDelimFactor ) {
00927
00928 cv.nSubDelimFactor = 0.5;
00929
00930 pXSubDelimDelta = pXDelta * cv.nSubDelimFactor;
00931 pYSubDelimDelta = pYDelta * cv.nSubDelimFactor;
00932 } else
00933 bOk = false;
00934 }
00935 }
00936 }
00937 if ( bOk ) {
00938 x1 = p1.x();
00939 y1 = p1.y();
00940 x2 = p2a.x();
00941 y2 = p2a.y();
00942 xGA = pGA.x();
00943 yGA = pGA.y();
00944 xGZ = pGZ.x();
00945 yGZ = pGZ.y();
00946 p1X = x1;
00947 p1Y = y1;
00948 p2X = x2;
00949 p2Y = y2;
00950 pGAX = xGA;
00951 pGAY = yGA;
00952 pGZX = xGZ;
00953 pGZY = yGZ;
00954
00955
00956 const QPen oldGridPen( gridPen );
00957 if ( para.axisShowGrid() ) {
00958 gridPen.setColor( para.axisGridSubColor() );
00959 gridPen.setWidth( gridSubLineWidth );
00960 gridPen.setStyle( para.axisGridSubStyle() );
00961 }
00962 const QPen oldPen( painter->pen() );
00963 painter->setPen( pen );
00964 double nSubDelim = ( labelTexts->count() - 1 )
00965 / cv.nSubDelimFactor;
00966
00967
00968 modf( nSubDelim, &nSubDelim );
00969
00970 int logarithCnt = 1;
00971 double xLogarithOffs = 0;
00972 double yLogarithOffs = 0;
00973 double dDummy;
00974 double mainDelim = 0.0;
00975 bool paint = true;
00976
00977 for ( double iDelim = 1.0;
00978 iDelim <= nSubDelim + 1.0;
00979 iDelim += 1.0, logarithCnt++ ) {
00980
00981 if ( mainDelim > 0.0 )
00982 paint = true;
00983 else
00984 paint = false;
00985
00986 if ( cv.bLogarithmic )
00987 {
00988 if ( logarithCnt == 11 )
00989 {
00990 xLogarithOffs +=
00991 pXDelta * log10( 10*cv.nSubDelimFactor*10 );
00992 yLogarithOffs +=
00993 pYDelta * log10( 10*cv.nSubDelimFactor*10 );
00994 logarithCnt=1;
00995 }
00996
00997 pXSubDelimDelta =
00998 pXDelta * log10( 10*cv.nSubDelimFactor*logarithCnt );
00999 pYSubDelimDelta =
01000 pYDelta * log10( 10*cv.nSubDelimFactor*logarithCnt );
01001 }
01002
01003 if ( para.axisShowGrid() && !bMultiRowBarChart) {
01004
01005 if( 0.0 != modf((iDelim-1.0) * cv.nSubDelimFactor, &dDummy) )
01006
01007 saveDrawLine( *painter,
01008 QPoint( static_cast<int>( pGAX - pGXMicroAdjust ),
01009 static_cast<int>( pGAY - pGYMicroAdjust ) ),
01010 QPoint( static_cast<int>( pGZX - pGXMicroAdjust ),
01011 static_cast<int>( pGZY - pGYMicroAdjust ) ),
01012 gridPen );
01013
01014 if( cv.bLogarithmic ){
01015 pGAX = xGA + pXSubDelimDelta + xLogarithOffs;
01016 pGAY = yGA + pYSubDelimDelta + yLogarithOffs;
01017 pGZX = xGZ + pXSubDelimDelta + xLogarithOffs;
01018 pGZY = yGZ + pYSubDelimDelta + yLogarithOffs;
01019 }else{
01020 pGAX = xGA + iDelim * pXSubDelimDelta;
01021 pGAY = yGA + iDelim * pYSubDelimDelta;
01022 pGZX = xGZ + iDelim * pXSubDelimDelta;
01023 pGZY = yGZ + iDelim * pYSubDelimDelta;
01024
01025
01026
01027
01028
01029
01030
01031
01032 }
01033 }
01034
01035
01036
01037
01038
01039 if ( paint )
01040 painter->drawLine( QPoint( static_cast<int>( p1X ), static_cast<int>( p1Y ) ),
01041 QPoint( static_cast<int>( p2X ), static_cast<int>( p2Y ) ) );
01042
01043 mainDelim += 1.0;
01044
01045
01046 if( cv.bLogarithmic ){
01047 p1X = x1 + pXSubDelimDelta + xLogarithOffs;
01048 p1Y = y1 + pYSubDelimDelta + yLogarithOffs;
01049 p2X = x2 + pXSubDelimDelta + xLogarithOffs;
01050 p2Y = y2 + pYSubDelimDelta + yLogarithOffs;
01051 }else{
01052 p1X = x1 + iDelim * pXSubDelimDelta;
01053 p1Y = y1 + iDelim * pYSubDelimDelta;
01054 p2X = x2 + iDelim * pXSubDelimDelta;
01055 p2Y = y2 + iDelim * pYSubDelimDelta;
01056 }
01057
01058 if ( mainDelim >= nSubDelim/(labelTexts->count() -1) )
01059 mainDelim = 0.0;
01060
01061
01062 }
01063
01064 if( bDrawAdditionalSubGridLine
01065 && para.axisShowGrid() ) {
01066
01067 saveDrawLine( *painter,
01068 QPoint( static_cast<int>( pGAX - pGXMicroAdjust ),
01069 static_cast<int>( pGAY - pGYMicroAdjust ) ),
01070 QPoint( static_cast<int>( pGZX - pGXMicroAdjust ),
01071 static_cast<int>( pGZY - pGYMicroAdjust ) ),
01072 gridPen );
01073
01074 }
01075 painter->setPen( oldPen );
01076 gridPen = oldGridPen;
01077 }
01078 }
01079 x1 = p1.x();
01080 y1 = p1.y();
01081 x2 = p2.x();
01082 y2 = p2.y();
01083 xGA = pGA.x();
01084 yGA = pGA.y();
01085 xGZ = pGZ.x();
01086 yGZ = pGZ.y();
01087 p1X = x1;
01088 p1Y = y1;
01089 p2X = x2;
01090 p2Y = y2;
01091 pGAX = xGA;
01092 pGAY = yGA;
01093 pGZX = xGZ;
01094 pGZY = yGZ;
01095 xT = cv.pTextsX;
01096 yT = cv.pTextsY;
01097
01098 if ( para.axisShowGrid() ) {
01099 gridPen.setWidth( gridLineWidth );
01100 gridPen.setStyle( para.axisGridStyle() );
01101
01102 if( !para.axisLineVisible() )
01103 saveDrawLine( *painter, cv.orig, cv.dest, gridPen );
01104 }
01105 if( nLeaveOut ) {
01106 leaveOutGridPen = gridPen;
01107 leaveOutGridPen.setWidth( gridLineWidth / 2 );
01108 leaveOutGridPen.setStyle( Qt::DotLine );
01109 }
01110
01111
01112
01113
01114 double iLabel = 0.0;
01115 if( cv.autoDtLabels )
01116 {
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133 int pXD = static_cast <int> (cv.pXDelimDeltaFaktor * 1.25 * (cv.nTxtHeight+4));
01134 int pYD = static_cast <int> (cv.pYDelimDeltaFaktor * 1.25 * (cv.nTxtHeight+4));
01135 int orgXD = pXD;
01136 int orgYD = pYD;
01137 cv.pTextsW = fabs( (0.0 == pXDelta) ? pXD : pXDelta );
01138 cv.pTextsH = fabs( (0.0 == pYDelta) ? pYD : pYDelta );
01139
01140 double pSecX = x1;
01141 double pSecY = y1;
01142 bool secPaint= false;
01143 double pMinX = x1;
01144 double pMinY = y1;
01145 bool minPaint= false;
01146 double pHourX = x1;
01147 double pHourY = y1;
01148 bool hourPaint= false;
01149 double pDayX = x1;
01150 double pDayY = y1;
01151 bool dayPaint= false;
01152
01153
01154
01155
01156
01157 double pMonthX = x1;
01158 double pMonthY = y1;
01159 bool monthPaint= false;
01160
01161
01162
01163
01164 double pYearX = x1;
01165 double pYearY = y1;
01166 bool yearPaint= false;
01167
01168 double pXYDelta = fabs( pXDelta ) + fabs( pYDelta );
01169
01170 if( 0.0 == para.trueAxisDeltaPixels() )
01171 ( ( KDChartAxisParams& ) para ).setTrueAxisDeltaPixels( QMIN(_logicalWidth, _logicalHeight) / 150 );
01172
01173 bool dtGoDown = cv.dtLow > cv.dtHigh;
01174 int mult = dtGoDown ? -1 : 1;
01175 const QDateTime& startDt = dtGoDown ? cv.dtHigh : cv.dtLow;
01176
01177 ( ( KDChartAxisParams& ) para ).setAxisDtLowPos( x1, y1 );
01178
01179 ( ( KDChartAxisParams& ) para ).setTrueAxisDtLow( startDt );
01180 ( ( KDChartAxisParams& ) para ).setTrueAxisDtScale( cv.dtDeltaScale );
01181
01182 int gridDX = pGZ.x() - pGA.x();
01183 int gridDY = pGZ.y() - pGA.y();
01184 if ( para.axisShowGrid() ) {
01185 gridPen.setColor( para.axisGridColor() );
01186 gridPen.setWidth( gridLineWidth );
01187 gridPen.setStyle( para.axisGridStyle() );
01188 }
01189 QPen subGridPen( gridPen.color(), 1, para.axisGridStyle() );
01190 QPen subSubGridPen( gridPen.color(), 1, para.axisGridSubStyle() );
01191 QPen pen = subGridPen;
01192
01193 QDateTime dt( startDt );
01194 QDateTime newDt( startDt );
01195 for( uint i=1; i <= nLabels; ++i ){
01196 switch( cv.dtDeltaScale ) {
01197 case KDChartAxisParams::ValueScaleSecond:
01198 dtAddSecs( dt, 1 * mult, newDt );
01199 break;
01200 case KDChartAxisParams::ValueScaleMinute:
01201 dtAddSecs( dt, 60 * mult, newDt );
01202 break;
01203 case KDChartAxisParams::ValueScaleHour:
01204 dtAddSecs( dt, 3600 * mult, newDt );
01205 break;
01206 case KDChartAxisParams::ValueScaleDay:
01207 dtAddDays( dt, 1 * mult, newDt );
01208 break;
01209 case KDChartAxisParams::ValueScaleWeek:
01210 dtAddDays( dt, 7 * mult, newDt );
01211 break;
01212 case KDChartAxisParams::ValueScaleMonth:
01213 dtAddMonths( dt,1 * mult, newDt );
01214 break;
01215 case KDChartAxisParams::ValueScaleQuarter:
01216 dtAddMonths( dt,3 * mult, newDt );
01217 break;
01218 case KDChartAxisParams::ValueScaleYear:
01219 dtAddYears( dt, 1 * mult, newDt );
01220 break;
01221 default:
01222 dtAddDays( dt, 1 * mult, newDt );
01223 break;
01224 }
01225 const QDateTime& testDt
01226 = dtGoDown
01227 ? ( ( newDt < cv.dtLow )
01228 ? cv.dtLow
01229 : newDt )
01230 : ( ( newDt > cv.dtHigh )
01231 ? cv.dtHigh
01232 : newDt );
01233
01234
01235
01236
01237
01238
01239
01240
01241 bool endLoop = (i == nLabels) || (&testDt != &newDt);
01242
01243 secPaint = ( KDChartAxisParams::ValueScaleSecond >= cv.dtDeltaScale ) &&
01244 ( testDt.time().second() != dt.time().second() ||
01245 ( endLoop && ((pSecX != x1) || (pSecY != y1))));
01246 minPaint = ( KDChartAxisParams::ValueScaleMinute >= cv.dtDeltaScale ) &&
01247 ( testDt.time().minute() != dt.time().minute() ||
01248 ( endLoop && ((pMinX != x1) || (pMinY != y1))));
01249 hourPaint = ( KDChartAxisParams::ValueScaleHour >= cv.dtDeltaScale ) &&
01250 ( testDt.time().hour() != dt.time().hour() ||
01251 ( endLoop && ((pHourX != x1) || (pHourY != y1))));
01252 dayPaint = ( KDChartAxisParams::ValueScaleDay >= cv.dtDeltaScale ) &&
01253 ( testDt.date().day() != dt.date().day() ||
01254 ( endLoop && ((pDayX != x1) || (pDayY != y1))));
01255
01256
01257
01258
01259
01260 monthPaint = ( KDChartAxisParams::ValueScaleMonth >= cv.dtDeltaScale ) &&
01261 ( testDt.date().month() != dt.date().month() ||
01262 ( endLoop && ((pMonthX != x1) || (pMonthY != y1))));
01263 yearPaint = ( KDChartAxisParams::ValueScaleYear >= cv.dtDeltaScale ) &&
01264 ( testDt.date().year() != dt.date().year() ||
01265 ( endLoop && ((pYearX != x1) || (pYearY != y1))));
01266
01267 p1X = x1 + iLabel * pXDelta;
01268 p1Y = y1 + iLabel * pYDelta;
01269 p2X = p1X + pXDelta;
01270 p2Y = p1Y + pYDelta;
01271 pXD = orgXD;
01272 pYD = orgYD;
01273
01274 if( endLoop ){
01275 ( ( KDChartAxisParams& ) para ).setAxisDtHighPos( p1X, p1Y );
01276
01277 ( ( KDChartAxisParams& ) para ).setTrueAxisDtHigh( dt );
01278 }
01279 pen = subGridPen;
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296 if( secPaint ){
01297 painter->drawLine( QPoint( static_cast<int>( pSecX+pXD ),
01298 static_cast<int>( pSecY+pYD ) ),
01299 QPoint( static_cast<int>( p2X + pXD ),
01300 static_cast<int>( p2Y + pYD ) ) );
01301 if( (pXDelta/2.0 < p2X - pSecX) || (pYDelta/2.0 < p2Y - pSecY) ){
01302 QPen oldPen( painter->pen() );
01303 painter->setPen( QPen( labelsColor ) );
01304 painter->drawText( static_cast<int>( pSecX+pXD-orgXD ),
01305 static_cast<int>( pSecY+pYD-orgYD ),
01306 static_cast<int>( fabs((0.0 == pXDelta) ? cv.pTextsW : (p2X - pSecX))),
01307 static_cast<int>( fabs((0.0 == pYDelta) ? cv.pTextsH : (p2Y - pSecY))),
01308 cv.textAlign | Qt::DontClip,
01309 QString::number( dt.time().second() ) );
01310 painter->setPen( oldPen );
01311 if ( para.axisShowGrid() ){
01312
01313 saveDrawLine( *painter,
01314 QPoint( static_cast<int>( pSecX ),
01315 static_cast<int>( pSecY ) ),
01316 QPoint( static_cast<int>( pSecX + gridDX ),
01317 static_cast<int>( pSecY + gridDY ) ),
01318 pen );
01319 pen = gridPen;
01320 }
01321 if( !minPaint || pMinX != pSecX || pMinY != pSecY ){
01322 painter->drawLine( QPoint( static_cast<int>( pSecX ),
01323 static_cast<int>( pSecY ) ),
01324 QPoint( static_cast<int>( pSecX+pXD ),
01325 static_cast<int>( pSecY+pYD ) ) );
01326 }
01327 }
01328 if( endLoop && !minPaint )
01329 painter->drawLine( QPoint( static_cast<int>( p2X ),
01330 static_cast<int>( p2Y ) ),
01331 QPoint( static_cast<int>( p2X+pXD ),
01332 static_cast<int>( p2Y+pYD ) ) );
01333 pSecX = p1X + pXDelta;
01334 pSecY = p1Y + pYDelta;
01335 pXD += orgXD;
01336 pYD += orgYD;
01337 }
01338 if( minPaint ){
01339 painter->drawLine( QPoint( static_cast<int>( pMinX+pXD ),
01340 static_cast<int>( pMinY+pYD ) ),
01341 QPoint( static_cast<int>( p2X + pXD ),
01342 static_cast<int>( p2Y + pYD ) ) );
01343 if( (pXDelta/2.0 < p2X - pMinX) || (pYDelta/2.0 < p2Y - pMinY) ){
01344 QPen oldPen( painter->pen() );
01345 painter->setPen( QPen( labelsColor ) );
01346 painter->drawText( static_cast<int>( pMinX+pXD-orgXD ),
01347 static_cast<int>( pMinY+pYD-orgYD ),
01348 static_cast<int>( fabs((0.0 == pXDelta) ? cv.pTextsW : (p2X - pMinX)) ),
01349 static_cast<int>( fabs((0.0 == pYDelta) ? cv.pTextsH : (p2Y - pMinY)) ),
01350 cv.textAlign | Qt::DontClip,
01351 QString::number( dt.time().minute() ) );
01352 painter->setPen( oldPen );
01353 if ( para.axisShowGrid() ){
01354 if( !secPaint && 10 < pXYDelta ){
01355 saveDrawLine( *painter,
01356 QPoint( static_cast<int>( pMinX+pXDelta/2 ),
01357 static_cast<int>( pMinY+pYDelta/2 ) ),
01358 QPoint( static_cast<int>( pMinX+pXDelta/2 + gridDX ),
01359 static_cast<int>( pMinY+pYDelta/2 + gridDY ) ),
01360 subSubGridPen );
01361 }
01362 saveDrawLine( *painter,
01363 QPoint( static_cast<int>( pMinX ),
01364 static_cast<int>( pMinY ) ),
01365 QPoint( static_cast<int>( pMinX + gridDX ),
01366 static_cast<int>( pMinY + gridDY ) ),
01367 pen );
01368 pen = gridPen;
01369 }
01370 if( !hourPaint || pHourX != pMinX || pHourY != pMinY ){
01371 painter->drawLine( QPoint( static_cast<int>( pMinX ),
01372 static_cast<int>( pMinY ) ),
01373 QPoint( static_cast<int>( pMinX+pXD ),
01374 static_cast<int>( pMinY+pYD ) ) );
01375 }
01376 }
01377 if( endLoop && !hourPaint )
01378 painter->drawLine( QPoint( static_cast<int>( p2X ),
01379 static_cast<int>( p2Y ) ),
01380 QPoint( static_cast<int>( p2X+pXD ),
01381 static_cast<int>( p2Y+pYD ) ) );
01382 pMinX = p1X + pXDelta;
01383 pMinY = p1Y + pYDelta;
01384 pXD += orgXD;
01385 pYD += orgYD;
01386 }
01387 if( hourPaint ){
01388 painter->drawLine( QPoint( static_cast<int>( pHourX+pXD ),
01389 static_cast<int>( pHourY+pYD ) ),
01390 QPoint( static_cast<int>( p2X + pXD ),
01391 static_cast<int>( p2Y + pYD ) ) );
01392
01393
01394
01395
01396
01397 if( (pXDelta/2.0 < p2X - pHourX) || (pYDelta/2.0 < p2Y - pHourY) ){
01398
01399
01400
01401
01402
01403
01404
01405
01406 QPen oldPen( painter->pen() );
01407 painter->setPen( QPen( labelsColor ) );
01408 painter->drawText( static_cast<int>( pHourX+pXD-orgXD ),
01409 static_cast<int>( pHourY+pYD-orgYD ),
01410 static_cast<int>( fabs((0.0 == pXDelta) ? cv.pTextsW : (p2X - pHourX))),
01411 static_cast<int>( fabs((0.0 == pYDelta) ? cv.pTextsH : (p2Y - pHourY))),
01412 cv.textAlign | Qt::DontClip,
01413 QString::number( dt.time().hour() ) );
01414 painter->setPen( oldPen );
01415 if ( para.axisShowGrid() ){
01416 if( !minPaint && 10 < pXYDelta ){
01417 saveDrawLine( *painter,
01418 QPoint( static_cast<int>( pHourX+pXDelta/2 ),
01419 static_cast<int>( pHourY+pYDelta/2 ) ),
01420 QPoint( static_cast<int>( pHourX+pXDelta/2 + gridDX ),
01421 static_cast<int>( pHourY+pYDelta/2 + gridDY ) ),
01422 subSubGridPen );
01423 }
01424 saveDrawLine( *painter,
01425 QPoint( static_cast<int>( pHourX ),
01426 static_cast<int>( pHourY ) ),
01427 QPoint( static_cast<int>( pHourX + gridDX ),
01428 static_cast<int>( pHourY + gridDY ) ),
01429 pen );
01430 pen = gridPen;
01431 }
01432 if( !dayPaint || pDayX != pHourX || pDayY != pHourY ){
01433 painter->drawLine( QPoint( static_cast<int>( pHourX ),
01434 static_cast<int>( pHourY ) ),
01435 QPoint( static_cast<int>( pHourX+pXD ),
01436 static_cast<int>( pHourY+pYD ) ) );
01437 }
01438 }
01439 if( endLoop && !dayPaint )
01440 painter->drawLine( QPoint( static_cast<int>( p2X ),
01441 static_cast<int>( p2Y ) ),
01442 QPoint( static_cast<int>( p2X+pXD ),
01443 static_cast<int>( p2Y+pYD ) ) );
01444 pHourX = p1X + pXDelta;
01445 pHourY = p1Y + pYDelta;
01446 pXD += orgXD;
01447 pYD += orgYD;
01448 }
01449 if( dayPaint ){
01450 painter->drawLine( QPoint( static_cast<int>( pDayX+pXD ),
01451 static_cast<int>( pDayY+pYD ) ),
01452 QPoint( static_cast<int>( p2X + pXD ),
01453 static_cast<int>( p2Y + pYD ) ) );
01454 if( (pXDelta/2.0 < p2X - pDayX) || (pYDelta/2.0 < p2Y - pDayY) ){
01455 QPen oldPen( painter->pen() );
01456 painter->setPen( QPen( labelsColor ) );
01457 painter->drawText( static_cast<int>( pDayX+pXD-orgXD ),
01458 static_cast<int>( pDayY+pYD-orgYD ),
01459 static_cast<int>( fabs((0.0 == pXDelta) ? cv.pTextsW : (p2X - pDayX)) ),
01460 static_cast<int>( fabs((0.0 == pYDelta) ? cv.pTextsH : (p2Y - pDayY)) ),
01461 cv.textAlign | Qt::DontClip,
01462 QString::number( dt.date().day() ) );
01463 painter->setPen( oldPen );
01464
01465
01466
01467 if ( para.axisShowGrid() ){
01468 if( !hourPaint && 10 < pXYDelta ){
01469 saveDrawLine( *painter,
01470 QPoint( static_cast<int>( pDayX+pXDelta/2 ),
01471 static_cast<int>( pDayY+pYDelta/2 ) ),
01472 QPoint( static_cast<int>( pDayX+pXDelta/2 + gridDX ),
01473 static_cast<int>( pDayY+pYDelta/2 + gridDY ) ),
01474 subSubGridPen );
01475 }
01476 saveDrawLine( *painter,
01477 QPoint( static_cast<int>( pDayX ),
01478 static_cast<int>( pDayY ) ),
01479 QPoint( static_cast<int>( pDayX + gridDX ),
01480 static_cast<int>( pDayY + gridDY ) ),
01481 pen );
01482 pen = gridPen;
01483 }
01484 if( !monthPaint || pMonthX != pDayX || pMonthY != pDayY ){
01485 painter->drawLine( QPoint( static_cast<int>( pDayX ),
01486 static_cast<int>( pDayY ) ),
01487 QPoint( static_cast<int>( pDayX+pXD ),
01488 static_cast<int>( pDayY+pYD ) ) );
01489 }
01490 }
01491
01492
01493
01494 if( endLoop && !monthPaint )
01495 painter->drawLine( QPoint( static_cast<int>( p2X ),
01496 static_cast<int>( p2Y ) ),
01497 QPoint( static_cast<int>( p2X+pXD ),
01498 static_cast<int>( p2Y+pYD ) ) );
01499 pDayX = p1X + pXDelta;
01500 pDayY = p1Y + pYDelta;
01501 pXD += orgXD;
01502 pYD += orgYD;
01503 }
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547 if( monthPaint ){
01548 painter->drawLine( QPoint( static_cast<int>( pMonthX+pXD ),
01549 static_cast<int>( pMonthY+pYD ) ),
01550 QPoint( static_cast<int>( p2X + pXD ),
01551 static_cast<int>( p2Y + pYD ) ) );
01552 if( (pXDelta/2.0 < p2X - pMonthX) || (pYDelta/2.0 < p2Y - pMonthY) ){
01553 QPen oldPen( painter->pen() );
01554 painter->setPen( QPen( labelsColor ) );
01555 painter->drawText( static_cast<int>( pMonthX+pXD-orgXD ),
01556 static_cast<int>( pMonthY+pYD-orgYD ),
01557 static_cast<int>( fabs((0.0 == pXDelta) ? cv.pTextsW : (p2X - pMonthX)) ),
01558 static_cast<int>( fabs((0.0 == pYDelta) ? cv.pTextsH : (p2Y - pMonthY)) ),
01559 cv.textAlign | Qt::DontClip,
01560 QString::number( dt.date().month() ) );
01561 painter->setPen( oldPen );
01562 if ( para.axisShowGrid() ){
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574 saveDrawLine( *painter,
01575 QPoint( static_cast<int>( pMonthX ),
01576 static_cast<int>( pMonthY ) ),
01577 QPoint( static_cast<int>( pMonthX + gridDX ),
01578 static_cast<int>( pMonthY + gridDY ) ),
01579 pen );
01580 pen = gridPen;
01581 }
01582 if( !yearPaint || pYearX != pMonthX || pYearY != pMonthY ){
01583 painter->drawLine( QPoint( static_cast<int>( pMonthX ),
01584 static_cast<int>( pMonthY ) ),
01585 QPoint( static_cast<int>( pMonthX+pXD ),
01586 static_cast<int>( pMonthY+pYD ) ) );
01587 }
01588 }
01589 if( endLoop && !yearPaint )
01590 painter->drawLine( QPoint( static_cast<int>( p2X ),
01591 static_cast<int>( p2Y ) ),
01592 QPoint( static_cast<int>( p2X+pXD ),
01593 static_cast<int>( p2Y+pYD ) ) );
01594 pMonthX = p1X + pXDelta;
01595 pMonthY = p1Y + pYDelta;
01596 pXD += orgXD;
01597 pYD += orgYD;
01598 }
01599 if( yearPaint ){
01600 painter->drawLine( QPoint( static_cast<int>( pYearX+pXD ),
01601 static_cast<int>( pYearY+pYD ) ),
01602 QPoint( static_cast<int>( p2X + pXD ),
01603 static_cast<int>( p2Y + pYD ) ) );
01604 if( (pXDelta/2.0 < p2X - pYearX) || (pYDelta/2.0 < p2Y - pYearY) ){
01605 QPen oldPen( painter->pen() );
01606 painter->setPen( QPen( labelsColor ) );
01607 painter->drawText( static_cast<int>( pYearX+pXD-orgXD ),
01608 static_cast<int>( pYearY+pYD-orgYD ),
01609 static_cast<int>( fabs((0.0 == pXDelta) ? cv.pTextsW : (p2X - pYearX)) ),
01610 static_cast<int>( fabs((0.0 == pYDelta) ? cv.pTextsH : (p2Y - pYearY)) ),
01611 cv.textAlign | Qt::DontClip,
01612 QString::number( dt.date().year() ) );
01613 painter->setPen( oldPen );
01614 if ( para.axisShowGrid() ){
01615 if( !monthPaint && 10 < pXYDelta ){
01616 saveDrawLine( *painter,
01617 QPoint( static_cast<int>( pYearX+pXDelta/2 ),
01618 static_cast<int>( pYearY+pYDelta/2 ) ),
01619 QPoint( static_cast<int>( pYearX+pXDelta/2 + gridDX ),
01620 static_cast<int>( pYearY+pYDelta/2 + gridDY ) ),
01621 subSubGridPen );
01622 }
01623 saveDrawLine( *painter,
01624 QPoint( static_cast<int>( pYearX ),
01625 static_cast<int>( pYearY ) ),
01626 QPoint( static_cast<int>( pYearX + gridDX ),
01627 static_cast<int>( pYearY + gridDY ) ),
01628 pen );
01629 pen = gridPen;
01630 }
01631 painter->drawLine( QPoint( static_cast<int>( pYearX ),
01632 static_cast<int>( pYearY ) ),
01633 QPoint( static_cast<int>( pYearX+pXD ),
01634 static_cast<int>( pYearY+pYD ) ) );
01635 }
01636 if( endLoop )
01637 painter->drawLine( QPoint( static_cast<int>( p2X ),
01638 static_cast<int>( p2Y ) ),
01639 QPoint( static_cast<int>( p2X+pXD ),
01640 static_cast<int>( p2Y+pYD ) ) );
01641 pYearX = p1X + pXDelta;
01642 pYearY = p1Y + pYDelta;
01643 pXD += orgXD;
01644 pYD += orgYD;
01645 }
01646 if( &testDt != &newDt )
01647 break;
01648 dt = newDt;
01649 iLabel += 1.0;
01650 }
01651 if( !commonDtHeader.isEmpty() ){
01652 QPen oldPen( painter->pen() );
01653 painter->setPen( QPen( labelsColor ) );
01654 painter->drawText( static_cast<int>( x1 + pXD ), static_cast<int>( y1 + pYD ),
01655 commonDtHeader );
01656 painter->setPen( oldPen );
01657 }
01658 }else{
01659 int iLeaveOut = nLeaveOut;
01660 QString label;
01661 for ( QStringList::Iterator labelIter = labelTexts->begin();
01662 labelIter != labelTexts->end();
01663 ++labelIter ) {
01664 QDateTime dt;
01665 if( cv.isDateTime ){
01666 #if COMPAT_QT_VERSION >= 0x030000
01667 dt = QDateTime::fromString( *labelIter,
01668 Qt::ISODate );
01669 label = dt.toString( formatDT );
01670 #else
01671 dt = dateTimeFromString( *labelIter );
01672 label = dt.toString();
01673 #endif
01674 }else{
01675 label = *labelIter;
01676 }
01677
01678 if( iLeaveOut < nLeaveOut )
01679 ++iLeaveOut;
01680 else
01681 iLeaveOut = 0;
01682
01683
01684
01685
01686 bool showDelim = para.axisShowFractionalValuesDelimiters();
01687 if ( para.axisShowGrid() && !bMultiRowBarChart ) {
01688 if ( !label.isNull() || showDelim ){
01689 if( !iLeaveOut )
01690
01691
01692 saveDrawLine( *painter,
01693 QPoint( static_cast<int>( pGAX - pGXMicroAdjust ),
01694 static_cast<int>( pGAY - pGYMicroAdjust ) ),
01695 QPoint( static_cast<int>( pGZX - pGXMicroAdjust ),
01696 static_cast<int>( pGZY - pGYMicroAdjust ) ),
01697 gridPen );
01698
01699 else if( para.axisShowSubDelimiters() )
01700
01701 saveDrawLine( *painter,
01702 QPoint( static_cast<int>( pGAX - pGXMicroAdjust ),
01703 static_cast<int>( pGAY - pGYMicroAdjust ) ),
01704 QPoint( static_cast<int>( pGZX - pGXMicroAdjust ),
01705 static_cast<int>( pGZY - pGYMicroAdjust ) ),
01706 leaveOutGridPen );
01707 }
01708 }
01709 if ( para.axisLabelsVisible() ) {
01710 if( !iLeaveOut ) {
01711
01712
01713
01714
01715
01716
01717 if ( !label.isNull() || showDelim )
01718 painter->drawLine( QPoint( static_cast<int>( p1X ),
01719 static_cast<int>( p1Y ) ),
01720 QPoint( static_cast<int>( p2X ),
01721 static_cast<int>( p2Y ) ) );
01722
01723 cv.pLastX = p1X;
01724 cv.pLastY = p1Y;
01725 QPen oldPen( painter->pen() );
01726 painter->setPen( QPen( labelsColor ) );
01727 if( para.axisLabelsDontShrinkFont()
01728 && isHorizontalAxis
01729 && (Qt::AlignHCenter == (cv.textAlign & Qt::AlignHCenter)) ) {
01730 double w = fm.width( label ) + 4.0;
01731 double x0 = cv.pTextsX + cv.pTextsW / 2.0;
01732
01733 painter->drawText( static_cast<int>( x0 - w / 2.0 ),
01734 static_cast<int>( cv.pTextsY ),
01735 static_cast<int>( w ),
01736 static_cast<int>( cv.pTextsH ),
01737 cv.textAlign, label );
01738 } else {
01739 if( nRotation ){
01740 KDDrawText::drawRotatedText(
01741 painter,
01742 nRotation,
01743 painter->worldMatrix().map(
01744 QPoint( static_cast<int>( cv.pTextsX ),
01745 static_cast<int>( cv.pTextsY ) ) ),
01746 label,
01747 0,
01748 cv.textAlign,
01749 false,
01750 &fm,
01751 screenOutput,screenOutput,0,
01752 screenOutput );
01753 } else {
01754
01755 painter->drawText( static_cast<int>( cv.pTextsX ),
01756 static_cast<int>( cv.pTextsY ),
01757 static_cast<int>( cv.pTextsW ),
01758 static_cast<int>( cv.pTextsH ),
01759 cv.textAlign | Qt::DontClip,
01760 label );
01761
01762
01763
01764
01765
01766
01767
01768
01769 }
01770 }
01771 painter->setPen( oldPen );
01772 }
01773 }
01774
01775
01776 if( cv.isDateTime ){
01777 if( labelTexts->begin() == labelIter ){
01778 ((KDChartAxisParams&)para).setAxisDtLowPos(
01779 pGAX - pGXMicroAdjust,
01780 pGAY - pGYMicroAdjust );
01781
01782 ( ( KDChartAxisParams& ) para ).setTrueAxisDtLow( dt );
01783 }else{
01784 ((KDChartAxisParams&)para).setAxisDtHighPos(
01785 pGAX - pGXMicroAdjust,
01786 pGAY - pGYMicroAdjust );
01787
01788 ( ( KDChartAxisParams& ) para ).setTrueAxisDtHigh( dt );
01789 }
01790 }
01791
01792 iLabel += 1.0;
01793 p1X = x1 + iLabel * pXDelta;
01794 p1Y = y1 + iLabel * pYDelta;
01795 p2X = x2 + iLabel * pXDelta;
01796 p2Y = y2 + iLabel * pYDelta;
01797 cv.pTextsX = xT + iLabel * pXDelta;
01798 cv.pTextsY = yT + iLabel * pYDelta;
01799
01800 pGAX = xGA + iLabel * pXDelta;
01801 pGAY = yGA + iLabel * pYDelta;
01802 pGZX = xGZ + iLabel * pXDelta;
01803 pGZY = yGZ + iLabel * pYDelta;
01804
01805
01806
01807
01808
01809
01810 }
01811 }
01812
01813
01814
01815 if ( cv.bSteadyCalc &&
01816 ( para.axisValuesDecreasing() ||
01817 (0.0 != para.trueAxisLow()) ) ) {
01818 double x = p1.x();
01819 double y = p1.y();
01820 double mult = para.trueAxisLow() / para.trueAxisDelta();
01821 x -= mult * pXDelta;
01822 y -= mult * pYDelta;
01823 axisZeroLineStartX = x;
01824 axisZeroLineStartY = y;
01825
01826
01827 }
01828
01829 painter->setClipping( oldClippingFlag );
01830 }
01831
01832
01833
01834
01835
01836 if ( cv.bSteadyCalc && !cv.isDateTime ) {
01837 ( ( KDChartAxisParams& ) para ).setAxisZeroLineStart( axisZeroLineStartX, axisZeroLineStartY );
01838 double axisZeroLineStart;
01839 int minCoord, maxCoord;
01840 double xFactor, yFactor;
01841 switch( cv.basicPos ){
01842 case KDChartAxisParams::AxisPosLeft:
01843 xFactor = 1.0;
01844 yFactor = 0.0;
01845 axisZeroLineStart = axisZeroLineStartY;
01846 minCoord = QMIN( cv.orig.y(), cv.dest.y() );
01847 maxCoord = QMAX( cv.orig.y(), cv.dest.y() );
01848
01849 break;
01850 case KDChartAxisParams::AxisPosRight:
01851 xFactor = -1.0;
01852 yFactor = 0.0;
01853 axisZeroLineStart = axisZeroLineStartY;
01854 minCoord = QMIN( cv.orig.y(), cv.dest.y() );
01855 maxCoord = QMAX( cv.orig.y(), cv.dest.y() );
01856 break;
01857 case KDChartAxisParams::AxisPosTop:
01858 xFactor = 0.0;
01859 yFactor = 1.0;
01860 axisZeroLineStart = axisZeroLineStartX;
01861 minCoord = QMIN( cv.orig.x(), cv.dest.x() );
01862 maxCoord = QMAX( cv.orig.x(), cv.dest.x() );
01863 break;
01864 case KDChartAxisParams::AxisPosBottom:
01865 xFactor = 0.0;
01866 yFactor = -1.0;
01867 axisZeroLineStart = axisZeroLineStartX;
01868 minCoord = QMIN( cv.orig.x(), cv.dest.x() );
01869 maxCoord = QMAX( cv.orig.x(), cv.dest.x() );
01870 break;
01871 default:
01872 xFactor = 0.0;
01873 yFactor = 0.0;
01874 axisZeroLineStart = 0.0;
01875 minCoord = 0;
01876 maxCoord = 0;
01877 }
01878 if( axisZeroLineStart >= minCoord &&
01879 axisZeroLineStart <= maxCoord ){
01880 QPoint pZ0( static_cast<int>( para.axisZeroLineStartX() ),
01881 static_cast<int>( para.axisZeroLineStartY() ) );
01882 QPoint pZ( static_cast<int>( para.axisZeroLineStartX()
01883 + xFactor * _dataRect.width() ),
01884 static_cast<int>( para.axisZeroLineStartY()
01885 + yFactor * _dataRect.height() ) );
01886
01887 saveDrawLine( *painter,
01888 pZ0,
01889 pZ,
01890 QPen( para.axisZeroLineColor(),
01891 lineWidth ) );
01892 }
01893 }
01894
01895 }
01896
01897 }
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930 for( iAxis = 0; iAxis < KDCHART_MAX_AXES; ++iAxis ){
01931 internal__KDChart__CalcValues& cv = calcVal[iAxis];
01932 const KDChartAxisParams & para = params()->axisParams( iAxis );
01933 if( cv.processThisAxis && para.axisLineVisible() ){
01934 painter->setPen( QPen( para.axisLineColor(),
01935 para.axisTrueLineWidth() ) );
01936 int x = cv.dest.x();
01937 if( 2.0 >= QABS(cv.pLastX - x) )
01938 x = static_cast < int > ( cv.pLastX );
01939 int y = cv.dest.y();
01940 if( 2.0 >= QABS(cv.pLastY - y) )
01941 y = static_cast < int > ( cv.pLastY );
01942 painter->drawLine( cv.orig, QPoint(x,y) );
01943 }
01944 }
01945
01946 painter->restore();
01947 }
01948
01949
01950 double fastPow10( int x )
01951 {
01952 double res = 1.0;
01953 if( 0 <= x ){
01954 for( int i = 1; i <= x; ++i )
01955 res *= 10.0;
01956 }else{
01957 for( int i = -1; i >= x; --i )
01958 res /= 10.0;
01959 }
01960 return res;
01961 }
01962 double fastPow10( double x )
01963 {
01964 return pow(10.0, x);
01965 }
01966
01967
01987
01988 void KDChartAxesPainter::calculateLabelTexts(
01989 QPainter* painter,
01990 const KDChartTableDataBase& data,
01991 const KDChartParams& params,
01992 uint axisNumber,
01993 double averageValueP1000,
01994 double delimLen,
01995
01996 KDChartAxisParams::AxisPos& basicPos,
01997 QPoint& orig,
01998 QPoint& dest,
01999 double& pXDeltaFactor,
02000 double& pYDeltaFactor,
02001 double& pXDelimDeltaFaktor,
02002 double& pYDelimDeltaFaktor,
02003 double& nSubDelimFactor,
02004 double& pDelimDelta,
02005 double& nTxtHeight,
02006 double& pTextsX,
02007 double& pTextsY,
02008 double& pTextsW,
02009 double& pTextsH,
02010 int& textAlign,
02011 bool& isLogarithmic,
02012 bool& isDateTime,
02013 bool& autoDtLabels,
02014 QDateTime& dtLow,
02015 QDateTime& dtHigh,
02016 KDChartAxisParams::ValueScale& dtDeltaScale,
02017 bool adjustTheValues,
02018 double trueDelta,
02019 double trueDeltaPix )
02020 {
02021
02022 const KDChartAxisParams & para = params.axisParams( axisNumber );
02023
02024
02025 const bool bDecreasing = para.axisValuesDecreasing();
02026
02027 basicPos = KDChartAxisParams::basicAxisPos( axisNumber );
02028
02029 pXDeltaFactor = 0.0;
02030 pYDeltaFactor = 0.0;
02031 pXDelimDeltaFaktor = 0.0;
02032 pYDelimDeltaFaktor = 0.0;
02033 int axisLength;
02034 switch ( basicPos ) {
02035 case KDChartAxisParams::AxisPosBottom: {
02036 axisLength = para.axisTrueAreaRect().width();
02037 orig = bDecreasing
02038 ? para.axisTrueAreaRect().topRight()
02039 : para.axisTrueAreaRect().topLeft();
02040 dest = bDecreasing
02041 ? para.axisTrueAreaRect().topLeft()
02042 : para.axisTrueAreaRect().topRight();
02043 pYDelimDeltaFaktor = 1.0;
02044 pXDeltaFactor = bDecreasing ? -1.0 : 1.0;
02045
02046
02047
02048 }
02049 break;
02050 case KDChartAxisParams::AxisPosLeft: {
02051 axisLength = para.axisTrueAreaRect().height();
02052 orig = bDecreasing
02053 ? para.axisTrueAreaRect().topRight()
02054 : para.axisTrueAreaRect().bottomRight();
02055 dest = bDecreasing
02056 ? para.axisTrueAreaRect().bottomRight()
02057 : para.axisTrueAreaRect().topRight();
02058 pXDelimDeltaFaktor = -1.0;
02059 pYDeltaFactor = bDecreasing ? 1.0 : -1.0;
02060 }
02061 break;
02062 case KDChartAxisParams::AxisPosTop: {
02063 axisLength = para.axisTrueAreaRect().width();
02064 orig = bDecreasing
02065 ? para.axisTrueAreaRect().bottomRight()
02066 : para.axisTrueAreaRect().bottomLeft();
02067 dest = bDecreasing
02068 ? para.axisTrueAreaRect().bottomLeft()
02069 : para.axisTrueAreaRect().bottomRight();
02070 pYDelimDeltaFaktor = -1.0;
02071 pXDeltaFactor = bDecreasing ? -1.0 : 1.0;
02072 }
02073 break;
02074 case KDChartAxisParams::AxisPosRight: {
02075 axisLength = para.axisTrueAreaRect().height();
02076 orig = bDecreasing
02077 ? para.axisTrueAreaRect().topLeft()
02078 : para.axisTrueAreaRect().bottomLeft();
02079 dest = bDecreasing
02080 ? para.axisTrueAreaRect().bottomLeft()
02081 : para.axisTrueAreaRect().topLeft();
02082 pXDelimDeltaFaktor = 1.0;
02083 pYDeltaFactor = bDecreasing ? 1.0 : -1.0;
02084 }
02085 break;
02086 default: {
02087 axisLength = 0;
02088 qDebug( "IMPLEMENTATION ERROR: KDChartAxesPainter::paintAxes() unhandled enum value." );
02089 }
02090 break;
02091 }
02092
02093
02094 uint dataset, dataset2, chart;
02095 if ( !params.axisDatasets( axisNumber, dataset, dataset2, chart ) ) {
02096 dataset = KDCHART_ALL_DATASETS;
02097 dataset2 = KDCHART_ALL_DATASETS;
02098 chart = 0;
02099
02100
02101 }
02102
02103
02104 uint dataDataset, dataDataset2;
02105 if( params.findDatasets( KDChartParams::DataEntry,
02106 KDChartParams::ExtraLinesAnchor,
02107 dataDataset,
02108 dataDataset2,
02109 chart ) ) {
02110
02111
02112 if( ( KDCHART_ALL_DATASETS != dataset
02113 && KDCHART_NO_DATASET != dataset )
02114 || ( KDCHART_ALL_DATASETS != dataDataset
02115 && KDCHART_NO_DATASET != dataDataset ) ){
02116 int ds = (KDCHART_ALL_DATASETS != dataset)
02117 ? dataset
02118 : 0;
02119 int dds = (KDCHART_ALL_DATASETS != dataDataset)
02120 ? dataDataset
02121 : 0;
02122 dataDataset = QMAX( ds, dds );
02123 }
02124 if( ( KDCHART_ALL_DATASETS != dataset2
02125 && KDCHART_NO_DATASET != dataset2 )
02126 || ( KDCHART_ALL_DATASETS != dataDataset2
02127 && KDCHART_NO_DATASET != dataDataset2 ) ){
02128 int ds2 = (KDCHART_ALL_DATASETS != dataset2)
02129 ? dataset2
02130 : KDCHART_MAX_AXES-1;
02131 int dds2 = (KDCHART_ALL_DATASETS != dataDataset2)
02132 ? dataDataset2
02133 : KDCHART_MAX_AXES-1;
02134 dataDataset2 = QMIN( ds2, dds2 );
02135 }
02136 }
02137 else {
02138
02139 qDebug( "IMPLEMENTATION ERROR: findDatasets( DataEntry, ExtraLinesAnchor ) should *always* return true. (b)" );
02140 dataDataset = KDCHART_ALL_DATASETS;
02141 }
02142
02143
02144
02145 if ( para.axisLabelsFontUseRelSize() ){
02146 nTxtHeight = para.axisLabelsFontRelSize()
02147 * averageValueP1000;
02148
02149 }else {
02150 QFontInfo info( para.axisLabelsFont() );
02151 nTxtHeight = info.pointSize();
02152
02153 }
02154
02155 const int behindComma = para.axisDigitsBehindComma();
02156 const int divPow10 = para.axisLabelsDivPow10();
02157 const QString decimalPoint = para.axisLabelsDecimalPoint();
02158 const QString thousandsPoint = para.axisLabelsThousandsPoint();
02159 const QString prefix = para.axisLabelsPrefix();
02160 const QString postfix = para.axisLabelsPostfix();
02161 const int totalLen = para.axisLabelsTotalLen();
02162 const QChar padFill = para.axisLabelsPadFill();
02163 const bool blockAlign = para.axisLabelsBlockAlign();
02164
02165 QStringList labelTexts;
02166 int colNum = para.labelTextsDataRow();
02167 bool bDone = true;
02168 switch ( para.axisLabelTextsFormDataRow() ) {
02169 case KDChartAxisParams::LabelsFromDataRowYes: {
02170
02171 int trueBehindComma = -1;
02172 QVariant value;
02173 for ( uint iDataset = 0; iDataset < data.usedRows(); iDataset++ ) {
02174 if( data.cellCoord( iDataset, colNum, value, 1 ) ){
02175 if( QVariant::String == value.type() )
02176 labelTexts.append( value.toString() );
02177 else {
02178 labelTexts.append( applyLabelsFormat( value.toDouble(),
02179 divPow10,
02180 behindComma,
02181 para.axisValueDelta(),
02182 trueBehindComma,
02183 decimalPoint,
02184 thousandsPoint,
02185 prefix,
02186 postfix,
02187 totalLen,
02188 padFill,
02189 blockAlign ) );
02190
02191 }
02192 }
02193 }
02194 break;
02195 }
02196 case KDChartAxisParams::LabelsFromDataRowGuess: {
02197 QVariant value;
02198 for ( uint iDataset = 0; iDataset < data.usedRows(); iDataset++ ) {
02199 if( data.cellCoord( iDataset, colNum, value, 1 ) ){
02200 if( QVariant::String == value.type() ){
02201 const QString sVal( value.toString() );
02202 if( !sVal.isEmpty() && !sVal.isNull() )
02203 labelTexts.append( sVal );
02204 }
02205 }else{
02206 labelTexts.clear();
02207 bDone = false;
02208 break;
02209 }
02210 }
02211 break;
02212 }
02213 case KDChartAxisParams::LabelsFromDataRowNo: {
02214 bDone = false;
02215 break;
02216 }
02217 default:
02218
02219 qDebug( "KDChart: Unknown label texts source" );
02220 }
02221
02222
02223 const bool dataCellsHaveSeveralCoordinates =
02224 (KDCHART_ALL_DATASETS == dataDataset)
02225 ? data.cellsHaveSeveralCoordinates()
02226 : data.cellsHaveSeveralCoordinates( dataDataset, dataDataset2 );
02227 if( dataCellsHaveSeveralCoordinates && !para.axisSteadyValueCalc() )
02228 ((KDChartParams&)params).setAxisLabelTextParams(
02229 axisNumber,
02230 true,
02231 KDCHART_AXIS_LABELS_AUTO_LIMIT,
02232 KDCHART_AXIS_LABELS_AUTO_LIMIT,
02233 KDCHART_AXIS_LABELS_AUTO_DELTA,
02234 para.axisLabelsDigitsBehindComma() );
02235
02236
02237 const KDChartParams::ChartType params_chartType
02238 = ( 0 == chart )
02239 ? params.chartType()
02240 : params.additionalChartType();
02241
02242
02243
02244 const bool bSteadyCalc = para.axisSteadyValueCalc();
02245
02246
02247 isLogarithmic = bSteadyCalc &&
02248 (KDChartParams::Line == params_chartType) &&
02249 (KDChartAxisParams::AxisCalcLogarithmic == para.axisCalcMode());
02250
02251
02252
02253
02254
02255 const bool bVertAxis = (KDChartAxisParams::AxisPosLeft == basicPos) ||
02256 (KDChartAxisParams::AxisPosRight == basicPos);
02257
02258
02259 const int coordinate = bVertAxis ? 1 : 2;
02260
02261
02262 const QVariant::Type valueType =
02263 (KDCHART_ALL_DATASETS == dataDataset)
02264 ? data.cellsValueType( coordinate )
02265 : data.cellsValueType( dataDataset, dataDataset2, coordinate );
02266 isDateTime = valueType == QVariant::DateTime;
02267 bool bIsDouble = valueType == QVariant::Double;
02268
02269 autoDtLabels = isDateTime && ( KDCHART_AXIS_LABELS_AUTO_DATETIME_FORMAT
02270 == para.axisLabelsDateTimeFormat() );
02271
02272 if( autoDtLabels || bSteadyCalc )
02273 ( ( KDChartAxisParams& ) para ).setAxisLabelsTouchEdges( true );
02274
02275 bool bStatistical = KDChartParams::HiLo == params_chartType
02276 || KDChartParams::BoxWhisker == params_chartType;
02277
02278 if ( !bVertAxis && KDChartParams::BoxWhisker == params_chartType
02279 && ! para.axisLabelStringCount() ) {
02280 uint ds1 = (KDCHART_ALL_DATASETS == dataDataset)
02281 ? 0
02282 : dataDataset;
02283 uint ds2 = (KDCHART_ALL_DATASETS == dataDataset)
02284 ? data.usedRows() - 1
02285 : dataDataset2;
02286 for (uint i = ds1; i <= ds2; ++i)
02287 labelTexts.append(
02288 QObject::tr( "Series " ) + QString::number( i + 1 ) );
02289 bDone = true;
02290 }
02291
02292 double nLow = 1.0 + bSteadyCalc;
02293 double nHigh = 10.0;
02294 double nDelta = 1.0;
02295 if ( !bDone ) {
02296 bDone = true;
02297
02298
02299 if ( ! isLogarithmic
02300 && ! para.axisLabelStringCount()
02301 && ! ( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueStart() )
02302 && ! ( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueEnd() )
02303 && ! ( para.axisValueStart() == para.axisValueEnd() )
02304 && ! ( KDCHART_AXIS_LABELS_AUTO_DELTA == para.axisValueDelta() )
02305 && ! ( 0.0 == para.axisValueDelta() ) ) {
02306 nLow = para.axisValueStart().toDouble();
02307 nHigh = para.axisValueEnd().toDouble();
02308 nDelta = para.axisValueDelta();
02309 int behindComma = para.axisDigitsBehindComma();
02310 int trueBehindComma = -1;
02311 bool upwards = (nLow < nHigh);
02312 if( upwards != (0.0 < nDelta) )
02313 nDelta *= -1.0;
02314 double nVal = nLow;
02315 bDone = false;
02316 bool bShowVeryLastLabel = false;
02317
02318 while( bShowVeryLastLabel || (upwards ? (nVal <= nHigh) : (nVal >= nHigh)) ){
02319
02320 labelTexts.append( applyLabelsFormat( nVal,
02321 divPow10,
02322 behindComma,
02323 nDelta,
02324 trueBehindComma,
02325 decimalPoint,
02326 thousandsPoint,
02327 prefix,
02328 postfix,
02329 totalLen,
02330 padFill,
02331 blockAlign ) );
02332 nVal += nDelta;
02333
02334 if( ! (upwards ? (nVal <= nHigh) : (nVal >= nHigh)) ){
02335
02336 if( bShowVeryLastLabel )
02337 bShowVeryLastLabel = false;
02338 else{
02339 QString sHigh( applyLabelsFormat( nHigh,
02340 divPow10,
02341 behindComma,
02342 nDelta,
02343 trueBehindComma,
02344 decimalPoint,
02345 thousandsPoint,
02346 prefix,
02347 postfix,
02348 totalLen,
02349 padFill,
02350 blockAlign ) );
02351 QString sValue( applyLabelsFormat( nVal,
02352 divPow10,
02353 behindComma,
02354 nDelta,
02355 trueBehindComma,
02356 decimalPoint,
02357 thousandsPoint,
02358 prefix,
02359 postfix,
02360 totalLen,
02361 padFill,
02362 blockAlign ) );
02363 bShowVeryLastLabel = (sValue == sHigh);
02364
02365 }
02366 }
02367 bDone = true;
02368 }
02369 ( ( KDChartAxisParams& ) para ).setTrueAxisLowHighDelta( nLow, nHigh, nDelta );
02370
02371 }
02372 else if ( para.axisLabelStringCount() ) {
02373 int nLabels = bSteadyCalc
02374 ? para.axisLabelStringCount()
02375 : bStatistical ? data.usedRows() : data.usedCols();
02376 calculateBasicTextFactors( nTxtHeight, para, averageValueP1000,
02377 basicPos, orig, delimLen, nLabels,
02378
02379 pDelimDelta,
02380 pTextsX, pTextsY, pTextsW, pTextsH,
02381 textAlign );
02382 bool useShortLabels = false;
02383 QStringList tmpList( para.axisLabelStringList() );
02384
02385
02386 int iStart = 0;
02387 int iEnd = para.axisLabelStringCount() - 1;
02388 if( ! ( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueStart() )
02389 || ! ( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueEnd() ) ) {
02390 const bool testStart = !( QVariant::String == para.axisValueStart().type() );
02391 const bool testEnd = !( QVariant::String == para.axisValueEnd().type() );
02392 QString sStart = testStart
02393 ? para.axisValueStart().toString().upper()
02394 : QString::null;
02395 QString sEnd = testEnd
02396 ? para.axisValueEnd().toString().upper()
02397 : QString::null;
02398
02399 uint i = 0;
02400 for ( QStringList::Iterator it = tmpList.begin();
02401 it != tmpList.end(); ++it, ++i ) {
02402 if ( 0 == iStart &&
02403 0 == QString::compare( sStart, ( *it ).upper() ) ) {
02404 iStart = i;
02405 }
02406 if ( 0 == QString::compare( sEnd, ( *it ).upper() ) ) {
02407 iEnd = i;
02408 }
02409 }
02410 }
02411
02412
02413
02414 if ( para.axisLabelStringCount()
02415 && para.axisShortLabelsStringCount()
02416 && para.axisLabelStringList() != para.axisShortLabelsStringList() ) {
02417 QFont font( para.axisLabelsFont() );
02418 if ( para.axisLabelsFontUseRelSize() )
02419 font.setPixelSize( static_cast < int > ( nTxtHeight ) );
02420 painter->setFont( font );
02421 QFontMetrics fm( painter->fontMetrics() );
02422
02423 QStringList::Iterator it = tmpList.begin();
02424 for ( int i = 0; i < nLabels; ++i ) {
02425 if ( it != tmpList.end() ) {
02426 if ( fm.width( *it ) > pTextsW ) {
02427 useShortLabels = true;
02428 break;
02429 }
02430 ++it;
02431 }
02432 }
02433 }
02434 if ( useShortLabels )
02435 tmpList = para.axisShortLabelsStringList();
02436 else
02437 tmpList = para.axisLabelStringList();
02438
02439
02440 double ddelta
02441 = ( KDCHART_AXIS_LABELS_AUTO_DELTA == para.axisValueDelta() )
02442 ? 1.0
02443 : para.axisValueDelta();
02444 modf( ddelta, &ddelta );
02445 bool positive = ( 0.0 <= ddelta );
02446 int delta = static_cast < int > ( fabs( ddelta ) );
02447
02448 QStringList::Iterator it = positive
02449 ? tmpList.begin()
02450 : tmpList.fromLast();
02451 if ( positive )
02452 for ( int i = 0; i < (int)tmpList.count(); ++i ) {
02453 if ( i >= iStart )
02454 break;
02455 ++it;
02456 }
02457 else
02458 for ( int i = tmpList.count() - 1; i >= 0; --i ) {
02459 if ( i <= iEnd )
02460 break;
02461 --it;
02462 }
02463
02464 int meter = delta;
02465 int i2 = positive ? iStart : iEnd;
02466 for ( int iLabel = 0; iLabel < nLabels; ) {
02467 if ( positive ) {
02468 if ( it == tmpList.end() ) {
02469 it = tmpList.begin();
02470 i2 = 0;
02471 }
02472 } else {
02473 if ( it == tmpList.begin() ) {
02474 it = tmpList.end();
02475 i2 = tmpList.count();
02476 }
02477 }
02478 if ( ( positive && i2 >= iStart )
02479 || ( !positive && i2 <= iEnd ) ) {
02480 if ( meter >= delta ) {
02481 labelTexts << *it;
02482 ++iLabel;
02483 meter = 1;
02484 } else {
02485 meter += 1;
02486 }
02487 }
02488 if ( positive ) {
02489 if ( i2 == iEnd ) {
02490 it = tmpList.begin();
02491 i2 = 0;
02492 } else {
02493 ++it;
02494 ++i2;
02495 }
02496 } else {
02497 if ( i2 == iStart ) {
02498 it = tmpList.end();
02499 i2 = tmpList.count();
02500 } else {
02501 --it;
02502 --i2;
02503 }
02504 }
02505 }
02506 } else {
02507
02508
02509 uint dset = ( dataset == KDCHART_ALL_DATASETS ) ? 0 : dataset;
02510
02511 bDone = false;
02512 QVariant value;
02513 for ( uint col = 0; col < data.usedCols(); ++col ) {
02514 if( data.cellCoord( dset, col, value, coordinate ) ){
02515 if( QVariant::String == value.type() ){
02516 const QString sVal = value.toString();
02517 if( !sVal.isEmpty() && !sVal.isNull() ){
02518 labelTexts.append( sVal );
02519 bDone = true;
02520 }
02521 }else{
02522 labelTexts.clear();
02523 bDone = false;
02524 break;
02525 }
02526 }
02527 }
02528 }
02529 }
02530
02531
02532 if ( bDone ) {
02533
02534
02535
02536
02537
02538
02539
02540 }
02541 else {
02542
02543
02544
02545 if ( data.usedCols() && bSteadyCalc ) {
02546
02547 double nLow = 0.01;
02548 double nHigh = 0.0;
02549 double orgLow = 0.0;
02550 double orgHigh = 0.0;
02551 double nDelta = 0.0;
02552 double nDist = 0.0;
02553
02554
02555 enum { Normal, Stacked, Percent } mode;
02556
02557 if( bVertAxis ){
02558 switch ( params_chartType ) {
02559 case KDChartParams::Bar:
02560 if ( KDChartParams::BarStacked
02561 == params.barChartSubType() )
02562 mode = Stacked;
02563 else if ( KDChartParams::BarPercent
02564 == params.barChartSubType() )
02565 mode = Percent;
02566 else
02567 mode = Normal;
02568 break;
02569 case KDChartParams::Line:
02570 if ( KDChartParams::LineStacked
02571 == params.lineChartSubType() )
02572 mode = Stacked;
02573 else if ( KDChartParams::LinePercent
02574 == params.lineChartSubType() )
02575 mode = Percent;
02576 else
02577 mode = Normal;
02578 break;
02579 case KDChartParams::Area:
02580 if ( KDChartParams::AreaStacked
02581 == params.areaChartSubType() )
02582 mode = Stacked;
02583 else if ( KDChartParams::AreaPercent
02584 == params.areaChartSubType() )
02585 mode = Percent;
02586 else
02587 mode = Normal;
02588 break;
02589 case KDChartParams::HiLo:
02590 case KDChartParams::BoxWhisker:
02591 mode = Normal;
02592 break;
02593 case KDChartParams::Polar:
02594 if ( KDChartParams::PolarStacked
02595 == params.polarChartSubType() )
02596 mode = Stacked;
02597 else if ( KDChartParams::PolarPercent
02598 == params.polarChartSubType() )
02599 mode = Percent;
02600 else
02601 mode = Normal;
02602 break;
02603 default: {
02604
02605 qDebug( "IMPLEMENTATION ERROR: Unknown params_chartType in calculateLabelTexts()" );
02606 mode = Normal;
02607 }
02608 }
02609 }else
02610 mode = Normal;
02611
02612 uint nLabels = 200;
02613
02614
02615 bool bOrdFactorsOk = false;
02616
02617 if( adjustTheValues ){
02618 nDelta = fabs( trueDelta );
02619 pDelimDelta = trueDeltaPix;
02620 nLow = QMIN( para.trueAxisLow(), para.trueAxisHigh() );
02621
02622 double orgLow( nLow );
02623 modf( nLow / nDelta, &nLow );
02624 nLow *= nDelta;
02625 if ( nLow > orgLow )
02626 nLow -= nDelta;
02627 if ( 0.0 < nLow && 0.0 >= orgLow )
02628 nLow = 0.0;
02629 nHigh = nLow;
02630 double dx = fabs( pXDeltaFactor * pDelimDelta );
02631 double dy = fabs( pYDeltaFactor * pDelimDelta );
02632 double x = 0.0;
02633 double y = 0.0;
02634 nLabels = 1;
02635 if( axisLength ){
02636 do{
02637 ++nLabels;
02638 nHigh += nDelta;
02639 x += dx;
02640 y += dy;
02641 }while( x < axisLength && y < axisLength );
02642 nHigh -= nDelta;
02643 --nLabels;
02644 }
02645 nDist = nHigh - nLow;
02646 bOrdFactorsOk = true;
02647
02648 }
02649
02650 if( !bOrdFactorsOk ){
02651 const bool bAutoCalcStart =
02652 ( Percent != mode )
02653 && ( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueStart() );
02654 const bool bAutoCalcEnd =
02655 ( Percent != mode )
02656 && ( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueEnd() );
02657
02658 if( !bIsDouble && !isDateTime ){
02659
02660 nLow = 0.0;
02661 nHigh = 10.0;
02662 nDist = 10.0;
02663 nDelta = 1.0;
02664 nSubDelimFactor = 0.5;
02665 bIsDouble = true;
02666 bOrdFactorsOk = true;
02667 }else if( mode == Percent ){
02668
02669 nLow = 0.0;
02670 nHigh = 100.0;
02671 nDist = 100.0;
02672 nDelta = 10.0;
02673 nSubDelimFactor = 0.25;
02674 bOrdFactorsOk = true;
02675 }else{
02676
02677
02678 const bool bStackedMode = (mode == Stacked);
02679 if( bAutoCalcStart ){
02680 if ( dataDataset == KDCHART_ALL_DATASETS ) {
02681 if( bIsDouble ){
02682 nLow = bStackedMode
02683 ? QMIN( data.minColSum(), 0.0 )
02684 : data.minValue( coordinate,
02685 isLogarithmic );
02686
02687
02688 }else{
02689 dtLow = data.minDtValue( coordinate );
02690 }
02691 } else {
02692 if( bIsDouble ){
02693 nLow = bStackedMode
02694 ? QMIN( data.minColSum( dataDataset, dataDataset2 ),
02695 0.0 )
02696 : data.minInRows( dataDataset,dataDataset2,
02697 coordinate,
02698 isLogarithmic );
02699 }else{
02700 dtLow = data.minDtInRows( dataDataset,dataDataset2,
02701 coordinate );
02702 }
02703 }
02704 }else{
02705 if( bIsDouble ){
02706 if( QVariant::Double == para.axisValueStart().type() )
02707 nLow = para.axisValueStart().toDouble();
02708 }else{
02709 if( QVariant::DateTime == para.axisValueStart().type() )
02710 dtLow = para.axisValueStart().toDateTime();
02711 }
02712 }
02713
02714
02715 if( bAutoCalcEnd ){
02716 if ( dataDataset == KDCHART_ALL_DATASETS ) {
02717 if( bIsDouble ){
02718 nHigh = bStackedMode
02719 ? QMAX( data.maxColSum(), 0.0 )
02720 : data.maxValue( coordinate );
02721
02722 }else{
02723 dtHigh = data.maxDtValue( coordinate );
02724 }
02725 } else {
02726 if( bIsDouble )
02727 nHigh = bStackedMode
02728 ? QMAX( data.maxColSum( dataDataset, dataDataset2 ),
02729 0.0 )
02730 : data.maxInRows( dataDataset,dataDataset2,
02731 coordinate );
02732 else
02733 dtHigh = data.maxDtInRows( dataDataset,dataDataset2,
02734 coordinate );
02735 }
02736
02737 }else{
02738 if( bIsDouble ){
02739 if( QVariant::Double == para.axisValueEnd().type() )
02740 nHigh = para.axisValueEnd().toDouble();
02741 }else{
02742 if( QVariant::DateTime == para.axisValueEnd().type() )
02743 dtHigh = para.axisValueEnd().toDateTime();
02744 }
02745 }
02746 }
02747
02748
02749
02750
02751 if( bIsDouble ) {
02752 if( DBL_MAX == nLow
02753 || ( ( 0.0 == nHigh || 0 == nHigh )
02754 && ( 0.0 == nLow || 0 == nLow ) ) ) {
02755
02756 nLow = 0.0;
02757 nHigh = 10.0;
02758 nDist = 10.0;
02759 nDelta = 1.0;
02760 nSubDelimFactor = 0.5;
02761 bOrdFactorsOk = true;
02762
02763 }else if( nLow == nHigh ){
02764
02765
02766 if( nLow < 0.0 )
02767 nHigh = 0.0;
02768 else
02769 nLow = 0.0;
02770
02771 }else if( nHigh < nLow ){
02772
02773 double nTmp = nLow;
02774 nLow = nHigh;
02775 nHigh = nTmp;
02776 }
02777 } else if( isDateTime ){
02778 bool toggleDts = dtLow > dtHigh;
02779 if( toggleDts ) {
02780 QDateTime dt( dtLow );
02781 dtLow = dtHigh;
02782 dtHigh = dt;
02783 }
02784 double secDist = dtLow.secsTo( dtHigh );
02785 secDist += (dtHigh.time().msec() - dtLow.time().msec()) / 1000.0;
02786 const double aDist = fabs( secDist );
02787 const double secMin = 60.0;
02788 const double secHour = 60.0 * secMin;
02789 const double secDay = 24.0 * secHour;
02790
02791
02792
02793
02794
02795
02796
02797
02798 const double secMonth = 30 * secDay;
02799 const double secYear = 12 * secMonth;
02800 if( 2.0*secMin > aDist )
02801 dtDeltaScale = KDChartAxisParams::ValueScaleSecond;
02802 else if( 2.0*secHour > aDist )
02803 dtDeltaScale = KDChartAxisParams::ValueScaleMinute;
02804 else if( 2.0*secDay > aDist )
02805 dtDeltaScale = KDChartAxisParams::ValueScaleHour;
02806
02807
02808 else if( 2.0*secMonth > aDist )
02809 dtDeltaScale = KDChartAxisParams::ValueScaleDay;
02810
02811
02812 else if( 2.0*secYear > aDist )
02813 dtDeltaScale = KDChartAxisParams::ValueScaleMonth;
02814 else if( 10.0*secYear > aDist )
02815 dtDeltaScale = KDChartAxisParams::ValueScaleQuarter;
02816 else
02817 dtDeltaScale = KDChartAxisParams::ValueScaleYear;
02818
02819
02820
02821 const int monthLow = dtLow.date().month();
02822
02823 const int dayLow = dtLow.date().day();
02824 const int hourLow = dtLow.time().hour();
02825 const int minuteLow = dtLow.time().minute();
02826 const int secondLow = dtLow.time().second();
02827
02828
02829 const int monthHigh = dtHigh.date().month();
02830
02831 const int hourHigh = dtHigh.time().hour();
02832 const int minuteHigh = dtHigh.time().minute();
02833 const int secondHigh = dtHigh.time().second();
02834 int yearLowD = 0;
02835 int monthLowD = 0;
02836 int dayLowD = 0;
02837 int hourLowD = 0;
02838 int minuteLowD = 0;
02839 int secondLowD = 0;
02840 int yearHighD = 0;
02841 int monthHighD = 0;
02842 int dayHighD = 0;
02843 int hourHighD = 0;
02844 int minuteHighD = 0;
02845 int secondHighD = 0;
02846 bool gotoEndOfMonth = false;
02847 switch( dtDeltaScale ) {
02848 case KDChartAxisParams::ValueScaleSecond:
02849
02850 if( 5.0 < aDist ){
02851 secondLowD = secondLow % 5;
02852 if( secondHigh % 5 )
02853 secondHighD = 5 - secondHigh % 5;
02854 }
02855 break;
02856 case KDChartAxisParams::ValueScaleMinute:
02857
02858 secondLowD = secondLow;
02859 secondHighD = 59-secondHigh;
02860 break;
02861 case KDChartAxisParams::ValueScaleHour:
02862
02863 minuteLowD = minuteLow;
02864 secondLowD = secondLow;
02865 minuteHighD = 59-minuteHigh;
02866 secondHighD = 59-secondHigh;
02867 break;
02868 case KDChartAxisParams::ValueScaleDay:
02869
02870 hourLowD = hourLow;
02871 minuteLowD = minuteLow;
02872 secondLowD = secondLow;
02873 hourHighD = 23-hourHigh;
02874 minuteHighD = 59-minuteHigh;
02875 secondHighD = 59-secondHigh;
02876 break;
02877 case KDChartAxisParams::ValueScaleWeek:
02878
02879
02880
02881
02882
02883
02884
02885
02886
02887
02888 break;
02889 case KDChartAxisParams::ValueScaleMonth:
02890
02891 if( 1 < dayLow )
02892 dayLowD = dayLow - 1;
02893 hourLowD = hourLow;
02894 minuteLowD = minuteLow;
02895 secondLowD = secondLow;
02896 gotoEndOfMonth = true;
02897 break;
02898 case KDChartAxisParams::ValueScaleQuarter:
02899
02900 monthLowD = ( monthLow - 1 ) % 3;
02901 dayLowD = dayLow;
02902 hourLowD = hourLow;
02903 minuteLowD = minuteLow;
02904 secondLowD = secondLow;
02905 if( ( monthHigh - 1 ) % 3 )
02906 monthHighD = 3 - ( monthHigh - 1 ) % 3;
02907 gotoEndOfMonth = true;
02908 break;
02909 case KDChartAxisParams::ValueScaleYear:
02910
02911 monthLowD = monthLow;
02912 dayLowD = dayLow;
02913 hourLowD = hourLow;
02914 minuteLowD = minuteLow;
02915 secondLowD = secondLow;
02916 if( 12 > monthHigh )
02917 monthHighD = 12 - monthHigh;
02918 gotoEndOfMonth = true;
02919 break;
02920 default:
02921
02922 break;
02923 }
02924 dtLow = dtLow.addSecs( -1 * (secondLowD + 60*minuteLowD + 3600*hourLowD) );
02925 dtLow = dtLow.addDays( -1 * dayLowD );
02926 dtAddMonths( dtLow, -1 * monthLowD, dtLow );
02927 dtAddYears( dtLow, -1 * yearLowD, dtLow );
02928 dtHigh = dtHigh.addSecs( secondHighD + 60*minuteHighD + 3600* hourHighD );
02929 dtHigh = dtHigh.addDays( dayHighD );
02930 dtAddMonths( dtHigh, monthHighD, dtHigh );
02931 dtAddYears( dtHigh, yearHighD, dtHigh );
02932 if( gotoEndOfMonth ){
02933 dtHigh.setDate( QDate( dtHigh.date().year(),
02934 dtHigh.date().month(),
02935 dtHigh.date().daysInMonth() ) );
02936 dtHigh.setTime( QTime( 23, 59, 59 ) );
02937 }
02938 if( toggleDts ) {
02939 QDateTime dt( dtLow );
02940 dtLow = dtHigh;
02941 dtHigh = dt;
02942 }
02943
02944
02945
02946
02947 nSubDelimFactor = 0.0;
02948 bOrdFactorsOk = true;
02949 }
02950
02951
02952 if( !bOrdFactorsOk ) {
02953
02954
02955 nDist = nHigh - nLow;
02956 if( !isLogarithmic ){
02957
02958
02959
02960
02961 int maxEmpty = para.axisMaxEmptyInnerSpan();
02962 if( bAutoCalcStart ) {
02963
02964 if( 0.0 < nLow ) {
02965 if( maxEmpty == KDCHART_AXIS_IGNORE_EMPTY_INNER_SPAN
02966 || maxEmpty > ( nLow / nHigh * 100.0 ) )
02967 nLow = 0.0;
02968 else if( nDist / 100.0 < nLow )
02969 nLow -= nDist / 100.0;
02970 }
02971 else if( nDist / 100.0 < fabs( nLow ) )
02972 nLow -= nDist / 100.0;
02973 nDist = nHigh - nLow;
02974
02975 }
02976 if( bAutoCalcEnd ) {
02977
02978 if( 0.0 > nHigh ) {
02979 if( maxEmpty == KDCHART_AXIS_IGNORE_EMPTY_INNER_SPAN
02980 || maxEmpty > ( nHigh / nLow * 100.0 ) )
02981 nHigh = 0.0;
02982 else if( nDist / 100.0 > nHigh )
02983 nHigh += nDist / 100.0;
02984 }
02985 else if( nDist / 100.0 < fabs( nHigh ) )
02986 nHigh += nDist / 100.0;
02987 nDist = nHigh - nLow;
02988
02989 }
02990 }
02991 }
02992
02993
02994 if( isLogarithmic ){
02995 if( bIsDouble ) {
02996
02997 if( 0.0 == QABS( nLow ) )
02998 nLow = -5;
02999 else{
03000
03001 nLow = log10( QABS( nLow ) );
03002
03003
03004
03005 }
03006 nHigh = log10( QABS( nHigh ) );
03007
03008
03009 double intPart=0.0;
03010 double fractPart = modf( nLow, &intPart );
03011
03012 if( 0.0 > nLow && 0.0 != fractPart )
03013 nLow = intPart - 1.0;
03014 else
03015 nLow = intPart;
03016 fractPart = modf( nHigh, &intPart );
03017 if( 0.0 != fractPart )
03018 nHigh = intPart + 1.0;
03019
03020 nDist = nHigh - nLow;
03021 nDelta = 1.0;
03022 nSubDelimFactor = 0.1;
03023
03024 bOrdFactorsOk = true;
03025 }
03026 }
03027
03028
03029 if ( !bOrdFactorsOk ) {
03030
03031
03032 double nDivisor;
03033 double nRound;
03034 nDist = nHigh - nLow;
03035
03036
03037 orgLow = nLow;
03038 orgHigh = nHigh;
03039 calculateOrdinateFactors( para, isLogarithmic,
03040 nDist, nDivisor, nRound,
03041 nDelta, nSubDelimFactor,
03042 nLow, nHigh );
03043 nLabels = params.roundVal( nDist / nDelta );
03044
03045
03046
03047
03048
03049
03050
03051
03052
03053 if( para.axisSteadyValueCalc() ) {
03054 ++nLabels;
03055
03056 }
03057 }
03058
03059
03060
03061
03062 if( ! ( KDCHART_AXIS_LABELS_AUTO_DELTA
03063 == para.axisValueDelta() ) ){
03064 nDist = nHigh - nLow;
03065 nDelta = para.axisValueDelta();
03066 nLabels = params.roundVal( nDist / nDelta );
03067
03068
03069
03070
03071 if( para.axisSteadyValueCalc() ) {
03072 ++nLabels;
03073
03074
03075
03076 }
03077 }
03078
03079
03080 if( bVertAxis ) {
03081 double areaHeight = para.axisTrueAreaRect().height();
03082 double nDivisor;
03083 double nRound;
03084 orgLow = nLow;
03085 orgHigh = nHigh;
03086
03087 bool bTryNext = false;
03088 uint minLabels = para.axisSteadyValueCalc() ? 3 : 2;
03089
03090 int pass = 0;
03091 do{
03092 nDist = nHigh - nLow;
03093 nLow = orgLow;
03094 nHigh = orgHigh;
03095
03096
03097
03098
03099 calculateOrdinateFactors( para, isLogarithmic,
03100 nDist, nDivisor, nRound,
03101 nDelta,
03102 nSubDelimFactor, nLow, nHigh,
03103 bTryNext );
03104 nLabels = params.roundVal( nDist / nDelta );
03105
03106
03107
03108
03109
03110
03111
03112
03113 if( !bAutoCalcEnd && orgHigh > nLow + nLabels * nDelta ) {
03114 ++nLabels;
03115
03116 }
03117 if( para.axisSteadyValueCalc() ) {
03118 ++nLabels;
03119
03120 }
03121
03122
03123 bTryNext = true;
03124 ++pass;
03125 }while ( ( pass < 2 )
03126 || ( ( minLabels < nLabels )
03127 && ( areaHeight < ( nTxtHeight * 1.5 ) * nLabels ) ) );
03128 }
03129 }
03130
03131
03132 if( bIsDouble ) {
03133 int trueBehindComma = -1;
03134 double nVal = nLow;
03135 for ( uint i = 0; i < nLabels; ++i ) {
03136 if( isLogarithmic ) {
03137 labelTexts.append( applyLabelsFormat(
03138 fastPow10( static_cast < int > ( nVal ) ),
03139 divPow10,
03140 behindComma,
03141 1.0 == nDelta ? KDCHART_AXIS_LABELS_AUTO_DELTA : nDelta,
03142 trueBehindComma,
03143 decimalPoint,
03144 thousandsPoint,
03145 prefix,
03146 postfix,
03147 totalLen,
03148 padFill,
03149 blockAlign ) );
03150 } else {
03151 labelTexts.append( applyLabelsFormat( nVal,
03152 divPow10,
03153 behindComma,
03154 nDelta,
03155 trueBehindComma,
03156 decimalPoint,
03157 thousandsPoint,
03158 prefix,
03159 postfix,
03160 totalLen,
03161 padFill,
03162 blockAlign ) );
03163 }
03164 nVal += nDelta;
03165 }
03166
03167
03168
03169
03170 if ( para.axisSteadyValueCalc() ) {
03171 nHigh = nVal - nDelta;
03172 }
03173 ( ( KDChartAxisParams& ) para ).setTrueAxisLowHighDelta( nLow, nHigh, nDelta );
03174
03175
03176 } else {
03177 bool goDown = dtLow > dtHigh;
03178 int mult = goDown ? -1 : 1;
03179 QDateTime dt( dtLow );
03180 nLabels = 0;
03181
03182
03183
03184
03185
03186
03187 bool bDone=false;
03188 while( !bDone ) {
03189
03190
03191
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211
03212 ++nLabels;
03213 if( autoDtLabels )
03214 labelTexts.append( "x" );
03215 else
03216 #if COMPAT_QT_VERSION >= 0x030000
03217 labelTexts.append( dt.toString( Qt::ISODate ) );
03218 #else
03219 labelTexts.append( dateTimeToString( dt ) );
03220 #endif
03221 bDone = (goDown ? (dt < dtLow ) : (dt > dtHigh));
03222
03223
03224 {
03225 switch( dtDeltaScale ) {
03226 case KDChartAxisParams::ValueScaleSecond:
03227 dtAddSecs( dt, 1 * mult, dt );
03228 break;
03229 case KDChartAxisParams::ValueScaleMinute:
03230 dtAddSecs( dt, 60 * mult, dt );
03231 break;
03232 case KDChartAxisParams::ValueScaleHour:
03233 dtAddSecs( dt, 3600 * mult, dt );
03234 break;
03235 case KDChartAxisParams::ValueScaleDay:
03236 dtAddDays( dt, 1 * mult, dt );
03237 break;
03238 case KDChartAxisParams::ValueScaleWeek:
03239 dtAddDays( dt, 7 * mult, dt );
03240 break;
03241 case KDChartAxisParams::ValueScaleMonth:
03242 dtAddMonths( dt,1 * mult, dt );
03243 break;
03244 case KDChartAxisParams::ValueScaleQuarter:
03245 dtAddMonths( dt,3 * mult, dt );
03246 break;
03247 case KDChartAxisParams::ValueScaleYear:
03248 dtAddYears( dt, 1 * mult, dt );
03249 break;
03250 default:
03251 dtAddDays( dt, 1 * mult, dt );
03252 break;
03253 }
03254 }
03255 }
03256
03257
03258 ( ( KDChartAxisParams& ) para ).setTrueAxisDtLowHighDeltaScale(
03259 dtLow, dtHigh,
03260 dtDeltaScale );
03261
03262
03263 }
03264 bDone = true;
03265 }
03266
03267
03268 if ( !bDone ) {
03269
03270 uint count = bStatistical
03271 ? (data.usedRows() ? data.usedRows() : 1)
03272 : (data.usedCols() ? data.usedCols() : 1);
03273
03274 double start( 1.0 + (bSteadyCalc ? 0.0 : static_cast < double >(data.colsScrolledBy())) );
03275
03276
03277
03278
03279
03280
03281
03282
03283
03284 double delta( 1.0 );
03285 double finis( start + delta * ( count - 1 ) );
03286 const bool startIsDouble = QVariant::Double == para.axisValueStart().type();
03287 const bool endIsDouble = QVariant::Double == para.axisValueEnd().type();
03288
03289 bool deltaIsAuto = true;
03290 if ( !( KDCHART_AXIS_LABELS_AUTO_DELTA == para.axisValueDelta() ) ) {
03291 delta = para.axisValueDelta();
03292 deltaIsAuto = false;
03293 }
03294 if ( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueStart() ) {
03295 if ( ( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueEnd() ) ) {
03296 finis = start + delta * ( count - 1 );
03297 } else {
03298 if( endIsDouble ){
03299 finis = para.axisValueEnd().toDouble();
03300 start = finis - delta * ( count - 1 );
03301
03302 } else {
03303
03304
03305
03306
03307
03308 }
03309 }
03310 }else{
03311 if ( startIsDouble ) {
03312 start = para.axisValueStart().toDouble() + (bSteadyCalc ? 0.0 : static_cast < double >(data.colsScrolledBy()));
03313
03314 } else {
03315
03316
03317
03318
03319
03320 }
03321 if ( !( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueEnd() ) ) {
03322 if (endIsDouble ) {
03323 finis = para.axisValueEnd().toDouble();
03324 if ( deltaIsAuto ) {
03325 delta = ( finis - start ) / count;
03326 } else {
03327 count = static_cast < uint > (
03328 ( finis - start ) / delta );
03329 }
03330 } else {
03331
03332
03333
03334
03335
03336
03337
03338 }
03339 }
03340 else {
03341 finis = start + delta * ( count - 1 );
03342 }
03343 }
03344 QString prefix( QObject::tr( "Item " ) );
03345 QString postfix;
03346
03347
03348 if ( startIsDouble && endIsDouble ) {
03349 int precis =
03350 KDCHART_AXIS_LABELS_AUTO_DIGITS == para.axisDigitsBehindComma()
03351 ? 0
03352 : para.axisDigitsBehindComma();
03353 double s = start;
03354 double f = finis;
03355
03356 bool up = ( 0.0 < delta );
03357
03358
03359
03360 double value = up ? s : f;
03361 uint nLabels = 0;
03362 while ( up ? ( value <= f ) : ( value >= s ) ) {
03363 ++nLabels;
03364 value += delta * up ? 1.0 : -1.0;
03365 }
03366 calculateBasicTextFactors( nTxtHeight, para,
03367 averageValueP1000,
03368 basicPos, orig, delimLen, nLabels,
03369
03370 pDelimDelta,
03371 pTextsX, pTextsY, pTextsW, pTextsH,
03372 textAlign );
03373 QFont font( para.axisLabelsFont() );
03374 if ( para.axisLabelsFontUseRelSize() )
03375 font.setPixelSize( static_cast < int > ( nTxtHeight ) );
03376 painter->setFont( font );
03377 QFontMetrics fm( painter->fontMetrics() );
03378
03379 if ( fm.width( prefix +
03380 QString::number( -fabs( ( s + f ) / 2.0 + delta ),
03381 'f', precis ) )
03382 > pTextsW ) {
03383 prefix = "";
03384 postfix = "";
03385 }
03386
03387 value = up ? s : f;
03388 while ( up ? ( value <= f ) : ( value >= s ) ) {
03389 labelTexts.append(
03390 prefix + QString::number( value, 'f', precis )
03391 + postfix );
03392 value += delta * up ? 1.0 : -1.0;
03393 }
03394 } else {
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404 calculateBasicTextFactors( nTxtHeight, para,
03405 averageValueP1000,
03406 basicPos, orig, delimLen,
03407 count,
03408
03409 pDelimDelta,
03410 pTextsX, pTextsY, pTextsW, pTextsH,
03411 textAlign );
03412 QFont font( para.axisLabelsFont() );
03413 if ( para.axisLabelsFontUseRelSize() )
03414 font.setPixelSize( static_cast < int > ( nTxtHeight ) );
03415 painter->setFont( font );
03416 QFontMetrics fm( painter->fontMetrics() );
03417
03418 if ( fm.width( prefix + QString::number( count - 1 ) )
03419 > pTextsW ) {
03420 prefix = "";
03421 postfix = "";
03422 }
03423
03424 for ( uint i = 1; i <= count; ++i )
03425 labelTexts.append(
03426 prefix + QString::number( i ) + postfix );
03427 }
03428 }
03429 }
03430
03431
03432
03433
03434 uint nLabels = labelTexts.count()
03435 ? labelTexts.count()
03436 : 0;
03437 ( ( KDChartAxisParams& ) para ).setAxisLabelTexts( &labelTexts );
03438
03439 if( !adjustTheValues ){
03440
03441 calculateBasicTextFactors( nTxtHeight, para, averageValueP1000,
03442 basicPos, orig, delimLen, nLabels,
03443
03444 pDelimDelta,
03445 pTextsX, pTextsY, pTextsW, pTextsH,
03446 textAlign );
03447 }
03448
03449 ( ( KDChartAxisParams& ) para ).setTrueAxisDeltaPixels( pDelimDelta );
03450
03451
03452
03453
03454
03455
03456
03457
03458
03459
03460
03461
03462 }
03463
03464
03485
03486 void KDChartAxesPainter::calculateBasicTextFactors( double nTxtHeight,
03487 const KDChartAxisParams& para,
03488 double ,
03489 KDChartAxisParams::AxisPos basicPos,
03490 const QPoint& orig,
03491 double delimLen,
03492 uint nLabels,
03493
03494 double& pDelimDelta,
03495 double& pTextsX,
03496 double& pTextsY,
03497 double& pTextsW,
03498 double& pTextsH,
03499 int& textAlign )
03500 {
03501 switch ( basicPos ) {
03502 case KDChartAxisParams::AxisPosBottom: {
03503 bool bTouchEdges = para.axisLabelsTouchEdges();
03504 double wid = para.axisTrueAreaRect().width();
03505 double divi = bTouchEdges
03506 ? ( 1 < nLabels ? nLabels - 1 : 1 )
03507 : ( nLabels ? nLabels : 10 );
03508 pDelimDelta = wid / divi;
03509
03510 pTextsW = pDelimDelta - 4.0;
03511 pTextsX = orig.x() + 2.0
03512 - ( bTouchEdges
03513 ? pDelimDelta / 2.0
03514 : 0.0 );
03515 pTextsH = para.axisTrueAreaRect().height() - delimLen * 1.33;
03516 pTextsY = orig.y()
03517 + delimLen * 1.33;
03518 textAlign = Qt::AlignHCenter | Qt::AlignTop;
03519
03520
03521
03522 }
03523 break;
03524 case KDChartAxisParams::AxisPosLeft: {
03525 double hig = para.axisTrueAreaRect().height();
03526 pDelimDelta = hig / ( 1 < nLabels ? nLabels - 1 : 1 );
03527
03528 pTextsX = para.axisTrueAreaRect().bottomLeft().x()
03529 + 2.0;
03530 pTextsY = orig.y() - nTxtHeight / 2;
03531 pTextsW = para.axisTrueAreaRect().width()
03532 - delimLen * 1.33 - 2.0;
03533 pTextsH = nTxtHeight;
03534 textAlign = Qt::AlignRight | Qt::AlignVCenter;
03535 }
03536 break;
03537 case KDChartAxisParams::AxisPosTop: {
03538 bool bTouchEdges = para.axisLabelsTouchEdges();
03539 double wid = para.axisTrueAreaRect().width();
03540 double divi = bTouchEdges
03541 ? ( 1 < nLabels ? nLabels - 1 : 1 )
03542 : ( nLabels ? nLabels : 10 );
03543 pDelimDelta = wid / divi;
03544
03545 pTextsW = pDelimDelta - 4.0;
03546 pDelimDelta = wid / divi;
03547
03548 pTextsX = orig.x() + 2.0
03549 - ( bTouchEdges
03550 ? pDelimDelta / 2.0
03551 : 0.0 );
03552 pTextsH = para.axisTrueAreaRect().height() - delimLen * 1.33;
03553 pTextsY = para.axisTrueAreaRect().topLeft().y();
03554 textAlign = Qt::AlignHCenter | Qt::AlignBottom;
03555 }
03556 break;
03557 case KDChartAxisParams::AxisPosRight: {
03558 double hig = para.axisTrueAreaRect().height();
03559 pDelimDelta = hig / ( 1 < nLabels ? nLabels - 1 : 1 );
03560
03561 pTextsX = para.axisTrueAreaRect().bottomLeft().x()
03562 + delimLen * 1.33;
03563 pTextsY = orig.y() - nTxtHeight / 2;
03564 pTextsW = para.axisTrueAreaRect().width()
03565 - delimLen * 1.33 - 2.0;
03566 pTextsH = nTxtHeight;
03567 textAlign = Qt::AlignLeft | Qt::AlignVCenter;
03568 }
03569 break;
03570 default: {
03571 qDebug( "IMPLEMENTATION ERROR: KDChartAxesPainter::calculateBasicTextFactors() unhandled enum value." );
03572
03573 }
03574 break;
03575 }
03576 }
03577
03578
03593 QString KDChartAxesPainter::truncateBehindComma( const double nVal,
03594 const int behindComma,
03595 const double nDelta,
03596 int& trueBehindComma )
03597 {
03598 const int nTrustedPrecision = 6;
03599
03600 const bool bUseAutoDigits = KDCHART_AXIS_LABELS_AUTO_DIGITS == behindComma;
03601 const bool bAutoDelta = KDCHART_AXIS_LABELS_AUTO_DELTA == nDelta;
03602 QString sVal;
03603 sVal.setNum( nVal, 'f', bUseAutoDigits ? nTrustedPrecision
03604 : QMIN(behindComma, nTrustedPrecision) );
03605
03606
03607 if ( bUseAutoDigits ) {
03608 int comma = sVal.find( '.' );
03609 if ( -1 < comma ) {
03610 if ( bAutoDelta ) {
03611 int i = sVal.length();
03612 while ( 1 < i
03613 && '0' == sVal[ i - 1 ] )
03614 --i;
03615 sVal.truncate( i );
03616 if ( '.' == sVal[ i - 1 ] )
03617 sVal.truncate( i - 1 );
03618 } else {
03619 if ( 0 > trueBehindComma ) {
03620 QString sDelta = QString::number( nDelta, 'f', nTrustedPrecision );
03621 int i = sDelta.length();
03622 while ( 1 < i
03623 && '0' == sDelta[ i - 1 ] )
03624 --i;
03625 sDelta.truncate( i );
03626 if ( '.' == sDelta[ i - 1 ] )
03627 trueBehindComma = 0;
03628 else {
03629 int deltaComma = sDelta.find( '.' );
03630 if ( -1 < deltaComma )
03631 trueBehindComma = sDelta.length() - deltaComma - 1;
03632 else
03633 trueBehindComma = 0;
03634 }
03635 }
03636
03637 int nPos = comma + ( trueBehindComma ? trueBehindComma + 1 : 0 );
03638 sVal.truncate( nPos );
03639 }
03640 }
03641 }
03642
03643 return sVal;
03644 }
03645
03646
03647 QString KDChartAxesPainter::applyLabelsFormat( const double nVal,
03648 int divPow10,
03649 int behindComma,
03650 double nDelta,
03651 int& trueBehindComma,
03652 const QString& decimalPoint,
03653 const QString& thousandsPoint,
03654 const QString& prefix,
03655 const QString& postfix,
03656 int totalLen,
03657 const QChar& padFill,
03658 bool blockAlign )
03659 {
03660
03661 QString sVal = truncateBehindComma( nVal / fastPow10( divPow10 ),
03662 behindComma,
03663 nDelta,
03664 trueBehindComma );
03665
03666 int posComma = sVal.find( '.' );
03667 if( 0 <= posComma ){
03668 sVal.replace( posComma, 1, decimalPoint);
03669 }else{
03670 posComma = sVal.length();
03671 }
03672 if( thousandsPoint.length() ){
03673 const int minLen = (0 < sVal.length() && '-' == sVal[0])
03674 ? 4
03675 : 3;
03676 int n = posComma;
03677 while( minLen < n ){
03678 n -= 3;
03679 sVal.insert(n, thousandsPoint);
03680 }
03681 }
03682 sVal.append( postfix );
03683 int nFill = totalLen - (sVal.length() + prefix.length());
03684 if( 0 > nFill )
03685 nFill = 0;
03686 if( !blockAlign )
03687 sVal.prepend( prefix );
03688 for(int i=0; i < nFill; ++i)
03689 sVal.prepend( padFill );
03690 if( blockAlign )
03691 sVal.prepend( prefix );
03692 if ( totalLen > 0 )
03693 sVal.truncate( totalLen );
03694
03695
03696
03697
03698
03699 if ( behindComma == 0 && QString::number(nVal).find('.') > 0 )
03700 sVal = QString::null;
03701 return sVal;
03702 }
03703
03709 void KDChartAxesPainter::calculateOrdinateFactors(
03710 const KDChartAxisParams& para,
03711 bool isLogarithmic,
03712 double& nDist,
03713 double& nDivisor,
03714 double& nRound,
03715 double& nDelta,
03716 double& nSubDelimFactor,
03717 double& nLow,
03718 double& nHigh,
03719 bool findNextRound )
03720 {
03721 if ( findNextRound ) {
03722 if ( 1.0 > nRound )
03723 nRound = 1.0;
03724 else
03725 if ( 2.0 > nRound )
03726 nRound = 2.0;
03727 else
03728 if ( 2.5 > nRound )
03729 nRound = 2.5;
03730 else
03731 if ( 5.0 > nRound )
03732 nRound = 5.0;
03733 else {
03734 nDivisor *= 10.0;
03735 nRound = 1.0;
03736 }
03737 } else {
03738 nDivisor = 1.0;
03739 QString sDistDigis2;
03740 sDistDigis2.setNum( nDist, 'f', 24);
03741 if ( 1.0 > nDist ) {
03742 sDistDigis2.remove( 0, 2 );
03743 nDivisor = 0.01;
03744 while ( 0 < sDistDigis2.length()
03745 && '0' == sDistDigis2[ 0 ] ) {
03746 nDivisor *= 0.1;
03747 sDistDigis2.remove( 0, 1 );
03748 }
03749 } else {
03750 if ( 10.0 > nDist ) {
03751 nDivisor = 0.1;
03752
03753 sDistDigis2.remove( 1, 1 );
03754 } else
03755 if ( 100.0 > nDist )
03756 nDivisor = 1.0;
03757 else {
03758 int comma = sDistDigis2.find( '.' );
03759 if ( -1 < comma )
03760 sDistDigis2.truncate( comma );
03761 nDivisor = fastPow10( (int)sDistDigis2.length() - 2 );
03762 }
03763 }
03764 sDistDigis2.truncate( 2 );
03765 bool bOk;
03766 double nDistDigis2( sDistDigis2.toDouble( &bOk ) );
03767 if ( !bOk )
03768 nDistDigis2 = 10.0;
03769 if ( 75.0 <= nDistDigis2 )
03770 nRound = 5.0;
03771 else
03772 if ( 40.0 <= nDistDigis2 )
03773 nRound = 2.5;
03774 else
03775 if ( 20.0 <= nDistDigis2 )
03776 nRound = 2.0;
03777 else
03778 nRound = 1.0;
03779 }
03780
03781 nDelta = nRound * nDivisor;
03782
03783
03784 if( isLogarithmic )
03785 nDelta = static_cast < int > ( nDelta ) < nDelta
03786 ? static_cast < int > ( nDelta ) + 1
03787 : static_cast < int > ( nDelta );
03788
03789 bool bInvertedAxis = ( 0.0 > nDist );
03790 if( bInvertedAxis )
03791 nDelta *= -1.0;
03792
03793
03794
03795
03796
03797
03798
03799
03800
03801 if( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueStart()
03802 || !para.axisValueStartIsExact() ) {
03803 double orgLow( nLow );
03804 modf( nLow / nDelta, &nLow );
03805 nLow *= nDelta;
03806 if( bInvertedAxis ){
03807 if ( nLow < orgLow )
03808 nLow += nDelta;
03809 if ( 0.0 > nLow && 0.0 <= orgLow )
03810 nLow = 0.0;
03811 }else{
03812 if ( nLow > orgLow )
03813 nLow -= nDelta;
03814 if ( 0.0 < nLow && 0.0 >= orgLow )
03815 nLow = 0.0;
03816 }
03817 }
03818 if ( KDCHART_AXIS_LABELS_AUTO_LIMIT == para.axisValueEnd() ) {
03819 double orgHigh( nHigh );
03820 modf( nHigh / nDelta, &nHigh );
03821 nHigh *= nDelta;
03822 if( bInvertedAxis ){
03823 if ( nHigh > orgHigh )
03824 nHigh -= nDelta;
03825 if ( 0.0 < nHigh && 0.0 >= orgHigh )
03826 nHigh = 0.0;
03827 }else{
03828 if ( nHigh < orgHigh )
03829 nHigh += nDelta;
03830 if ( 0.0 > nHigh && 0.0 <= orgHigh )
03831 nHigh = 0.0;
03832 }
03833 }
03834
03835
03836
03837
03838 if ( 1.0 == nRound )
03839 nSubDelimFactor = 0.5;
03840 else
03841 if ( 2.0 == nRound )
03842 nSubDelimFactor = 0.25;
03843 else
03844 if ( 2.5 == nRound )
03845 nSubDelimFactor = 0.2;
03846 else
03847 if ( 5.0 == nRound )
03848 nSubDelimFactor = 0.2;
03849 else {
03850
03851 qDebug( "IMPLEMENTATION ERROR: Unknown nRound in calculateOrdinateFactors()" );
03852 nSubDelimFactor = 1.0;
03853 }
03854
03855 nDist = nHigh - nLow;
03856 }
03857
03858
03859 void KDChartAxesPainter::saveDrawLine( QPainter& painter,
03860 QPoint pA,
03861 QPoint pZ,
03862 QPen pen )
03863 {
03864 const QPen oldPen( painter.pen() );
03865 bool bNice = ( pen.color() == oldPen.color() )
03866 && ( pen.width() == oldPen.width() )
03867 && ( pen.style() == oldPen.style() );
03868 if ( !bNice )
03869 painter.setPen( pen );
03870 painter.drawLine( pA, pZ );
03871 if ( !bNice )
03872 painter.setPen( oldPen );
03873 }
03874
03875
03876 void KDChartAxesPainter::dtAddSecs( const QDateTime& org, const int secs, QDateTime& dest )
03877 {
03878
03879 int s = org.time().second();
03880 int m = org.time().minute();
03881 int h = org.time().hour();
03882 int days = 0;
03883 if( -1 < secs ){
03884 int mins = (s + secs) / 60;
03885 if( 0 == mins )
03886 s += secs;
03887 else{
03888 s = (s + secs) % 60;
03889 int hours = (m + mins) / 60;
03890 if( 0 == hours )
03891 m += mins;
03892 else{
03893 m = (m + mins) % 60;
03894 days = (h + hours) / 24;
03895 if( 0 == days )
03896 h += hours;
03897 else{
03898 h = (h + hours) % 24;
03899 }
03900 }
03901 }
03902 }
03903 dest.setTime( QTime(h,m,s) );
03904 dest.setDate( org.date() );
03905 if( days )
03906 dtAddDays( dest, days, dest );
03907
03908 }
03909
03910
03911 void KDChartAxesPainter::dtAddDays( const QDateTime& org, const int days, QDateTime& dest )
03912 {
03913
03914 int d = org.date().day();
03915 int m = org.date().month();
03916 int y = org.date().year();
03917 int dd = (-1 < days) ? 1 : -1;
03918 int di = 0;
03919 while( di != days ){
03920 d += dd;
03921
03922 if( 1 > d ){
03923 if( 1 < m ){
03924 --m;
03925 d = QDate( y,m,1 ).daysInMonth();
03926 }
03927 else{
03928 --y;
03929 m = 12;
03930 d = 31;
03931 }
03932
03933 }else if( QDate( y,m,1 ).daysInMonth() < d ){
03934 if( 12 > m )
03935 ++m;
03936 else{
03937 ++y;
03938 m = 1;
03939 }
03940 d = 1;
03941 }
03942 di += dd;
03943 }
03944 dest = QDateTime( QDate( y,m,d ), org.time() );
03945
03946 }
03947
03948
03949 void KDChartAxesPainter::dtAddMonths( const QDateTime& org, const int months, QDateTime& dest )
03950 {
03951
03952 int d = org.date().day();
03953 int m = org.date().month();
03954 int y = org.date().year();
03955 int md = (-1 < months) ? 1 : -1;
03956 int mi = 0;
03957 while( mi != months ){
03958 m += md;
03959 if( 1 > m ){
03960 --y;
03961 m = 12;
03962 }else if( 12 < m ){
03963 ++y;
03964 m = 1;
03965 }
03966 mi += md;
03967 }
03968
03969 dest = QDateTime( QDate( y,m,QMIN( d, QDate( y,m,1 ).daysInMonth() ) ),
03970 org.time() );
03971
03972 }
03973
03974
03975 void KDChartAxesPainter::dtAddYears( const QDateTime& org, const int years, QDateTime& dest )
03976 {
03977
03978 int d = org.date().day();
03979 int m = org.date().month();
03980 int y = org.date().year() + years;
03981 dest.setTime( org.time() );
03982
03983 dest = QDateTime( QDate( y,m,QMIN( d, QDate( y,m,d ).daysInMonth() ) ),
03984 org.time() );
03985
03986 }
03987
03988
03989
03990 void KDChartAxesPainter::calculateAbscissaInfos( const KDChartParams& params,
03991 const KDChartTableDataBase& data,
03992 uint datasetStart,
03993 uint datasetEnd,
03994 double logWidth,
03995 const QRect& dataRect,
03996 abscissaInfos& infos )
03997 {
03998 if( params.axisParams( KDChartAxisParams::AxisPosBottom ).axisVisible()
03999 && ( KDChartAxisParams::AxisTypeUnknown
04000 != params.axisParams( KDChartAxisParams::AxisPosBottom ).axisType() ) )
04001 infos.abscissaPara = ¶ms.axisParams( KDChartAxisParams::AxisPosBottom );
04002 else
04003 if( params.axisParams( KDChartAxisParams::AxisPosBottom2 ).axisVisible()
04004 && ( KDChartAxisParams::AxisTypeUnknown
04005 != params.axisParams( KDChartAxisParams::AxisPosBottom2 ).axisType() ) )
04006 infos.abscissaPara = ¶ms.axisParams( KDChartAxisParams::AxisPosBottom2 );
04007 else
04008 if( params.axisParams( KDChartAxisParams::AxisPosTop ).axisVisible()
04009 && ( KDChartAxisParams::AxisTypeUnknown
04010 != params.axisParams( KDChartAxisParams::AxisPosTop ).axisType() ) )
04011 infos.abscissaPara = ¶ms.axisParams( KDChartAxisParams::AxisPosTop );
04012 else
04013 if( params.axisParams( KDChartAxisParams::AxisPosTop2 ).axisVisible()
04014 && ( KDChartAxisParams::AxisTypeUnknown
04015 != params.axisParams( KDChartAxisParams::AxisPosTop2 ).axisType() ) )
04016 infos.abscissaPara = ¶ms.axisParams( KDChartAxisParams::AxisPosTop2 );
04017 else
04018
04019 infos.abscissaPara = ¶ms.axisParams( KDChartAxisParams::AxisPosBottom );
04020
04021 if( infos.abscissaPara->axisLabelsTouchEdges() )
04022 infos.bCenterThePoints = false;
04023
04024 infos.bAbscissaDecreasing = infos.abscissaPara->axisValuesDecreasing();
04025 infos.bAbscissaIsLogarithmic
04026 = KDChartAxisParams::AxisCalcLogarithmic == infos.abscissaPara->axisCalcMode();
04027
04028
04029
04030
04031 infos.numValues = 0;
04032 if ( params.numValues() > -1 )
04033 infos.numValues = params.numValues();
04034 else
04035 infos.numValues = data.usedCols();
04036
04037 QVariant::Type type2Ref = QVariant::Invalid;
04038 infos.bCellsHaveSeveralCoordinates =
04039 data.cellsHaveSeveralCoordinates( datasetStart, datasetEnd,
04040 &type2Ref );
04041
04042 infos.numLabels = (infos.abscissaPara &&
04043 infos.abscissaPara->axisLabelTexts())
04044 ? infos.abscissaPara->axisLabelTexts()->count()
04045 : infos.numValues;
04046 if( 0 >= infos.numLabels )
04047 infos.numLabels = 1;
04048
04049 infos.bAbscissaHasTrueAxisValues =
04050 infos.abscissaPara && (0.0 != infos.abscissaPara->trueAxisDelta());
04051 infos.abscissaStart = infos.bAbscissaHasTrueAxisValues
04052 ? infos.abscissaPara->trueAxisLow()
04053 : 0.0;
04054 infos.abscissaEnd = infos.bAbscissaHasTrueAxisValues
04055 ? infos.abscissaPara->trueAxisHigh()
04056 : 1.0 * (infos.numLabels - 1);
04057 infos.abscissaSpan = fabs( infos.abscissaEnd - infos.abscissaStart );
04058 infos.abscissaDelta = infos.bAbscissaHasTrueAxisValues
04059 ? infos.abscissaPara->trueAxisDelta()
04060 : ( ( 0.0 != infos.abscissaSpan )
04061 ? ( infos.abscissaSpan / infos.numLabels )
04062 : infos.abscissaSpan );
04063
04064
04065
04066
04067
04068 infos.bAbscissaHasTrueAxisDtValues =
04069 (QVariant::DateTime == type2Ref) &&
04070 infos.abscissaPara &&
04071 infos.abscissaPara->trueAxisDtLow().isValid();
04072 if( infos.bAbscissaHasTrueAxisDtValues ){
04073 infos.numLabels = 200;
04074 infos.bCenterThePoints = false;
04075 }
04076
04077 infos.dtLowPos = infos.bAbscissaHasTrueAxisDtValues
04078 ? infos.abscissaPara->axisDtLowPosX() - dataRect.x()
04079 : 0.0;
04080 infos.dtHighPos = infos.bAbscissaHasTrueAxisDtValues
04081 ? infos.abscissaPara->axisDtHighPosX() - dataRect.x()
04082 : logWidth;
04083 infos.abscissaDtStart = infos.bAbscissaHasTrueAxisDtValues
04084 ? infos.abscissaPara->trueAxisDtLow()
04085 : QDateTime();
04086 infos.abscissaDtEnd = infos.bAbscissaHasTrueAxisDtValues
04087 ? infos.abscissaPara->trueAxisDtHigh()
04088 : QDateTime();
04089
04090
04091 infos.abscissaDtStart.setTime(
04092 QTime( infos.abscissaDtStart.time().hour(),
04093 infos.abscissaDtStart.time().minute(),
04094 infos.abscissaDtStart.time().second(),
04095 0 ) );
04096 infos.abscissaDtEnd.setTime(
04097 QTime( infos.abscissaDtEnd.time().hour(),
04098 infos.abscissaDtEnd.time().minute(),
04099 infos.abscissaDtEnd.time().second(),
04100 999 ) );
04101
04102
04103
04104 infos.bScaleLessThanDay = ( infos.bAbscissaHasTrueAxisDtValues
04105 ? infos.abscissaPara->trueAxisDtDeltaScale()
04106 : KDChartAxisParams::ValueScaleDay )
04107 < KDChartAxisParams::ValueScaleDay;
04108
04109 if( infos.bAbscissaHasTrueAxisDtValues ){
04110 if( infos.bScaleLessThanDay ){
04111 infos.abscissaDtSpan = infos.abscissaDtStart.secsTo( infos.abscissaDtEnd );
04112
04113
04114
04115
04116
04117
04118
04119 }
04120 else{
04121 infos.abscissaDtSpan = infos.abscissaDtStart.daysTo( infos.abscissaDtEnd );
04122 if( infos.abscissaDtStart.time().msec() || infos.abscissaDtEnd.time().msec() )
04123 infos.abscissaDtSpan +=
04124 ( infos.abscissaDtEnd.time().msec() -
04125 infos.abscissaDtStart.time().msec() ) / (86400.0 * 1000.0);
04126 if( infos.abscissaDtEnd.time().second() )
04127 infos.abscissaDtSpan += infos.abscissaDtEnd.time().second() / 86400.0;
04128 if( infos.abscissaDtEnd.time().minute() )
04129 infos.abscissaDtSpan += infos.abscissaDtEnd.time().minute() / 1440.0;
04130 if( infos.abscissaDtEnd.time().hour() )
04131 infos.abscissaDtSpan += infos.abscissaDtEnd.time().hour() / 24.0;
04132 }
04133 }else
04134 infos.abscissaDtSpan = 10.0;
04135 if( 0 == infos.abscissaDtSpan || 0.0 == infos.abscissaDtSpan )
04136 infos.abscissaDtSpan = 1.0;
04137
04138
04139 infos.abscissaDtPixelsPerScaleUnit = (infos.dtHighPos - infos.dtLowPos) / infos.abscissaDtSpan;
04140 if( infos.bAbscissaHasTrueAxisDtValues )
04141 infos.abscissaDelta = 20.0;
04142
04143 infos.pointDist
04144 = ( infos.abscissaPara && (0.0 != infos.abscissaPara->trueAxisDeltaPixels()) )
04145 ? infos.abscissaPara->trueAxisDeltaPixels()
04146 : ( logWidth /
04147 (
04148 (1 > ((double)(infos.numLabels) - (infos.bCenterThePoints ? 0.0 : 1.0)))
04149 ? ((double)(infos.numLabels) - (infos.bCenterThePoints ? 0.0 : 1.0))
04150 : 1 ) );
04151
04152 infos.abscissaPixelsPerUnit = ( 0.0 != infos.abscissaDelta )
04153 ? ( infos.pointDist / infos.abscissaDelta )
04154 : infos.pointDist;
04155
04156
04157 infos.abscissaZeroPos = infos.abscissaPara->axisZeroLineStartX() - dataRect.x();
04158
04159
04160
04161
04162
04163
04164
04165
04166
04167
04168
04169
04170
04171
04172 }
04173
04174
04175
04176 bool KDChartAxesPainter::calculateAbscissaAxisValue( const QVariant& value,
04177 abscissaInfos& ai,
04178 int colNumber,
04179 double& xValue )
04180 {
04181 if( ai.bCellsHaveSeveralCoordinates ) {
04182 if( QVariant::Double == value.type() ) {
04183 double dVal = value.toDouble();
04184 if( ai.bAbscissaIsLogarithmic ){
04185 if( 0.0 < dVal )
04186 xValue = ai.abscissaPixelsPerUnit * log10( dVal );
04187 else
04188 xValue = -10250.0;
04189 }else{
04190 xValue = ai.abscissaPixelsPerUnit * dVal;
04191 }
04192 xValue *= ai.bAbscissaDecreasing ? -1.0 : 1.0;
04193 xValue += ai.abscissaZeroPos;
04194 }
04195 else if( ai.bAbscissaHasTrueAxisDtValues &&
04196 QVariant::DateTime == value.type() ) {
04197 const QDateTime dtVal = value.toDateTime();
04198 double dT = ( ai.bScaleLessThanDay )
04199 ? ai.abscissaDtStart.secsTo( dtVal )
04200 : ai.abscissaDtStart.daysTo( dtVal );
04201
04202
04203
04204
04205
04206
04207
04208
04209
04210
04211
04212
04213
04214
04215
04216
04217
04218
04219
04220 xValue = ai.abscissaDtPixelsPerScaleUnit * dT;
04221 if( dtVal.time().msec() )
04222 xValue += (ai.abscissaDtPixelsPerScaleUnit * dtVal.time().msec())
04223 / ( ai.bScaleLessThanDay
04224 ? 1000.0
04225 : (1000.0 * 86400.0) );
04226
04227 if( !ai.bScaleLessThanDay ){
04228 if( dtVal.time().second() )
04229 xValue += (ai.abscissaDtPixelsPerScaleUnit * dtVal.time().second())
04230 / 86400.0;
04231 if( dtVal.time().minute() )
04232 xValue += (ai.abscissaDtPixelsPerScaleUnit * dtVal.time().minute())
04233 / 1440.0;
04234 if( dtVal.time().hour() )
04235 xValue += (ai.abscissaDtPixelsPerScaleUnit * dtVal.time().hour())
04236 / 24.0;
04237 }
04238 xValue *= ai.bAbscissaDecreasing ? -1.0 : 1.0;
04239 xValue += ai.dtLowPos;
04240
04241
04242 }
04243 else
04244 return false;
04245 } else
04246 xValue = ai.pointDist * ( double ) colNumber;
04247 return true;
04248 }
04249
04250
04251
04252
04253
04254
04255
04256
04257
04258
04259
04260
04261
04272 void KDChartAxesPainter::paintData( QPainter* painter,
04273 KDChartTableDataBase* data,
04274 bool paint2nd,
04275 KDChartDataRegionList* regions )
04276 {
04277 bool bNormalMode = isNormalMode();
04278
04279 uint chart = paint2nd ? 1 : 0;
04280
04281
04282
04283 uint axesCount;
04284 KDChartParams::AxesArray ordinateAxes;
04285 ordinateAxes.resize( KDCHART_CNT_ORDINATES );
04286 if( !params()->chartAxes( chart, axesCount, ordinateAxes ) ) {
04287
04288 return;
04289
04290
04291
04292
04293 }
04294
04295
04296
04297
04298 double logWidth = _dataRect.width();
04299 double areaWidthP1000 = logWidth / 1000.0;
04300
04301 int nClipShiftUp = clipShiftUp(bNormalMode, areaWidthP1000);
04302 QRect ourClipRect( _dataRect );
04303 if ( 0 < ourClipRect.top() ) {
04304 ourClipRect.setTop( ourClipRect.top() - nClipShiftUp );
04305 ourClipRect.setHeight( ourClipRect.height() + nClipShiftUp - 1 );
04306 } else
04307 ourClipRect.setHeight( ourClipRect.height() + nClipShiftUp / 2 - 1 );
04308
04309
04310
04311
04312
04313
04314 const QWMatrix & world = painter->worldMatrix();
04315 ourClipRect =
04316 #if COMPAT_QT_VERSION >= 0x030000
04317 world.mapRect( ourClipRect );
04318 #else
04319 world.map( ourClipRect );
04320 #endif
04321 painter->setClipRect( ourClipRect );
04322 painter->translate( _dataRect.x(), _dataRect.y() );
04323
04324 painter->setPen( params()->outlineDataColor() );
04325
04326
04327 uint chartDatasetStart, chartDatasetEnd;
04328 findChartDatasets( data, paint2nd, chart, chartDatasetStart, chartDatasetEnd );
04329
04330
04331 for( uint aI = 0; aI < axesCount; ++aI ) {
04332
04333 uint axis = ordinateAxes.at( aI );
04334
04335 const KDChartAxisParams* axisPara = ¶ms()->axisParams( axis );
04336
04337 uint datasetStart, datasetEnd;
04338 uint axisDatasetStart, axisDatasetEnd;
04339 uint dummy;
04340 if( params()->axisDatasets( axis,
04341 axisDatasetStart,
04342 axisDatasetEnd, dummy )
04343 && ( KDCHART_ALL_DATASETS != axisDatasetStart ) ) {
04344
04345 if( KDCHART_NO_DATASET == axisDatasetStart ){
04346
04347 continue;
04348
04349 }
04350
04351 if( axisDatasetStart >= chartDatasetStart
04352 && axisDatasetStart <= chartDatasetEnd )
04353 datasetStart = QMAX( axisDatasetStart, chartDatasetStart );
04354 else if( axisDatasetStart <= chartDatasetStart
04355 && axisDatasetEnd >= chartDatasetStart )
04356 datasetStart = chartDatasetStart;
04357 else
04358 datasetStart = 20;
04359 if( axisDatasetEnd >= chartDatasetStart
04360 && axisDatasetEnd <= chartDatasetEnd )
04361 datasetEnd = QMIN( axisDatasetEnd, chartDatasetEnd );
04362 else if( axisDatasetEnd >= chartDatasetEnd
04363 && axisDatasetStart <= chartDatasetEnd )
04364 datasetEnd = chartDatasetEnd;
04365 else
04366 datasetEnd = 0;
04367 } else {
04368 datasetStart = chartDatasetStart;
04369 datasetEnd = chartDatasetEnd;
04370 }
04371
04372
04373
04374
04375
04376 double logHeight = axisPara->axisTrueAreaRect().height();
04377 double axisYOffset = axisPara->axisTrueAreaRect().y() - _dataRect.y();
04378
04379
04380
04381
04382
04383
04384
04385
04386 double maxColumnValue = axisPara->trueAxisHigh();
04387 double minColumnValue = axisPara->trueAxisLow();
04388 double columnValueDistance = maxColumnValue - minColumnValue;
04389
04390
04391
04392 specificPaintData( painter,
04393 ourClipRect,
04394 data,
04395 regions,
04396 axisPara,
04397 bNormalMode,
04398 chart,
04399 logWidth,
04400 areaWidthP1000,
04401 logHeight,
04402 axisYOffset,
04403 minColumnValue,
04404 maxColumnValue,
04405 columnValueDistance,
04406 chartDatasetStart,
04407 chartDatasetEnd,
04408 datasetStart,
04409 datasetEnd );
04410 }
04411 painter->translate( - _dataRect.x(), - _dataRect.y() );
04412 }