00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "KDChartCartesianCoordinatePlane.h"
00024 #include "KDChartCartesianCoordinatePlane_p.h"
00025
00026 #include <QFont>
00027 #include <QList>
00028 #include <QtDebug>
00029 #include <QPainter>
00030 #include <QApplication>
00031
00032 #include "KDChartAbstractDiagram.h"
00033 #include "KDChartAbstractCartesianDiagram.h"
00034 #include "CartesianCoordinateTransformation.h"
00035 #include "KDChartGridAttributes.h"
00036 #include "KDChartPaintContext.h"
00037 #include "KDChartPainterSaver_p.h"
00038 #include "KDChartBarDiagram.h"
00039 #include "KDChartStockDiagram.h"
00040
00041 #include <KDABLibFakes>
00042
00043
00044 using namespace KDChart;
00045
00046 #define d d_func()
00047
00048 CartesianCoordinatePlane::Private::Private()
00049 : AbstractCoordinatePlane::Private()
00050 , bPaintIsRunning( false )
00051 , hasOwnGridAttributesHorizontal ( false )
00052 , hasOwnGridAttributesVertical ( false )
00053
00054 , isometricScaling ( false )
00055 , horizontalMin(0)
00056 , horizontalMax(0)
00057 , verticalMin(0)
00058 , verticalMax(0)
00059 , autoAdjustHorizontalRangeToData(67)
00060 , autoAdjustVerticalRangeToData( 67)
00061 , autoAdjustGridToZoom( true )
00062 , fixedDataCoordinateSpaceRelation( false )
00063 , xAxisStartAtZero(true)
00064 , reverseVerticalPlane( false )
00065 , reverseHorizontalPlane( false )
00066 {
00067 }
00068
00069 CartesianCoordinatePlane::CartesianCoordinatePlane ( Chart* parent )
00070 : AbstractCoordinatePlane ( new Private(), parent )
00071 {
00072
00073 }
00074
00075 CartesianCoordinatePlane::~CartesianCoordinatePlane()
00076 {
00077
00078 }
00079
00080 void CartesianCoordinatePlane::init()
00081 {
00082
00083 }
00084
00085
00086 void CartesianCoordinatePlane::addDiagram ( AbstractDiagram* diagram )
00087 {
00088 Q_ASSERT_X ( dynamic_cast<AbstractCartesianDiagram*> ( diagram ),
00089 "CartesianCoordinatePlane::addDiagram", "Only cartesian "
00090 "diagrams can be added to a cartesian coordinate plane!" );
00091 AbstractCoordinatePlane::addDiagram ( diagram );
00092 connect ( diagram, SIGNAL ( layoutChanged ( AbstractDiagram* ) ),
00093 SLOT ( slotLayoutChanged ( AbstractDiagram* ) ) );
00094
00095 connect( diagram, SIGNAL( propertiesChanged() ),this, SIGNAL( propertiesChanged() ) );
00096 }
00097
00098
00099 void CartesianCoordinatePlane::paint ( QPainter* painter )
00100 {
00101
00102
00103 if( d->bPaintIsRunning ){
00104 return;
00105 }
00106 d->bPaintIsRunning = true;
00107
00108
00109
00110 AbstractDiagramList diags = diagrams();
00111 if ( !diags.isEmpty() )
00112 {
00113 PaintContext ctx;
00114 ctx.setPainter ( painter );
00115 ctx.setCoordinatePlane ( this );
00116 const QRectF drawArea( drawingArea() );
00117 ctx.setRectangle ( drawArea );
00118
00119
00120 PainterSaver painterSaver( painter );
00121 QRect clipRect = drawArea.toRect().adjusted( -1, -1, 1, 1 );
00122 QRegion clipRegion( clipRect );
00123 painter->setClipRegion( clipRegion );
00124
00125
00126 d->grid->drawGrid( &ctx );
00127
00128
00129 for ( int i = 0; i < diags.size(); i++ )
00130 {
00131 if ( diags[i]->isHidden() ) {
00132 continue;
00133 }
00134
00135 PainterSaver diagramPainterSaver( painter );
00136 diags[i]->paint ( &ctx );
00137
00138 }
00139
00140
00141
00142
00143
00144 }
00145 d->bPaintIsRunning = false;
00146
00147 }
00148
00149
00150 void CartesianCoordinatePlane::slotLayoutChanged ( AbstractDiagram* )
00151 {
00152
00153 layoutDiagrams();
00154 }
00155
00156 QRectF CartesianCoordinatePlane::getRawDataBoundingRectFromDiagrams() const
00157 {
00158
00159 qreal minX = 0;
00160 qreal maxX = 0;
00161 qreal minY = 0;
00162 qreal maxY = 0
00163 ;
00164 bool bStarting = true;
00165 Q_FOREACH( const AbstractDiagram* diagram, diagrams() )
00166 {
00167 QPair<QPointF, QPointF> dataBoundariesPair = diagram->dataBoundaries();
00168
00169 if ( bStarting || dataBoundariesPair.first.x() < minX ) minX = dataBoundariesPair.first.x();
00170 if ( bStarting || dataBoundariesPair.first.y() < minY ) minY = dataBoundariesPair.first.y();
00171 if ( bStarting || dataBoundariesPair.second.x() > maxX ) maxX = dataBoundariesPair.second.x();
00172 if ( bStarting || dataBoundariesPair.second.y() > maxY ) maxY = dataBoundariesPair.second.y();
00173 bStarting = false;
00174 }
00175
00176 QRectF dataBoundingRect;
00177 dataBoundingRect.setBottomLeft( QPointF(minX, minY) );
00178 dataBoundingRect.setTopRight( QPointF(maxX, maxY) );
00179 return dataBoundingRect;
00180 }
00181
00182
00183 QRectF CartesianCoordinatePlane::adjustedToMaxEmptyInnerPercentage(
00184 const QRectF& r, unsigned int percentX, unsigned int percentY ) const
00185 {
00186 QRectF erg( r );
00187 if( ( axesCalcModeX() != Logarithmic || r.left() < 0.0 ) && (percentX > 0) && (percentX != 100) ) {
00188 const bool isPositive = (r.left() >= 0);
00189 if( (r.right() >= 0) == isPositive ){
00190 const qreal innerBound =
00191 isPositive ? qMin(r.left(), r.right()) : qMax(r.left(), r.right());
00192 const qreal outerBound =
00193 isPositive ? qMax(r.left(), r.right()) : qMin(r.left(), r.right());
00194 if( innerBound / outerBound * 100 <= percentX )
00195 {
00196 if(d->xAxisStartAtZero)
00197 {
00198 if( isPositive )
00199 erg.setLeft( 0.0 );
00200 else
00201 erg.setRight( 0.0 );
00202 }
00203 }
00204 }
00205 }
00206 if( ( axesCalcModeY() != Logarithmic || r.bottom() < 0.0 ) && (percentY > 0) && (percentY != 100) ) {
00207
00208 const bool isPositive = (r.bottom() >= 0);
00209 if( (r.top() >= 0) == isPositive ){
00210 const qreal innerBound =
00211 isPositive ? qMin(r.top(), r.bottom()) : qMax(r.top(), r.bottom());
00212 const qreal outerBound =
00213 isPositive ? qMax(r.top(), r.bottom()) : qMin(r.top(), r.bottom());
00214
00215 if( innerBound / outerBound * 100 <= percentY )
00216 {
00217 if( isPositive )
00218 erg.setBottom( 0.0 );
00219 else
00220 erg.setTop( 0.0 );
00221 }
00222 }
00223
00224 }
00225 return erg;
00226 }
00227
00228
00229 QRectF CartesianCoordinatePlane::calculateRawDataBoundingRect() const
00230 {
00231
00232 const bool bAutoAdjustHorizontalRange = (d->autoAdjustHorizontalRangeToData < 100);
00233 const bool bAutoAdjustVerticalRange = (d->autoAdjustVerticalRangeToData < 100);
00234
00235 const bool bHardHorizontalRange = (d->horizontalMin != d->horizontalMax) && ! bAutoAdjustHorizontalRange;
00236 const bool bHardVerticalRange = (d->verticalMin != d->verticalMax) && ! bAutoAdjustVerticalRange;
00237 QRectF dataBoundingRect;
00238
00239
00240 if ( bHardHorizontalRange && bHardVerticalRange ) {
00241 dataBoundingRect.setLeft( d->horizontalMin );
00242 dataBoundingRect.setRight( d->horizontalMax );
00243 dataBoundingRect.setBottom( d->verticalMin );
00244 dataBoundingRect.setTop( d->verticalMax );
00245 }else{
00246
00247 dataBoundingRect = getRawDataBoundingRectFromDiagrams();
00248 if ( bHardHorizontalRange ) {
00249 dataBoundingRect.setLeft( d->horizontalMin );
00250 dataBoundingRect.setRight( d->horizontalMax );
00251 }
00252 if ( bHardVerticalRange ) {
00253 dataBoundingRect.setBottom( d->verticalMin );
00254 dataBoundingRect.setTop( d->verticalMax );
00255 }
00256 }
00257
00258
00259 dataBoundingRect = adjustedToMaxEmptyInnerPercentage(
00260 dataBoundingRect, d->autoAdjustHorizontalRangeToData, d->autoAdjustVerticalRangeToData );
00261 if( bAutoAdjustHorizontalRange ){
00262 const_cast<CartesianCoordinatePlane::Private *>(d)->horizontalMin = dataBoundingRect.left();
00263 const_cast<CartesianCoordinatePlane::Private *>(d)->horizontalMax = dataBoundingRect.right();
00264 }
00265 if( bAutoAdjustVerticalRange ){
00266 const_cast<CartesianCoordinatePlane*>(this)->d->verticalMin = dataBoundingRect.bottom();
00267 const_cast<CartesianCoordinatePlane*>(this)->d->verticalMax = dataBoundingRect.top();
00268 }
00269
00270 return dataBoundingRect;
00271 }
00272
00273
00274 DataDimensionsList CartesianCoordinatePlane::getDataDimensionsList() const
00275 {
00276
00277 DataDimensionsList l;
00278 const AbstractCartesianDiagram* dgr
00279 = diagrams().isEmpty() ? 0 : dynamic_cast<const AbstractCartesianDiagram*> (diagrams().first() );
00280 if( dgr && dgr->referenceDiagram() )
00281 dgr = dgr->referenceDiagram();
00282 const BarDiagram *barDiagram = qobject_cast< const BarDiagram* >( dgr );
00283 const StockDiagram *stockDiagram = qobject_cast< const StockDiagram* >( dgr );
00284
00285
00286
00287
00288
00289 const Qt::Orientation diagramOrientation = barDiagram != 0 ? barDiagram->orientation() : Qt::Vertical;
00290
00291 const bool diagramIsVertical = diagramOrientation == Qt::Vertical;
00292
00293
00294 if( dgr ){
00295 const QRectF r( calculateRawDataBoundingRect() );
00296
00297
00298
00299
00300 const GridAttributes gaH( gridAttributes( Qt::Horizontal ) );
00301 const GridAttributes gaV( gridAttributes( Qt::Vertical ) );
00302
00303 l.append(
00304 DataDimension(
00305 r.left(), r.right(),
00306 diagramIsVertical ? ( !stockDiagram && dgr->datasetDimension() > 1 ) : true,
00307 axesCalcModeX(),
00308 gaH.gridGranularitySequence(),
00309 gaH.gridStepWidth(),
00310 gaH.gridSubStepWidth() ) );
00311
00312 l.append(
00313 DataDimension(
00314 r.bottom(), r.top(),
00315 diagramIsVertical ? true : ( dgr->datasetDimension() > 1 ),
00316 axesCalcModeY(),
00317 gaV.gridGranularitySequence(),
00318 gaV.gridStepWidth(),
00319 gaV.gridSubStepWidth() ) );
00320 }else{
00321 l.append( DataDimension() );
00322 l.append( DataDimension() );
00323 }
00324 return l;
00325 }
00326
00327 QRectF CartesianCoordinatePlane::drawingArea() const
00328 {
00329
00330
00331
00332
00333
00334
00335 const QRect rect( areaGeometry() );
00336 return QRectF ( rect.left()+1, rect.top()+1, rect.width() - 3, rect.height() - 3 );
00337 }
00338
00339
00340 QRectF CartesianCoordinatePlane::logicalArea() const
00341 {
00342 if ( d->dimensions.isEmpty() )
00343 return QRectF();
00344
00345 const DataDimension dimX = d->dimensions.first();
00346 const DataDimension dimY = d->dimensions.last();
00347 const QPointF pt( qMin( dimX.start, dimX.end ), qMax( dimY.start, dimY.end ) );
00348 const QSizeF siz( qAbs( dimX.distance() ), -qAbs( dimY.distance() ) );
00349 const QRectF dataBoundingRect( pt, siz );
00350
00351
00352
00353 QPointF topLeft;
00354 if( !d->reverseVerticalPlane && !d->reverseHorizontalPlane )
00355 topLeft = dataBoundingRect.topLeft();
00356 else if( d->reverseVerticalPlane && !d->reverseHorizontalPlane )
00357 topLeft = dataBoundingRect.bottomLeft();
00358 else if( d->reverseVerticalPlane && d->reverseHorizontalPlane )
00359 topLeft = dataBoundingRect.bottomRight();
00360 else if( !d->reverseVerticalPlane && d->reverseHorizontalPlane )
00361 topLeft = dataBoundingRect.topRight();
00362
00363 const double width = dataBoundingRect.width() * ( d->reverseHorizontalPlane ? -1.0 : 1.0 );
00364 const double height = dataBoundingRect.height() * ( d->reverseVerticalPlane ? -1.0 : 1.0 );
00365
00366 return QRectF( topLeft, QSizeF( width, height ) );
00367 }
00368
00369 QRectF CartesianCoordinatePlane::diagramArea() const
00370 {
00371 const QRectF logArea( logicalArea() );
00372 QPointF physicalTopLeft = d->coordinateTransformation.translate( logArea.topLeft() );
00373 QPointF physicalBottomRight = d->coordinateTransformation.translate( logArea.bottomRight() );
00374
00375 return QRectF( physicalTopLeft, physicalBottomRight ).normalized();
00376 }
00377
00378 QRectF CartesianCoordinatePlane::visibleDiagramArea() const
00379 {
00380 return diagramArea().intersected( drawingArea() );
00381 }
00382
00383 void CartesianCoordinatePlane::layoutDiagrams()
00384 {
00385 if ( diagrams().isEmpty() )
00386 {
00387
00388 }
00389
00390 d->dimensions = gridDimensionsList();
00391
00392 Q_ASSERT_X ( d->dimensions.count() == 2, "CartesianCoordinatePlane::layoutDiagrams",
00393 "Error: gridDimensionsList() did not return exactly two dimensions." );
00394
00395
00396 const QRectF physicalArea( drawingArea() );
00397
00398 const QRectF logArea( logicalArea() );
00399
00400 d->coordinateTransformation.unitVectorX = logArea.width() != 0 ? physicalArea.width() / logArea.width() : 1.0;
00401 d->coordinateTransformation.unitVectorY = logArea.height() != 0 ? physicalArea.height() / logArea.height() : 1.0;
00402
00403 const double diagramXUnitInCoordinatePlane = d->coordinateTransformation.unitVectorX;
00404 const double diagramYUnitInCoordinatePlane = d->coordinateTransformation.unitVectorY;
00405
00406 double scaleX;
00407 double scaleY;
00408
00409
00410
00411 if ( d->isometricScaling )
00412 {
00413 double scale = qMin ( qAbs ( diagramXUnitInCoordinatePlane ),
00414 qAbs ( diagramYUnitInCoordinatePlane ) );
00415
00416 scaleX = qAbs( scale / diagramXUnitInCoordinatePlane );
00417 scaleY = qAbs( scale / diagramYUnitInCoordinatePlane );
00418 } else {
00419 scaleX = 1.0;
00420 scaleY = 1.0;
00421 }
00422
00423 const QPointF logicalTopLeft = logArea.topLeft();
00424
00425 QPointF coordinateOrigin = QPointF ( logicalTopLeft.x() * -diagramXUnitInCoordinatePlane,
00426 logicalTopLeft.y() * -diagramYUnitInCoordinatePlane );
00427 coordinateOrigin += physicalArea.topLeft();
00428
00429 d->coordinateTransformation.originTranslation = coordinateOrigin;
00430
00431
00432
00433 const QRectF normalizedLogArea = logArea.normalized();
00434 d->coordinateTransformation.diagramRect = QRectF( normalizedLogArea.bottomLeft(), normalizedLogArea.topRight() );
00435
00436 d->coordinateTransformation.isoScaleX = scaleX;
00437 d->coordinateTransformation.isoScaleY = scaleY;
00438
00439
00440 handleFixedDataCoordinateSpaceRelation( physicalArea );
00441
00442 update();
00443 }
00444
00445 void CartesianCoordinatePlane::setFixedDataCoordinateSpaceRelation( bool fixed )
00446 {
00447 d->fixedDataCoordinateSpaceRelation = fixed;
00448 d->fixedDataCoordinateSpaceRelationOldSize = QRectF();
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 }
00465
00466 bool CartesianCoordinatePlane::hasFixedDataCoordinateSpaceRelation() const
00467 {
00468 return d->fixedDataCoordinateSpaceRelation;
00469 }
00470
00471 void CartesianCoordinatePlane::setXAxisStartAtZero(bool fixedStart)
00472 {
00473 if(d->xAxisStartAtZero == fixedStart)
00474 return;
00475
00476 d->xAxisStartAtZero = fixedStart;
00477 }
00478
00479 bool CartesianCoordinatePlane::xAxisStartAtZero() const
00480 {
00481 return d->xAxisStartAtZero;
00482 }
00483
00484 void CartesianCoordinatePlane::handleFixedDataCoordinateSpaceRelation( const QRectF& geometry )
00485 {
00486
00487 if( !d->fixedDataCoordinateSpaceRelation )
00488 return;
00489
00490
00491 if( geometry.height() < 1 || geometry.width() < 1 )
00492 return;
00493
00494
00495 if( d->fixedDataCoordinateSpaceRelationOldSize != geometry && !d->fixedDataCoordinateSpaceRelationOldSize.isNull() )
00496 {
00497 const double newZoomX = zoomFactorX() * d->fixedDataCoordinateSpaceRelationOldSize.width() / geometry.width();
00498 const double newZoomY = zoomFactorY() * d->fixedDataCoordinateSpaceRelationOldSize.height() / geometry.height();
00499
00500 const QPointF oldCenter = zoomCenter();
00501 const QPointF newCenter = QPointF( oldCenter.x() * geometry.width() / d->fixedDataCoordinateSpaceRelationOldSize.width(),
00502 oldCenter.y() * geometry.height() / d->fixedDataCoordinateSpaceRelationOldSize.height() );
00503
00504
00505
00506 bool bChanged = false;
00507 if( doneSetZoomFactorY( newZoomY ) )
00508 bChanged = true;
00509 if( doneSetZoomFactorX( newZoomX ) )
00510 bChanged = true;
00511 if( doneSetZoomCenter( newCenter ) )
00512 bChanged = true;
00513 if( bChanged ){
00514 emit propertiesChanged();
00515 }
00516 }
00517
00518 d->fixedDataCoordinateSpaceRelationOldSize = geometry;
00519 }
00520
00521 const QPointF CartesianCoordinatePlane::translate( const QPointF& diagramPoint ) const
00522 {
00523
00524
00525
00526
00527 return d->coordinateTransformation.translate ( diagramPoint );
00528 }
00529
00530 const QPointF CartesianCoordinatePlane::translateBack( const QPointF& screenPoint ) const
00531 {
00532 return d->coordinateTransformation.translateBack ( screenPoint );
00533 }
00534
00535 void CartesianCoordinatePlane::setIsometricScaling ( bool onOff )
00536 {
00537 if ( d->isometricScaling != onOff )
00538 {
00539 d->isometricScaling = onOff;
00540 layoutDiagrams();
00541 emit propertiesChanged();
00542 }
00543 }
00544
00545 bool CartesianCoordinatePlane::doesIsometricScaling () const
00546 {
00547 return d->isometricScaling;
00548 }
00549
00550 bool CartesianCoordinatePlane::doneSetZoomFactorX( double factor )
00551 {
00552 const bool done = ( d->coordinateTransformation.zoom.xFactor != factor );
00553 if( done ){
00554 d->coordinateTransformation.zoom.xFactor = factor;
00555 if( d->autoAdjustGridToZoom )
00556 d->grid->setNeedRecalculate();
00557 }
00558 return done;
00559 }
00560
00561 bool CartesianCoordinatePlane::doneSetZoomFactorY( double factor )
00562 {
00563 const bool done = ( d->coordinateTransformation.zoom.yFactor != factor );
00564 if( done ){
00565 d->coordinateTransformation.zoom.yFactor = factor;
00566 if( d->autoAdjustGridToZoom )
00567 d->grid->setNeedRecalculate();
00568 }
00569 return done;
00570 }
00571
00572 bool CartesianCoordinatePlane::doneSetZoomCenter( const QPointF& point )
00573 {
00574 const bool done = ( d->coordinateTransformation.zoom.center() != point );
00575 if( done ){
00576 d->coordinateTransformation.zoom.setCenter( point );
00577 if( d->autoAdjustGridToZoom )
00578 d->grid->setNeedRecalculate();
00579 }
00580 return done;
00581 }
00582
00583 void CartesianCoordinatePlane::setZoomFactors( double factorX, double factorY )
00584 {
00585 if( doneSetZoomFactorX( factorX ) || doneSetZoomFactorY( factorY ) ){
00586 emit propertiesChanged();
00587 }
00588 }
00589
00590 void CartesianCoordinatePlane::setZoomFactorX( double factor )
00591 {
00592 if( doneSetZoomFactorX( factor ) ){
00593 emit propertiesChanged();
00594 }
00595 }
00596
00597 void CartesianCoordinatePlane::setZoomFactorY( double factor )
00598 {
00599 if( doneSetZoomFactorY( factor ) ){
00600 emit propertiesChanged();
00601 }
00602 }
00603
00604 void CartesianCoordinatePlane::setZoomCenter( const QPointF& point )
00605 {
00606 if( doneSetZoomCenter( point ) ){
00607 emit propertiesChanged();
00608 }
00609 }
00610
00611 QPointF CartesianCoordinatePlane::zoomCenter() const
00612 {
00613 return d->coordinateTransformation.zoom.center();
00614 }
00615
00616 double CartesianCoordinatePlane::zoomFactorX() const
00617 {
00618 return d->coordinateTransformation.zoom.xFactor;
00619 }
00620
00621 double CartesianCoordinatePlane::zoomFactorY() const
00622 {
00623 return d->coordinateTransformation.zoom.yFactor;
00624 }
00625
00626
00627 CartesianCoordinatePlane::AxesCalcMode CartesianCoordinatePlane::axesCalcModeY() const
00628 {
00629 return d->coordinateTransformation.axesCalcModeY;
00630 }
00631
00632 CartesianCoordinatePlane::AxesCalcMode CartesianCoordinatePlane::axesCalcModeX() const
00633 {
00634 return d->coordinateTransformation.axesCalcModeX;
00635 }
00636
00637 void CartesianCoordinatePlane::setAxesCalcModes( AxesCalcMode mode )
00638 {
00639 if( d->coordinateTransformation.axesCalcModeY != mode ||
00640 d->coordinateTransformation.axesCalcModeX != mode ){
00641 d->coordinateTransformation.axesCalcModeY = mode;
00642 d->coordinateTransformation.axesCalcModeX = mode;
00643 emit propertiesChanged();
00644 emit viewportCoordinateSystemChanged();
00645 Q_FOREACH( AbstractDiagram* diag, diagrams() )
00646 slotLayoutChanged( diag );
00647 }
00648 }
00649
00650 void CartesianCoordinatePlane::setAxesCalcModeY( AxesCalcMode mode )
00651 {
00652 if( d->coordinateTransformation.axesCalcModeY != mode ){
00653 d->coordinateTransformation.axesCalcModeY = mode;
00654 emit propertiesChanged();
00655 setGridNeedsRecalculate();
00656 emit viewportCoordinateSystemChanged();
00657 }
00658 }
00659
00660 void CartesianCoordinatePlane::setAxesCalcModeX( AxesCalcMode mode )
00661 {
00662 if( d->coordinateTransformation.axesCalcModeX != mode ){
00663 d->coordinateTransformation.axesCalcModeX = mode;
00664 emit propertiesChanged();
00665 emit viewportCoordinateSystemChanged();
00666 }
00667 }
00668
00669 void CartesianCoordinatePlane::setHorizontalRange( const QPair< qreal, qreal > & range )
00670 {
00671 if ( d->horizontalMin != range.first || d->horizontalMax != range.second ) {
00672 d->autoAdjustHorizontalRangeToData = 100;
00673 d->horizontalMin = range.first;
00674 d->horizontalMax = range.second;
00675 layoutDiagrams();
00676 emit propertiesChanged();
00677 }
00678 }
00679
00680 void CartesianCoordinatePlane::setVerticalRange( const QPair< qreal, qreal > & range )
00681 {
00682
00683 if ( d->verticalMin != range.first || d->verticalMax != range.second ) {
00684 d->autoAdjustVerticalRangeToData = 100;
00685 d->verticalMin = range.first;
00686 d->verticalMax = range.second;
00687 layoutDiagrams();
00688 emit propertiesChanged();
00689 }
00690 }
00691
00692 QPair< qreal, qreal > CartesianCoordinatePlane::horizontalRange( ) const
00693 {
00694 return QPair<qreal, qreal>( d->horizontalMin, d->horizontalMax );
00695 }
00696
00697 QPair< qreal, qreal > CartesianCoordinatePlane::verticalRange( ) const
00698 {
00699 return QPair<qreal, qreal>( d->verticalMin, d->verticalMax );
00700 }
00701
00702 void CartesianCoordinatePlane::adjustRangesToData()
00703 {
00704 const QRectF dataBoundingRect( getRawDataBoundingRectFromDiagrams() );
00705 d->horizontalMin = dataBoundingRect.left();
00706 d->horizontalMax = dataBoundingRect.right();
00707 d->verticalMin = dataBoundingRect.top();
00708 d->verticalMax = dataBoundingRect.bottom();
00709 layoutDiagrams();
00710 emit propertiesChanged();
00711 }
00712
00713 void CartesianCoordinatePlane::adjustHorizontalRangeToData()
00714 {
00715 const QRectF dataBoundingRect( getRawDataBoundingRectFromDiagrams() );
00716 d->horizontalMin = dataBoundingRect.left();
00717 d->horizontalMax = dataBoundingRect.right();
00718 layoutDiagrams();
00719 emit propertiesChanged();
00720 }
00721
00722 void CartesianCoordinatePlane::adjustVerticalRangeToData()
00723 {
00724 const QRectF dataBoundingRect( getRawDataBoundingRectFromDiagrams() );
00725 d->verticalMin = dataBoundingRect.bottom();
00726 d->verticalMax = dataBoundingRect.top();
00727 layoutDiagrams();
00728 emit propertiesChanged();
00729 }
00730
00731 void CartesianCoordinatePlane::setAutoAdjustHorizontalRangeToData( unsigned int percentEmpty )
00732 {
00733 if ( d->autoAdjustHorizontalRangeToData != percentEmpty )
00734 {
00735 d->autoAdjustHorizontalRangeToData = percentEmpty;
00736 d->horizontalMin = 0.0;
00737 d->horizontalMax = 0.0;
00738 layoutDiagrams();
00739 emit propertiesChanged();
00740 }
00741 }
00742
00743 void CartesianCoordinatePlane::setAutoAdjustVerticalRangeToData( unsigned int percentEmpty )
00744 {
00745 if ( d->autoAdjustVerticalRangeToData != percentEmpty )
00746 {
00747 d->autoAdjustVerticalRangeToData = percentEmpty;
00748 d->verticalMin = 0.0;
00749 d->verticalMax = 0.0;
00750 layoutDiagrams();
00751 emit propertiesChanged();
00752 }
00753 }
00754
00755 unsigned int CartesianCoordinatePlane::autoAdjustHorizontalRangeToData() const
00756 {
00757 return d->autoAdjustHorizontalRangeToData;
00758 }
00759
00760 unsigned int CartesianCoordinatePlane::autoAdjustVerticalRangeToData() const
00761 {
00762 return d->autoAdjustVerticalRangeToData;
00763 }
00764
00765 void CartesianCoordinatePlane::setGridAttributes(
00766 Qt::Orientation orientation,
00767 const GridAttributes& a )
00768 {
00769 if( orientation == Qt::Horizontal )
00770 d->gridAttributesHorizontal = a;
00771 else
00772 d->gridAttributesVertical = a;
00773 setHasOwnGridAttributes( orientation, true );
00774 update();
00775 emit propertiesChanged();
00776 }
00777
00778 void CartesianCoordinatePlane::resetGridAttributes(
00779 Qt::Orientation orientation )
00780 {
00781 setHasOwnGridAttributes( orientation, false );
00782 update();
00783 }
00784
00785 const GridAttributes CartesianCoordinatePlane::gridAttributes(
00786 Qt::Orientation orientation ) const
00787 {
00788 if( hasOwnGridAttributes( orientation ) ){
00789 if( orientation == Qt::Horizontal )
00790 return d->gridAttributesHorizontal;
00791 else
00792 return d->gridAttributesVertical;
00793 }else{
00794 return globalGridAttributes();
00795 }
00796 }
00797
00798 void CartesianCoordinatePlane::setHasOwnGridAttributes(
00799 Qt::Orientation orientation, bool on )
00800 {
00801 if( orientation == Qt::Horizontal )
00802 d->hasOwnGridAttributesHorizontal = on;
00803 else
00804 d->hasOwnGridAttributesVertical = on;
00805 emit propertiesChanged();
00806 }
00807
00808 bool CartesianCoordinatePlane::hasOwnGridAttributes(
00809 Qt::Orientation orientation ) const
00810 {
00811 return
00812 ( orientation == Qt::Horizontal )
00813 ? d->hasOwnGridAttributesHorizontal
00814 : d->hasOwnGridAttributesVertical;
00815 }
00816
00817 void CartesianCoordinatePlane::setAutoAdjustGridToZoom( bool autoAdjust )
00818 {
00819 if( d->autoAdjustGridToZoom != autoAdjust ){
00820 d->autoAdjustGridToZoom = autoAdjust;
00821 d->grid->setNeedRecalculate();
00822 emit propertiesChanged();
00823 }
00824 }
00825
00826 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE)
00827 const
00828 #endif
00829 bool CartesianCoordinatePlane::autoAdjustGridToZoom() const
00830 {
00831 return d->autoAdjustGridToZoom;
00832 }
00833
00834 AbstractCoordinatePlane* CartesianCoordinatePlane::sharedAxisMasterPlane( QPainter* painter )
00835 {
00836 CartesianCoordinatePlane* plane = this;
00837 AbstractCartesianDiagram* diag = dynamic_cast< AbstractCartesianDiagram* >( plane->diagram() );
00838 const CartesianAxis* sharedAxis = 0;
00839 if( diag != 0 )
00840 {
00841 const CartesianAxisList axes = diag->axes();
00842 KDAB_FOREACH( const CartesianAxis* a, axes )
00843 {
00844 CartesianCoordinatePlane* p = const_cast< CartesianCoordinatePlane* >(
00845 dynamic_cast< const CartesianCoordinatePlane* >( a->coordinatePlane() ) );
00846 if( p != 0 && p != this )
00847 {
00848 plane = p;
00849 sharedAxis = a;
00850 }
00851 }
00852 }
00853
00854 if( plane == this || painter == 0 )
00855 return plane;
00856
00857 const QPointF zero = QPointF( 0, 0 );
00858 const QPointF tenX = QPointF( 10, 0 );
00859 const QPointF tenY = QPointF( 0, 10 );
00860
00861
00862 if( sharedAxis->isOrdinate() )
00863 {
00864 painter->translate( translate( zero ).x(), 0.0 );
00865 const qreal factor = (translate( tenX ) - translate( zero ) ).x() / ( plane->translate( tenX ) - plane->translate( zero ) ).x();
00866 painter->scale( factor, 1.0 );
00867 painter->translate( -plane->translate( zero ).x(), 0.0 );
00868 }
00869 if( sharedAxis->isAbscissa() )
00870 {
00871 painter->translate( 0.0, translate( zero ).y() );
00872 const qreal factor = (translate( tenY ) - translate( zero ) ).y() / ( plane->translate( tenY ) - plane->translate( zero ) ).y();
00873 painter->scale( 1.0, factor );
00874 painter->translate( 0.0, -plane->translate( zero ).y() );
00875 }
00876
00877
00878 return plane;
00879 }
00880
00881 void CartesianCoordinatePlane::setHorizontalRangeReversed( bool reverse )
00882 {
00883 if( d->reverseHorizontalPlane == reverse )
00884 return;
00885
00886 d->reverseHorizontalPlane = reverse;
00887 layoutDiagrams();
00888 emit propertiesChanged();
00889 }
00890
00891 bool CartesianCoordinatePlane::isHorizontalRangeReversed() const
00892 {
00893 return d->reverseHorizontalPlane;
00894 }
00895
00896 void CartesianCoordinatePlane::setVerticalRangeReversed( bool reverse )
00897 {
00898 if( d->reverseVerticalPlane == reverse )
00899 return;
00900
00901 d->reverseVerticalPlane = reverse;
00902 layoutDiagrams();
00903 emit propertiesChanged();
00904 }
00905
00906 bool CartesianCoordinatePlane::isVerticalRangeReversed() const
00907 {
00908 return d->reverseVerticalPlane;
00909 }
00910
00911 QRectF CartesianCoordinatePlane::visibleDataRange() const
00912 {
00913 QRectF result;
00914
00915 const QRectF drawArea = drawingArea();
00916
00917 result.setTopLeft( translateBack( drawArea.topLeft() ) );
00918 result.setBottomRight( translateBack( drawArea.bottomRight() ) );
00919
00920 return result;
00921 }
00922
00923 void CartesianCoordinatePlane::setGeometry( const QRect& rectangle )
00924 {
00925 if( rectangle == geometry() )
00926 return;
00927
00928 AbstractCoordinatePlane::setGeometry( rectangle );
00929 Q_FOREACH( AbstractDiagram* diagram, diagrams() ) {
00930 diagram->resize( drawingArea().size() );
00931 }
00932 }