KD Chart 2  [rev.2.5.1]
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Pages
KDChartWidget.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 
23 #include <KDChartWidget.h>
24 #include <KDChartWidget_p.h>
25 
26 #include <KDChartAbstractDiagram.h>
27 #include <KDChartBarDiagram.h>
28 #include <KDChartChart.h>
30 #include <KDChartLineDiagram.h>
31 #include <KDChartPlotter.h>
32 #include <KDChartPieDiagram.h>
33 #include <KDChartPolarDiagram.h>
34 #include <KDChartRingDiagram.h>
35 #include <KDChartLegend.h>
36 
37 #include <QDebug>
38 
39 #include <KDABLibFakes>
40 
41 #define d d_func()
42 
43 using namespace KDChart;
44 
45 Widget::Private::Private( Widget * qq )
46  : q( qq ),
47  layout( q ),
48  m_model( q ),
49  m_chart( q ),
50  m_cartPlane( &m_chart ),
51  m_polPlane( &m_chart ),
52  usedDatasetWidth( 0 )
53 {
54  KDAB_SET_OBJECT_NAME( layout );
55  KDAB_SET_OBJECT_NAME( m_model );
56  KDAB_SET_OBJECT_NAME( m_chart );
57 
58  layout.addWidget( &m_chart );
59 }
60 
61 Widget::Private::~Private() {}
62 
63 
76 Widget::Widget( QWidget* parent ) :
77  QWidget(parent), _d( new Private( this ) )
78 {
79  // as default we have a cartesian coordinate plane ...
80  // ... and a line diagram
81  setType( Line );
82 }
83 
88 {
89  delete _d; _d = 0;
90 }
91 
92 void Widget::init()
93 {
94 }
95 
96 void Widget::setDataset( int column, const QVector< qreal > & data, const QString& title )
97 {
98  if ( ! checkDatasetWidth( 1 ) )
99  return;
100 
101  QStandardItemModel & model = d->m_model;
102 
103  justifyModelSize( data.size(), column + 1 );
104 
105  for ( int i = 0; i < data.size(); ++i )
106  {
107  const QModelIndex index = model.index( i, column );
108  model.setData( index, QVariant( data[i] ), Qt::DisplayRole );
109  }
110  if ( ! title.isEmpty() )
111  model.setHeaderData( column, Qt::Horizontal, QVariant( title ) );
112 }
113 
114 void Widget::setDataset( int column, const QVector< QPair< qreal, qreal > > & data, const QString& title )
115 {
116  if ( ! checkDatasetWidth( 2 ))
117  return;
118 
119  QStandardItemModel & model = d->m_model;
120 
121  justifyModelSize( data.size(), (column + 1) * 2 );
122 
123  for ( int i = 0; i < data.size(); ++i )
124  {
125  QModelIndex index = model.index( i, column * 2 );
126  model.setData( index, QVariant( data[i].first ), Qt::DisplayRole );
127 
128  index = model.index( i, column * 2 + 1 );
129  model.setData( index, QVariant( data[i].second ), Qt::DisplayRole );
130  }
131  if ( ! title.isEmpty() ) {
132  model.setHeaderData( column, Qt::Horizontal, QVariant( title ) );
133  }
134 }
135 
136 void Widget::setDataCell( int row, int column, qreal data )
137 {
138  if ( ! checkDatasetWidth( 1 ) )
139  return;
140 
141  QStandardItemModel & model = d->m_model;
142 
143  justifyModelSize( row + 1, column + 1 );
144 
145  const QModelIndex index = model.index( row, column );
146  model.setData( index, QVariant( data ), Qt::DisplayRole );
147 }
148 
149 void Widget::setDataCell( int row, int column, QPair< qreal, qreal > data )
150 {
151  if ( ! checkDatasetWidth( 2 ))
152  return;
153 
154  QStandardItemModel & model = d->m_model;
155 
156  justifyModelSize( row + 1, (column + 1) * 2 );
157 
158  QModelIndex index = model.index( row, column * 2 );
159  model.setData( index, QVariant( data.first ), Qt::DisplayRole );
160 
161  index = model.index( row, column * 2 + 1 );
162  model.setData( index, QVariant( data.second ), Qt::DisplayRole );
163 }
164 
165 /*
166  * Resets all data.
167  */
169 {
170  d->m_model.clear();
171  d->usedDatasetWidth = 0;
172 }
173 
177 void Widget::setGlobalLeading( int left, int top, int right, int bottom )
178 {
179  d->m_chart.setGlobalLeading( left, top, right, bottom );
180 }
181 
185 void Widget::setGlobalLeadingLeft( int leading )
186 {
187  d->m_chart.setGlobalLeadingLeft( leading );
188 }
189 
194 {
195  return d->m_chart.globalLeadingLeft();
196 }
197 
201 void Widget::setGlobalLeadingTop( int leading )
202 {
203  d->m_chart.setGlobalLeadingTop( leading );
204 }
205 
210 {
211  return d->m_chart.globalLeadingTop();
212 }
213 
217 void Widget::setGlobalLeadingRight( int leading )
218 {
219  d->m_chart.setGlobalLeadingRight( leading );
220 }
221 
226 {
227  return d->m_chart.globalLeadingRight();
228 }
229 
234 {
235  d->m_chart.setGlobalLeadingBottom( leading );
236 }
237 
242 {
243  return d->m_chart.globalLeadingBottom();
244 }
245 
250 {
251  return d->m_chart.headerFooter();
252 }
253 
258 {
259  return d->m_chart.headerFooters();
260 }
261 
265 void Widget::addHeaderFooter( const QString& text,
267  Position position)
268 {
269  HeaderFooter* newHeader = new HeaderFooter( &d->m_chart );
270  newHeader->setType( type );
271  newHeader->setPosition( position );
272  newHeader->setText( text );
273  d->m_chart.addHeaderFooter( newHeader ); // we need this explicit call !
274 }
275 
280 {
281  header->setParent( &d->m_chart );
282  d->m_chart.addHeaderFooter( header ); // we need this explicit call !
283 }
284 
286 {
287  header->setParent( &d->m_chart );
288  d->m_chart.replaceHeaderFooter( header, oldHeader );
289 }
290 
292 {
293  d->m_chart.takeHeaderFooter( header );
294 }
295 
300 {
301  return d->m_chart.legend();
302 }
303 
308 {
309  return d->m_chart.legends();
310 }
311 
315 void Widget::addLegend( Position position )
316 {
317  Legend* legend = new Legend( diagram(), &d->m_chart );
318  legend->setPosition( position );
319  d->m_chart.addLegend( legend );
320 }
321 
325 void Widget::addLegend( Legend* legend )
326 {
327  legend->setDiagram( diagram() );
328  legend->setParent( &d->m_chart );
329  d->m_chart.addLegend( legend );
330 }
331 
332 void Widget::replaceLegend( Legend* legend, Legend* oldLegend )
333 {
334  legend->setDiagram( diagram() );
335  legend->setParent( &d->m_chart );
336  d->m_chart.replaceLegend( legend, oldLegend );
337 }
338 
339 void Widget::takeLegend( Legend* legend )
340 {
341  d->m_chart.takeLegend( legend );
342 }
343 
345 {
346  if ( coordinatePlane() == 0 )
347  qDebug() << "diagram(): coordinatePlane() was NULL";
348 
349  return coordinatePlane()->diagram();
350 }
351 
353 {
354  return dynamic_cast<BarDiagram*>( diagram() );
355 }
357 {
358  return dynamic_cast<LineDiagram*>( diagram() );
359 }
361 {
362  return dynamic_cast<Plotter*>( diagram() );
363 }
365 {
366  return dynamic_cast<PieDiagram*>( diagram() );
367 }
369 {
370  return dynamic_cast<RingDiagram*>( diagram() );
371 }
373 {
374  return dynamic_cast<PolarDiagram*>( diagram() );
375 }
376 
378 {
379  return d->m_chart.coordinatePlane();
380 }
381 
383 {
384  return (type == KDChart::Widget::Bar) || (type == KDChart::Widget::Line);
385 }
386 
388 {
389  return (type == KDChart::Widget::Pie)
390  || (type == KDChart::Widget::Ring)
391  || (type == KDChart::Widget::Polar);
392 }
393 
394 void Widget::setType( ChartType chartType, SubType chartSubType )
395 {
396  AbstractDiagram* diag = 0;
397  const ChartType oldType = type();
398 
399  if ( chartType != oldType ) {
400  if ( chartType != NoType ) {
401  if ( isCartesian( chartType ) && ! isCartesian( oldType ) )
402  {
403  if ( coordinatePlane() == &d->m_polPlane ) {
404  d->m_chart.takeCoordinatePlane( &d->m_polPlane );
405  d->m_chart.addCoordinatePlane( &d->m_cartPlane );
406  } else {
407  d->m_chart.replaceCoordinatePlane( &d->m_cartPlane );
408  }
409  }
410  else if ( isPolar( chartType ) && ! isPolar( oldType ) )
411  {
412  if ( coordinatePlane() == &d->m_cartPlane ) {
413  d->m_chart.takeCoordinatePlane( &d->m_cartPlane );
414  d->m_chart.addCoordinatePlane( &d->m_polPlane );
415  } else {
416  d->m_chart.replaceCoordinatePlane( &d->m_polPlane );
417  }
418  }
419  }
420  switch ( chartType ) {
421  case Bar:
422  diag = new BarDiagram( &d->m_chart, &d->m_cartPlane );
423  break;
424  case Line:
425  diag = new LineDiagram( &d->m_chart, &d->m_cartPlane );
426  break;
427  case Plot:
428  diag = new Plotter( &d->m_chart, &d->m_cartPlane );
429  break;
430  case Pie:
431  diag = new PieDiagram( &d->m_chart, &d->m_polPlane );
432  break;
433  case Polar:
434  diag = new PolarDiagram( &d->m_chart, &d->m_polPlane );
435  break;
436  case Ring:
437  diag = new RingDiagram( &d->m_chart, &d->m_polPlane );
438  break;
439  case NoType:
440  break;
441  }
442  if ( diag != NULL ) {
443  if ( isCartesian( oldType ) && isCartesian( chartType ) ) {
444  AbstractCartesianDiagram *oldDiag =
445  qobject_cast<AbstractCartesianDiagram*>( coordinatePlane()->diagram() );
446  AbstractCartesianDiagram *newDiag =
447  qobject_cast<AbstractCartesianDiagram*>( diag );
448  Q_FOREACH( CartesianAxis* axis, oldDiag->axes() ) {
449  oldDiag->takeAxis( axis );
450  newDiag->addAxis ( axis );
451  }
452  }
453  diag->setModel( &d->m_model );
454  coordinatePlane()->replaceDiagram( diag );
455 
456  LegendList legends = d->m_chart.legends();
457  Q_FOREACH(Legend* l, legends)
458  l->setDiagram( diag );
459  //checkDatasetWidth( d->usedDatasetWidth );
460  }
461  //coordinatePlane()->setGridNeedsRecalculate();
462  }
463 
464  if ( chartType != NoType ) {
465  if ( chartType != oldType || chartSubType != subType() )
466  setSubType( chartSubType );
467  d->m_chart.resize( size() ); // triggering immediate update
468  }
469 }
470 
472 {
473  BarDiagram* barDia = qobject_cast< BarDiagram* >( diagram() );
474  LineDiagram* lineDia = qobject_cast< LineDiagram* >( diagram() );
475  Plotter* plotterDia = qobject_cast< Plotter* >( diagram() );
476 
477 //FIXME(khz): Add the impl for these chart types - or remove them from here:
478 // PieDiagram* pieDia = qobject_cast< PieDiagram* >( diagram() );
479 // PolarDiagram* polarDia = qobject_cast< PolarDiagram* >( diagram() );
480 // RingDiagram* ringDia = qobject_cast< RingDiagram* >( diagram() );
481 
482 #define SET_SUB_TYPE(DIAGRAM, SUBTYPE) \
483 { \
484  if ( DIAGRAM ) \
485  DIAGRAM->setType( SUBTYPE ); \
486 }
487  switch ( subType )
488  {
489  case Normal:
490  SET_SUB_TYPE( barDia, BarDiagram::Normal );
491  SET_SUB_TYPE( lineDia, LineDiagram::Normal );
492  SET_SUB_TYPE( plotterDia, Plotter::Normal );
493  break;
494  case Stacked:
497  //SET_SUB_TYPE( plotterDia, Plotter::Stacked );
498  break;
499  case Percent:
502  SET_SUB_TYPE( plotterDia, Plotter::Percent );
503  break;
504  case Rows:
505  SET_SUB_TYPE( barDia, BarDiagram::Rows );
506  break;
507  default:
508  Q_ASSERT_X ( false,
509  "Widget::setSubType", "Sub-type not supported!" );
510  break;
511  }
512 // coordinatePlane()->show();
513 }
514 
519 {
520  // PENDING(christoph) save the type out-of-band:
521  AbstractDiagram * const dia = const_cast<Widget*>( this )->diagram();
522  if ( qobject_cast< BarDiagram* >( dia ) )
523  return Bar;
524  else if ( qobject_cast< LineDiagram* >( dia ) )
525  return Line;
526  else if ( qobject_cast< Plotter* >( dia ) )
527  return Plot;
528  else if ( qobject_cast< PieDiagram* >( dia ) )
529  return Pie;
530  else if ( qobject_cast< PolarDiagram* >( dia ) )
531  return Polar;
532  else if ( qobject_cast< RingDiagram* >( dia ) )
533  return Ring;
534  else
535  return NoType;
536 }
537 
539 {
540  // PENDING(christoph) save the type out-of-band:
541  Widget::SubType retVal = Normal;
542 
543  AbstractDiagram * const dia = const_cast<Widget*>( this )->diagram();
544  BarDiagram* barDia = qobject_cast< BarDiagram* >( dia );
545  LineDiagram* lineDia = qobject_cast< LineDiagram* >( dia );
546  Plotter* plotterDia = qobject_cast< Plotter* >( dia );
547 
548 //FIXME(khz): Add the impl for these chart types - or remove them from here:
549 // PieDiagram* pieDia = qobject_cast< PieDiagram* >( diagram() );
550 // PolarDiagram* polarDia = qobject_cast< PolarDiagram* >( diagram() );
551 // RingDiagram* ringDia = qobject_cast< RingDiagram* >( diagram() );
552 
553 #define TEST_SUB_TYPE(DIAGRAM, INTERNALSUBTYPE, SUBTYPE) \
554 { \
555  if ( DIAGRAM && DIAGRAM->type() == INTERNALSUBTYPE ) \
556  retVal = SUBTYPE; \
557 }
558  const Widget::ChartType mainType = type();
559  switch ( mainType )
560  {
561  case Bar:
565  TEST_SUB_TYPE( barDia, BarDiagram::Rows, Rows );
566  break;
567  case Line:
571  break;
572  case Plot:
573  TEST_SUB_TYPE( plotterDia, Plotter::Normal, Normal );
574  TEST_SUB_TYPE( plotterDia, Plotter::Percent, Percent );
575  break;
576  case Pie:
577  // no impl. yet
578  break;
579  case Polar:
580  // no impl. yet
581  break;
582  case Ring:
583  // no impl. yet
584  break;
585  default:
586  Q_ASSERT_X ( false,
587  "Widget::subType", "Chart type not supported!" );
588  break;
589  }
590  return retVal;
591 }
592 
593 
597 bool Widget::checkDatasetWidth( int width )
598 {
599  if ( width == diagram()->datasetDimension() )
600  {
601  d->usedDatasetWidth = width;
602  return true;
603  }
604  qDebug() << "The current diagram type doesn't support this data dimension.";
605  return false;
606 /* if ( d->usedDatasetWidth == width || d->usedDatasetWidth == 0 ) {
607  d->usedDatasetWidth = width;
608  diagram()->setDatasetDimension( width );
609  return true;
610  }
611  qDebug() << "It's impossible to mix up the different setDataset() methods on the same widget.";
612  return false;*/
613 }
614 
618 void Widget::justifyModelSize( int rows, int columns )
619 {
620  QAbstractItemModel & model = d->m_model;
621  const int currentRows = model.rowCount();
622  const int currentCols = model.columnCount();
623 
624  if ( currentCols < columns )
625  if ( ! model.insertColumns( currentCols, columns - currentCols ))
626  qDebug() << "justifyModelSize: could not increase model size.";
627  if ( currentRows < rows )
628  if ( ! model.insertRows( currentRows, rows - currentRows ))
629  qDebug() << "justifyModelSize: could not increase model size.";
630 
631  Q_ASSERT( model.rowCount() >= rows );
632  Q_ASSERT( model.columnCount() >= columns );
633 }

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