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