KD Chart 2 [rev.2.4]

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 <QGridLayout>
00027 #include <QRubberBand>
00028 #include <QMouseEvent>
00029 #include <QtCore/qmath.h>
00030 
00031 #include "KDChartChart.h"
00032 #include "KDChartGridAttributes.h"
00033 
00034 #include <KDABLibFakes>
00035 
00036 
00037 using namespace KDChart;
00038 
00039 #define d d_func()
00040 
00041 AbstractCoordinatePlane::Private::Private()
00042     : AbstractArea::Private()
00043     , parent( 0 )
00044     , grid( 0 )
00045     , referenceCoordinatePlane( 0 )
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 
00087     update();
00088 }
00089 
00090 /*virtual*/
00091 void AbstractCoordinatePlane::replaceDiagram ( AbstractDiagram* diagram, AbstractDiagram* oldDiagram_ )
00092 {
00093     if( diagram && oldDiagram_ != diagram ){
00094         AbstractDiagram* oldDiagram = oldDiagram_;
00095         if( d->diagrams.count() ){
00096             if( ! oldDiagram ){
00097                 oldDiagram = d->diagrams.first();
00098                 if( oldDiagram == diagram )
00099                     return;
00100             }
00101             takeDiagram( oldDiagram );
00102         }
00103         delete oldDiagram;
00104         addDiagram( diagram );
00105         layoutDiagrams();
00106         layoutPlanes(); // there might be new axes, etc
00107         update();
00108     }
00109 }
00110 
00111 /*virtual*/
00112 void AbstractCoordinatePlane::takeDiagram ( AbstractDiagram* diagram )
00113 {
00114     const int idx = d->diagrams.indexOf( diagram );
00115     if( idx != -1 ){
00116         d->diagrams.removeAt( idx );
00117         diagram->setParent( 0 );
00118         diagram->setCoordinatePlane( 0 );
00119         disconnect( diagram, SIGNAL( modelsChanged() ), this, SLOT( layoutPlanes() ) );
00120         disconnect( diagram, SIGNAL( modelDataChanged() ), this, SLOT( update()) );
00121         disconnect( diagram, SIGNAL( modelDataChanged() ), this, SLOT( relayout()) );
00122         layoutDiagrams();
00123         update();
00124     }
00125 }
00126 
00127 
00128 AbstractDiagram* AbstractCoordinatePlane::diagram()
00129 {
00130     if ( d->diagrams.isEmpty() )
00131     {
00132         return 0;
00133     } else {
00134         return d->diagrams.first();
00135     }
00136 }
00137 
00138 AbstractDiagramList AbstractCoordinatePlane::diagrams()
00139 {
00140     return d->diagrams;
00141 }
00142 
00143 ConstAbstractDiagramList AbstractCoordinatePlane::diagrams() const
00144 {
00145     ConstAbstractDiagramList list;
00146 #ifndef QT_NO_STL
00147     qCopy( d->diagrams.begin(), d->diagrams.end(), std::back_inserter( list ) );
00148 #else
00149     Q_FOREACH( AbstractDiagram * a, d->diagrams )
00150         list.push_back( a );
00151 #endif
00152     return list;
00153 }
00154 
00155 QSize KDChart::AbstractCoordinatePlane::minimumSizeHint() const
00156 {
00157     return QSize( 200, 200 );
00158 }
00159 
00160 
00161 QSizePolicy KDChart::AbstractCoordinatePlane::sizePolicy() const
00162 {
00163     return QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
00164 }
00165 
00166 void KDChart::AbstractCoordinatePlane::setGlobalGridAttributes( const GridAttributes& a )
00167 {
00168     d->gridAttributes = a;
00169     update();
00170 }
00171 
00172 GridAttributes KDChart::AbstractCoordinatePlane::globalGridAttributes() const
00173 {
00174     return d->gridAttributes;
00175 }
00176 
00177 KDChart::DataDimensionsList KDChart::AbstractCoordinatePlane::gridDimensionsList()
00178 {
00179     //KDChart::DataDimensionsList l( d->grid->updateData( this ) );
00180     //qDebug() << "AbstractCoordinatePlane::gridDimensionsList() Y-range:" << l.last().end - l.last().start << "   step width:" << l.last().stepWidth;
00181     //qDebug() << "AbstractCoordinatePlane::gridDimensionsList() X-range:" << l.first().end - l.first().start << "   step width:" << l.first().stepWidth;
00182     return d->grid->updateData( this );
00183 }
00184 
00185 void KDChart::AbstractCoordinatePlane::setGridNeedsRecalculate()
00186 {
00187     d->grid->setNeedRecalculate();
00188 }
00189 
00190 void KDChart::AbstractCoordinatePlane::setReferenceCoordinatePlane( AbstractCoordinatePlane * plane )
00191 {
00192     d->referenceCoordinatePlane = plane;
00193 }
00194 
00195 AbstractCoordinatePlane * KDChart::AbstractCoordinatePlane::referenceCoordinatePlane( ) const
00196 {
00197     return d->referenceCoordinatePlane;
00198 }
00199 
00200 void KDChart::AbstractCoordinatePlane::setParent( KDChart::Chart* parent )
00201 {
00202     d->parent = parent;
00203 }
00204 
00205 const KDChart::Chart* KDChart::AbstractCoordinatePlane::parent() const
00206 {
00207     return d->parent;
00208 }
00209 
00210 KDChart::Chart* KDChart::AbstractCoordinatePlane::parent()
00211 {
00212     return d->parent;
00213 }
00214 
00215 /* pure virtual in QLayoutItem */
00216 bool KDChart::AbstractCoordinatePlane::isEmpty() const
00217 {
00218     return false; // never empty!
00219     // coordinate planes with no associated diagrams
00220     // are showing a default grid of ()1..10, 1..10) stepWidth 1
00221 }
00222 /* pure virtual in QLayoutItem */
00223 Qt::Orientations KDChart::AbstractCoordinatePlane::expandingDirections() const
00224 {
00225     return Qt::Vertical | Qt::Horizontal;
00226 }
00227 /* pure virtual in QLayoutItem */
00228 QSize KDChart::AbstractCoordinatePlane::maximumSize() const
00229 {
00230     // No maximum size set. Especially not parent()->size(), we are not layouting
00231     // to the parent widget's size when using Chart::paint()!
00232     return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
00233 }
00234 /* pure virtual in QLayoutItem */
00235 QSize KDChart::AbstractCoordinatePlane::minimumSize() const
00236 {
00237     return QSize(60, 60); // this default can be overwritten by derived classes
00238 }
00239 /* pure virtual in QLayoutItem */
00240 QSize KDChart::AbstractCoordinatePlane::sizeHint() const
00241 {
00242     // we return our maxiumu (which is the full size of the Chart)
00243     // even if we know the plane will be smaller
00244     return maximumSize();
00245 }
00246 /* pure virtual in QLayoutItem */
00247 void KDChart::AbstractCoordinatePlane::setGeometry( const QRect& r )
00248 {
00249 //    qDebug() << "KDChart::AbstractCoordinatePlane::setGeometry(" << r << ") called";
00250     if( d->geometry != r ){
00251         //qDebug() << "entering KDChart::AbstractCoordinatePlane::setGeometry(" << r << ")";
00252         // inform the outside word by Signal geometryChanged()
00253         // via a queued connection to internal_geometryChanged()
00254         emit internal_geometryChanged( d->geometry, r );
00255 
00256         d->geometry = r;
00257         // Note: We do *not* call update() here
00258         //       because it would invoke KDChart::update() recursively.
00259         //qDebug() << "leaving  KDChart::AbstractCoordinatePlane::setGeometry(" << r << ")";
00260     }
00261 }
00262 /* pure virtual in QLayoutItem */
00263 QRect KDChart::AbstractCoordinatePlane::geometry() const
00264 {
00265     return d->geometry;
00266 }
00267 
00268 void KDChart::AbstractCoordinatePlane::update()
00269 {
00270     //qDebug("KDChart::AbstractCoordinatePlane::update() called");
00271     emit needUpdate();
00272 }
00273 
00274 void KDChart::AbstractCoordinatePlane::relayout()
00275 {
00276     //qDebug("KDChart::AbstractCoordinatePlane::relayout() called");
00277     emit needRelayout();
00278 }
00279 
00280 void KDChart::AbstractCoordinatePlane::layoutPlanes()
00281 {
00282     //qDebug("KDChart::AbstractCoordinatePlane::relayout() called");
00283     emit needLayoutPlanes();
00284 }
00285 
00286 void KDChart::AbstractCoordinatePlane::setRubberBandZoomingEnabled( bool enable )
00287 {
00288     d->enableRubberBandZooming = enable;
00289 
00290     if( !enable && d->rubberBand != 0 )
00291     {
00292         delete d->rubberBand;
00293         d->rubberBand = 0;
00294     }
00295 }
00296 
00297 bool KDChart::AbstractCoordinatePlane::isRubberBandZoomingEnabled() const
00298 {
00299     return d->enableRubberBandZooming;
00300 }
00301 
00302 void KDChart::AbstractCoordinatePlane::mousePressEvent( QMouseEvent* event )
00303 {
00304     if( event->button() == Qt::LeftButton )
00305     {
00306         if( d->enableRubberBandZooming && d->rubberBand == 0 )
00307             d->rubberBand = new QRubberBand( QRubberBand::Rectangle, qobject_cast< QWidget* >( parent() ) );
00308 
00309         if( d->rubberBand != 0 )
00310         {
00311             d->rubberBandOrigin = event->pos();
00312             d->rubberBand->setGeometry( QRect( event->pos(), QSize() ) );
00313             d->rubberBand->show();
00314 
00315             event->accept();
00316         }
00317     }
00318     else if( event->button() == Qt::RightButton )
00319     {
00320         if( d->enableRubberBandZooming && !d->rubberBandZoomConfigHistory.isEmpty() )
00321         {
00322             // restore the last config from the stack
00323             ZoomParameters config = d->rubberBandZoomConfigHistory.pop();
00324             setZoomFactorX( config.xFactor );
00325             setZoomFactorY( config.yFactor );
00326             setZoomCenter( config.center() );
00327 
00328             QWidget* const p = qobject_cast< QWidget* >( parent() );
00329             if( p != 0 )
00330                 p->update();
00331 
00332             event->accept();
00333         }
00334     }
00335 
00336     KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
00337     {
00338         a->mousePressEvent( event );
00339     }
00340 }
00341 
00342 void KDChart::AbstractCoordinatePlane::mouseDoubleClickEvent( QMouseEvent* event )
00343 {
00344     if( event->button() == Qt::RightButton )
00345     {
00346         // othewise the second click gets lost
00347         // which is pretty annoying when zooming out fast
00348         mousePressEvent( event );
00349     }
00350     KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
00351     {
00352         a->mouseDoubleClickEvent( event );
00353     }
00354 }
00355 
00356 void KDChart::AbstractCoordinatePlane::mouseReleaseEvent( QMouseEvent* event )
00357 {
00358     if( d->rubberBand != 0 )
00359     {
00360         // save the old config on the stack
00361         d->rubberBandZoomConfigHistory.push( ZoomParameters( zoomFactorX(), zoomFactorY(), zoomCenter() ) );
00362 
00363         // this is the height/width of the rubber band in pixel space
00364         const double rubberWidth = static_cast< double >( d->rubberBand->width() );
00365         const double rubberHeight = static_cast< double >( d->rubberBand->height() );
00366 
00367         if( rubberWidth > 0.0 && rubberHeight > 0.0 )
00368         {
00369             // this is the center of the rubber band in pixel space
00370             const qreal centerX = qFloor( d->rubberBand->geometry().width() / 2.0 + d->rubberBand->geometry().x() );
00371             const qreal centerY = qCeil( d->rubberBand->geometry().height() / 2.0 + d->rubberBand->geometry().y() );
00372 
00373             const qreal rubberCenterX = static_cast< qreal >( centerX - geometry().x() );
00374             const qreal rubberCenterY = static_cast< qreal >( centerY - geometry().y() );
00375 
00376             // this is the height/width of the plane in pixel space
00377             const double myWidth = static_cast< double >( geometry().width() );
00378             const double myHeight = static_cast< double >( geometry().height() );
00379 
00380             // this describes the new center of zooming, relative to the plane pixel space
00381             const double newCenterX = rubberCenterX / zoomFactorX() / myWidth + zoomCenter().x() - 0.5 / zoomFactorX();
00382             const double newCenterY = rubberCenterY / zoomFactorY() / myHeight + zoomCenter().y() - 0.5 / zoomFactorY();
00383 
00384             // this will be the new zoom factor
00385             const double newZoomFactorX = zoomFactorX() * myWidth / rubberWidth;
00386             const double newZoomFactorY = zoomFactorY() * myHeight / rubberHeight;
00387 
00388             // and this the new center
00389             const QPointF newZoomCenter( newCenterX, newCenterY );
00390 
00391             setZoomFactorX( newZoomFactorX );
00392             setZoomFactorY( newZoomFactorY );
00393             setZoomCenter( newZoomCenter );
00394         }
00395 
00396         d->rubberBand->parentWidget()->update();
00397         delete d->rubberBand;
00398         d->rubberBand = 0;
00399 
00400         event->accept();
00401     }
00402 
00403     KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
00404     {
00405         a->mouseReleaseEvent( event );
00406     }
00407 }
00408 
00409 void KDChart::AbstractCoordinatePlane::mouseMoveEvent( QMouseEvent* event )
00410 {
00411     if( d->rubberBand != 0 )
00412     {
00413         const QRect normalized = QRect( d->rubberBandOrigin, event->pos() ).normalized();
00414         d->rubberBand->setGeometry( normalized &  geometry() );
00415 
00416         event->accept();
00417     }
00418 
00419     KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
00420     {
00421         a->mouseMoveEvent( event );
00422     }
00423 }
00424 
00425 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE)
00426 const
00427 #endif
00428 bool KDChart::AbstractCoordinatePlane::isVisiblePoint( const QPointF& point ) const
00429 {
00430     return d->isVisiblePoint( this, point );
00431 }
00432 
00433 AbstractCoordinatePlane* KDChart::AbstractCoordinatePlane::sharedAxisMasterPlane( QPainter* p )
00434 {
00435     Q_UNUSED( p );
00436     return this;
00437 }
00438 
00439 #if !defined(QT_NO_DEBUG_STREAM)
00440 #include "KDChartEnums.h"
00441 
00442 QDebug KDChart::operator<<( QDebug stream, const DataDimension& r )
00443 {
00444     stream << "DataDimension("
00445            << " start=" << r.start
00446            << " end=" << r.end
00447            << " sequence=" << KDChartEnums::granularitySequenceToString( r.sequence )
00448            << " isCalculated=" << r.isCalculated
00449            << " calcMode=" << ( r.calcMode == AbstractCoordinatePlane::Logarithmic ? "Logarithmic" : "Linear" )
00450            << " stepWidth=" << r.stepWidth
00451            << " subStepWidth=" << r.subStepWidth
00452            << " )";
00453     return stream;
00454 }
00455 #endif
00456 
00457 #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/