KD Chart 2  [rev.2.5]
KDChartAbstractCoordinatePlane.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (C) 2001-2012 Klaralvdalens Datakonsult AB.  All rights reserved.
00003 **
00004 ** This file is part of the KD Chart library.
00005 **
00006 ** Licensees holding valid commercial KD Chart licenses may use this file in
00007 ** accordance with the KD Chart Commercial License Agreement provided with
00008 ** the Software.
00009 **
00010 **
00011 ** This file may be distributed and/or modified under the terms of the
00012 ** GNU General Public License version 2 and version 3 as published by the
00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
00014 **
00015 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00016 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00017 **
00018 ** Contact info@kdab.com if any conditions of this licensing are not
00019 ** clear to you.
00020 **
00021 **********************************************************************/
00022 
00023 #include "KDChartAbstractCoordinatePlane.h"
00024 #include "KDChartAbstractCoordinatePlane_p.h"
00025 
00026 #include "KDChartChart.h"
00027 #include "KDChartGridAttributes.h"
00028 
00029 #include <KDABLibFakes>
00030 
00031 #include <QGridLayout>
00032 #include <QRubberBand>
00033 #include <QMouseEvent>
00034 #include <QtCore/qmath.h>
00035 
00036 using namespace KDChart;
00037 
00038 #define d d_func()
00039 
00040 AbstractCoordinatePlane::Private::Private()
00041     : AbstractArea::Private()
00042     , parent( 0 )
00043     , grid( 0 )
00044     , referenceCoordinatePlane( 0 )
00045     , enableCornerSpacers( true )
00046     , enableRubberBandZooming( false )
00047     , rubberBand( 0 )
00048 {
00049     // this bloc left empty intentionally
00050 }
00051 
00052 
00053 AbstractCoordinatePlane::AbstractCoordinatePlane ( KDChart::Chart* parent )
00054     : AbstractArea ( new Private() )
00055 {
00056     d->parent = parent;
00057     d->init();
00058 }
00059 
00060 AbstractCoordinatePlane::~AbstractCoordinatePlane()
00061 {
00062     emit destroyedCoordinatePlane( this );
00063 }
00064 
00065 void AbstractCoordinatePlane::init()
00066 {
00067     d->initialize();  // virtual method to init the correct grid: cartesian, polar, ...
00068     connect( this, SIGNAL(internal_geometryChanged( QRect, QRect )),
00069              this, SIGNAL(geometryChanged( QRect, QRect )),
00070              Qt::QueuedConnection );
00071 }
00072 
00073 void AbstractCoordinatePlane::addDiagram ( AbstractDiagram* diagram )
00074 {
00075     // diagrams are invisible and paint through their paint() method
00076     diagram->hide();
00077 
00078     d->diagrams.append( diagram );
00079     diagram->setParent( d->parent );
00080     diagram->setCoordinatePlane( this );
00081     layoutDiagrams();
00082     layoutPlanes(); // there might be new axes, etc
00083     connect( diagram, SIGNAL( modelsChanged() ), this, SLOT( layoutPlanes() ) );
00084     connect( diagram, SIGNAL( modelDataChanged() ), this, SLOT( update()) );
00085     connect( diagram, SIGNAL( modelDataChanged() ), this, SLOT( relayout()) );
00086     connect( this, SIGNAL( boundariesChanged() ), diagram, SIGNAL( boundariesChanged() ) );
00087 
00088     update();
00089     emit boundariesChanged();
00090 }
00091 
00092 /*virtual*/
00093 void AbstractCoordinatePlane::replaceDiagram ( AbstractDiagram* diagram, AbstractDiagram* oldDiagram_ )
00094 {
00095     if( diagram && oldDiagram_ != diagram ){
00096         AbstractDiagram* oldDiagram = oldDiagram_;
00097         if( d->diagrams.count() ){
00098             if( ! oldDiagram ){
00099                 oldDiagram = d->diagrams.first();
00100                 if( oldDiagram == diagram )
00101                     return;
00102             }
00103             takeDiagram( oldDiagram );
00104         }
00105         delete oldDiagram;
00106         addDiagram( diagram );
00107         layoutDiagrams();
00108         layoutPlanes(); // there might be new axes, etc
00109         update();
00110     }
00111 }
00112 
00113 /*virtual*/
00114 void AbstractCoordinatePlane::takeDiagram ( AbstractDiagram* diagram )
00115 {
00116     const int idx = d->diagrams.indexOf( diagram );
00117     if( idx != -1 ){
00118         d->diagrams.removeAt( idx );
00119         diagram->setParent( 0 );
00120         diagram->setCoordinatePlane( 0 );
00121         disconnect( diagram, SIGNAL( modelsChanged() ), this, SLOT( layoutPlanes() ) );
00122         disconnect( diagram, SIGNAL( modelDataChanged() ), this, SLOT( update()) );
00123         disconnect( diagram, SIGNAL( modelDataChanged() ), this, SLOT( relayout()) );
00124         layoutDiagrams();
00125         update();
00126     }
00127 }
00128 
00129 
00130 AbstractDiagram* AbstractCoordinatePlane::diagram()
00131 {
00132     if ( d->diagrams.isEmpty() )
00133     {
00134         return 0;
00135     } else {
00136         return d->diagrams.first();
00137     }
00138 }
00139 
00140 AbstractDiagramList AbstractCoordinatePlane::diagrams()
00141 {
00142     return d->diagrams;
00143 }
00144 
00145 ConstAbstractDiagramList AbstractCoordinatePlane::diagrams() const
00146 {
00147     ConstAbstractDiagramList list;
00148 #ifndef QT_NO_STL
00149     qCopy( d->diagrams.begin(), d->diagrams.end(), std::back_inserter( list ) );
00150 #else
00151     Q_FOREACH( AbstractDiagram * a, d->diagrams )
00152         list.push_back( a );
00153 #endif
00154     return list;
00155 }
00156 
00157 void KDChart::AbstractCoordinatePlane::setGlobalGridAttributes( const GridAttributes& a )
00158 {
00159     d->gridAttributes = a;
00160     update();
00161 }
00162 
00163 GridAttributes KDChart::AbstractCoordinatePlane::globalGridAttributes() const
00164 {
00165     return d->gridAttributes;
00166 }
00167 
00168 KDChart::DataDimensionsList KDChart::AbstractCoordinatePlane::gridDimensionsList()
00169 {
00170     return d->grid->updateData( this );
00171 }
00172 
00173 void KDChart::AbstractCoordinatePlane::setGridNeedsRecalculate()
00174 {
00175     d->grid->setNeedRecalculate();
00176 }
00177 
00178 void KDChart::AbstractCoordinatePlane::setReferenceCoordinatePlane( AbstractCoordinatePlane * plane )
00179 {
00180     d->referenceCoordinatePlane = plane;
00181 }
00182 
00183 AbstractCoordinatePlane * KDChart::AbstractCoordinatePlane::referenceCoordinatePlane( ) const
00184 {
00185     return d->referenceCoordinatePlane;
00186 }
00187 
00188 void KDChart::AbstractCoordinatePlane::setParent( KDChart::Chart* parent )
00189 {
00190     d->parent = parent;
00191 }
00192 
00193 const KDChart::Chart* KDChart::AbstractCoordinatePlane::parent() const
00194 {
00195     return d->parent;
00196 }
00197 
00198 KDChart::Chart* KDChart::AbstractCoordinatePlane::parent()
00199 {
00200     return d->parent;
00201 }
00202 
00203 /* pure virtual in QLayoutItem */
00204 bool KDChart::AbstractCoordinatePlane::isEmpty() const
00205 {
00206     return false; // never empty!
00207     // coordinate planes with no associated diagrams
00208     // are showing a default grid of ()1..10, 1..10) stepWidth 1
00209 }
00210 /* pure virtual in QLayoutItem */
00211 Qt::Orientations KDChart::AbstractCoordinatePlane::expandingDirections() const
00212 {
00213     return Qt::Vertical | Qt::Horizontal;
00214 }
00215 /* pure virtual in QLayoutItem */
00216 QSize KDChart::AbstractCoordinatePlane::maximumSize() const
00217 {
00218     // No maximum size set. Especially not parent()->size(), we are not layouting
00219     // to the parent widget's size when using Chart::paint()!
00220     return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
00221 }
00222 /* pure virtual in QLayoutItem */
00223 QSize KDChart::AbstractCoordinatePlane::minimumSize() const
00224 {
00225     return QSize(60, 60); // this default can be overwritten by derived classes
00226 }
00227 /* pure virtual in QLayoutItem */
00228 QSize KDChart::AbstractCoordinatePlane::sizeHint() const
00229 {
00230     // we return our maxiumu (which is the full size of the Chart)
00231     // even if we know the plane will be smaller
00232     return maximumSize();
00233 }
00234 /* pure virtual in QLayoutItem */
00235 void KDChart::AbstractCoordinatePlane::setGeometry( const QRect& r )
00236 {
00237     if ( d->geometry != r ) {
00238         // inform the outside word by Signal geometryChanged()
00239         // via a queued connection to internal_geometryChanged()
00240         emit internal_geometryChanged( d->geometry, r );
00241 
00242         d->geometry = r;
00243         // Note: We do *not* call update() here
00244         //       because it would invoke KDChart::update() recursively.
00245     }
00246 }
00247 /* pure virtual in QLayoutItem */
00248 QRect KDChart::AbstractCoordinatePlane::geometry() const
00249 {
00250     return d->geometry;
00251 }
00252 
00253 void KDChart::AbstractCoordinatePlane::update()
00254 {
00255     //qDebug("KDChart::AbstractCoordinatePlane::update() called");
00256     emit needUpdate();
00257 }
00258 
00259 void KDChart::AbstractCoordinatePlane::relayout()
00260 {
00261     //qDebug("KDChart::AbstractCoordinatePlane::relayout() called");
00262     emit needRelayout();
00263 }
00264 
00265 void KDChart::AbstractCoordinatePlane::layoutPlanes()
00266 {
00267     //qDebug("KDChart::AbstractCoordinatePlane::relayout() called");
00268     emit needLayoutPlanes();
00269 }
00270 
00271 void KDChart::AbstractCoordinatePlane::setRubberBandZoomingEnabled( bool enable )
00272 {
00273     d->enableRubberBandZooming = enable;
00274 
00275     if( !enable && d->rubberBand != 0 )
00276     {
00277         delete d->rubberBand;
00278         d->rubberBand = 0;
00279     }
00280 }
00281 
00282 bool KDChart::AbstractCoordinatePlane::isRubberBandZoomingEnabled() const
00283 {
00284     return d->enableRubberBandZooming;
00285 }
00286 
00287 void KDChart::AbstractCoordinatePlane::setCornerSpacersEnabled( bool enable )
00288 {
00289     if ( d->enableCornerSpacers == enable ) return;
00290 
00291     d->enableCornerSpacers = enable;
00292     emit needRelayout();
00293 }
00294 
00295 bool KDChart::AbstractCoordinatePlane::isCornerSpacersEnabled() const
00296 {
00297     return d->enableCornerSpacers;
00298 }
00299 
00300 void KDChart::AbstractCoordinatePlane::mousePressEvent( QMouseEvent* event )
00301 {
00302     if( event->button() == Qt::LeftButton )
00303     {
00304         if( d->enableRubberBandZooming && d->rubberBand == 0 )
00305             d->rubberBand = new QRubberBand( QRubberBand::Rectangle, qobject_cast< QWidget* >( parent() ) );
00306 
00307         if( d->rubberBand != 0 )
00308         {
00309             d->rubberBandOrigin = event->pos();
00310             d->rubberBand->setGeometry( QRect( event->pos(), QSize() ) );
00311             d->rubberBand->show();
00312 
00313             event->accept();
00314         }
00315     }
00316     else if( event->button() == Qt::RightButton )
00317     {
00318         if( d->enableRubberBandZooming && !d->rubberBandZoomConfigHistory.isEmpty() )
00319         {
00320             // restore the last config from the stack
00321             ZoomParameters config = d->rubberBandZoomConfigHistory.pop();
00322             setZoomFactorX( config.xFactor );
00323             setZoomFactorY( config.yFactor );
00324             setZoomCenter( config.center() );
00325 
00326             QWidget* const p = qobject_cast< QWidget* >( parent() );
00327             if( p != 0 )
00328                 p->update();
00329 
00330             event->accept();
00331         }
00332     }
00333 
00334     KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
00335     {
00336         a->mousePressEvent( event );
00337     }
00338 }
00339 
00340 void KDChart::AbstractCoordinatePlane::mouseDoubleClickEvent( QMouseEvent* event )
00341 {
00342     if( event->button() == Qt::RightButton )
00343     {
00344         // othewise the second click gets lost
00345         // which is pretty annoying when zooming out fast
00346         mousePressEvent( event );
00347     }
00348     KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
00349     {
00350         a->mouseDoubleClickEvent( event );
00351     }
00352 }
00353 
00354 void KDChart::AbstractCoordinatePlane::mouseReleaseEvent( QMouseEvent* event )
00355 {
00356     if( d->rubberBand != 0 )
00357     {
00358         // save the old config on the stack
00359         d->rubberBandZoomConfigHistory.push( ZoomParameters( zoomFactorX(), zoomFactorY(), zoomCenter() ) );
00360 
00361         // this is the height/width of the rubber band in pixel space
00362         const qreal rubberWidth = static_cast< qreal >( d->rubberBand->width() );
00363         const qreal rubberHeight = static_cast< qreal >( d->rubberBand->height() );
00364 
00365         if( rubberWidth > 0.0 && rubberHeight > 0.0 )
00366         {
00367             // this is the center of the rubber band in pixel space
00368             const qreal centerX = qFloor( d->rubberBand->geometry().width() / 2.0 + d->rubberBand->geometry().x() );
00369             const qreal centerY = qCeil( d->rubberBand->geometry().height() / 2.0 + d->rubberBand->geometry().y() );
00370 
00371             const qreal rubberCenterX = static_cast< qreal >( centerX - geometry().x() );
00372             const qreal rubberCenterY = static_cast< qreal >( centerY - geometry().y() );
00373 
00374             // this is the height/width of the plane in pixel space
00375             const qreal myWidth = static_cast< qreal >( geometry().width() );
00376             const qreal myHeight = static_cast< qreal >( geometry().height() );
00377 
00378             // this describes the new center of zooming, relative to the plane pixel space
00379             const qreal newCenterX = rubberCenterX / myWidth / zoomFactorX() + zoomCenter().x() - 0.5 / zoomFactorX();
00380             const qreal newCenterY = rubberCenterY / myHeight / zoomFactorY() + zoomCenter().y() - 0.5 / zoomFactorY();
00381 
00382             // this will be the new zoom factor
00383             const qreal newZoomFactorX = zoomFactorX() * myWidth / rubberWidth;
00384             const qreal newZoomFactorY = zoomFactorY() * myHeight / rubberHeight;
00385 
00386             // and this the new center
00387             const QPointF newZoomCenter( newCenterX, newCenterY );
00388 
00389             setZoomFactorX( newZoomFactorX );
00390             setZoomFactorY( newZoomFactorY );
00391             setZoomCenter( newZoomCenter );
00392         }
00393 
00394         d->rubberBand->parentWidget()->update();
00395         delete d->rubberBand;
00396         d->rubberBand = 0;
00397 
00398         event->accept();
00399     }
00400 
00401     KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
00402     {
00403         a->mouseReleaseEvent( event );
00404     }
00405 }
00406 
00407 void KDChart::AbstractCoordinatePlane::mouseMoveEvent( QMouseEvent* event )
00408 {
00409     if( d->rubberBand != 0 )
00410     {
00411         const QRect normalized = QRect( d->rubberBandOrigin, event->pos() ).normalized();
00412         d->rubberBand->setGeometry( normalized &  geometry() );
00413 
00414         event->accept();
00415     }
00416 
00417     KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
00418     {
00419         a->mouseMoveEvent( event );
00420     }
00421 }
00422 
00423 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE)
00424 const
00425 #endif
00426 bool KDChart::AbstractCoordinatePlane::isVisiblePoint( const QPointF& point ) const
00427 {
00428     return d->isVisiblePoint( this, point );
00429 }
00430 
00431 AbstractCoordinatePlane* KDChart::AbstractCoordinatePlane::sharedAxisMasterPlane( QPainter* p )
00432 {
00433     Q_UNUSED( p );
00434     return this;
00435 }
00436 
00437 #if !defined(QT_NO_DEBUG_STREAM)
00438 #include "KDChartEnums.h"
00439 
00440 QDebug KDChart::operator<<( QDebug stream, const DataDimension& r )
00441 {
00442     stream << "DataDimension("
00443            << " start=" << r.start
00444            << " end=" << r.end
00445            << " sequence=" << KDChartEnums::granularitySequenceToString( r.sequence )
00446            << " isCalculated=" << r.isCalculated
00447            << " calcMode=" << ( r.calcMode == AbstractCoordinatePlane::Logarithmic ? "Logarithmic" : "Linear" )
00448            << " stepWidth=" << r.stepWidth
00449            << " subStepWidth=" << r.subStepWidth
00450            << " )";
00451     return stream;
00452 }
00453 #endif
00454 
00455 #undef d
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/