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