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