00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #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
00060
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
00082 return false;
00083 }
00084
00085
00086
00087
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
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
00153 if( ! d->diagram() || ! d->diagram()->coordinatePlane() ) {
00154
00155 return;
00156 }
00157 AbstractCoordinatePlane* plane = d->diagram()->coordinatePlane();
00158 if( plane ){
00159 plane->layoutPlanes();
00160
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
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
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
00202
00203 ctx.setRectangle(
00204 QRectF (
00205
00206 QPointF(rect.left(), rect.top()),
00207 QSizeF(rect.width(), rect.height() ) ) );
00208
00209 QRegion clipRegion( rect.adjusted( -1, -1, 1, 1 ) );
00210 painter->save();
00211 painter->setClipRegion( clipRegion );
00212 paintCtx( &ctx );
00213 painter->restore();
00214
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
00234 QPointF topPoint ( f, 0 );
00235 QPointF bottomPoint ( f, 0 );
00236
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
00248 QPointF leftPoint = plane->translate( QPointF( 0, f ) );
00249
00250
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
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
00316
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
00339
00340 titleItem.setGeometry( QRect( QPoint(-size.width() / 2, -size.height() / 2), size ) );
00341
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
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
00381
00382 if( ! d->diagram()->model() )
00383 return;
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 DataDimensionsList dimensions( plane->gridDimensionsList() );
00394
00395
00396
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
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 const qreal MinimumPixelsBetweenRulers = qMin( dimX.stepWidth, dimY.stepWidth );
00420
00421
00422
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
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
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
00462
00463
00464
00465 if( isAbscissa() && ! dimX.isCalculated ){
00466
00467 dimX.stepWidth = dimX.stepWidth ? dimX.stepWidth : 1.0;
00468
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
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
00495
00496
00497
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
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
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
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
00558 QVector< int > drawnXTicks;
00559
00560 QVector< int > drawnYTicks;
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 const bool isBarDiagram = referenceDiagramIsBarDiagram(d->diagram());
00571
00572
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
00583 headerLabels =
00584 isOrdinate()
00585 ? d->diagram()->datasetLabels()
00586 : d->diagram()->itemRowLabels();
00587
00588 useConfiguredStepsLabels = isAbscissa() &&
00589 dimX.stepWidth &&
00590 (( (headerLabels.count() - 1)/ dimX.stepWidth ) != numberOfUnitRulers);
00591 if( useConfiguredStepsLabels ) {
00592 numberOfUnitRulers = ( headerLabels.count() - 1 )/ dimX.stepWidth;
00593
00594
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
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
00637
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
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
00686
00687 if ( !drawLabels || hardLabelsCount < 1 || ( dimX.stepWidth != 1.0 && ! dim.isCalculated ) )
00688 {
00689
00690
00691 if( useConfiguredStepsLabels ){
00692 labelItem->setText( customizedLabel(headerLabels[ iLabel ]) );
00693 labelItem2->setText(customizedLabel(headerLabels[ iLabel+1 ]) );
00694 }else{
00695
00696 labelItem->setText( customizedLabel(headerLabelsCount ? headerLabels[static_cast<int>(i)]
00697 : QString::number( i, 'f', precision )) );
00698
00699
00700
00701 labelItem2->setText( customizedLabel(headerLabelsCount ? headerLabels[static_cast<int>(i+labelDiff)]
00702 : QString::number( i + labelDiff, 'f', precision )) );
00703
00704
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
00746
00747 while( i <= maxValueX ) {
00748
00749
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
00762
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
00776
00777
00778
00779
00780
00781
00782
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
00793
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
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
00821 labelItem2->setText( labelItem->text() );
00822
00823
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
00856
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
00872
00873
00874 while ( labelValue <= maxLimit ) {
00875 QPointF leftPoint = plane->translate( QPointF( 0, labelValue ) );
00876 const qreal translatedValue = leftPoint.y();
00877
00878
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
00903 labelValue = minValueY;
00904
00905 while ( labelValue <= maxLimit ) {
00906
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
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
00951 }
00952
00953
00954
00955 bool CartesianAxis::isEmpty() const
00956 {
00957 return false;
00958 }
00959
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 );
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
00989
00990 }else{
00991 firstOverlap = measure / 2;
00992 }
00993 }
00994
00995 if( i == last ){
00996 if( isBarDiagram ){
00997
00998
00999 }else{
01000 lastOverlap = measure / 2;
01001 }
01002 }
01003 }
01004
01005
01006
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
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
01047 if ( labels().count() ){
01048
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
01085 h += labelGap;
01086 }
01087
01088 if ( drawTitle ) {
01089
01090 h += titleItem.sizeHint().height() + titleGap;
01091 w = titleItem.sizeHint().width() + 2.0;
01092 }
01093
01094 h += qAbs( tickLength() ) * 3.0;
01095 result = QSize ( static_cast<int>( w ), static_cast<int>( h ) );
01096
01097
01098
01099
01100 d->amountOfLeftOverlap = leftOverlap;
01101 d->amountOfRightOverlap = rightOverlap;
01102
01103
01104
01105
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
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,
01127 topOverlap, bottomOverlap );
01128 }else{
01129
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,
01139 topOverlap, bottomOverlap );
01140 }
01141 }
01142
01143 w += labelGap;
01144 }
01145
01146 if ( drawTitle ) {
01147
01148 w += titleItem.sizeHint().width() + titleGap;
01149 h = titleItem.sizeHint().height() + 2.0;
01150
01151 }
01152
01153 w += qAbs( tickLength() ) * 3.0;
01154
01155 result = QSize ( static_cast<int>( w ), static_cast<int>( h ) );
01156
01157
01158
01159
01160
01161 d->amountOfTopOverlap = topOverlap;
01162 d->amountOfBottomOverlap = bottomOverlap;
01163
01164
01165
01166
01167
01168
01169 }
01170 break;
01171 default:
01172 Q_ASSERT( false );
01173 break;
01174 };
01175
01176
01177 return result;
01178 }
01179
01180 QSize CartesianAxis::minimumSize() const
01181 {
01182 return maximumSize();
01183 }
01184
01185 QSize CartesianAxis::sizeHint() const
01186 {
01187 return maximumSize();
01188 }
01189
01190 void CartesianAxis::setGeometry( const QRect& r )
01191 {
01192
01193
01194 d->geometry = r;
01195 }
01196
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
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260