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