1
/****************************************************************************
2
** Copyright (C) 2007 Klaralvdalens Datakonsult AB. All rights reserved.
4
** This file is part of the KD Chart library.
6
** This file may be used under the terms of the GNU General Public
7
** License versions 2.0 or 3.0 as published by the Free Software
8
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
9
** included in the packaging of this file. Alternatively you may (at
10
** your option) use any later version of the GNU General Public
11
** License if such license has been publicly approved by
12
** Klarälvdalens Datakonsult AB (or its successors, if any).
14
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
15
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
16
** A PARTICULAR PURPOSE. Klarälvdalens Datakonsult AB reserves all rights
17
** not expressly granted herein.
19
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22
**********************************************************************/
24
#include "KDChartAbstractCoordinatePlane.h"
25
#include "KDChartAbstractCoordinatePlane_p.h"
27
#include <QGridLayout>
28
#include <QRubberBand>
29
#include <QMouseEvent>
31
#include "KDChartChart.h"
32
#include "KDChartGridAttributes.h"
34
#include <KDABLibFakes>
37
using namespace KDChart;
41
AbstractCoordinatePlane::Private::Private()
42
: AbstractArea::Private()
45
, referenceCoordinatePlane( 0 )
46
, enableRubberBandZooming( false )
49
// this bloc left empty intentionally
53
AbstractCoordinatePlane::AbstractCoordinatePlane ( KDChart::Chart* parent )
54
: AbstractArea ( new Private() )
60
AbstractCoordinatePlane::~AbstractCoordinatePlane()
62
emit destroyedCoordinatePlane( this );
65
void AbstractCoordinatePlane::init()
67
d->initialize(); // virtual method to init the correct grid: cartesian, polar, ...
68
connect( this, SIGNAL(internal_geometryChanged( QRect, QRect )),
69
this, SIGNAL(geometryChanged( QRect, QRect )),
70
Qt::QueuedConnection );
73
void AbstractCoordinatePlane::addDiagram ( AbstractDiagram* diagram )
75
// diagrams are invisible and paint through their paint() method
78
d->diagrams.append( diagram );
79
diagram->setParent( d->parent );
80
diagram->setCoordinatePlane( this );
82
layoutPlanes(); // there might be new axes, etc
83
connect( diagram, SIGNAL( modelsChanged() ), this, SLOT( layoutPlanes() ) );
88
void AbstractCoordinatePlane::replaceDiagram ( AbstractDiagram* diagram, AbstractDiagram* oldDiagram_ )
90
if( diagram && oldDiagram_ != diagram ){
91
AbstractDiagram* oldDiagram = oldDiagram_;
92
if( d->diagrams.count() ){
94
oldDiagram = d->diagrams.first();
95
if( oldDiagram == diagram )
98
takeDiagram( oldDiagram );
101
addDiagram( diagram );
103
layoutPlanes(); // there might be new axes, etc
109
void AbstractCoordinatePlane::takeDiagram ( AbstractDiagram* diagram )
111
const int idx = d->diagrams.indexOf( diagram );
113
d->diagrams.removeAt( idx );
114
diagram->setParent( 0 );
115
diagram->setCoordinatePlane( 0 );
116
disconnect( diagram, SIGNAL( modelsChanged() ), this, SLOT( layoutPlanes() ) );
123
AbstractDiagram* AbstractCoordinatePlane::diagram()
125
if ( d->diagrams.isEmpty() )
129
return d->diagrams.first();
133
AbstractDiagramList AbstractCoordinatePlane::diagrams()
138
ConstAbstractDiagramList AbstractCoordinatePlane::diagrams() const
140
ConstAbstractDiagramList list;
142
qCopy( d->diagrams.begin(), d->diagrams.end(), std::back_inserter( list ) );
144
Q_FOREACH( AbstractDiagram * a, d->diagrams )
150
QSize KDChart::AbstractCoordinatePlane::minimumSizeHint() const
152
return QSize( 200, 200 );
156
QSizePolicy KDChart::AbstractCoordinatePlane::sizePolicy() const
158
return QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
161
void KDChart::AbstractCoordinatePlane::setGlobalGridAttributes( const GridAttributes& a )
163
d->gridAttributes = a;
167
GridAttributes KDChart::AbstractCoordinatePlane::globalGridAttributes() const
169
return d->gridAttributes;
172
KDChart::DataDimensionsList KDChart::AbstractCoordinatePlane::gridDimensionsList()
174
//KDChart::DataDimensionsList l( d->grid->updateData( this ) );
175
//qDebug() << "AbstractCoordinatePlane::gridDimensionsList() Y-range:" << l.last().end - l.last().start << " step width:" << l.last().stepWidth;
176
//qDebug() << "AbstractCoordinatePlane::gridDimensionsList() X-range:" << l.first().end - l.first().start << " step width:" << l.first().stepWidth;
177
return d->grid->updateData( this );
180
void KDChart::AbstractCoordinatePlane::setGridNeedsRecalculate()
182
d->grid->setNeedRecalculate();
185
void KDChart::AbstractCoordinatePlane::setReferenceCoordinatePlane( AbstractCoordinatePlane * plane )
187
d->referenceCoordinatePlane = plane;
190
AbstractCoordinatePlane * KDChart::AbstractCoordinatePlane::referenceCoordinatePlane( ) const
192
return d->referenceCoordinatePlane;
195
void KDChart::AbstractCoordinatePlane::setParent( KDChart::Chart* parent )
200
const KDChart::Chart* KDChart::AbstractCoordinatePlane::parent() const
205
KDChart::Chart* KDChart::AbstractCoordinatePlane::parent()
210
/* pure virtual in QLayoutItem */
211
bool KDChart::AbstractCoordinatePlane::isEmpty() const
213
return false; // never empty!
214
// coordinate planes with no associated diagrams
215
// are showing a default grid of ()1..10, 1..10) stepWidth 1
217
/* pure virtual in QLayoutItem */
218
Qt::Orientations KDChart::AbstractCoordinatePlane::expandingDirections() const
220
return Qt::Vertical | Qt::Horizontal;
222
/* pure virtual in QLayoutItem */
223
QSize KDChart::AbstractCoordinatePlane::maximumSize() const
225
// No maximum size set. Especially not parent()->size(), we are not layouting
226
// to the parent widget's size when using Chart::paint()!
227
return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
229
/* pure virtual in QLayoutItem */
230
QSize KDChart::AbstractCoordinatePlane::minimumSize() const
232
return QSize(60, 60); // this default can be overwritten by derived classes
234
/* pure virtual in QLayoutItem */
235
QSize KDChart::AbstractCoordinatePlane::sizeHint() const
237
// we return our maxiumu (which is the full size of the Chart)
238
// even if we know the plane will be smaller
239
return maximumSize();
241
/* pure virtual in QLayoutItem */
242
void KDChart::AbstractCoordinatePlane::setGeometry( const QRect& r )
244
// qDebug() << "KDChart::AbstractCoordinatePlane::setGeometry(" << r << ") called";
245
if( d->geometry != r ){
246
//qDebug() << "entering KDChart::AbstractCoordinatePlane::setGeometry(" << r << ")";
247
// inform the outside word by Signal geometryChanged()
248
// via a queued connection to internal_geometryChanged()
249
emit internal_geometryChanged( d->geometry, r );
252
// Note: We do *not* call update() here
253
// because it would invoke KDChart::update() recursively.
254
//qDebug() << "leaving KDChart::AbstractCoordinatePlane::setGeometry(" << r << ")";
257
/* pure virtual in QLayoutItem */
258
QRect KDChart::AbstractCoordinatePlane::geometry() const
263
void KDChart::AbstractCoordinatePlane::update()
265
//qDebug("KDChart::AbstractCoordinatePlane::update() called");
269
void KDChart::AbstractCoordinatePlane::relayout()
271
//qDebug("KDChart::AbstractCoordinatePlane::relayout() called");
275
void KDChart::AbstractCoordinatePlane::layoutPlanes()
277
//qDebug("KDChart::AbstractCoordinatePlane::relayout() called");
278
emit needLayoutPlanes();
281
void KDChart::AbstractCoordinatePlane::setRubberBandZoomingEnabled( bool enable )
283
d->enableRubberBandZooming = enable;
285
if( !enable && d->rubberBand != 0 )
287
delete d->rubberBand;
292
bool KDChart::AbstractCoordinatePlane::isRubberBandZoomingEnabled() const
294
return d->enableRubberBandZooming;
297
void KDChart::AbstractCoordinatePlane::mousePressEvent( QMouseEvent* event )
299
if( event->button() == Qt::LeftButton )
301
if( d->enableRubberBandZooming && d->rubberBand == 0 )
302
d->rubberBand = new QRubberBand( QRubberBand::Rectangle, qobject_cast< QWidget* >( parent() ) );
304
if( d->rubberBand != 0 )
306
d->rubberBandOrigin = event->pos();
307
d->rubberBand->setGeometry( QRect( event->pos(), QSize() ) );
308
d->rubberBand->show();
313
else if( event->button() == Qt::RightButton )
315
if( d->enableRubberBandZooming && !d->rubberBandZoomConfigHistory.isEmpty() )
317
// restore the last config from the stack
318
ZoomParameters config = d->rubberBandZoomConfigHistory.pop();
319
setZoomFactorX( config.xFactor );
320
setZoomFactorY( config.yFactor );
321
setZoomCenter( config.center() );
323
QWidget* const p = qobject_cast< QWidget* >( parent() );
331
KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
333
a->mousePressEvent( event );
337
void KDChart::AbstractCoordinatePlane::mouseDoubleClickEvent( QMouseEvent* event )
339
if( event->button() == Qt::RightButton )
341
// othewise the second click gets lost
342
// which is pretty annoying when zooming out fast
343
mousePressEvent( event );
345
KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
347
a->mouseDoubleClickEvent( event );
351
void KDChart::AbstractCoordinatePlane::mouseReleaseEvent( QMouseEvent* event )
353
if( d->rubberBand != 0 )
355
// save the old config on the stack
356
d->rubberBandZoomConfigHistory.push( ZoomParameters( zoomFactorX(), zoomFactorY(), zoomCenter() ) );
358
// this is the height/width of the rubber band in pixel space
359
const double rubberWidth = static_cast< double >( d->rubberBand->width() );
360
const double rubberHeight = static_cast< double >( d->rubberBand->height() );
362
if( rubberWidth > 0.0 && rubberHeight > 0.0 )
364
// this is the center of the rubber band in pixel space
365
const double rubberCenterX = static_cast< double >( d->rubberBand->geometry().center().x() - geometry().x() );
366
const double rubberCenterY = static_cast< double >( d->rubberBand->geometry().center().y() - geometry().y() );
368
// this is the height/width of the plane in pixel space
369
const double myWidth = static_cast< double >( geometry().width() );
370
const double myHeight = static_cast< double >( geometry().height() );
372
// this describes the new center of zooming, relative to the plane pixel space
373
const double newCenterX = rubberCenterX / myWidth / zoomFactorX() + zoomCenter().x() - 0.5 / zoomFactorX();
374
const double newCenterY = rubberCenterY / myHeight / zoomFactorY() + zoomCenter().y() - 0.5 / zoomFactorY();
376
// this will be the new zoom factor
377
const double newZoomFactorX = zoomFactorX() * myWidth / rubberWidth;
378
const double newZoomFactorY = zoomFactorY() * myHeight / rubberHeight;
380
// and this the new center
381
const QPointF newZoomCenter( newCenterX, newCenterY );
383
setZoomFactorX( newZoomFactorX );
384
setZoomFactorY( newZoomFactorY );
385
setZoomCenter( newZoomCenter );
388
d->rubberBand->parentWidget()->update();
389
delete d->rubberBand;
395
KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
397
a->mouseReleaseEvent( event );
401
void KDChart::AbstractCoordinatePlane::mouseMoveEvent( QMouseEvent* event )
403
if( d->rubberBand != 0 )
405
const QRect normalized = QRect( d->rubberBandOrigin, event->pos() ).normalized();
406
d->rubberBand->setGeometry( normalized & geometry() );
411
KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
413
a->mouseMoveEvent( event );
417
#if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE)
420
bool KDChart::AbstractCoordinatePlane::isVisiblePoint( const QPointF& point ) const
422
return d->isVisiblePoint( this, point );
425
AbstractCoordinatePlane* KDChart::AbstractCoordinatePlane::sharedAxisMasterPlane( QPainter* p )
431
#if !defined(QT_NO_DEBUG_STREAM)
432
#include "KDChartEnums.h"
434
QDebug KDChart::operator<<( QDebug stream, const DataDimension& r )
436
stream << "DataDimension("
437
<< " start=" << r.start
439
<< " sequence=" << KDChartEnums::granularitySequenceToString( r.sequence )
440
<< " isCalculated=" << r.isCalculated
441
<< " calcMode=" << ( r.calcMode == AbstractCoordinatePlane::Logarithmic ? "Logarithmic" : "Linear" )
442
<< " stepWidth=" << r.stepWidth
443
<< " subStepWidth=" << r.subStepWidth