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