kchart

KDChartAxesPainter.cpp

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