KDChartAbstractCoordinatePlane.cpp

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

Generated on Thu Mar 4 23:19:09 2010 for KD Chart 2 by  doxygen 1.5.4