KChart

KChartAbstractCoordinatePlane.cpp
1 /*
2  * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #include "KChartAbstractCoordinatePlane.h"
10 #include "KChartAbstractCoordinatePlane_p.h"
11 
12 #include "KChartChart.h"
13 #include "KChartGridAttributes.h"
14 
15 #include <QGridLayout>
16 #include <QRubberBand>
17 #include <QMouseEvent>
18 #include <qmath.h>
19 
20 using namespace KChart;
21 
22 #define d d_func()
23 
24 AbstractCoordinatePlane::Private::Private()
25  : AbstractArea::Private()
26  , parent( nullptr )
27  , grid( nullptr )
28  , referenceCoordinatePlane( nullptr )
29  , enableCornerSpacers( true )
30  , enableRubberBandZooming( false )
31  , rubberBand( nullptr )
32 {
33  // this block left empty intentionally
34 }
35 
36 
37 AbstractCoordinatePlane::AbstractCoordinatePlane ( KChart::Chart* parent )
38  : AbstractArea ( new Private() )
39 {
40  d->parent = parent;
41  d->init();
42 }
43 
44 AbstractCoordinatePlane::~AbstractCoordinatePlane()
45 {
46  Q_EMIT destroyedCoordinatePlane( this );
47 }
48 
49 void AbstractCoordinatePlane::init()
50 {
51  d->initialize(); // virtual method to init the correct grid: cartesian, polar, ...
52  connect( this, SIGNAL(internal_geometryChanged(QRect,QRect)),
53  this, SIGNAL(geometryChanged(QRect,QRect)),
55 }
56 
58 {
59  // diagrams are invisible and paint through their paint() method
60  diagram->hide();
61 
62  d->diagrams.append( diagram );
63  diagram->setParent( d->parent );
64  diagram->setCoordinatePlane( this );
65  layoutDiagrams();
66  layoutPlanes(); // there might be new axes, etc
67  connect( diagram, SIGNAL(modelsChanged()), this, SLOT(layoutPlanes()) );
68  connect( diagram, SIGNAL(modelDataChanged()), this, SLOT(update()) );
69  connect( diagram, SIGNAL(modelDataChanged()), this, SLOT(relayout()) );
70  connect( this, SIGNAL(boundariesChanged()), diagram, SIGNAL(boundariesChanged()) );
71 
72  update();
74 }
75 
76 /*virtual*/
78 {
79  if ( diagram && oldDiagram_ != diagram ) {
80  AbstractDiagram* oldDiagram = oldDiagram_;
81  if ( d->diagrams.count() ) {
82  if ( ! oldDiagram ) {
83  oldDiagram = d->diagrams.first();
84  if ( oldDiagram == diagram )
85  return;
86  }
87  takeDiagram( oldDiagram );
88  }
89  delete oldDiagram;
90  addDiagram( diagram );
91  layoutDiagrams();
92  layoutPlanes(); // there might be new axes, etc
93  update();
94  }
95 }
96 
97 /*virtual*/
99 {
100  const int idx = d->diagrams.indexOf( diagram );
101  if ( idx != -1 ) {
102  d->diagrams.removeAt( idx );
103  diagram->setParent( nullptr );
104  diagram->setCoordinatePlane( nullptr );
105  disconnect( diagram, SIGNAL(modelsChanged()), this, SLOT(layoutPlanes()) );
106  disconnect( diagram, SIGNAL(modelDataChanged()), this, SLOT(update()) );
107  disconnect( diagram, SIGNAL(modelDataChanged()), this, SLOT(relayout()) );
108  layoutDiagrams();
109  update();
110  }
111 }
112 
113 
115 {
116  if ( d->diagrams.isEmpty() )
117  {
118  return nullptr;
119  } else {
120  return d->diagrams.first();
121  }
122 }
123 
125 {
126  return d->diagrams;
127 }
128 
130 {
132 #ifndef QT_NO_STL
133  qCopy( d->diagrams.begin(), d->diagrams.end(), std::back_inserter( list ) );
134 #else
135  Q_FOREACH( AbstractDiagram * a, d->diagrams )
136  list.push_back( a );
137 #endif
138  return list;
139 }
140 
142 {
143  d->gridAttributes = a;
144  update();
145 }
146 
148 {
149  return d->gridAttributes;
150 }
151 
153 {
154  return d->grid->updateData( this );
155 }
156 
158 {
159  d->grid->setNeedRecalculate();
160 }
161 
163 {
164  d->referenceCoordinatePlane = plane;
165 }
166 
168 {
169  return d->referenceCoordinatePlane;
170 }
171 
173 {
174  d->parent = parent;
175 }
176 
177 const KChart::Chart* KChart::AbstractCoordinatePlane::parent() const
178 {
179  return d->parent;
180 }
181 
182 KChart::Chart* KChart::AbstractCoordinatePlane::parent()
183 {
184  return d->parent;
185 }
186 
187 /* pure virtual in QLayoutItem */
189 {
190  return false; // never empty!
191  // coordinate planes with no associated diagrams
192  // are showing a default grid of ()1..10, 1..10) stepWidth 1
193 }
194 /* pure virtual in QLayoutItem */
196 {
197  return Qt::Vertical | Qt::Horizontal;
198 }
199 /* pure virtual in QLayoutItem */
201 {
202  // No maximum size set. Especially not parent()->size(), we are not layouting
203  // to the parent widget's size when using Chart::paint()!
204  return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
205 }
206 /* pure virtual in QLayoutItem */
208 {
209  return QSize(60, 60); // this default can be overwritten by derived classes
210 }
211 /* pure virtual in QLayoutItem */
213 {
214  // we return our maxiumu (which is the full size of the Chart)
215  // even if we know the plane will be smaller
216  return maximumSize();
217 }
218 /* pure virtual in QLayoutItem */
220 {
221  if ( d->geometry != r ) {
222  // inform the outside word by Signal geometryChanged()
223  // via a queued connection to internal_geometryChanged()
224  Q_EMIT internal_geometryChanged( d->geometry, r );
225 
226  d->geometry = r;
227  // Note: We do *not* call update() here
228  // because it would invoke KChart::update() recursively.
229  }
230 }
231 /* pure virtual in QLayoutItem */
233 {
234  return d->geometry;
235 }
236 
238 {
239  //qDebug("KChart::AbstractCoordinatePlane::update() called");
240  Q_EMIT needUpdate();
241 }
242 
244 {
245  //qDebug("KChart::AbstractCoordinatePlane::relayout() called");
246  Q_EMIT needRelayout();
247 }
248 
250 {
251  //qDebug("KChart::AbstractCoordinatePlane::relayout() called");
252  Q_EMIT needLayoutPlanes();
253 }
254 
256 {
257  d->enableRubberBandZooming = enable;
258 
259  if ( !enable && d->rubberBand != nullptr )
260  {
261  delete d->rubberBand;
262  d->rubberBand = nullptr;
263  }
264 }
265 
267 {
268  return d->enableRubberBandZooming;
269 }
270 
272 {
273  if ( d->enableCornerSpacers == enable ) return;
274 
275  d->enableCornerSpacers = enable;
276  Q_EMIT needRelayout();
277 }
278 
280 {
281  return d->enableCornerSpacers;
282 }
283 
284 void KChart::AbstractCoordinatePlane::mousePressEvent( QMouseEvent* event )
285 {
286  if ( event->button() == Qt::LeftButton )
287  {
288  if ( d->enableRubberBandZooming && d->rubberBand == nullptr )
289  d->rubberBand = new QRubberBand( QRubberBand::Rectangle, qobject_cast< QWidget* >( parent() ) );
290 
291  if ( d->rubberBand != nullptr )
292  {
293  d->rubberBandOrigin = event->pos();
294  d->rubberBand->setGeometry( QRect( event->pos(), QSize() ) );
295  d->rubberBand->show();
296 
297  event->accept();
298  }
299  }
300  else if ( event->button() == Qt::RightButton )
301  {
302  if ( d->enableRubberBandZooming && !d->rubberBandZoomConfigHistory.isEmpty() )
303  {
304  // restore the last config from the stack
305  ZoomParameters config = d->rubberBandZoomConfigHistory.pop();
306  setZoomFactorX( config.xFactor );
307  setZoomFactorY( config.yFactor );
308  setZoomCenter( config.center() );
309 
310  QWidget* const p = qobject_cast< QWidget* >( parent() );
311  if ( p != nullptr )
312  p->update();
313 
314  event->accept();
315  }
316  }
317 
318  Q_FOREACH( AbstractDiagram * a, d->diagrams )
319  {
320  a->mousePressEvent( event );
321  }
322 }
323 
324 void KChart::AbstractCoordinatePlane::mouseDoubleClickEvent( QMouseEvent* event )
325 {
326  if ( event->button() == Qt::RightButton )
327  {
328  // otherwise the second click gets lost
329  // which is pretty annoying when zooming out fast
330  mousePressEvent( event );
331  }
332  Q_FOREACH( AbstractDiagram * a, d->diagrams )
333  {
334  a->mouseDoubleClickEvent( event );
335  }
336 }
337 
338 void KChart::AbstractCoordinatePlane::mouseReleaseEvent( QMouseEvent* event )
339 {
340  if ( d->rubberBand != nullptr )
341  {
342  // save the old config on the stack
343  d->rubberBandZoomConfigHistory.push( ZoomParameters( zoomFactorX(), zoomFactorY(), zoomCenter() ) );
344 
345  // this is the height/width of the rubber band in pixel space
346  const qreal rubberWidth = static_cast< qreal >( d->rubberBand->width() );
347  const qreal rubberHeight = static_cast< qreal >( d->rubberBand->height() );
348 
349  if ( rubberWidth > 0.0 && rubberHeight > 0.0 )
350  {
351  // this is the center of the rubber band in pixel space
352  const qreal centerX = qFloor( d->rubberBand->geometry().width() / 2.0 + d->rubberBand->geometry().x() );
353  const qreal centerY = qCeil( d->rubberBand->geometry().height() / 2.0 + d->rubberBand->geometry().y() );
354 
355  const qreal rubberCenterX = static_cast< qreal >( centerX - geometry().x() );
356  const qreal rubberCenterY = static_cast< qreal >( centerY - geometry().y() );
357 
358  // this is the height/width of the plane in pixel space
359  const qreal myWidth = static_cast< qreal >( geometry().width() );
360  const qreal myHeight = static_cast< qreal >( geometry().height() );
361 
362  // this describes the new center of zooming, relative to the plane pixel space
363  const qreal newCenterX = rubberCenterX / myWidth / zoomFactorX() + zoomCenter().x() - 0.5 / zoomFactorX();
364  const qreal newCenterY = rubberCenterY / myHeight / zoomFactorY() + zoomCenter().y() - 0.5 / zoomFactorY();
365 
366  // this will be the new zoom factor
367  const qreal newZoomFactorX = zoomFactorX() * myWidth / rubberWidth;
368  const qreal newZoomFactorY = zoomFactorY() * myHeight / rubberHeight;
369 
370  // and this the new center
371  const QPointF newZoomCenter( newCenterX, newCenterY );
372 
373  setZoomFactorX( newZoomFactorX );
374  setZoomFactorY( newZoomFactorY );
375  setZoomCenter( newZoomCenter );
376  }
377 
378  d->rubberBand->parentWidget()->update();
379  delete d->rubberBand;
380  d->rubberBand = nullptr;
381 
382  event->accept();
383  }
384 
385  Q_FOREACH( AbstractDiagram * a, d->diagrams )
386  {
387  a->mouseReleaseEvent( event );
388  }
389 }
390 
391 void KChart::AbstractCoordinatePlane::mouseMoveEvent( QMouseEvent* event )
392 {
393  if ( d->rubberBand != nullptr )
394  {
395  const QRect normalized = QRect( d->rubberBandOrigin, event->pos() ).normalized();
396  d->rubberBand->setGeometry( normalized & geometry() );
397 
398  event->accept();
399  }
400 
401  Q_FOREACH( AbstractDiagram * a, d->diagrams )
402  {
403  a->mouseMoveEvent( event );
404  }
405 }
406 
407 #if defined(Q_COMPILER_MANGLES_RETURN_TYPE)
408 const
409 #endif
411 {
412  return d->isVisiblePoint( this, point );
413 }
414 
415 AbstractCoordinatePlane* KChart::AbstractCoordinatePlane::sharedAxisMasterPlane( QPainter* p )
416 {
417  Q_UNUSED( p );
418  return this;
419 }
420 
421 #if !defined(QT_NO_DEBUG_STREAM)
422 #include "KChartEnums.h"
423 
424 QDebug KChart::operator<<( QDebug stream, const DataDimension& r )
425 {
426  stream << "DataDimension("
427  << " start=" << r.start
428  << " end=" << r.end
429  << " sequence=" << KChartEnums::granularitySequenceToString( r.sequence )
430  << " isCalculated=" << r.isCalculated
431  << " calcMode=" << ( r.calcMode == AbstractCoordinatePlane::Logarithmic ? "Logarithmic" : "Linear" )
432  << " stepWidth=" << r.stepWidth
433  << " subStepWidth=" << r.subStepWidth
434  << " )";
435  return stream;
436 }
437 #endif
438 
439 #undef d
void setCornerSpacersEnabled(bool enable)
Enables or disables the use of spacers in the plane corners.
Helper class for one dimension of data, e.g.
DataDimensionsList gridDimensionsList()
Returns the dimensions used for drawing the grid lines.
QSize maximumSize() const override
pure virtual in QLayoutItem
Class only listed here to document inheritance of some KChart classes.
void modelDataChanged()
This signal is emitted, when the model data is changed.
AbstractDiagram defines the interface for diagram classes.
bool isEmpty() const override
pure virtual in QLayoutItem
void push_back(const T &value)
void update()
Calling update() on the plane triggers the global KChart::Chart::update()
LeftButton
int height() const const
int x() const const
int y() const const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
void setParent(QWidget *parent)
virtual void mouseReleaseEvent(QMouseEvent *event) override
void update()
void setGridNeedsRecalculate()
Used by the chart to clear the cached grid data.
const QRect & geometry() const const
void layoutPlanes()
Calling layoutPlanes() on the plane triggers the global KChart::Chart::slotLayoutPlanes() ...
QSize minimumSize() const override
pure virtual in QLayoutItem
void setRubberBandZoomingEnabled(bool enable)
Enables or disables zooming with a rubber band using the mouse.
void setParent(Chart *parent)
Called internally by KChart::Chart.
AbstractCoordinatePlane * referenceCoordinatePlane() const
There are two ways, in which planes can be caused to interact, in where they are put layouting wise: ...
virtual void takeDiagram(AbstractDiagram *diagram)
Removes the diagram from the plane, without deleting it.
void setReferenceCoordinatePlane(AbstractCoordinatePlane *plane)
Set another coordinate plane to be used as the reference plane for this one.
Qt::MouseButton button() const const
bool isVisiblePoint(const QPointF &point) const
Tests, if a point is visible on the coordinate plane.
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane.
ZoomParameters stores the center and the factor of zooming internally.
void hide()
QRect geometry() const override
pure virtual in QLayoutItem
virtual void setCoordinatePlane(AbstractCoordinatePlane *plane)
Set the coordinate plane associated with the diagram.
QSize sizeHint() const override
pure virtual in QLayoutItem
An area in the chart with a background, a frame, etc.
virtual void replaceDiagram(AbstractDiagram *diagram, AbstractDiagram *oldDiagram=nullptr)
Replaces the old diagram, or appends the diagram, it there is none yet.
virtual void addDiagram(AbstractDiagram *diagram)
Adds a diagram to this coordinate plane.
Qt::Orientations expandingDirections() const override
pure virtual in QLayoutItem
virtual void mouseMoveEvent(QMouseEvent *event) override
QSize maximumSize() const const
void modelsChanged()
This signal is emitted when either the model or the AttributesModel is replaced.
static QString granularitySequenceToString(GranularitySequence sequence)
Converts the specified granularity sequence enum to a string representation.
Definition: KChartEnums.h:95
virtual bool event(QEvent *event) override
void setGeometry(const QRect &r) override
pure virtual in QLayoutItem
void setGlobalGridAttributes(const GridAttributes &)
Set the grid attributes to be used by this coordinate plane.
int width() const const
Definition of global enums.
virtual void mousePressEvent(QMouseEvent *event) override
A set of attributes controlling the appearance of grids.
virtual void layoutPlanes()
Triggers layouting of all coordinate planes on the current chart.
void boundariesChanged()
Emitted upon change of a data boundary.
A chart with one or more diagrams.
Definition: KChartChart.h:84
typedef Orientations
QPoint pos() const const
void relayout()
Calling relayout() on the plane triggers the global KChart::Chart::slotRelayout() ...
Global namespace.
QueuedConnection
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
T qobject_cast(QObject *object)
QObject * parent() const const
virtual void mouseDoubleClickEvent(QMouseEvent *event) override
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Oct 25 2021 22:37:44 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.