KDChartAbstractCoordinatePlane.cpp

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