KDChartCartesianAxis.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002  ** Copyright (C) 2007 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 #include <limits>
00047 
00048 using namespace KDChart;
00049 
00050 #define d (d_func())
00051 
00052 CartesianAxis::CartesianAxis ( AbstractCartesianDiagram* diagram )
00053     : AbstractAxis ( new Private( diagram, this ), diagram )
00054 {
00055     init();
00056 }
00057 
00058 CartesianAxis::~CartesianAxis ()
00059 {
00060     // when we remove the first axis it will unregister itself and
00061     // propagate the next one to the primary, thus the while loop
00062     while ( d->mDiagram ) {
00063         AbstractCartesianDiagram *cd = qobject_cast<AbstractCartesianDiagram*>( d->mDiagram );
00064         cd->takeAxis( this );
00065     }
00066     Q_FOREACH( AbstractDiagram *diagram, d->secondaryDiagrams ) {
00067         AbstractCartesianDiagram *cd = qobject_cast<AbstractCartesianDiagram*>( diagram );
00068         cd->takeAxis( this );
00069     }
00070 }
00071 
00072 void CartesianAxis::init ()
00073 {
00074     d->position = Bottom;
00075 }
00076 
00077 
00078 bool CartesianAxis::compare( const CartesianAxis* other )const
00079 {
00080     if( other == this ) return true;
00081     if( ! other ){
00082         //qDebug() << "CartesianAxis::compare() cannot compare to Null pointer";
00083         return false;
00084     }
00085     /*
00086     qDebug() << (position()            == other->position());
00087     qDebug() << (titleText()           == other->titleText());
00088     qDebug() << (titleTextAttributes() == other->titleTextAttributes());
00089     */
00090     return  ( static_cast<const AbstractAxis*>(this)->compare( other ) ) &&
00091             ( position()            == other->position() ) &&
00092             ( titleText()           == other->titleText() ) &&
00093             ( titleTextAttributes() == other->titleTextAttributes() );
00094 }
00095 
00096 
00097 void CartesianAxis::setTitleText( const QString& text )
00098 {
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     qreal 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 ( dim.end - f > std::numeric_limits< float >::epsilon() ) {
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                 if( fLogSubstep == 0 )
00268                     fLogSubstep = 1.0;
00269                 logSubstep = 0;
00270             }
00271             f += fLogSubstep;
00272             ++logSubstep;
00273         }else{
00274             f += dim.subStepWidth;
00275         }
00276     }
00277 }
00278 
00279 
00280 const TextAttributes CartesianAxis::Private::titleTextAttributesWithAdjustedRotation() const
00281 {
00282     TextAttributes titleTA( titleTextAttributes );
00283     if( axis()->isOrdinate() ){
00284         int rotation = titleTA.rotation() + 270;
00285         if( rotation >= 360 )
00286             rotation -= 360;
00287 
00288         // limit the allowed values to 0, 90, 180, 270:
00289         if( rotation  < 90 )
00290             rotation = 0;
00291         else if( rotation  < 180 )
00292             rotation = 90;
00293         else if( rotation  < 270 )
00294             rotation = 180;
00295         else if( rotation  < 360 )
00296             rotation = 270;
00297         else
00298             rotation = 0;
00299 
00300         titleTA.setRotation( rotation );
00301     }
00302     return titleTA;
00303 }
00304 
00305 
00306 void CartesianAxis::Private::drawTitleText( QPainter* painter, CartesianCoordinatePlane* plane, const QRect& areaGeoRect ) const
00307 {
00308     const TextAttributes titleTA( titleTextAttributesWithAdjustedRotation() );
00309     if( titleTA.isVisible() ) {
00310         TextLayoutItem titleItem( titleText,
00311                                   titleTA,
00312                                   plane->parent(),
00313                                   KDChartEnums::MeasureOrientationMinimum,
00314                                   Qt::AlignHCenter|Qt::AlignVCenter );
00315         QPointF point;
00316         const QSize size( titleItem.sizeHint() );
00317         //FIXME(khz): We definitely need to provide a way that users can decide
00318         //            the position of an axis title.
00319         switch( position )
00320         {
00321         case Top:
00322             point.setX( areaGeoRect.left() + areaGeoRect.width() / 2.0);
00323             point.setY( areaGeoRect.top()  + size.height() / 2 );
00324             break;
00325         case Bottom:
00326             point.setX( areaGeoRect.left() + areaGeoRect.width() / 2.0);
00327             point.setY( areaGeoRect.bottom() - size.height() / 2 );
00328             break;
00329         case Left:
00330             point.setX( areaGeoRect.left() + size.width() / 2 );
00331             point.setY( areaGeoRect.top() + areaGeoRect.height() / 2.0);
00332             break;
00333         case Right:
00334             point.setX( areaGeoRect.right() - size.width() / 2 );
00335             point.setY( areaGeoRect.top() + areaGeoRect.height() / 2.0);
00336             break;
00337         }
00338         PainterSaver painterSaver( painter );
00339         painter->translate( point );
00340         //if( axis()->isOrdinate() )
00341         //    painter->rotate( 270.0 );
00342         titleItem.setGeometry( QRect( QPoint(-size.width() / 2, -size.height() / 2), size ) );
00343         //painter->drawRect(titleItem.geometry().adjusted(0,0,-1,-1));
00344         titleItem.paint( painter );
00345     }
00346 }
00347 
00348 
00349 static void calculateNextLabel( qreal& labelValue, qreal step, bool isLogarithmic)
00350 {
00351     if ( isLogarithmic ){
00352         labelValue *= 10.0;
00353         if( labelValue == 0.0 )
00354             labelValue = 1.0;//std::numeric_limits< double >::epsilon();
00355     }else{
00356         //qDebug() << "new axis label:" << labelValue << "+" << step << "=" << labelValue+step;
00357         labelValue += step;
00358     }
00359 /*    if( qAbs(labelValue) < 1.0e-15 )
00360         labelValue = 0.0;*/
00361 }
00362 
00363 
00364 static bool referenceDiagramIsBarDiagram( const AbstractDiagram * diagram )
00365 {
00366     const AbstractCartesianDiagram * dia =
00367             qobject_cast< const AbstractCartesianDiagram * >( diagram );
00368     if( dia && dia->referenceDiagram() )
00369         dia = dia->referenceDiagram();
00370     return qobject_cast< const BarDiagram* >( dia ) != 0;
00371 }
00372 
00373 
00374 void CartesianAxis::paintCtx( PaintContext* context )
00375 {
00376 
00377     Q_ASSERT_X ( d->diagram(), "CartesianAxis::paint",
00378                  "Function call not allowed: The axis is not assigned to any diagram." );
00379 
00380     CartesianCoordinatePlane* plane = dynamic_cast<CartesianCoordinatePlane*>(context->coordinatePlane());
00381     Q_ASSERT_X ( plane, "CartesianAxis::paint",
00382                  "Bad function call: PaintContext::coodinatePlane() NOT a cartesian plane." );
00383 
00384     // note: Not having any data model assigned is no bug
00385     //       but we can not draw an axis then either.
00386     if( ! d->diagram()->model() )
00387         return;
00388 
00389 
00390     /*
00391      * let us paint the labels at a
00392      * smaller resolution
00393      * Same mini pixel value as for
00394      * Cartesian Grid
00395      */
00396     //const qreal MinimumPixelsBetweenRulers = 1.0;
00397     DataDimensionsList dimensions( plane->gridDimensionsList() );
00398     //qDebug("CartesianAxis::paintCtx() gets DataDimensionsList.first():   start: %f   end: %f   stepWidth: %f", dimensions.first().start, dimensions.first().end, dimensions.first().stepWidth);
00399 
00400     // test for programming errors: critical
00401     Q_ASSERT_X ( dimensions.count() == 2, "CartesianAxis::paint",
00402                  "Error: plane->gridDimensionsList() did not return exactly two dimensions." );
00403     DataDimension dimX =
00404             AbstractGrid::adjustedLowerUpperRange( dimensions.first(), true, true );
00405     const DataDimension dimY =
00406             AbstractGrid::adjustedLowerUpperRange( dimensions.last(), true, true );
00407     const DataDimension& dim = (isAbscissa() ? dimX : dimY);
00408 
00409     /*
00410     if(isAbscissa())
00411         qDebug() << "         " << "Abscissa:" << dimX.start <<".."<<dimX.end <<"  step"<<dimX.stepWidth;
00412     else
00413         qDebug() << "         " << "Ordinate:" << dimY.start <<".."<<dimY.end <<"  step"<<dimY.stepWidth;
00414     */
00415 
00416 
00417     /*
00418      * let us paint the labels at a
00419      * smaller resolution
00420      * Same mini pixel value as for
00421      * Cartesian Grid
00422      */
00423     const qreal MinimumPixelsBetweenRulers = qMin(  dimX.stepWidth,  dimY.stepWidth );//1.0;
00424 
00425     // preparations:
00426     // - calculate the range that will be displayed:
00427     const qreal absRange = qAbs( dim.distance() );
00428 
00429     qreal numberOfUnitRulers;
00430     if ( isAbscissa() ) {
00431         if( dimX.isCalculated )
00432             numberOfUnitRulers = absRange / qAbs( dimX.stepWidth ) + 1.0;
00433         else
00434             numberOfUnitRulers = d->diagram()->model()->rowCount() - 1.0;
00435     }else{
00436         numberOfUnitRulers = absRange / qAbs( dimY.stepWidth ) + 1.0;
00437 
00438     }
00439 
00440     //    qDebug() << "absRange" << absRange << "dimY.stepWidth:" << dimY.stepWidth << "numberOfUnitRulers:" << numberOfUnitRulers;
00441 
00442     qreal numberOfSubUnitRulers;
00443     if ( isAbscissa() ){
00444         if( dimX.isCalculated )
00445             numberOfSubUnitRulers = absRange / qAbs( dimX.subStepWidth ) + 1.0;
00446         else
00447             numberOfSubUnitRulers = dimX.subStepWidth>0 ? absRange / qAbs( dimX.subStepWidth ) + 1.0 : 0.0;
00448     }else{
00449         numberOfSubUnitRulers = absRange / qAbs( dimY.subStepWidth ) + 1.0;
00450     }
00451 
00452     // - calculate the absolute range in screen pixels:
00453     const QPointF p1 = plane->translate( QPointF(dimX.start, dimY.start) );
00454     const QPointF p2 = plane->translate( QPointF(dimX.end,   dimY.end) );
00455 
00456     double screenRange;
00457     if ( isAbscissa() )
00458     {
00459         screenRange = qAbs ( p1.x() - p2.x() );
00460     } else {
00461         screenRange = qAbs ( p1.y() - p2.y() );
00462     }
00463 
00464     const bool useItemCountLabels = isAbscissa() && ! dimX.isCalculated;
00465 
00466     const bool drawUnitRulers = screenRange / ( numberOfUnitRulers / dimX.stepWidth ) > MinimumPixelsBetweenRulers;
00467     const bool drawSubUnitRulers =
00468         (numberOfSubUnitRulers != 0.0) &&
00469         (screenRange / numberOfSubUnitRulers > MinimumPixelsBetweenRulers);
00470 
00471     const TextAttributes labelTA = textAttributes();
00472     const bool drawLabels = labelTA.isVisible();
00473 
00474     // - find the reference point at which to start drawing and the increment (line distance);
00475     QPointF rulerRef;
00476     const QRect areaGeoRect( areaGeometry() );
00477     const QRect geoRect( geometry() );
00478     QRectF rulerRect;
00479     double rulerWidth;
00480     double rulerHeight;
00481 
00482     QPainter* const ptr = context->painter();
00483 
00484     //for debugging: if( isAbscissa() )ptr->drawRect(areaGeoRect.adjusted(0,0,-1,-1));
00485     //qDebug() << "         " << (isAbscissa() ? "Abscissa":"Ordinate") << "axis painting with geometry" << areaGeoRect;
00486 
00487     // FIXME references are of course different for all locations:
00488     rulerWidth = areaGeoRect.width();
00489     rulerHeight =  areaGeoRect.height();
00490     switch( position() )
00491     {
00492     case Top:
00493         rulerRef.setX( areaGeoRect.topLeft().x() );
00494         rulerRef.setY( areaGeoRect.topLeft().y() + rulerHeight );
00495         break;
00496     case Bottom:
00497         rulerRef.setX( areaGeoRect.bottomLeft().x() );
00498         rulerRef.setY( areaGeoRect.bottomLeft().y() - rulerHeight );
00499         break;
00500     case Right:
00501         rulerRef.setX( areaGeoRect.bottomRight().x() - rulerWidth );
00502         rulerRef.setY( areaGeoRect.bottomRight().y() );
00503         break;
00504     case Left:
00505         rulerRef.setX( areaGeoRect.bottomLeft().x() + rulerWidth );
00506         rulerRef.setY( areaGeoRect.bottomLeft().y() );
00507         break;
00508     }
00509 
00510     // set up the lines to paint:
00511 
00512     // set up a map of integer positions,
00513 
00514     // - starting with the fourth
00515     // - the the halfs
00516     // - then the tens
00517     // this will override all halfs and fourth that hit a higher-order ruler
00518     // MAKE SURE TO START AT (0, 0)!
00519 
00520     // set up a reference point,  a step vector and a unit vector for the drawing:
00521 
00522     const qreal minValueY = dimY.start;
00523     const qreal maxValueY = dimY.end;
00524     const qreal minValueX = dimX.start;
00525     const qreal maxValueX = dimX.end;
00526     const bool isLogarithmicX = (dimX.calcMode == AbstractCoordinatePlane::Logarithmic );
00527     const bool isLogarithmicY = (dimY.calcMode == AbstractCoordinatePlane::Logarithmic );
00528 //#define AXES_PAINTING_DEBUG 1
00529 #ifdef AXES_PAINTING_DEBUG
00530     qDebug() << "CartesianAxis::paint: reference values:" << endl
00531              << "-- range x/y: " << dimX.distance() << "/" << dimY.distance() << endl
00532              << "-- absRange: " << absRange << endl
00533              << "-- numberOfUnitRulers: " << numberOfUnitRulers << endl
00534              << "-- screenRange: " << screenRange << endl
00535              << "-- drawUnitRulers: " << drawUnitRulers << endl
00536              << "-- drawLabels: " << drawLabels << endl
00537              << "-- ruler reference point:: " << rulerRef << endl
00538              << "-- minValueX: " << minValueX << "   maxValueX: " << maxValueX << endl
00539              << "-- minValueY: " << minValueY << "   maxValueY: " << maxValueY << endl
00540         ;
00541 #endif
00542 
00543     // solving issue #4075 in a quick way:
00544     ptr->setPen ( labelTA.pen() ); // perhaps we want to add a setter method later?
00545 
00546     //ptr->setPen ( Qt::black );
00547 
00548     const QObject* referenceArea = plane->parent();
00549 
00550     // that QVector contains all drawn x-ticks (so no subticks are drawn there also)
00551     QVector< int > drawnXTicks;
00552     // and that does the same for the y-ticks
00553     QVector< int > drawnYTicks;
00554 
00555     /*
00556      * Find out if it is a bar diagram
00557      * bar diagrams display their data per column
00558      * we need to handle the last label another way
00559      * 1 - Last label == QString null ( Header Labels )
00560      * 2 - Display labels and ticks in the middle of the column
00561      */
00562 
00563     const bool isBarDiagram = referenceDiagramIsBarDiagram(d->diagram());
00564 
00565     // this draws the unit rulers
00566     if ( drawUnitRulers ) {
00567         const QStringList labelsList(      labels() );
00568         const QStringList shortLabelsList( shortLabels() );
00569         const int hardLabelsCount  = labelsList.count();
00570         const int shortLabelsCount = shortLabelsList.count();
00571         bool useShortLabels = false;
00572 
00573 
00574         bool useConfiguredStepsLabels = false;
00575         QStringList headerLabels;
00576         if( useItemCountLabels ){
00577             //qDebug() << (isOrdinate() ? "is Ordinate" : "is Abscissa");
00578             headerLabels =
00579                 isOrdinate()
00580                 ? d->diagram()->datasetLabels()
00581                 : d->diagram()->itemRowLabels();
00582             // check if configured stepWidth
00583             useConfiguredStepsLabels = isAbscissa() &&
00584                     dimX.stepWidth &&
00585                     (( (headerLabels.count() - 1)/ dimX.stepWidth ) != numberOfUnitRulers);
00586             if( useConfiguredStepsLabels ) {
00587                 numberOfUnitRulers = ( headerLabels.count() - 1 )/ dimX.stepWidth;
00588                 // we need to register data values for the steps
00589                 // in case it is configured by the user
00590                 QStringList configuredStepsLabels;
00591                 double value = headerLabels.isEmpty() ? 0.0 : headerLabels.first().toDouble();
00592                 configuredStepsLabels << QString::number( value );
00593                 for (  int i = 0; i < numberOfUnitRulers; i++ ) {
00594                     //qDebug() << value;
00595                     value += dimX.stepWidth;
00596                     configuredStepsLabels.append( QString::number( value ) );
00597                 }
00598                 headerLabels = configuredStepsLabels;
00599             }
00600 
00601             if (  isBarDiagram )
00602                 headerLabels.append( QString::null );
00603         }
00604 
00605 
00606         const int headerLabelsCount = headerLabels.count();
00607         //qDebug() << "headerLabelsCount" << headerLabelsCount;
00608 
00609         TextLayoutItem* labelItem =
00610             drawLabels
00611             ? new TextLayoutItem( QString::number( minValueY ),
00612                                   labelTA,
00613                                   referenceArea,
00614                                   KDChartEnums::MeasureOrientationMinimum,
00615                                   Qt::AlignLeft )
00616             : 0;
00617         TextLayoutItem* labelItem2 =
00618             drawLabels
00619             ? new TextLayoutItem( QString::number( minValueY ),
00620                                   labelTA,
00621                                   referenceArea,
00622                                   KDChartEnums::MeasureOrientationMinimum,
00623                                   Qt::AlignLeft )
00624             : 0;
00625         const QFontMetricsF met(
00626             drawLabels
00627             ? labelItem->realFont()
00628             : QFontMetricsF( QApplication::font(), GlobalMeasureScaling::paintDevice() ) );
00629         const qreal halfFontHeight = met.height() * 0.5;
00630 
00631         if ( isAbscissa() ) {
00632 
00633             // If we have a labels list AND a short labels list, we first find out,
00634             // if there is enough space for the labels: if not, use the short labels.
00635             if( drawLabels && hardLabelsCount > 0 && shortLabelsCount > 0 ){
00636                 bool labelsAreOverlapping = false;
00637                 int iLabel = 0;
00638                 qreal i = minValueX;
00639                 while ( i < maxValueX && !labelsAreOverlapping )
00640                 {
00641                     if ( dimX.stepWidth != 1.0 && ! dim.isCalculated )
00642                     {
00643                         labelItem->setText(  customizedLabel(QString::number( i, 'f', 0 )) );
00644                         labelItem2->setText( customizedLabel(QString::number( i + dimX.stepWidth, 'f', 0 )) );
00645                     } else {
00646 
00647                         int index = iLabel;
00648                         labelItem->setText(  customizedLabel(labelsList[ index < hardLabelsCount ? index : 0 ]) );
00649                         labelItem2->setText( customizedLabel(labelsList[ index < hardLabelsCount - 1 ? index + 1 : 0]) );
00650                     }
00651                     QPointF firstPos( i, 0.0 );
00652                     firstPos = plane->translate( firstPos );
00653 
00654                     QPointF secondPos( i + dimX.stepWidth, 0.0 );
00655                     secondPos = plane->translate( secondPos );
00656 
00657                     labelsAreOverlapping = labelItem->intersects( *labelItem2, firstPos, secondPos );
00658                     if ( iLabel++ > hardLabelsCount - 1 )
00659                         iLabel = 0;
00660                     if ( isLogarithmicX )
00661                         i *= 10.0;
00662                     else
00663                         i += dimX.stepWidth;
00664 
00665                 }
00666 
00667                 useShortLabels = labelsAreOverlapping;
00668             }
00669 
00670             qreal labelDiff = dimX.stepWidth;
00671             //      qDebug() << "initial labelDiff " << labelDiff;
00672             if ( drawLabels )
00673             {
00674 
00675                 qreal i = minValueX;
00676                 int iLabel = 0;
00677                 const int precision = ( QString::number( labelDiff  ).section( QLatin1Char('.'), 1,  2 ) ).length();
00678 
00679                 while ( i + labelDiff < maxValueX )
00680                 {
00681 
00682                     //qDebug() << "drawLabels" << drawLabels << "  hardLabelsCount" << hardLabelsCount
00683                     //        << "  dimX.stepWidth" << dimX.stepWidth << "  dim.isCalculated" << dim.isCalculated;
00684                     if ( !drawLabels || hardLabelsCount < 1 || ( dimX.stepWidth != 1.0 && ! dim.isCalculated ) )
00685                     {
00686                         // Check intersects for the header label - we need to pass the full string
00687                         // here and not only the i value.
00688                         if( useConfiguredStepsLabels ){
00689                             labelItem->setText( customizedLabel(headerLabels[ iLabel   ]) );
00690                             labelItem2->setText(customizedLabel(headerLabels[ iLabel+1 ]) );
00691                         }else{
00692                             //qDebug() << "i + labelDiff " << i + labelDiff;
00693                             labelItem->setText( customizedLabel(headerLabelsCount > i && i >= 0 ? 
00694                                     headerLabels[static_cast<int>(i)] :
00695                                     QString::number( i, 'f', precision )) );
00696                             //           qDebug() << "1 - labelItem->text() " << labelItem->text();
00697                             //qDebug() << "labelDiff" << labelDiff
00698                             //        << "  index" << i+labelDiff << "  count" << headerLabelsCount;
00699                             labelItem2->setText( customizedLabel(headerLabelsCount > i + labelDiff && i + labelDiff >= 0 ? 
00700                                     headerLabels[static_cast<int>(i+labelDiff)] :
00701                                     QString::number( i + labelDiff, 'f', precision )) );
00702                             //qDebug() << "2 - labelItem->text() " << labelItem->text();
00703                             //qDebug() << "labelItem2->text() " << labelItem2->text();
00704                         }
00705                     } else {
00706                         const int idx = (iLabel < hardLabelsCount    ) ? iLabel     : 0;
00707                         const int idx2= (iLabel < hardLabelsCount - 1) ? iLabel + 1 : 0;
00708                         const int shortIdx =  (iLabel < shortLabelsCount    ) ? iLabel     : 0;
00709                         const int shortIdx2 = (iLabel < shortLabelsCount - 1) ? iLabel + 1 : 0;
00710                         labelItem->setText(  customizedLabel(
00711                                 useShortLabels ? shortLabelsList[ shortIdx ] : labelsList[ idx ] ) );
00712                         labelItem2->setText( customizedLabel(
00713                                 useShortLabels ? shortLabelsList[ shortIdx2 ] : labelsList[ idx2 ] ) );
00714                     }
00715 
00716                     QPointF firstPos( i, 0.0 );
00717                     firstPos = plane->translate( firstPos );
00718 
00719                     QPointF secondPos( i + labelDiff, 0.0 );
00720                     secondPos = plane->translate( secondPos );
00721 
00722 
00723                     if ( labelItem->intersects( *labelItem2, firstPos, secondPos ) )
00724                     {
00725                         i = minValueX;
00726 
00727                         // fix for issue #4179:
00728                         labelDiff *= 10.0;
00729                         // old code:
00730                         // labelDiff += labelDiff;
00731 
00732                         iLabel = 0;
00733                     }
00734                     else
00735                     {
00736                         i += labelDiff;
00737                     }
00738 
00739                     ++iLabel;
00740                     if ( (iLabel > hardLabelsCount - 1) && !useConfiguredStepsLabels )
00741                     {
00742                         iLabel = 0;
00743                     }
00744                 }
00745             }
00746 
00747             int idxLabel = 0;
00748             qreal iLabelF = minValueX;
00749             //qDebug() << iLabelF;
00750             qreal i = minValueX;
00751             qreal labelStep = 0.0;
00752             //    qDebug() << "dimX.stepWidth:" << dimX.stepWidth  << "labelDiff:" << labelDiff;
00753             //dimX.stepWidth = 0.5;
00754             while( i <= maxValueX ) {
00755                 // Line charts: we want the first tick to begin at 0.0 not at 0.5 otherwise labels and
00756                 // values does not fit each others
00757                 QPointF topPoint ( i + ( isBarDiagram ? 0.5 : 0.0 ), 0.0 );
00758                 QPointF bottomPoint ( topPoint );
00759                 topPoint = plane->translate( topPoint );
00760                 bottomPoint = plane->translate( bottomPoint );
00761                 topPoint.setY( rulerRef.y() + tickLength() );
00762                 bottomPoint.setY( rulerRef.y() );
00763 
00764                 const qreal translatedValue = topPoint.x();
00765                 const bool bIsVisibleLabel =
00766                         ( translatedValue >= geoRect.left() && translatedValue <= geoRect.right() );
00767 
00768                 // fix for issue #4179:
00769                 bool painttick = bIsVisibleLabel && labelStep <= 0;;
00770                 // old code:
00771                 // bool painttick = true;
00772 
00773                 //Dont paint more ticks than we need
00774                 //when diagram type is Bar
00775                 if (  isBarDiagram && i == maxValueX )
00776                     painttick = false;
00777 
00778                 if ( bIsVisibleLabel && painttick )
00779                     ptr->drawLine( topPoint, bottomPoint );
00780 
00781                 drawnXTicks.append( static_cast<int>( topPoint.x() ) );
00782                 if( drawLabels ) {
00783                     if( bIsVisibleLabel ){
00784                         if ( isLogarithmicX )
00785                             labelItem->setText( customizedLabel(QString::number( i, 'f', 0 )) );
00786                         /* We dont need that
00787                         * it causes header labels to be skipped even if there is enough
00788                         * space for them to displayed.
00789                         * Commenting for now - I need to test more in details - Let me know if I am wrong here.
00790                         */
00791                         /*
00792                         else if( (dimX.stepWidth != 1.0) && ! dimX.isCalculated ) {
00793                         labelItem->setText( customizedLabel(QString::number( i, 'f', 0 )) );
00794                         }
00795                         */
00796                         else {
00797                             const int idx = idxLabel + static_cast<int>(minValueX);
00798                             labelItem->setText(
00799                                     customizedLabel(
00800                                           hardLabelsCount
00801                                     ? ( useShortLabels    ? shortLabelsList[ idx ] : labelsList[ idx ] )
00802                                 : ( headerLabelsCount ? headerLabels[ idx ] : QString::number( iLabelF ))));
00803                             //qDebug() << "x - labelItem->text() " << labelItem->text() << headerLabelsCount;
00804                         }
00805                         // No need to call labelItem->setParentWidget(), since we are using
00806                         // the layout item temporarily only.
00807                         if( labelStep <= 0 ) {
00808                             const PainterSaver p( ptr );
00809                             const QSize size( labelItem->sizeHint() );
00810                             labelItem->setGeometry(
00811                                 QRect(
00812                                     QPoint(
00813                                         static_cast<int>( topPoint.x() - size.width() / 2 ),
00814                                         static_cast<int>( topPoint.y() +
00815                                                         ( position() == Bottom
00816                                                             ? halfFontHeight
00817                                                             : ((halfFontHeight + size.height()) * -1.0) ) ) ),
00818                                     size ) );
00819 
00820                             QRect labelGeo = labelItem->geometry();
00821                             // if our item would only half fit, we disable clipping for that one
00822                             if( labelGeo.left() < geoRect.left() && labelGeo.right() > geoRect.left() )
00823                                 ptr->setClipping( false );
00824                             if( labelGeo.left() < geoRect.right() && labelGeo.right() > geoRect.right() )
00825                                 ptr->setClipping( false );
00826 
00827                             labelItem->setGeometry( labelGeo );
00828 
00829                             labelStep = labelDiff - dimX.stepWidth;
00830                             labelItem->paint( ptr );
00831 
00832                             // do not call customizedLabel() again:
00833                             labelItem2->setText( labelItem->text() );
00834 
00835                         } else {
00836                             labelStep -= dimX.stepWidth;
00837                         }
00838                     }
00839 
00840                     if( hardLabelsCount ) {
00841                         if( useShortLabels && idxLabel >= shortLabelsCount - 1 )
00842                             idxLabel = 0;
00843                         else if( !useShortLabels && idxLabel >= hardLabelsCount - 1 )
00844                             idxLabel = 0;
00845                         else{
00846                             idxLabel += static_cast<int>(dimX.stepWidth);
00847                             //qDebug() << "dimX.stepWidth:" << dimX.stepWidth << "  idxLabel:" << idxLabel;
00848                         }
00849                     } else if( headerLabelsCount ) {
00850                         if( idxLabel >= headerLabelsCount - 1 ) {
00851                             idxLabel = 0;
00852                         }else
00853                             ++idxLabel;
00854                     } else {
00855                         iLabelF += dimX.stepWidth;
00856                     }
00857                 }
00858                 if ( isLogarithmicX )
00859                 {
00860                     i *= 10.0;
00861                     if( i == 0.0 )
00862                         i = 1.0;//std::numeric_limits< double >::epsilon();
00863                 }
00864                 else
00865                 {
00866                     i += dimX.stepWidth;
00867                 }
00868             }
00869         } else {
00870             const PainterSaver p( ptr );
00871             const double maxLimit = maxValueY;
00872             const double steg = dimY.stepWidth;
00873             int maxLabelsWidth = 0;
00874             qreal labelValue;
00875             if( drawLabels && position() == Right ){
00876                 // Find the widest label, so we to know how much we need to right-shift
00877                 // our labels, to get them drawn right aligned:
00878                 labelValue = minValueY;
00879                 while ( labelValue <= maxLimit ) {
00880                     const QString labelText = diagram()->unitPrefix( static_cast< int >( labelValue ), Qt::Vertical, true ) + 
00881                                               QString::number( labelValue ) +
00882                                               diagram()->unitSuffix( static_cast< int >( labelValue ), Qt::Vertical, true );
00883                     labelItem->setText( customizedLabel( labelText ) );
00884                     maxLabelsWidth = qMax( maxLabelsWidth, labelItem->sizeHint().width() );
00885 
00886                     calculateNextLabel( labelValue, steg, isLogarithmicY );
00887                 }
00888             }
00889 
00890             ptr->setClipping( false );
00891             labelValue = minValueY;
00892             qreal step = steg;
00893             bool nextLabel = false;
00894             //qDebug("minValueY: %f   maxLimit: %f   steg: %f", minValueY, maxLimit, steg);
00895 
00896             if( drawLabels )
00897             {
00898                 // first calculate the steps depending on labels colision
00899                 while( labelValue <= maxLimit ) {
00900                     QPointF leftPoint = plane->translate( QPointF( 0, labelValue ) );
00901                     const qreal translatedValue = leftPoint.y();
00902                     //qDebug() << "geoRect:" << geoRect << "   geoRect.top()" << geoRect.top()
00903                     //<< "geoRect.bottom()" << geoRect.bottom() << "  translatedValue:" << translatedValue;
00904                     if( translatedValue > geoRect.top() && translatedValue <= geoRect.bottom() ){
00905                         const QString labelText = diagram()->unitPrefix( static_cast< int >( labelValue ), Qt::Vertical, true ) +
00906                                                   QString::number( labelValue ) +
00907                                                   diagram()->unitSuffix( static_cast< int >( labelValue ), Qt::Vertical, true );
00908                         const QString label2Text = diagram()->unitPrefix( static_cast< int >( labelValue + step ), Qt::Vertical, true ) +
00909                                                    QString::number( labelValue + step ) +
00910                                                    diagram()->unitSuffix( static_cast< int >( labelValue + step ), Qt::Vertical, true );
00911                         labelItem->setText(  customizedLabel( labelText ) );
00912                         labelItem2->setText( customizedLabel( QString::number( labelValue + step ) ) );
00913                         QPointF nextPoint = plane->translate(  QPointF( 0,  labelValue + step ) );
00914                         if ( labelItem->intersects( *labelItem2, leftPoint, nextPoint ) )
00915                         {
00916                             step += steg;
00917                             nextLabel = false;
00918                         }else{
00919                             nextLabel = true;
00920                         }
00921                     }else{
00922                         nextLabel = true;
00923                     }
00924 
00925                     if ( nextLabel || isLogarithmicY )
00926                         calculateNextLabel( labelValue, step, isLogarithmicY );
00927                     else
00928                         labelValue = minValueY;
00929                 }
00930 
00931                 // Second - Paint the labels
00932                 labelValue = minValueY;
00933                 //qDebug() << "axis labels starting at" << labelValue << "step width" << step;
00934                 while( labelValue <= maxLimit ) {
00935                     //qDebug() << "value now" << labelValue;
00936                     const QString labelText = diagram()->unitPrefix( static_cast< int >( labelValue ), Qt::Vertical, true ) + 
00937                                               QString::number( labelValue ) + 
00938                                               diagram()->unitSuffix( static_cast< int >( labelValue ), Qt::Vertical, true );
00939                     labelItem->setText( customizedLabel( labelText ) );
00940                     QPointF leftPoint = plane->translate( QPointF( 0, labelValue ) );
00941                     QPointF rightPoint ( 0.0, labelValue );
00942                     rightPoint = plane->translate( rightPoint );
00943                     leftPoint.setX( rulerRef.x() + tickLength() );
00944                     rightPoint.setX( rulerRef.x() );
00945 
00946                     const qreal translatedValue = rightPoint.y();
00947                     const bool bIsVisibleLabel =
00948                             ( translatedValue >= geoRect.top() && translatedValue <= geoRect.bottom() );
00949 
00950                     if( bIsVisibleLabel ){
00951                         ptr->drawLine( leftPoint, rightPoint );
00952                         drawnYTicks.append( static_cast<int>( leftPoint.y() ) );
00953                         const QSize labelSize( labelItem->sizeHint() );
00954                         leftPoint.setX( leftPoint.x() );
00955                         const int x =
00956                             static_cast<int>( leftPoint.x() + met.height() * ( position() == Left ? -0.5 : 0.5) )
00957                             - ( position() == Left ? labelSize.width() : (labelSize.width() - maxLabelsWidth) );
00958                         const int y =
00959                             static_cast<int>( leftPoint.y() - ( met.ascent() + met.descent() ) * 0.6 );
00960                         labelItem->setGeometry( QRect( QPoint( x, y ), labelSize ) );
00961                         labelItem->paint( ptr );
00962                     }
00963 
00964                     calculateNextLabel( labelValue, step, isLogarithmicY );
00965                 }
00966             }
00967         }
00968         delete labelItem;
00969         delete labelItem2;
00970     }
00971 
00972     // this draws the subunit rulers
00973     if ( drawSubUnitRulers ) {
00974         d->drawSubUnitRulers( ptr, plane, dim, rulerRef, isAbscissa() ? drawnXTicks : drawnYTicks );
00975     }
00976 
00977     if( ! titleText().isEmpty() ){
00978         d->drawTitleText( ptr, plane, areaGeoRect );
00979     }
00980 
00981     //qDebug() << "KDChart::CartesianAxis::paintCtx() done.";
00982 }
00983 
00984 
00985 /* pure virtual in QLayoutItem */
00986 bool CartesianAxis::isEmpty() const
00987 {
00988     return false; // if the axis exists, it has some (perhaps default) content
00989 }
00990 /* pure virtual in QLayoutItem */
00991 Qt::Orientations CartesianAxis::expandingDirections() const
00992 {
00993     Qt::Orientations ret;
00994     switch ( position() )
00995     {
00996     case Bottom:
00997     case Top:
00998         ret = Qt::Horizontal;
00999         break;
01000     case Left:
01001     case Right:
01002         ret = Qt::Vertical;
01003         break;
01004     default:
01005         Q_ASSERT( false ); // all positions need to be handeld
01006         break;
01007     };
01008     return ret;
01009 }
01010 
01011 
01012 static void calculateOverlap( int i, int first, int last,
01013                               int measure,
01014                               bool isBarDiagram,
01015                               int& firstOverlap, int& lastOverlap )
01016 {
01017     if( i == first ){
01018         if( isBarDiagram ){
01019             //TODO(khz): Calculate the amount of left overlap
01020             //           for bar diagrams.
01021         }else{
01022             firstOverlap = measure / 2;
01023         }
01024     }
01025     // we test both bounds in on go: first and last might be equal
01026     if( i == last ){
01027         if( isBarDiagram ){
01028             //TODO(khz): Calculate the amount of right overlap
01029             //           for bar diagrams.
01030         }else{
01031             lastOverlap = measure / 2;
01032         }
01033     }
01034 }
01035 
01036 
01037 /* pure virtual in QLayoutItem */
01038 QSize CartesianAxis::maximumSize() const
01039 {
01040     QSize result;
01041     if ( !d->diagram() )
01042         return result;
01043 
01044     const TextAttributes labelTA = textAttributes();
01045     const bool drawLabels = labelTA.isVisible();
01046 
01047     const TextAttributes titleTA( d->titleTextAttributesWithAdjustedRotation() );
01048     const bool drawTitle = titleTA.isVisible() && ! titleText().isEmpty();
01049 
01050     AbstractCoordinatePlane* plane = d->diagram()->coordinatePlane();
01051     //qDebug() << this<<"::maximumSize() uses plane geometry" << plane->geometry();
01052     QObject* refArea = plane->parent();
01053     TextLayoutItem labelItem( QString::null, labelTA, refArea,
01054                               KDChartEnums::MeasureOrientationMinimum, Qt::AlignLeft );
01055     TextLayoutItem titleItem( titleText(), titleTA, refArea,
01056                               KDChartEnums::MeasureOrientationMinimum, Qt::AlignHCenter | Qt::AlignVCenter );
01057     const qreal labelGap =
01058         drawLabels
01059         ? (QFontMetricsF( labelItem.realFont(), GlobalMeasureScaling::paintDevice() ).height() / 3.0)
01060         : 0.0;
01061     const qreal titleGap =
01062         drawTitle
01063         ? (QFontMetricsF( titleItem.realFont(), GlobalMeasureScaling::paintDevice() ).height() / 3.0)
01064         : 0.0;
01065 
01066     switch ( position() )
01067     {
01068     case Bottom:
01069     case Top: {
01070         const bool isBarDiagram = referenceDiagramIsBarDiagram(d->diagram());
01071         int leftOverlap = 0;
01072         int rightOverlap = 0;
01073 
01074         qreal w = 10.0;
01075         qreal h = 0.0;
01076         if( drawLabels ){
01077             // if there're no label strings, we take the biggest needed number as height
01078             if ( labels().count() ){
01079                 // find the longest label text:
01080                 const int first=0;
01081                 const int last=labels().count()-1;
01082                 const QStringList labelsList( labels() );
01083                 for ( int i = first; i <= last; ++i )
01084                 {
01085                     labelItem.setText( customizedLabel(labelsList[ i ]) );
01086                     const QSize siz = labelItem.sizeHint();
01087                     h = qMax( h, static_cast<qreal>(siz.height()) );
01088                     calculateOverlap( i, first, last, siz.width(), isBarDiagram,
01089                                       leftOverlap, rightOverlap );
01090 
01091                 }
01092             }else{
01093                 QStringList headerLabels = d->diagram()->itemRowLabels();
01094                 const int headerLabelsCount = headerLabels.count();
01095                 if( headerLabelsCount ){
01096                     const bool useFastCalcAlgorithm 
01097                         = (strcmp( metaObject()->className(), "KDChart::CartesianAxis" ) == 0);
01098                     const int first=0;
01099                     const int last=headerLabelsCount-1;
01100                     for ( int i = first;
01101                           i <= last;
01102                           i = (useFastCalcAlgorithm && i < last) ? last : (i+1) )
01103                     {
01104                         labelItem.setText( customizedLabel(headerLabels[ i ]) );
01105                         const QSize siz = labelItem.sizeHint();
01106                         h = qMax( h, static_cast<qreal>(siz.height()) );
01107                         calculateOverlap( i, first, last, siz.width(), isBarDiagram,
01108                                           leftOverlap, rightOverlap );
01109                     }
01110                 }else{
01111                     labelItem.setText(
01112                             customizedLabel(
01113                                     QString::number( plane->gridDimensionsList().first().end, 'f', 0 )));
01114                     const QSize siz = labelItem.sizeHint();
01115                     h = siz.height();
01116                     calculateOverlap( 0, 0, 0, siz.width(), isBarDiagram,
01117                                       leftOverlap, rightOverlap );
01118                 }
01119             }
01120             // we leave a little gap between axis labels and bottom (or top, resp.) side of axis
01121             h += labelGap;
01122         }
01123         // space for a possible title:
01124         if ( drawTitle ) {
01125             // we add the title height and leave a little gap between axis labels and axis title
01126             h += titleItem.sizeHint().height() + titleGap;
01127             w = titleItem.sizeHint().width() + 2.0;
01128         }
01129         // space for the ticks
01130         h += qAbs( tickLength() ) * 3.0;
01131         result = QSize ( static_cast<int>( w ), static_cast<int>( h ) );
01132 
01133 
01134         // If necessary adjust the widths
01135         // of the left (or right, resp.) side neighboring columns:
01136         d->amountOfLeftOverlap = leftOverlap;
01137         d->amountOfRightOverlap = rightOverlap;
01138         /* Unused code for a push-model:
01139         if( leftOverlap || rightOverlap ){
01140             QTimer::singleShot(200, const_cast<CartesianAxis*>(this),
01141                                SLOT(adjustLeftRightGridColumnWidths()));
01142         }
01143         */
01144     }
01145         break;
01146     case Left:
01147     case Right: {
01148         int topOverlap = 0;
01149         int bottomOverlap = 0;
01150 
01151         qreal w = 0.0;
01152         qreal h = 10.0;
01153         if( drawLabels ){
01154             // if there're no label strings, we take the biggest needed number as width
01155             if ( labels().count() == 0 )
01156             {
01157                 labelItem.setText(
01158                         customizedLabel(
01159                                 QString::number( plane->gridDimensionsList().last().end, 'f', 0 )));
01160                 const QSize siz = labelItem.sizeHint();
01161                 w = siz.width();
01162                 calculateOverlap( 0, 0, 0, siz.height(), false,// bar diagram flag is ignored for Ordinates
01163                                   topOverlap, bottomOverlap );
01164             }else{
01165                 // find the longest label text:
01166                 const int first=0;
01167                 const int last=labels().count()-1;
01168                 const QStringList labelsList( labels() );
01169                 for ( int i = first; i <= last; ++i )
01170                 {
01171                     labelItem.setText( customizedLabel(labelsList[ i ]) );
01172                     const QSize siz = labelItem.sizeHint();
01173                     qreal lw = siz.width();
01174                     w = qMax( w, lw );
01175                     calculateOverlap( 0, 0, 0, siz.height(), false,// bar diagram flag is ignored for Ordinates
01176                                       topOverlap, bottomOverlap );
01177                 }
01178             }
01179             // we leave a little gap between axis labels and left (or right, resp.) side of axis
01180             w += labelGap;
01181         }
01182         // space for a possible title:
01183         if ( drawTitle ) {
01184             // we add the title height and leave a little gap between axis labels and axis title
01185             w += titleItem.sizeHint().width() + titleGap;
01186             h = titleItem.sizeHint().height() + 2.0;
01187             //qDebug() << "left/right axis title item size-hint:" << titleItem.sizeHint();
01188         }
01189         // space for the ticks
01190         w += qAbs( tickLength() ) * 3.0;
01191 
01192         result = QSize ( static_cast<int>( w ), static_cast<int>( h ) );
01193         //qDebug() << "left/right axis width:" << result << "   w:" << w;
01194 
01195 
01196         // If necessary adjust the heights
01197         // of the top (or bottom, resp.) side neighboring rows:
01198         d->amountOfTopOverlap = topOverlap;
01199         d->amountOfBottomOverlap = bottomOverlap;
01200         /* Unused code for a push-model:
01201         if( topOverlap || bottomOverlap ){
01202             QTimer::singleShot(200, const_cast<CartesianAxis*>(this),
01203                                SLOT(adjustTopBottomGridRowHeights()));
01204         }
01205         */
01206     }
01207         break;
01208     default:
01209         Q_ASSERT( false ); // all positions need to be handled
01210         break;
01211     };
01212 //qDebug() << "*******************" << result;
01213     //result=QSize(0,0);
01214     return result;
01215 }
01216 /* pure virtual in QLayoutItem */
01217 QSize CartesianAxis::minimumSize() const
01218 {
01219     return maximumSize();
01220 }
01221 /* pure virtual in QLayoutItem */
01222 QSize CartesianAxis::sizeHint() const
01223 {
01224     return maximumSize();
01225 }
01226 /* pure virtual in QLayoutItem */
01227 void CartesianAxis::setGeometry( const QRect& r )
01228 {
01229 //    qDebug() << "KDChart::CartesianAxis::setGeometry(" << r << ") called"
01230 //             << (isAbscissa() ? "for Abscissa":"for Ordinate") << "axis";
01231     d->geometry = r;
01232 }
01233 /* pure virtual in QLayoutItem */
01234 QRect CartesianAxis::geometry() const
01235 {
01236     return d->geometry;
01237 }
01238 
01239 int CartesianAxis::tickLength( bool subUnitTicks ) const
01240 {
01241     int result = 0;
01242 
01243     if ( isAbscissa() ) {
01244         result = position() == Top ? -4 : 3;
01245     } else {
01246         result = position() == Left ? -4 : 3;
01247     }
01248 
01249     if ( subUnitTicks )
01250         result = result < 0 ? result + 1 : result - 1;
01251 
01252     return result;
01253 }
01254 
01255 
01256 
01257 
01258 
01259 /* unused code from KDChartCartesianAxis.h for using a push-model:
01260 Q_SIGNALS:
01261     void needAdjustLeftRightColumnsForOverlappingLabels(
01262             CartesianAxis* axis, int left, int right );
01263     void needAdjustTopBottomRowsForOverlappingLabels(
01264             CartesianAxis* axis, int top, int bottom );
01265 private Q_SLOTS:
01266     void adjustLeftRightGridColumnWidths();
01267     void adjustTopBottomGridRowHeights();
01268 */
01269 
01270 /*
01271 // Unused code trying to use a push-model: This did not work
01272 // since we can not re-layout the planes each time when
01273 // Qt layouting is calling sizeHint()
01274 void CartesianAxis::adjustLeftRightGridColumnWidths()
01275 {
01276     if( ! d->amountOfLeftOverlap && ! d->amountOfRightOverlap )
01277         return;
01278     const int leftOverlap = d->amountOfLeftOverlap;
01279     const int rightOverlap= d->amountOfRightOverlap;
01280     d->amountOfLeftOverlap = 0;
01281     d->amountOfRightOverlap = 0;
01282     emit needAdjustLeftRightColumnsForOverlappingLabels(
01283             this, leftOverlap, rightOverlap );
01284 }
01285 
01286 void CartesianAxis::adjustTopBottomGridRowHeights()
01287 {
01288     if( ! d->amountOfTopOverlap && ! d->amountOfBottomOverlap )
01289         return;
01290     const int topOverlap = d->amountOfTopOverlap;
01291     const int bottomOverlap= d->amountOfBottomOverlap;
01292     d->amountOfTopOverlap = 0;
01293     d->amountOfBottomOverlap = 0;
01294     emit needAdjustTopBottomRowsForOverlappingLabels(
01295             this, topOverlap, bottomOverlap );
01296 }
01297 */

Generated on Mon Sep 17 16:16:49 2007 for KD Chart 2 by  doxygen 1.5.1