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

Generated on Mon Sep 17 16:16:49 2007 for KD Chart 2 by  doxygen 1.5.1