Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

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 */

Generated on Thu May 10 11:06:25 2007 for KD Chart 2 by doxygen 1.3.6