KD Chart 2  [rev.2.5.1]
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Pages
KDChartAbstractCoordinatePlane.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2013 Klaralvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Chart library.
5 **
6 ** Licensees holding valid commercial KD Chart licenses may use this file in
7 ** accordance with the KD Chart Commercial License Agreement provided with
8 ** the Software.
9 **
10 **
11 ** This file may be distributed and/or modified under the terms of the
12 ** GNU General Public License version 2 and version 3 as published by the
13 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contact info@kdab.com if any conditions of this licensing are not
19 ** clear to you.
20 **
21 **********************************************************************/
22 
24 #include "KDChartAbstractCoordinatePlane_p.h"
25 
26 #include "KDChartChart.h"
27 #include "KDChartGridAttributes.h"
28 
29 #include <KDABLibFakes>
30 
31 #include <QGridLayout>
32 #include <QRubberBand>
33 #include <QMouseEvent>
34 #include <QtCore/qmath.h>
35 
36 using namespace KDChart;
37 
38 #define d d_func()
39 
40 AbstractCoordinatePlane::Private::Private()
41  : AbstractArea::Private()
42  , parent( 0 )
43  , grid( 0 )
44  , referenceCoordinatePlane( 0 )
45  , enableCornerSpacers( true )
46  , enableRubberBandZooming( false )
47  , rubberBand( 0 )
48 {
49  // this bloc left empty intentionally
50 }
51 
52 
53 AbstractCoordinatePlane::AbstractCoordinatePlane ( KDChart::Chart* parent )
54  : AbstractArea ( new Private() )
55 {
56  d->parent = parent;
57  d->init();
58 }
59 
61 {
62  emit destroyedCoordinatePlane( this );
63 }
64 
65 void AbstractCoordinatePlane::init()
66 {
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 );
71 }
72 
74 {
75  // diagrams are invisible and paint through their paint() method
76  diagram->hide();
77 
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() ) );
84  connect( diagram, SIGNAL( modelDataChanged() ), this, SLOT( update()) );
85  connect( diagram, SIGNAL( modelDataChanged() ), this, SLOT( relayout()) );
86  connect( this, SIGNAL( boundariesChanged() ), diagram, SIGNAL( boundariesChanged() ) );
87 
88  update();
89  emit boundariesChanged();
90 }
91 
92 /*virtual*/
94 {
95  if ( diagram && oldDiagram_ != diagram ) {
96  AbstractDiagram* oldDiagram = oldDiagram_;
97  if ( d->diagrams.count() ) {
98  if ( ! oldDiagram ) {
99  oldDiagram = d->diagrams.first();
100  if ( oldDiagram == diagram )
101  return;
102  }
103  takeDiagram( oldDiagram );
104  }
105  delete oldDiagram;
106  addDiagram( diagram );
107  layoutDiagrams();
108  layoutPlanes(); // there might be new axes, etc
109  update();
110  }
111 }
112 
113 /*virtual*/
115 {
116  const int idx = d->diagrams.indexOf( diagram );
117  if ( idx != -1 ) {
118  d->diagrams.removeAt( idx );
119  diagram->setParent( 0 );
120  diagram->setCoordinatePlane( 0 );
121  disconnect( diagram, SIGNAL( modelsChanged() ), this, SLOT( layoutPlanes() ) );
122  disconnect( diagram, SIGNAL( modelDataChanged() ), this, SLOT( update()) );
123  disconnect( diagram, SIGNAL( modelDataChanged() ), this, SLOT( relayout()) );
124  layoutDiagrams();
125  update();
126  }
127 }
128 
129 
131 {
132  if ( d->diagrams.isEmpty() )
133  {
134  return 0;
135  } else {
136  return d->diagrams.first();
137  }
138 }
139 
141 {
142  return d->diagrams;
143 }
144 
146 {
148 #ifndef QT_NO_STL
149  qCopy( d->diagrams.begin(), d->diagrams.end(), std::back_inserter( list ) );
150 #else
151  Q_FOREACH( AbstractDiagram * a, d->diagrams )
152  list.push_back( a );
153 #endif
154  return list;
155 }
156 
158 {
159  d->gridAttributes = a;
160  update();
161 }
162 
164 {
165  return d->gridAttributes;
166 }
167 
169 {
170  return d->grid->updateData( this );
171 }
172 
174 {
175  d->grid->setNeedRecalculate();
176 }
177 
179 {
180  d->referenceCoordinatePlane = plane;
181 }
182 
184 {
185  return d->referenceCoordinatePlane;
186 }
187 
189 {
190  d->parent = parent;
191 }
192 
194 {
195  return d->parent;
196 }
197 
199 {
200  return d->parent;
201 }
202 
203 /* pure virtual in QLayoutItem */
205 {
206  return false; // never empty!
207  // coordinate planes with no associated diagrams
208  // are showing a default grid of ()1..10, 1..10) stepWidth 1
209 }
210 /* pure virtual in QLayoutItem */
212 {
213  return Qt::Vertical | Qt::Horizontal;
214 }
215 /* pure virtual in QLayoutItem */
217 {
218  // No maximum size set. Especially not parent()->size(), we are not layouting
219  // to the parent widget's size when using Chart::paint()!
220  return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
221 }
222 /* pure virtual in QLayoutItem */
224 {
225  return QSize(60, 60); // this default can be overwritten by derived classes
226 }
227 /* pure virtual in QLayoutItem */
229 {
230  // we return our maxiumu (which is the full size of the Chart)
231  // even if we know the plane will be smaller
232  return maximumSize();
233 }
234 /* pure virtual in QLayoutItem */
236 {
237  if ( d->geometry != r ) {
238  // inform the outside word by Signal geometryChanged()
239  // via a queued connection to internal_geometryChanged()
240  emit internal_geometryChanged( d->geometry, r );
241 
242  d->geometry = r;
243  // Note: We do *not* call update() here
244  // because it would invoke KDChart::update() recursively.
245  }
246 }
247 /* pure virtual in QLayoutItem */
249 {
250  return d->geometry;
251 }
252 
254 {
255  //qDebug("KDChart::AbstractCoordinatePlane::update() called");
256  emit needUpdate();
257 }
258 
260 {
261  //qDebug("KDChart::AbstractCoordinatePlane::relayout() called");
262  emit needRelayout();
263 }
264 
266 {
267  //qDebug("KDChart::AbstractCoordinatePlane::relayout() called");
268  emit needLayoutPlanes();
269 }
270 
272 {
273  d->enableRubberBandZooming = enable;
274 
275  if ( !enable && d->rubberBand != 0 )
276  {
277  delete d->rubberBand;
278  d->rubberBand = 0;
279  }
280 }
281 
283 {
284  return d->enableRubberBandZooming;
285 }
286 
288 {
289  if ( d->enableCornerSpacers == enable ) return;
290 
291  d->enableCornerSpacers = enable;
292  emit needRelayout();
293 }
294 
296 {
297  return d->enableCornerSpacers;
298 }
299 
301 {
302  if ( event->button() == Qt::LeftButton )
303  {
304  if ( d->enableRubberBandZooming && d->rubberBand == 0 )
305  d->rubberBand = new QRubberBand( QRubberBand::Rectangle, qobject_cast< QWidget* >( parent() ) );
306 
307  if ( d->rubberBand != 0 )
308  {
309  d->rubberBandOrigin = event->pos();
310  d->rubberBand->setGeometry( QRect( event->pos(), QSize() ) );
311  d->rubberBand->show();
312 
313  event->accept();
314  }
315  }
316  else if ( event->button() == Qt::RightButton )
317  {
318  if ( d->enableRubberBandZooming && !d->rubberBandZoomConfigHistory.isEmpty() )
319  {
320  // restore the last config from the stack
321  ZoomParameters config = d->rubberBandZoomConfigHistory.pop();
322  setZoomFactorX( config.xFactor );
323  setZoomFactorY( config.yFactor );
324  setZoomCenter( config.center() );
325 
326  QWidget* const p = qobject_cast< QWidget* >( parent() );
327  if ( p != 0 )
328  p->update();
329 
330  event->accept();
331  }
332  }
333 
334  KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
335  {
336  a->mousePressEvent( event );
337  }
338 }
339 
341 {
342  if ( event->button() == Qt::RightButton )
343  {
344  // othewise the second click gets lost
345  // which is pretty annoying when zooming out fast
346  mousePressEvent( event );
347  }
348  KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
349  {
350  a->mouseDoubleClickEvent( event );
351  }
352 }
353 
355 {
356  if ( d->rubberBand != 0 )
357  {
358  // save the old config on the stack
359  d->rubberBandZoomConfigHistory.push( ZoomParameters( zoomFactorX(), zoomFactorY(), zoomCenter() ) );
360 
361  // this is the height/width of the rubber band in pixel space
362  const qreal rubberWidth = static_cast< qreal >( d->rubberBand->width() );
363  const qreal rubberHeight = static_cast< qreal >( d->rubberBand->height() );
364 
365  if ( rubberWidth > 0.0 && rubberHeight > 0.0 )
366  {
367  // this is the center of the rubber band in pixel space
368  const qreal centerX = qFloor( d->rubberBand->geometry().width() / 2.0 + d->rubberBand->geometry().x() );
369  const qreal centerY = qCeil( d->rubberBand->geometry().height() / 2.0 + d->rubberBand->geometry().y() );
370 
371  const qreal rubberCenterX = static_cast< qreal >( centerX - geometry().x() );
372  const qreal rubberCenterY = static_cast< qreal >( centerY - geometry().y() );
373 
374  // this is the height/width of the plane in pixel space
375  const qreal myWidth = static_cast< qreal >( geometry().width() );
376  const qreal myHeight = static_cast< qreal >( geometry().height() );
377 
378  // this describes the new center of zooming, relative to the plane pixel space
379  const qreal newCenterX = rubberCenterX / myWidth / zoomFactorX() + zoomCenter().x() - 0.5 / zoomFactorX();
380  const qreal newCenterY = rubberCenterY / myHeight / zoomFactorY() + zoomCenter().y() - 0.5 / zoomFactorY();
381 
382  // this will be the new zoom factor
383  const qreal newZoomFactorX = zoomFactorX() * myWidth / rubberWidth;
384  const qreal newZoomFactorY = zoomFactorY() * myHeight / rubberHeight;
385 
386  // and this the new center
387  const QPointF newZoomCenter( newCenterX, newCenterY );
388 
389  setZoomFactorX( newZoomFactorX );
390  setZoomFactorY( newZoomFactorY );
391  setZoomCenter( newZoomCenter );
392  }
393 
394  d->rubberBand->parentWidget()->update();
395  delete d->rubberBand;
396  d->rubberBand = 0;
397 
398  event->accept();
399  }
400 
401  KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
402  {
403  a->mouseReleaseEvent( event );
404  }
405 }
406 
408 {
409  if ( d->rubberBand != 0 )
410  {
411  const QRect normalized = QRect( d->rubberBandOrigin, event->pos() ).normalized();
412  d->rubberBand->setGeometry( normalized & geometry() );
413 
414  event->accept();
415  }
416 
417  KDAB_FOREACH( AbstractDiagram * a, d->diagrams )
418  {
419  a->mouseMoveEvent( event );
420  }
421 }
422 
423 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE)
424 const
425 #endif
426 bool KDChart::AbstractCoordinatePlane::isVisiblePoint( const QPointF& point ) const
427 {
428  return d->isVisiblePoint( this, point );
429 }
430 
432 {
433  Q_UNUSED( p );
434  return this;
435 }
436 
437 #if !defined(QT_NO_DEBUG_STREAM)
438 #include "KDChartEnums.h"
439 
440 QDebug KDChart::operator<<( QDebug stream, const DataDimension& r )
441 {
442  stream << "DataDimension("
443  << " start=" << r.start
444  << " end=" << r.end
446  << " isCalculated=" << r.isCalculated
447  << " calcMode=" << ( r.calcMode == AbstractCoordinatePlane::Logarithmic ? "Logarithmic" : "Linear" )
448  << " stepWidth=" << r.stepWidth
449  << " subStepWidth=" << r.subStepWidth
450  << " )";
451  return stream;
452 }
453 #endif
454 
455 #undef d

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/