# KDChartCartesianAxis.cpp

Go to the documentation of this file.

    00001 /****************************************************************************
    00002  ** Copyright (C) 2006 Klarävdalens Datakonsult AB.  All rights reserved.
    00003  **
    00004  ** This file is part of the KD Chart library.
    00005  **
    00006  ** This file may be distributed and/or modified under the terms of the
    00007  ** GNU General Public License version 2 as published by the Free Software
    00008  ** Foundation and appearing in the file LICENSE.GPL included in the
    00009  ** packaging of this file.
    00010  **
    00011  ** Licensees holding valid commercial KD Chart licenses may use this file in
    00012  ** accordance with the KD Chart Commercial License Agreement provided with
    00013  ** the Software.
    00014  **
    00015  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    00016  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    00017  **
    00018  ** See http://www.kdab.net/kdchart for
    00019  **   information about KD Chart Commercial License Agreements.
    00020  **
    00021  ** Contact info@kdab.net if any conditions of this
    00022  ** licensing are not clear to you.
    00023  **
    00024  **********************************************************************/
    00025
    00026 #include <cmath>
    00027
    00028 #include <QtDebug>
    00029 #include <QPainter>
    00030 #include <QPen>
    00031 #include <QBrush>
    00032 #include <QApplication>
    00033
    00034 #include "KDChartPaintContext.h"
    00035 #include "KDChartChart.h"
    00036 #include "KDChartCartesianAxis.h"
    00037 #include "KDChartCartesianAxis_p.h"
    00038 #include "KDChartAbstractCartesianDiagram.h"
    00039 #include "KDChartAbstractGrid.h"
    00040 #include "KDChartPainterSaver_p.h"
    00041 #include "KDChartLayoutItems.h"
    00042 #include "KDChartBarDiagram.h"
    00043
    00044 #include <KDABLibFakes>
    00045
    00046
    00047 using namespace KDChart;
    00048
    00049 #define d (d_func())
    00050
    00051 CartesianAxis::CartesianAxis ( AbstractCartesianDiagram* diagram )
    00052     : AbstractAxis ( new Private( diagram, this ), diagram )
    00053 {
    00054     init();
    00055 }
    00056
    00057 CartesianAxis::~CartesianAxis ()
    00058 {
    00059     // when we remove the first axis it will unregister itself and
    00060     // propagate the next one to the primary, thus the while loop
    00061     while ( d->mDiagram ) {
    00062         AbstractCartesianDiagram *cd = qobject_cast<AbstractCartesianDiagram*>( d->mDiagram );
    00063         cd->takeAxis( this );
    00064     }
    00065     Q_FOREACH( AbstractDiagram *diagram, d->secondaryDiagrams ) {
    00066         AbstractCartesianDiagram *cd = qobject_cast<AbstractCartesianDiagram*>( diagram );
    00067         cd->takeAxis( this );
    00068     }
    00069 }
    00070
    00071 void CartesianAxis::init ()
    00072 {
    00073     d->position = Bottom;
    00074 }
    00075
    00076
    00077 bool CartesianAxis::compare( const CartesianAxis* other )const
    00078 {
    00079     if( other == this ) return true;
    00080     if( ! other ){
    00081         //qDebug() << "CartesianAxis::compare() cannot compare to Null pointer";
    00082         return false;
    00083     }
    00084     /*
    00085     qDebug() << (position()            == other->position());
    00086     qDebug() << (titleText()           == other->titleText());
    00087     qDebug() << (titleTextAttributes() == other->titleTextAttributes());
    00088     */
    00089     return  ( static_cast<const AbstractAxis*>(this)->compare( other ) ) &&
    00090             ( position()            == other->position() ) &&
    00091             ( titleText()           == other->titleText() ) &&
    00092             ( titleTextAttributes() == other->titleTextAttributes() );
    00093 }
    00094
    00095
    00096 void CartesianAxis::setTitleText( const QString& text )
    00097 {
    00098     //FIXME(khz): Call update al all places where axis internals are changed!
    00099     d->titleText = text;
    00100     layoutPlanes();
    00101 }
    00102
    00103 QString CartesianAxis::titleText() const
    00104 {
    00105     return d->titleText;
    00106 }
    00107
    00108 void CartesianAxis::setTitleTextAttributes( const TextAttributes &a )
    00109 {
    00110     d->titleTextAttributes = a;
    00111     d->useDefaultTextAttributes = false;
    00112     layoutPlanes();
    00113 }
    00114
    00115 TextAttributes CartesianAxis::titleTextAttributes() const
    00116 {
    00117     if( hasDefaultTitleTextAttributes() ){
    00118         TextAttributes ta( textAttributes() );
    00119         Measure me( ta.fontSize() );
    00120         me.setValue( me.value() * 1.5 );
    00121         ta.setFontSize( me );
    00122         return ta;
    00123     }
    00124     return d->titleTextAttributes;
    00125 }
    00126
    00127 void CartesianAxis::resetTitleTextAttributes()
    00128 {
    00129     d->useDefaultTextAttributes = true;
    00130     layoutPlanes();
    00131 }
    00132
    00133 bool CartesianAxis::hasDefaultTitleTextAttributes() const
    00134 {
    00135     return d->useDefaultTextAttributes;
    00136 }
    00137
    00138
    00139 void CartesianAxis::setPosition ( Position p )
    00140 {
    00141     d->position = p;
    00142     layoutPlanes();
    00143 }
    00144
    00145 const CartesianAxis::Position CartesianAxis::position() const
    00146 {
    00147     return d->position;
    00148 }
    00149
    00150 void CartesianAxis::layoutPlanes()
    00151 {
    00152     //qDebug() << "CartesianAxis::layoutPlanes()";
    00153     if( ! d->diagram() || ! d->diagram()->coordinatePlane() ) {
    00154         //qDebug() << "CartesianAxis::layoutPlanes(): Sorry, found no plane.";
    00155         return;
    00156     }
    00157     AbstractCoordinatePlane* plane = d->diagram()->coordinatePlane();
    00158     if( plane ){
    00159         plane->layoutPlanes();
    00160         //qDebug() << "CartesianAxis::layoutPlanes() OK";
    00161     }
    00162 }
    00163
    00164 bool CartesianAxis::isAbscissa() const
    00165 {
    00166     return position() == Bottom || position() == Top;
    00167 }
    00168
    00169 bool CartesianAxis::isOrdinate() const
    00170 {
    00171     return position() == Left || position() == Right;
    00172 }
    00173
    00174 /*
    00175   void CartesianAxis::paintEvent( QPaintEvent* event )
    00176   {
    00177   Q_UNUSED( event );
    00178
    00179   if( ! d->diagram() || ! d->diagram()->coordinatePlane() ) return;
    00180
    00181   PaintContext context;
    00182   QPainter painter( this );
    00183   context.setPainter( &painter );
    00184   AbstractCoordinatePlane* plane = d->diagram()->coordinatePlane();
    00185   context.setCoordinatePlane( plane );
    00186   QRectF rect = QRectF ( 1, 1, plane->width() - 3, plane->height() - 3 );
    00187   context.setRectangle( rect );
    00188   d->geometry.setSize( size() );
    00189   paintCtx( &context );
    00190   }
    00191 */
    00192
    00193 void CartesianAxis::paint( QPainter* painter )
    00194 {
    00195     if( ! d->diagram() || ! d->diagram()->coordinatePlane() ) return;
    00196     PaintContext ctx;
    00197     ctx.setPainter ( painter );
    00198     ctx.setCoordinatePlane( d->diagram()->coordinatePlane() );
    00199     const QRect rect( areaGeometry() );
    00200
    00201     //qDebug() << "CartesianAxis::paint( QPainter* painter )  " << " areaGeometry()():" << rect << " sizeHint():" << sizeHint();
    00202
    00203     ctx.setRectangle(
    00204         QRectF (
    00205             //QPointF(0, 0),
    00206             QPointF(rect.left(), rect.top()),
    00207             QSizeF(rect.width(), rect.height() ) ) );
    00208     // enabling clipping so that we're not drawing outside
    00209     QRegion clipRegion( rect.adjusted( -1, -1, 1, 1 ) );
    00210     painter->save();
    00211     painter->setClipRegion( clipRegion );
    00212     paintCtx( &ctx );
    00213     painter->restore();
    00214     //qDebug() << "KDChart::CartesianAxis::paint() done.";
    00215 }
    00216
    00217 void CartesianAxis::Private::drawSubUnitRulers( QPainter* painter, CartesianCoordinatePlane* plane, const DataDimension& dim,
    00218                                                 const QPointF& rulerRef, const QVector<int>& drawnTicks ) const
    00219 {
    00220     const QRect geoRect( axis()->geometry() );
    00221     int nextMayBeTick = 0;
    00222     int mayBeTick = 0;
    00223     int logSubstep = 0;
    00224     float f = dim.start;
    00225     qreal fLogSubstep = f;
    00226     const bool isAbscissa = axis()->isAbscissa();
    00227     const bool isLogarithmic = (dim.calcMode == AbstractCoordinatePlane::Logarithmic );
    00228     const int subUnitTickLength = axis()->tickLength( true );
    00229     while ( f <= dim.end ) {
    00230         if( drawnTicks.count() > nextMayBeTick )
    00231             mayBeTick = drawnTicks[ nextMayBeTick ];
    00232         if ( isAbscissa ) {
    00233             // for the x-axis
    00234             QPointF topPoint ( f, 0 );
    00235             QPointF bottomPoint ( f, 0 );
    00236             // we don't draw the sub ticks, if we are at the same position as a normal tick
    00237             topPoint = plane->translate( topPoint );
    00238             bottomPoint = plane->translate( bottomPoint );
    00239             topPoint.setY( rulerRef.y() + subUnitTickLength );
    00240             bottomPoint.setY( rulerRef.y() );
    00241             if( qAbs( mayBeTick - topPoint.x() ) > 1 )
    00242                 painter->drawLine( topPoint, bottomPoint );
    00243             else {
    00244                 ++nextMayBeTick;
    00245             }
    00246         } else {
    00247             // for the y-axis
    00248             QPointF leftPoint = plane->translate( QPointF( 0, f ) );
    00249             //qDebug() << "geoRect:" << geoRect << "   geoRect.top()" << geoRect.top() << "geoRect.bottom()" << geoRect.bottom() << "  translatedValue:" << translatedValue;
    00250             // we don't draw the sub ticks, if we are at the same position as a normal tick
    00251             if( qAbs( mayBeTick - leftPoint.y() ) > 1 ){
    00252                 const qreal translatedValue = leftPoint.y();
    00253                 if( translatedValue > geoRect.top() && translatedValue <= geoRect.bottom() ){
    00254                     QPointF rightPoint ( 0, f );
    00255                     rightPoint = plane->translate( rightPoint );
    00256                     leftPoint.setX( rulerRef.x() + subUnitTickLength );
    00257                     rightPoint.setX( rulerRef.x() );
    00258                     painter->drawLine( leftPoint, rightPoint );
    00259                 }
    00260             } else {
    00261                 ++nextMayBeTick;
    00262             }
    00263         }
    00264         if ( isLogarithmic ){
    00265             if( logSubstep == 9 ){
    00266                 fLogSubstep *= 10.0;
    00267                 logSubstep = 0;
    00268             }
    00269             f += fLogSubstep;
    00270             ++logSubstep;
    00271         }else{
    00272             f += dim.subStepWidth;
    00273         }
    00274     }
    00275 }
    00276
    00277
    00278 const TextAttributes CartesianAxis::Private::titleTextAttributesWithAdjustedRotation() const
    00279 {
    00280     TextAttributes titleTA( titleTextAttributes );
    00281     if( axis()->isOrdinate() ){
    00282         int rotation = titleTA.rotation() + 270;
    00283         if( rotation >= 360 )
    00284             rotation -= 360;
    00285
    00286         // limit the allowed values to 0, 90, 180, 270:
    00287         if( rotation  < 90 )
    00288             rotation = 0;
    00289         else if( rotation  < 180 )
    00290             rotation = 90;
    00291         else if( rotation  < 270 )
    00292             rotation = 180;
    00293         else if( rotation  < 360 )
    00294             rotation = 270;
    00295         else
    00296             rotation = 0;
    00297
    00298         titleTA.setRotation( rotation );
    00299     }
    00300     return titleTA;
    00301 }
    00302
    00303
    00304 void CartesianAxis::Private::drawTitleText( QPainter* painter, CartesianCoordinatePlane* plane, const QRect& areaGeoRect ) const
    00305 {
    00306     const TextAttributes titleTA( titleTextAttributesWithAdjustedRotation() );
    00307     if( titleTA.isVisible() ) {
    00308         TextLayoutItem titleItem( titleText,
    00309                                   titleTA,
    00310                                   plane->parent(),
    00311                                   KDChartEnums::MeasureOrientationMinimum,
    00312                                   Qt::AlignHCenter|Qt::AlignVCenter );
    00313         QPointF point;
    00314         const QSize size( titleItem.sizeHint() );
    00315         //FIXME(khz): We definitely need to provide a way that users can decide
    00316         //            the position of an axis title.
    00317         switch( position )
    00318         {
    00319         case Top:
    00320             point.setX( areaGeoRect.left() + areaGeoRect.width() / 2.0);
    00321             point.setY( areaGeoRect.top()  + size.height() / 2 );
    00322             break;
    00323         case Bottom:
    00324             point.setX( areaGeoRect.left() + areaGeoRect.width() / 2.0);
    00325             point.setY( areaGeoRect.bottom() - size.height() / 2 );
    00326             break;
    00327         case Left:
    00328             point.setX( areaGeoRect.left() + size.width() / 2 );
    00329             point.setY( areaGeoRect.top() + areaGeoRect.height() / 2.0);
    00330             break;
    00331         case Right:
    00332             point.setX( areaGeoRect.right() - size.width() / 2 );
    00333             point.setY( areaGeoRect.top() + areaGeoRect.height() / 2.0);
    00334             break;
    00335         }
    00336         PainterSaver painterSaver( painter );
    00337         painter->translate( point );
    00338         //if( axis()->isOrdinate() )
    00339         //    painter->rotate( 270.0 );
    00340         titleItem.setGeometry( QRect( QPoint(-size.width() / 2, -size.height() / 2), size ) );
    00341         //painter->drawRect(titleItem.geometry().adjusted(0,0,-1,-1));
    00342         titleItem.paint( painter );
    00343     }
    00344 }
    00345
    00346
    00347 static void calculateNextLabel( qreal& labelValue, qreal step, bool isLogarithmic)
    00348 {
    00349     if ( isLogarithmic ){
    00350         labelValue *= 10.0;
    00351     }else{
    00352         //qDebug() << "new axis label:" << labelValue << "+" << step << "=" << labelValue+step;
    00353         labelValue += step;
    00354     }
    00355     if( qAbs(labelValue) < 1.0e-15 )
    00356         labelValue = 0.0;
    00357 }
    00358
    00359
    00360 static bool referenceDiagramIsBarDiagram( const AbstractDiagram * diagram )
    00361 {
    00362     const AbstractCartesianDiagram * dia =
    00363             qobject_cast< const AbstractCartesianDiagram * >( diagram );
    00364     if( dia && dia->referenceDiagram() )
    00365         dia = dia->referenceDiagram();
    00366     return qobject_cast< const BarDiagram* >( dia ) != 0;
    00367 }
    00368
    00369
    00370 void CartesianAxis::paintCtx( PaintContext* context )
    00371 {
    00372
    00373     Q_ASSERT_X ( d->diagram(), "CartesianAxis::paint",
    00374                  "Function call not allowed: The axis is not assigned to any diagram." );
    00375
    00376     CartesianCoordinatePlane* plane = dynamic_cast<CartesianCoordinatePlane*>(context->coordinatePlane());
    00377     Q_ASSERT_X ( plane, "CartesianAxis::paint",
    00378                  "Bad function call: PaintContext::coodinatePlane() NOT a cartesian plane." );
    00379
    00380     // note: Not having any data model assigned is no bug
    00381     //       but we can not draw an axis then either.
    00382     if( ! d->diagram()->model() )
    00383         return;
    00384
    00385
    00386     /*
    00387      * let us paint the labels at a
    00388      * smaller resolution
    00389      * Same mini pixel value as for
    00390      * Cartesian Grid
    00391      */
    00392     //const qreal MinimumPixelsBetweenRulers = 1.0;
    00393     DataDimensionsList dimensions( plane->gridDimensionsList() );
    00394     //qDebug("CartesianAxis::paintCtx() gets DataDimensionsList.first():   start: %f   end: %f   stepWidth: %f", dimensions.first().start, dimensions.first().end, dimensions.first().stepWidth);
    00395
    00396     // test for programming errors: critical
    00397     Q_ASSERT_X ( dimensions.count() == 2, "CartesianAxis::paint",
    00398                  "Error: plane->gridDimensionsList() did not return exactly two dimensions." );
    00399     DataDimension dimX =
    00400             AbstractGrid::adjustedLowerUpperRange( dimensions.first(), true, true );
    00401     const DataDimension dimY =
    00402             AbstractGrid::adjustedLowerUpperRange( dimensions.last(), true, true );
    00403     const DataDimension& dim = (isAbscissa() ? dimX : dimY);
    00404
    00405     /*
    00406     if(isAbscissa())
    00407         qDebug() << "         " << "Abscissa:" << dimX.start <<".."<<dimX.end <<"  step"<<dimX.stepWidth;
    00408     else
    00409         qDebug() << "         " << "Ordinate:" << dimY.start <<".."<<dimY.end <<"  step"<<dimY.stepWidth;
    00410     */
    00411
    00412
    00413     /*
    00414      * let us paint the labels at a
    00415      * smaller resolution
    00416      * Same mini pixel value as for
    00417      * Cartesian Grid
    00418      */
    00419     const qreal MinimumPixelsBetweenRulers = qMin(  dimX.stepWidth,  dimY.stepWidth );//1.0;
    00420
    00421     // preparations:
    00422     // - calculate the range that will be displayed:
    00423     const qreal absRange = qAbs( dim.distance() );
    00424
    00425     qreal numberOfUnitRulers;
    00426     if ( isAbscissa() ) {
    00427         if( dimX.isCalculated )
    00428             numberOfUnitRulers = absRange / qAbs( dimX.stepWidth ) + 1.0;
    00429         else
    00430             numberOfUnitRulers = d->diagram()->model()->rowCount() - 1.0;
    00431     }else{
    00432         numberOfUnitRulers = absRange / qAbs( dimY.stepWidth ) + 1.0;
    00433
    00434     }
    00435
    00436     //    qDebug() << "absRange" << absRange << "dimY.stepWidth:" << dimY.stepWidth << "numberOfUnitRulers:" << numberOfUnitRulers;
    00437
    00438     qreal numberOfSubUnitRulers;
    00439     if ( isAbscissa() ){
    00440         if( dimX.isCalculated )
    00441             numberOfSubUnitRulers = absRange / qAbs( dimX.subStepWidth ) + 1.0;
    00442         else
    00443             numberOfSubUnitRulers = dimX.subStepWidth>0 ? absRange / qAbs( dimX.subStepWidth ) + 1.0 : 0.0;
    00444     }else{
    00445         numberOfSubUnitRulers = absRange / qAbs( dimY.subStepWidth ) + 1.0;
    00446     }
    00447
    00448     // - calculate the absolute range in screen pixels:
    00449     const QPointF p1 = plane->translate( QPointF(dimX.start, dimY.start) );
    00450     const QPointF p2 = plane->translate( QPointF(dimX.end,   dimY.end) );
    00451
    00452     double screenRange;
    00453     if ( isAbscissa() )
    00454     {
    00455         screenRange = qAbs ( p1.x() - p2.x() );
    00456     } else {
    00457         screenRange = qAbs ( p1.y() - p2.y() );
    00458     }
    00459
    00460     const bool useItemCountLabels = isAbscissa() && ! dimX.isCalculated;
    00461     //qDebug() << "CartesianAxis::paintCtx useItemCountLabels "<< useItemCountLabels;
    00462
    00463     //qDebug() << "isAbscissa():" << isAbscissa() << "   dimX.isCalculated:" << dimX.isCalculated << "   dimX.stepWidth: "<<dimX.stepWidth;
    00464     //FIXME(khz): Remove this code, and do the calculation in the grid calc function
    00465     if( isAbscissa() && ! dimX.isCalculated ){
    00466         // dont ignore the users settings
    00467         dimX.stepWidth = dimX.stepWidth ? dimX.stepWidth : 1.0;
    00468         //qDebug() << "screenRange / numberOfUnitRulers <= MinimumPixelsBetweenRulers" << screenRange <<"/" << numberOfUnitRulers <<"<=" << MinimumPixelsBetweenRulers;
    00469         while( screenRange / numberOfUnitRulers <= MinimumPixelsBetweenRulers ){
    00470             dimX.stepWidth *= 10.0;
    00471             dimX.subStepWidth  *= 10.0;
    00472             numberOfUnitRulers = qAbs( dimX.distance() / dimX.stepWidth );
    00473         }
    00474     }
    00475
    00476     const bool drawUnitRulers = screenRange / ( numberOfUnitRulers / dimX.stepWidth ) > MinimumPixelsBetweenRulers;
    00477     const bool drawSubUnitRulers =
    00478         (numberOfSubUnitRulers != 0.0) &&
    00479         (screenRange / numberOfSubUnitRulers > MinimumPixelsBetweenRulers);
    00480
    00481     const TextAttributes labelTA = textAttributes();
    00482     const bool drawLabels = labelTA.isVisible();
    00483
    00484     // - find the reference point at which to start drawing and the increment (line distance);
    00485     QPointF rulerRef;
    00486     const QRect areaGeoRect( areaGeometry() );
    00487     const QRect geoRect( geometry() );
    00488     QRectF rulerRect;
    00489     double rulerWidth;
    00490     double rulerHeight;
    00491
    00492     QPainter* ptr = context->painter();
    00493
    00494     //for debugging: if( isAbscissa() )ptr->drawRect(areaGeoRect.adjusted(0,0,-1,-1));
    00495     //qDebug() << "         " << (isAbscissa() ? "Abscissa":"Ordinate") << "axis painting with geometry" << areaGeoRect;
    00496
    00497     // FIXME references are of course different for all locations:
    00498     rulerWidth = areaGeoRect.width();
    00499     rulerHeight =  areaGeoRect.height();
    00500     switch( position() )
    00501     {
    00502     case Top:
    00503         rulerRef.setX( areaGeoRect.topLeft().x() );
    00504         rulerRef.setY( areaGeoRect.topLeft().y() + rulerHeight );
    00505         break;
    00506     case Bottom:
    00507         rulerRef.setX( areaGeoRect.bottomLeft().x() );
    00508         rulerRef.setY( areaGeoRect.bottomLeft().y() - rulerHeight );
    00509         break;
    00510     case Right:
    00511         rulerRef.setX( areaGeoRect.bottomRight().x() - rulerWidth );
    00512         rulerRef.setY( areaGeoRect.bottomRight().y() );
    00513         break;
    00514     case Left:
    00515         rulerRef.setX( areaGeoRect.bottomLeft().x() + rulerWidth );
    00516         rulerRef.setY( areaGeoRect.bottomLeft().y() );
    00517         break;
    00518     }
    00519
    00520     // set up the lines to paint:
    00521
    00522     // set up a map of integer positions,
    00523
    00524     // - starting with the fourth
    00525     // - the the halfs
    00526     // - then the tens
    00527     // this will override all halfs and fourth that hit a higher-order ruler
    00528     // MAKE SURE TO START AT (0, 0)!
    00529
    00530     // set up a reference point,  a step vector and a unit vector for the drawing:
    00531
    00532     const qreal minValueY = dimY.start;
    00533     const qreal maxValueY = dimY.end;
    00534     const qreal minValueX = dimX.start;
    00535     const qreal maxValueX = dimX.end;
    00536     const bool isLogarithmicX = (dimX.calcMode == AbstractCoordinatePlane::Logarithmic );
    00537     const bool isLogarithmicY = (dimY.calcMode == AbstractCoordinatePlane::Logarithmic );
    00538 //#define AXES_PAINTING_DEBUG 1
    00539 #ifdef AXES_PAINTING_DEBUG
    00540     qDebug() << "CartesianAxis::paint: reference values:" << endl
    00541              << "-- range x/y: " << dimX.distance() << "/" << dimY.distance() << endl
    00542              << "-- absRange: " << absRange << endl
    00543              << "-- numberOfUnitRulers: " << numberOfUnitRulers << endl
    00544              << "-- screenRange: " << screenRange << endl
    00545              << "-- drawUnitRulers: " << drawUnitRulers << endl
    00546              << "-- drawLabels: " << drawLabels << endl
    00547              << "-- ruler reference point:: " << rulerRef << endl
    00548              << "-- minValueX: " << minValueX << "   maxValueX: " << maxValueX << endl
    00549              << "-- minValueY: " << minValueY << "   maxValueY: " << maxValueY << endl
    00550         ;
    00551 #endif
    00552
    00553     ptr->setPen ( Qt::black );
    00554
    00555     const QObject* referenceArea = plane->parent();
    00556
    00557     // that QVector contains all drawn x-ticks (so no subticks are drawn there also)
    00558     QVector< int > drawnXTicks;
    00559     // and that does the same for the y-ticks
    00560     QVector< int > drawnYTicks;
    00561
    00562     /*
    00563      * Find out if it is a bar diagram
    00564      * bar diagrams display their data per column
    00565      * we need to handle the last label another way
    00566      * 1 - Last label == QString null ( Header Labels )
    00567      * 2 - Display labels and ticks in the middle of the column
    00568      */
    00569
    00570     const bool isBarDiagram = referenceDiagramIsBarDiagram(d->diagram());
    00571
    00572     // this draws the unit rulers
    00573     if ( drawUnitRulers ) {
    00574         const int hardLabelsCount  = labels().count();
    00575         const int shortLabelsCount = shortLabels().count();
    00576         bool useShortLabels = false;
    00577
    00578
    00579         bool useConfiguredStepsLabels = false;
    00580         QStringList headerLabels;
    00581         if( useItemCountLabels ){
    00582             //qDebug() << (isOrdinate() ? "is Ordinate" : "is Abscissa");
    00583             headerLabels =
    00584                 isOrdinate()
    00585                 ? d->diagram()->datasetLabels()
    00586                 : d->diagram()->itemRowLabels();
    00587             // check if configured stepWidth
    00588             useConfiguredStepsLabels = isAbscissa() &&
    00589                     dimX.stepWidth &&
    00590                     (( (headerLabels.count() - 1)/ dimX.stepWidth ) != numberOfUnitRulers);
    00591             if( useConfiguredStepsLabels ) {
    00592                 numberOfUnitRulers = ( headerLabels.count() - 1 )/ dimX.stepWidth;
    00593                 // we need to register data values for the steps
    00594                 // in case it is configured by the user
    00595                 QStringList configuredStepsLabels;
    00596                 double value = headerLabels.first().toDouble();
    00597                 configuredStepsLabels << QString::number( value );
    00598                 for (  int i = 0; i < numberOfUnitRulers; i++ ) {
    00599                     value += dimX.stepWidth;
    00600                     configuredStepsLabels.append( QString::number( value ) );
    00601                 }
    00602                 headerLabels = configuredStepsLabels;
    00603             }
    00604
    00605             if (  isBarDiagram )
    00606                 headerLabels.append( QString::null );
    00607         }
    00608
    00609
    00610         const int headerLabelsCount = headerLabels.count();
    00611         //qDebug() << "headerLabelsCount" << headerLabelsCount;
    00612
    00613         TextLayoutItem* labelItem =
    00614             drawLabels
    00615             ? new TextLayoutItem( QString::number( minValueY ),
    00616                                   labelTA,
    00617                                   referenceArea,
    00618                                   KDChartEnums::MeasureOrientationMinimum,
    00619                                   Qt::AlignLeft )
    00620             : 0;
    00621         TextLayoutItem* labelItem2 =
    00622             drawLabels
    00623             ? new TextLayoutItem( QString::number( minValueY ),
    00624                                   labelTA,
    00625                                   referenceArea,
    00626                                   KDChartEnums::MeasureOrientationMinimum,
    00627                                   Qt::AlignLeft )
    00628             : 0;
    00629         const QFontMetricsF met(
    00630             drawLabels
    00631             ? labelItem->realFont()
    00632             : QFontMetricsF( QApplication::font() ) );
    00633         const qreal halfFontHeight = met.height() * 0.5;
    00634
    00635         if ( isAbscissa() ) {
    00636             // If we have a labels list AND a short labels list, we first find out,
    00637             // if there is enough space for the labels: if not, use the short labels.
    00638             if( drawLabels && hardLabelsCount > 0 && shortLabelsCount > 0 ){
    00639                 bool labelsAreOverlapping = false;
    00640                 int iLabel = 0;
    00641                 qreal i = minValueX;
    00642                 while ( i < maxValueX && !labelsAreOverlapping )
    00643                 {
    00644                     if ( dimX.stepWidth != 1.0 && ! dim.isCalculated )
    00645                     {
    00646                         labelItem->setText(  customizedLabel(QString::number( i, 'f', 0 )) );
    00647                         labelItem2->setText( customizedLabel(QString::number( i + dimX.stepWidth, 'f', 0 )) );
    00648                     } else {
    00649
    00650                         int index = iLabel;
    00651                         labelItem->setText(  customizedLabel(labels()[ index < hardLabelsCount ? index : 0 ]) );
    00652                         labelItem2->setText( customizedLabel(labels()[ index < hardLabelsCount - 1 ? index + 1 : 0]) );
    00653                     }
    00654                     QPointF firstPos( i, 0.0 );
    00655                     firstPos = plane->translate( firstPos );
    00656
    00657                     QPointF secondPos( i + dimX.stepWidth, 0.0 );
    00658                     secondPos = plane->translate( secondPos );
    00659
    00660                     labelsAreOverlapping = labelItem->intersects( *labelItem2, firstPos, secondPos );
    00661                     if ( iLabel++ > hardLabelsCount - 1 )
    00662                         iLabel = 0;
    00663                     if ( isLogarithmicX )
    00664                         i *= 10.0;
    00665                     else
    00666                         i += dimX.stepWidth;
    00667
    00668                 }
    00669
    00670                 useShortLabels = labelsAreOverlapping;
    00671             }
    00672
    00673             qreal labelDiff = dimX.stepWidth;
    00674             //qDebug() << "labelDiff " << labelDiff;
    00675             if ( drawLabels )
    00676             {
    00677
    00678                 qreal i = minValueX;
    00679                 int iLabel = 0;
    00680                 const int precision = ( QString::number( labelDiff  ).section( QLatin1Char('.'), 1,  2 ) ).length();
    00681
    00682                 while ( i + labelDiff < maxValueX )
    00683                 {
    00684
    00685                     //qDebug() << "drawLabels" << drawLabels << "  hardLabelsCount" << hardLabelsCount
    00686                     //        << "  dimX.stepWidth" << dimX.stepWidth << "  dim.isCalculated" << dim.isCalculated;
    00687                     if ( !drawLabels || hardLabelsCount < 1 || ( dimX.stepWidth != 1.0 && ! dim.isCalculated ) )
    00688                     {
    00689                         // Check intersects for the header label - we need to pass the full string
    00690                         // here and not only the i value.
    00691                         if( useConfiguredStepsLabels ){
    00692                             labelItem->setText( customizedLabel(headerLabels[ iLabel   ]) );
    00693                             labelItem2->setText(customizedLabel(headerLabels[ iLabel+1 ]) );
    00694                         }else{
    00695                             //qDebug() << "i + labelDiff " << i + labelDiff;
    00696                             labelItem->setText( customizedLabel(headerLabelsCount ? headerLabels[static_cast<int>(i)]
    00697                                 : QString::number( i, 'f', precision )) );
    00698                             //           qDebug() << "1 - labelItem->text() " << labelItem->text();
    00699                             //qDebug() << "labelDiff" << labelDiff
    00700                             //        << "  index" << i+labelDiff << "  count" << headerLabelsCount;
    00701                             labelItem2->setText( customizedLabel(headerLabelsCount ? headerLabels[static_cast<int>(i+labelDiff)]
    00702                                 : QString::number( i + labelDiff, 'f', precision )) );
    00703                             //qDebug() << "2 - labelItem->text() " << labelItem->text();
    00704                             //qDebug() << "labelItem2->text() " << labelItem2->text();
    00705                         }
    00706                     } else {
    00707                         const int idx = (iLabel < hardLabelsCount    ) ? iLabel     : 0;
    00708                         const int idx2= (iLabel < hardLabelsCount - 1) ? iLabel + 1 : 0;
    00709                         labelItem->setText(  customizedLabel(
    00710                                 useShortLabels ? shortLabels()[ idx ] : labels()[ idx ]) );
    00711                         labelItem2->setText( customizedLabel(
    00712                                 useShortLabels ? shortLabels()[ idx2] : labels()[ idx2]) );
    00713                     }
    00714
    00715                     QPointF firstPos( i, 0.0 );
    00716                     firstPos = plane->translate( firstPos );
    00717
    00718                     QPointF secondPos( i + labelDiff, 0.0 );
    00719                     secondPos = plane->translate( secondPos );
    00720
    00721
    00722                     if ( labelItem->intersects( *labelItem2, firstPos, secondPos ) )
    00723                     {
    00724                         i = minValueX;
    00725                         labelDiff += labelDiff;
    00726                         iLabel = 0;
    00727                     }
    00728                     else
    00729                     {
    00730                         i += labelDiff;
    00731                     }
    00732
    00733                     ++iLabel;
    00734                     if ( (iLabel > hardLabelsCount - 1) && !useConfiguredStepsLabels )
    00735                     {
    00736                         iLabel = 0;
    00737                     }
    00738                 }
    00739             }
    00740
    00741             int idxLabel = 0;
    00742             qreal iLabelF = minValueX;
    00743             qreal i = minValueX;
    00744             qreal labelStep = 0.0;
    00745             //qDebug() << "dimX.stepWidth:" << dimX.stepWidth;
    00746             //dimX.stepWidth = 0.5;
    00747             while( i <= maxValueX ) {
    00748                 // Line charts: we want the first tick to begin at 0.0 not at 0.5 otherwise labels and
    00749                 // values does not fit each others
    00750                 QPointF topPoint ( i + ( isBarDiagram ? 0.5 : 0.0 ), 0.0 );
    00751                 QPointF bottomPoint ( topPoint );
    00752                 topPoint = plane->translate( topPoint );
    00753                 bottomPoint = plane->translate( bottomPoint );
    00754                 topPoint.setY( rulerRef.y() + tickLength() );
    00755                 bottomPoint.setY( rulerRef.y() );
    00756
    00757                 const qreal translatedValue = topPoint.x();
    00758                 const bool bIsVisibleLabel =
    00759                         ( translatedValue >= geoRect.left() && translatedValue <= geoRect.right() );
    00760
    00761                 //Dont paint more ticks than we need
    00762                 //when diagram type is Bar
    00763                 bool painttick = true;
    00764                 if (  isBarDiagram && i == maxValueX )
    00765                     painttick = false;
    00766
    00767                 if ( bIsVisibleLabel && painttick )
    00768                     ptr->drawLine( topPoint, bottomPoint );
    00769
    00770                 drawnXTicks.append( static_cast<int>( topPoint.x() ) );
    00771                 if( drawLabels ) {
    00772                     if( bIsVisibleLabel ){
    00773                         if ( isLogarithmicX )
    00774                             labelItem->setText( customizedLabel(QString::number( i, 'f', 0 )) );
    00775                         /* We dont need that
    00776                         * it causes header labels to be skipped even if there is enough
    00777                         * space for them to displayed.
    00778                         * Commenting for now - I need to test more in details - Let me know if I am wrong here.
    00779                         */
    00780                         /*
    00781                         else if( (dimX.stepWidth != 1.0) && ! dimX.isCalculated ) {
    00782                         labelItem->setText( customizedLabel(QString::number( i, 'f', 0 )) );
    00783                         }
    00784                         */
    00785                         else {
    00786                             labelItem->setText(
    00787                                     customizedLabel(
    00788                                           hardLabelsCount
    00789                                         ? ( useShortLabels    ? shortLabels()[ idxLabel ] : labels()[ idxLabel ] )
    00790                                         : ( headerLabelsCount ? headerLabels[  idxLabel ] : QString::number( iLabelF ))));
    00791                         }
    00792                         // No need to call labelItem->setParentWidget(), since we are using
    00793                         // the layout item temporarily only.
    00794                         if( labelStep <= 0 ) {
    00795                             const QSize size( labelItem->sizeHint() );
    00796                             labelItem->setGeometry(
    00797                                 QRect(
    00798                                     QPoint(
    00799                                         static_cast<int>( topPoint.x() - size.width() / 2 ),
    00800                                         static_cast<int>( topPoint.y() +
    00801                                                         ( position() == Bottom
    00802                                                             ? halfFontHeight
    00803                                                             : ((halfFontHeight + size.height()) * -1.0) ) ) ),
    00804                                     size ) );
    00805
    00806                             bool origClipping = ptr->hasClipping();
    00807
    00808                             QRect labelGeo = labelItem->geometry();
    00809                             // if our item would only half fit, we disable clipping for that one
    00810                             if( labelGeo.left() < geoRect.left() && labelGeo.right() > geoRect.left() )
    00811                                 ptr->setClipping( false );
    00812                             if( labelGeo.left() < geoRect.right() && labelGeo.right() > geoRect.right() )
    00813                                 ptr->setClipping( false );
    00814
    00815                             labelItem->setGeometry( labelGeo );
    00816
    00817                             labelStep = labelDiff - dimX.stepWidth;
    00818                             labelItem->paint( ptr );
    00819
    00820                             // do not call customizedLabel() again:
    00821                             labelItem2->setText( labelItem->text() );
    00822
    00823                             // maybe enable clipping afterwards
    00824                             ptr->setClipping( origClipping );
    00825                         } else {
    00826                             labelStep -= dimX.stepWidth;
    00827                         }
    00828                     }
    00829
    00830                     if( hardLabelsCount ) {
    00831                         if( idxLabel >= hardLabelsCount  -1 )
    00832                             idxLabel = 0;
    00833                         else
    00834                             ++idxLabel;
    00835                     } else if( headerLabelsCount ) {
    00836                         if( idxLabel >= headerLabelsCount - 1 ) {
    00837                             idxLabel = 0;
    00838                         }else
    00839                             ++idxLabel;
    00840                     } else {
    00841                         iLabelF += dimX.stepWidth;
    00842                     }
    00843                 }
    00844                 if ( isLogarithmicX )
    00845                     i *= 10.0;
    00846                 else
    00847                     i += dimX.stepWidth;
    00848             }
    00849         } else {
    00850             const double maxLimit = maxValueY;
    00851             const double steg = dimY.stepWidth;
    00852             int maxLabelsWidth = 0;
    00853             qreal labelValue;
    00854             if( drawLabels && position() == Right ){
    00855                 // Find the widest label, so we to know how much we need to right-shift
    00856                 // our labels, to get them drawn right aligned:
    00857                 labelValue = minValueY;
    00858                 while ( labelValue <= maxLimit ) {
    00859                     labelItem->setText( customizedLabel(QString::number( labelValue )) );
    00860                     maxLabelsWidth = qMax( maxLabelsWidth, labelItem->sizeHint().width() );
    00861
    00862                     calculateNextLabel( labelValue, steg, isLogarithmicY );
    00863                 }
    00864             }
    00865
    00866             bool origClipping = ptr->hasClipping();
    00867             ptr->setClipping( false );
    00868             labelValue = minValueY;
    00869             qreal step = steg;
    00870             bool nextLabel = false;
    00871             //qDebug("minValueY: %f   maxLimit: %f   steg: %f", minValueY, maxLimit, steg);
    00872
    00873             // first calculate the steps depending on labels colision
    00874             while ( labelValue <= maxLimit ) {
    00875                 QPointF leftPoint = plane->translate( QPointF( 0, labelValue ) );
    00876                 const qreal translatedValue = leftPoint.y();
    00877                 //qDebug() << "geoRect:" << geoRect << "   geoRect.top()" << geoRect.top()
    00878                 //<< "geoRect.bottom()" << geoRect.bottom() << "  translatedValue:" << translatedValue;
    00879                 if( translatedValue > geoRect.top() && translatedValue <= geoRect.bottom() ){
    00880                     if ( drawLabels ) {
    00881                         labelItem->setText(  customizedLabel(QString::number( labelValue )) );
    00882                         labelItem2->setText( customizedLabel(QString::number( labelValue + step )) );
    00883                         QPointF nextPoint = plane->translate(  QPointF( 0,  labelValue + step ) );
    00884                         if ( labelItem->intersects( *labelItem2, leftPoint, nextPoint ) )
    00885                         {
    00886                             step += steg;
    00887                             nextLabel = false;
    00888                         }else{
    00889                             nextLabel = true;
    00890                         }
    00891                     }
    00892                 }else{
    00893                     nextLabel = true;
    00894                 }
    00895
    00896                 if ( nextLabel || isLogarithmicY )
    00897                     calculateNextLabel( labelValue, step, isLogarithmicY );
    00898                 else
    00899                     labelValue = minValueY;
    00900             }
    00901
    00902             // Second - Paint the labels
    00903             labelValue = minValueY;
    00904             //qDebug() << "axis labels starting at" << labelValue << "step width" << step;
    00905             while ( labelValue <= maxLimit ) {
    00906                 //qDebug() << "value now" << labelValue;
    00907                 labelItem->setText( customizedLabel(QString::number( labelValue )) );
    00908                 QPointF leftPoint = plane->translate( QPointF( 0, labelValue ) );
    00909                 QPointF rightPoint ( 0.0, labelValue );
    00910                 rightPoint = plane->translate( rightPoint );
    00911                 leftPoint.setX( rulerRef.x() + tickLength() );
    00912                 rightPoint.setX( rulerRef.x() );
    00913
    00914                 const qreal translatedValue = rightPoint.y();
    00915                 const bool bIsVisibleLabel =
    00916                         ( translatedValue >= geoRect.top() && translatedValue <= geoRect.bottom() );
    00917
    00918                 if( bIsVisibleLabel ){
    00919                     ptr->drawLine( leftPoint, rightPoint );
    00920                     drawnYTicks.append( static_cast<int>( leftPoint.y() ) );
    00921                     const QSize labelSize( labelItem->sizeHint() );
    00922                     leftPoint.setX( leftPoint.x() );
    00923                     const int x =
    00924                         static_cast<int>( leftPoint.x() + met.height() * ( position() == Left ? -0.5 : 0.5) )
    00925                         - ( position() == Left ? labelSize.width() : (labelSize.width() - maxLabelsWidth) );
    00926                     const int y =
    00927                         static_cast<int>( leftPoint.y() - ( met.ascent() + met.descent() ) * 0.6 );
    00928                     labelItem->setGeometry( QRect( QPoint( x, y ), labelSize ) );
    00929                     labelItem->paint( ptr );
    00930                 }
    00931
    00932                 calculateNextLabel( labelValue, step, isLogarithmicY );
    00933             }
    00934
    00935             ptr->setClipping( origClipping );
    00936         }
    00937         delete labelItem;
    00938         delete labelItem2;
    00939     }
    00940
    00941     // this draws the subunit rulers
    00942     if ( drawSubUnitRulers ) {
    00943         d->drawSubUnitRulers( ptr, plane, dim, rulerRef, isAbscissa() ? drawnXTicks : drawnYTicks );
    00944     }
    00945
    00946     if( ! titleText().isEmpty() ){
    00947         d->drawTitleText( ptr, plane, areaGeoRect );
    00948     }
    00949
    00950     //qDebug() << "KDChart::CartesianAxis::paintCtx() done.";
    00951 }
    00952
    00953
    00954 /* pure virtual in QLayoutItem */
    00955 bool CartesianAxis::isEmpty() const
    00956 {
    00957     return false; // if the axis exists, it has some (perhaps default) content
    00958 }
    00959 /* pure virtual in QLayoutItem */
    00960 Qt::Orientations CartesianAxis::expandingDirections() const
    00961 {
    00962     Qt::Orientations ret;
    00963     switch ( position() )
    00964     {
    00965     case Bottom:
    00966     case Top:
    00967         ret = Qt::Horizontal;
    00968         break;
    00969     case Left:
    00970     case Right:
    00971         ret = Qt::Vertical;
    00972         break;
    00973     default:
    00974         Q_ASSERT( false ); // all positions need to be handeld
    00975         break;
    00976     };
    00977     return ret;
    00978 }
    00979
    00980
    00981 static void calculateOverlap( int i, int first, int last,
    00982                               int measure,
    00983                               bool isBarDiagram,
    00984                               int& firstOverlap, int& lastOverlap )
    00985 {
    00986     if( i == first ){
    00987         if( isBarDiagram ){
    00988             //TODO(khz): Calculate the amount of left overlap
    00989             //           for bar diagrams.
    00990         }else{
    00991             firstOverlap = measure / 2;
    00992         }
    00993     }
    00994     // we test both bounds in on go: first and last might be equal
    00995     if( i == last ){
    00996         if( isBarDiagram ){
    00997             //TODO(khz): Calculate the amount of right overlap
    00998             //           for bar diagrams.
    00999         }else{
    01000             lastOverlap = measure / 2;
    01001         }
    01002     }
    01003 }
    01004
    01005
    01006 /* pure virtual in QLayoutItem */
    01007 QSize CartesianAxis::maximumSize() const
    01008 {
    01009     QSize result;
    01010     if ( !d->diagram() )
    01011         return result;
    01012
    01013     const TextAttributes labelTA = textAttributes();
    01014     const bool drawLabels = labelTA.isVisible();
    01015
    01016     const TextAttributes titleTA( d->titleTextAttributesWithAdjustedRotation() );
    01017     const bool drawTitle = titleTA.isVisible() && ! titleText().isEmpty();
    01018
    01019     AbstractCoordinatePlane* plane = d->diagram()->coordinatePlane();
    01020     //qDebug() << this<<"::maximumSize() uses plane geometry" << plane->geometry();
    01021     QObject* refArea = plane->parent();
    01022     TextLayoutItem labelItem( QString::null, labelTA, refArea,
    01023                               KDChartEnums::MeasureOrientationMinimum, Qt::AlignLeft );
    01024     TextLayoutItem titleItem( titleText(), titleTA, refArea,
    01025                               KDChartEnums::MeasureOrientationMinimum, Qt::AlignHCenter | Qt::AlignVCenter );
    01026     const qreal labelGap =
    01027         drawLabels
    01028         ? (QFontMetricsF( labelItem.realFont() ).height() / 3.0)
    01029         : 0.0;
    01030     const qreal titleGap =
    01031         drawTitle
    01032         ? (QFontMetricsF( titleItem.realFont() ).height() / 3.0)
    01033         : 0.0;
    01034
    01035     switch ( position() )
    01036     {
    01037     case Bottom:
    01038     case Top: {
    01039         const bool isBarDiagram = referenceDiagramIsBarDiagram(d->diagram());
    01040         int leftOverlap = 0;
    01041         int rightOverlap = 0;
    01042
    01043         qreal w = 10.0;
    01044         qreal h = 0.0;
    01045         if( drawLabels ){
    01046             // if there're no label strings, we take the biggest needed number as height
    01047             if ( labels().count() ){
    01048                 // find the longest label text:
    01049                 const int first=0;
    01050                 const int last=labels().count()-1;
    01051                 for ( int i = first; i <= last; ++i )
    01052                 {
    01053                     labelItem.setText( customizedLabel(labels()[ i ]) );
    01054                     const QSize siz = labelItem.sizeHint();
    01055                     h = qMax( h, static_cast<qreal>(siz.height()) );
    01056                     calculateOverlap( i, first, last, siz.width(), isBarDiagram,
    01057                                       leftOverlap, rightOverlap );
    01058
    01059                 }
    01060             }else{
    01061                 QStringList headerLabels = d->diagram()->itemRowLabels();
    01062                 const int headerLabelsCount = headerLabels.count();
    01063                 if( headerLabelsCount ){
    01064                     const int first=0;
    01065                     const int last=headerLabelsCount-1;
    01066                     for ( int i = first; i <= last; ++i )
    01067                     {
    01068                         labelItem.setText( customizedLabel(headerLabels[ i ]) );
    01069                         const QSize siz = labelItem.sizeHint();
    01070                         h = qMax( h, static_cast<qreal>(siz.height()) );
    01071                         calculateOverlap( i, first, last, siz.width(), isBarDiagram,
    01072                                           leftOverlap, rightOverlap );
    01073                     }
    01074                 }else{
    01075                     labelItem.setText(
    01076                             customizedLabel(
    01077                                     QString::number( plane->gridDimensionsList().first().end, 'f', 0 )));
    01078                     const QSize siz = labelItem.sizeHint();
    01079                     h = siz.height();
    01080                     calculateOverlap( 0, 0, 0, siz.width(), isBarDiagram,
    01081                                       leftOverlap, rightOverlap );
    01082                 }
    01083             }
    01084             // we leave a little gap between axis labels and bottom (or top, resp.) side of axis
    01085             h += labelGap;
    01086         }
    01087         // space for a possible title:
    01088         if ( drawTitle ) {
    01089             // we add the title height and leave a little gap between axis labels and axis title
    01090             h += titleItem.sizeHint().height() + titleGap;
    01091             w = titleItem.sizeHint().width() + 2.0;
    01092         }
    01093         // space for the ticks
    01094         h += qAbs( tickLength() ) * 3.0;
    01095         result = QSize ( static_cast<int>( w ), static_cast<int>( h ) );
    01096
    01097
    01098         // If necessary adjust the widths
    01099         // of the left (or right, resp.) side neighboring columns:
    01100         d->amountOfLeftOverlap = leftOverlap;
    01101         d->amountOfRightOverlap = rightOverlap;
    01102         /* Unused code for a push-model:
    01103         if( leftOverlap || rightOverlap ){
    01104             QTimer::singleShot(200, const_cast<CartesianAxis*>(this),
    01105                                SLOT(adjustLeftRightGridColumnWidths()));
    01106         }
    01107         */
    01108     }
    01109         break;
    01110     case Left:
    01111     case Right: {
    01112         int topOverlap = 0;
    01113         int bottomOverlap = 0;
    01114
    01115         qreal w = 0.0;
    01116         qreal h = 10.0;
    01117         if( drawLabels ){
    01118             // if there're no label strings, we take the biggest needed number as width
    01119             if ( labels().count() == 0 )
    01120             {
    01121                 labelItem.setText(
    01122                         customizedLabel(
    01123                                 QString::number( plane->gridDimensionsList().last().end, 'f', 0 )));
    01124                 const QSize siz = labelItem.sizeHint();
    01125                 w = siz.width();
    01126                 calculateOverlap( 0, 0, 0, siz.height(), false,// bar diagram flag is ignored for Ordinates
    01127                                   topOverlap, bottomOverlap );
    01128             }else{
    01129                 // find the longest label text:
    01130                 const int first=0;
    01131                 const int last=labels().count()-1;
    01132                 for ( int i = first; i <= last; ++i )
    01133                 {
    01134                     labelItem.setText( customizedLabel(labels()[ i ]) );
    01135                     const QSize siz = labelItem.sizeHint();
    01136                     qreal lw = siz.width();
    01137                     w = qMax( w, lw );
    01138                     calculateOverlap( 0, 0, 0, siz.height(), false,// bar diagram flag is ignored for Ordinates
    01139                                       topOverlap, bottomOverlap );
    01140                 }
    01141             }
    01142             // we leave a little gap between axis labels and left (or right, resp.) side of axis
    01143             w += labelGap;
    01144         }
    01145         // space for a possible title:
    01146         if ( drawTitle ) {
    01147             // we add the title height and leave a little gap between axis labels and axis title
    01148             w += titleItem.sizeHint().width() + titleGap;
    01149             h = titleItem.sizeHint().height() + 2.0;
    01150             //qDebug() << "left/right axis title item size-hint:" << titleItem.sizeHint();
    01151         }
    01152         // space for the ticks
    01153         w += qAbs( tickLength() ) * 3.0;
    01154
    01155         result = QSize ( static_cast<int>( w ), static_cast<int>( h ) );
    01156         //qDebug() << "left/right axis width:" << result << "   w:" << w;
    01157
    01158
    01159         // If necessary adjust the heights
    01160         // of the top (or bottom, resp.) side neighboring rows:
    01161         d->amountOfTopOverlap = topOverlap;
    01162         d->amountOfBottomOverlap = bottomOverlap;
    01163         /* Unused code for a push-model:
    01164         if( topOverlap || bottomOverlap ){
    01165             QTimer::singleShot(200, const_cast<CartesianAxis*>(this),
    01166                                SLOT(adjustTopBottomGridRowHeights()));
    01167         }
    01168         */
    01169     }
    01170         break;
    01171     default:
    01172         Q_ASSERT( false ); // all positions need to be handled
    01173         break;
    01174     };
    01175 //qDebug() << "*******************" << result;
    01176     //result=QSize(0,0);
    01177     return result;
    01178 }
    01179 /* pure virtual in QLayoutItem */
    01180 QSize CartesianAxis::minimumSize() const
    01181 {
    01182     return maximumSize();
    01183 }
    01184 /* pure virtual in QLayoutItem */
    01185 QSize CartesianAxis::sizeHint() const
    01186 {
    01187     return maximumSize();
    01188 }
    01189 /* pure virtual in QLayoutItem */
    01190 void CartesianAxis::setGeometry( const QRect& r )
    01191 {
    01192 //    qDebug() << "KDChart::CartesianAxis::setGeometry(" << r << ") called"
    01193 //             << (isAbscissa() ? "for Abscissa":"for Ordinate") << "axis";
    01194     d->geometry = r;
    01195 }
    01196 /* pure virtual in QLayoutItem */
    01197 QRect CartesianAxis::geometry() const
    01198 {
    01199     return d->geometry;
    01200 }
    01201
    01202 int CartesianAxis::tickLength( bool subUnitTicks ) const
    01203 {
    01204     int result = 0;
    01205
    01206     if ( isAbscissa() ) {
    01207         result = position() == Top ? -4 : 3;
    01208     } else {
    01209         result = position() == Left ? -4 : 3;
    01210     }
    01211
    01212     if ( subUnitTicks )
    01213         result = result < 0 ? result + 1 : result - 1;
    01214
    01215     return result;
    01216 }
    01217
    01218
    01219
    01220
    01221
    01222 /* unused code from KDChartCartesianAxis.h for using a push-model:
    01223 Q_SIGNALS:
    01224     void needAdjustLeftRightColumnsForOverlappingLabels(
    01225             CartesianAxis* axis, int left, int right );
    01226     void needAdjustTopBottomRowsForOverlappingLabels(
    01227             CartesianAxis* axis, int top, int bottom );
    01228 private Q_SLOTS:
    01229     void adjustLeftRightGridColumnWidths();
    01230     void adjustTopBottomGridRowHeights();
    01231 */
    01232
    01233 /*
    01234 // Unused code trying to use a push-model: This did not work
    01235 // since we can not re-layout the planes each time when
    01236 // Qt layouting is calling sizeHint()
    01237 void CartesianAxis::adjustLeftRightGridColumnWidths()
    01238 {
    01239     if( ! d->amountOfLeftOverlap && ! d->amountOfRightOverlap )
    01240         return;
    01241     const int leftOverlap = d->amountOfLeftOverlap;
    01242     const int rightOverlap= d->amountOfRightOverlap;
    01243     d->amountOfLeftOverlap = 0;
    01244     d->amountOfRightOverlap = 0;
    01245     emit needAdjustLeftRightColumnsForOverlappingLabels(
    01246             this, leftOverlap, rightOverlap );
    01247 }
    01248
    01249 void CartesianAxis::adjustTopBottomGridRowHeights()
    01250 {
    01251     if( ! d->amountOfTopOverlap && ! d->amountOfBottomOverlap )
    01252         return;
    01253     const int topOverlap = d->amountOfTopOverlap;
    01254     const int bottomOverlap= d->amountOfBottomOverlap;
    01255     d->amountOfTopOverlap = 0;
    01256     d->amountOfBottomOverlap = 0;
    01257     emit needAdjustTopBottomRowsForOverlappingLabels(
    01258             this, topOverlap, bottomOverlap );
    01259 }
    01260 */