00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <KDChartWidget.h>
00031 #include <KDChartWidget_p.h>
00032
00033 #include <KDChartAbstractDiagram.h>
00034 #include <KDChartBarDiagram.h>
00035 #include <KDChartChart.h>
00036 #include <KDChartAbstractCoordinatePlane.h>
00037 #include <KDChartLineDiagram.h>
00038 #include <KDChartPlotter.h>
00039 #include <KDChartPieDiagram.h>
00040 #include <KDChartPolarDiagram.h>
00041 #include <KDChartRingDiagram.h>
00042 #include <KDChartLegend.h>
00043
00044 #include <QDebug>
00045
00046 #include <KDABLibFakes>
00047
00048 #define d d_func()
00049
00050 using namespace KDChart;
00051
00052 Widget::Private::Private( Widget * qq )
00053 : q( qq ),
00054 layout( q ),
00055 m_model( q ),
00056 m_chart( q ),
00057 m_cartPlane( &m_chart ),
00058 m_polPlane( &m_chart ),
00059 usedDatasetWidth( 0 )
00060 {
00061 KDAB_SET_OBJECT_NAME( layout );
00062 KDAB_SET_OBJECT_NAME( m_model );
00063 KDAB_SET_OBJECT_NAME( m_chart );
00064
00065 layout.addWidget( &m_chart );
00066 }
00067
00068 Widget::Private::~Private() {}
00069
00070
00083 Widget::Widget( QWidget* parent ) :
00084 QWidget(parent), _d( new Private( this ) )
00085 {
00086
00087
00088 setType( Line );
00089 }
00090
00094 Widget::~Widget()
00095 {
00096 delete _d; _d = 0;
00097 }
00098
00099 void Widget::init()
00100 {
00101 }
00102
00103 void Widget::setDataset( int column, const QVector< double > & data, const QString& title )
00104 {
00105 if ( ! checkDatasetWidth( 1 ) )
00106 return;
00107
00108 QStandardItemModel & model = d->m_model;
00109
00110 justifyModelSize( data.size(), column + 1 );
00111
00112 for( int i = 0; i < data.size(); ++i )
00113 {
00114 const QModelIndex index = model.index( i, column );
00115 model.setData( index, QVariant( data[i] ), Qt::DisplayRole );
00116 }
00117 if ( ! title.isEmpty() )
00118 model.setHeaderData( column, Qt::Horizontal, QVariant( title ) );
00119 }
00120
00121 void Widget::setDataset( int column, const QVector< QPair< double, double > > & data, const QString& title )
00122 {
00123 if ( ! checkDatasetWidth( 2 ))
00124 return;
00125
00126 QStandardItemModel & model = d->m_model;
00127
00128 justifyModelSize( data.size(), (column + 1) * 2 );
00129
00130 for( int i = 0; i < data.size(); ++i )
00131 {
00132 QModelIndex index = model.index( i, column * 2 );
00133 model.setData( index, QVariant( data[i].first ), Qt::DisplayRole );
00134
00135 index = model.index( i, column * 2 + 1 );
00136 model.setData( index, QVariant( data[i].second ), Qt::DisplayRole );
00137 }
00138 if ( ! title.isEmpty() ){
00139 model.setHeaderData( column, Qt::Horizontal, QVariant( title ) );
00140 }
00141 }
00142
00143 void Widget::setDataCell( int row, int column, double data )
00144 {
00145 if ( ! checkDatasetWidth( 1 ) )
00146 return;
00147
00148 QStandardItemModel & model = d->m_model;
00149
00150 justifyModelSize( row + 1, column + 1 );
00151
00152 const QModelIndex index = model.index( row, column );
00153 model.setData( index, QVariant( data ), Qt::DisplayRole );
00154 }
00155
00156 void Widget::setDataCell( int row, int column, QPair< double, double > data )
00157 {
00158 if ( ! checkDatasetWidth( 2 ))
00159 return;
00160
00161 QStandardItemModel & model = d->m_model;
00162
00163 justifyModelSize( row + 1, (column + 1) * 2 );
00164
00165 QModelIndex index = model.index( row, column * 2 );
00166 model.setData( index, QVariant( data.first ), Qt::DisplayRole );
00167
00168 index = model.index( row, column * 2 + 1 );
00169 model.setData( index, QVariant( data.second ), Qt::DisplayRole );
00170 }
00171
00172
00173
00174
00175 void Widget::resetData()
00176 {
00177 d->m_model.clear();
00178 d->usedDatasetWidth = 0;
00179 }
00180
00184 void Widget::setGlobalLeading( int left, int top, int right, int bottom )
00185 {
00186 d->m_chart.setGlobalLeading( left, top, right, bottom );
00187 }
00188
00192 void Widget::setGlobalLeadingLeft( int leading )
00193 {
00194 d->m_chart.setGlobalLeadingLeft( leading );
00195 }
00196
00200 int Widget::globalLeadingLeft() const
00201 {
00202 return d->m_chart.globalLeadingLeft();
00203 }
00204
00208 void Widget::setGlobalLeadingTop( int leading )
00209 {
00210 d->m_chart.setGlobalLeadingTop( leading );
00211 }
00212
00216 int Widget::globalLeadingTop() const
00217 {
00218 return d->m_chart.globalLeadingTop();
00219 }
00220
00224 void Widget::setGlobalLeadingRight( int leading )
00225 {
00226 d->m_chart.setGlobalLeadingRight( leading );
00227 }
00228
00232 int Widget::globalLeadingRight() const
00233 {
00234 return d->m_chart.globalLeadingRight();
00235 }
00236
00240 void Widget::setGlobalLeadingBottom( int leading )
00241 {
00242 d->m_chart.setGlobalLeadingBottom( leading );
00243 }
00244
00248 int Widget::globalLeadingBottom() const
00249 {
00250 return d->m_chart.globalLeadingBottom();
00251 }
00252
00256 KDChart::HeaderFooter* Widget::firstHeaderFooter()
00257 {
00258 return d->m_chart.headerFooter();
00259 }
00260
00264 QList<KDChart::HeaderFooter*> Widget::allHeadersFooters()
00265 {
00266 return d->m_chart.headerFooters();
00267 }
00268
00272 void Widget::addHeaderFooter( const QString& text,
00273 HeaderFooter::HeaderFooterType type,
00274 Position position)
00275 {
00276 HeaderFooter* newHeader = new HeaderFooter( &d->m_chart );
00277 newHeader->setType( type );
00278 newHeader->setPosition( position );
00279 newHeader->setText( text );
00280 d->m_chart.addHeaderFooter( newHeader );
00281 }
00282
00286 void Widget::addHeaderFooter( HeaderFooter* header )
00287 {
00288 header->setParent( &d->m_chart );
00289 d->m_chart.addHeaderFooter( header );
00290 }
00291
00292 void Widget::replaceHeaderFooter( HeaderFooter* header, HeaderFooter* oldHeader )
00293 {
00294 header->setParent( &d->m_chart );
00295 d->m_chart.replaceHeaderFooter( header, oldHeader );
00296 }
00297
00298 void Widget::takeHeaderFooter( HeaderFooter* header )
00299 {
00300 d->m_chart.takeHeaderFooter( header );
00301 }
00302
00306 KDChart::Legend* Widget::legend()
00307 {
00308 return d->m_chart.legend();
00309 }
00310
00314 QList<KDChart::Legend*> Widget::allLegends()
00315 {
00316 return d->m_chart.legends();
00317 }
00318
00322 void Widget::addLegend( Position position )
00323 {
00324 Legend* legend = new Legend( diagram(), &d->m_chart );
00325 legend->setPosition( position );
00326 d->m_chart.addLegend( legend );
00327 }
00328
00332 void Widget::addLegend( Legend* legend )
00333 {
00334 legend->setDiagram( diagram() );
00335 legend->setParent( &d->m_chart );
00336 d->m_chart.addLegend( legend );
00337 }
00338
00339 void Widget::replaceLegend( Legend* legend, Legend* oldLegend )
00340 {
00341 legend->setDiagram( diagram() );
00342 legend->setParent( &d->m_chart );
00343 d->m_chart.replaceLegend( legend, oldLegend );
00344 }
00345
00346 void Widget::takeLegend( Legend* legend )
00347 {
00348 d->m_chart.takeLegend( legend );
00349 }
00350
00351 AbstractDiagram* Widget::diagram()
00352 {
00353 if ( coordinatePlane() == 0 )
00354 qDebug() << "diagram(): coordinatePlane() was NULL";
00355
00356 return coordinatePlane()->diagram();
00357 }
00358
00359 BarDiagram* Widget::barDiagram()
00360 {
00361 return dynamic_cast<BarDiagram*>( diagram() );
00362 }
00363 LineDiagram* Widget::lineDiagram()
00364 {
00365 return dynamic_cast<LineDiagram*>( diagram() );
00366 }
00367 Plotter* Widget::plotter()
00368 {
00369 return dynamic_cast<Plotter*>( diagram() );
00370 }
00371 PieDiagram* Widget::pieDiagram()
00372 {
00373 return dynamic_cast<PieDiagram*>( diagram() );
00374 }
00375 RingDiagram* Widget::ringDiagram()
00376 {
00377 return dynamic_cast<RingDiagram*>( diagram() );
00378 }
00379 PolarDiagram* Widget::polarDiagram()
00380 {
00381 return dynamic_cast<PolarDiagram*>( diagram() );
00382 }
00383
00384 AbstractCoordinatePlane* Widget::coordinatePlane()
00385 {
00386 return d->m_chart.coordinatePlane();
00387 }
00388
00389 static bool isCartesian( KDChart::Widget::ChartType type )
00390 {
00391 return (type == KDChart::Widget::Bar) || (type == KDChart::Widget::Line);
00392 }
00393
00394 static bool isPolar( KDChart::Widget::ChartType type )
00395 {
00396 return (type == KDChart::Widget::Pie)
00397 || (type == KDChart::Widget::Ring)
00398 || (type == KDChart::Widget::Polar);
00399 }
00400
00401 void Widget::setType( ChartType chartType, SubType chartSubType )
00402 {
00403 AbstractDiagram* diag = 0;
00404 const ChartType oldType = type();
00405
00406 if ( chartType != oldType ){
00407 if( chartType != NoType ){
00408 if ( isCartesian( chartType ) && ! isCartesian( oldType ) )
00409 {
00410 if( coordinatePlane() == &d->m_polPlane ){
00411 d->m_chart.takeCoordinatePlane( &d->m_polPlane );
00412 d->m_chart.addCoordinatePlane( &d->m_cartPlane );
00413 }else{
00414 d->m_chart.replaceCoordinatePlane( &d->m_cartPlane );
00415 }
00416 }
00417 else if ( isPolar( chartType ) && ! isPolar( oldType ) )
00418 {
00419 if( coordinatePlane() == &d->m_cartPlane ){
00420 d->m_chart.takeCoordinatePlane( &d->m_cartPlane );
00421 d->m_chart.addCoordinatePlane( &d->m_polPlane );
00422 }else{
00423 d->m_chart.replaceCoordinatePlane( &d->m_polPlane );
00424 }
00425 }
00426 }
00427 switch ( chartType ){
00428 case Bar:
00429 diag = new BarDiagram( &d->m_chart, &d->m_cartPlane );
00430 break;
00431 case Line:
00432 diag = new LineDiagram( &d->m_chart, &d->m_cartPlane );
00433 break;
00434 case Plot:
00435 diag = new Plotter( &d->m_chart, &d->m_cartPlane );
00436 break;
00437 case Pie:
00438 diag = new PieDiagram( &d->m_chart, &d->m_polPlane );
00439 break;
00440 case Polar:
00441 diag = new PolarDiagram( &d->m_chart, &d->m_polPlane );
00442 break;
00443 case Ring:
00444 diag = new RingDiagram( &d->m_chart, &d->m_polPlane );
00445 break;
00446 case NoType:
00447 break;
00448 }
00449 if ( diag != NULL ){
00450 if ( isCartesian( oldType ) && isCartesian( chartType ) ){
00451 AbstractCartesianDiagram *oldDiag =
00452 qobject_cast<AbstractCartesianDiagram*>( coordinatePlane()->diagram() );
00453 AbstractCartesianDiagram *newDiag =
00454 qobject_cast<AbstractCartesianDiagram*>( diag );
00455 Q_FOREACH( CartesianAxis* axis, oldDiag->axes() ) {
00456 oldDiag->takeAxis( axis );
00457 newDiag->addAxis ( axis );
00458 }
00459 }
00460 diag->setModel( &d->m_model );
00461 coordinatePlane()->replaceDiagram( diag );
00462
00463 LegendList legends = d->m_chart.legends();
00464 Q_FOREACH(Legend* l, legends)
00465 l->setDiagram( diag );
00466
00467 }
00468
00469 }
00470
00471 if ( chartType != NoType ){
00472 if ( chartType != oldType || chartSubType != subType() )
00473 setSubType( chartSubType );
00474 d->m_chart.resize( size() );
00475 }
00476 }
00477
00478 void Widget::setSubType( SubType subType )
00479 {
00480 BarDiagram* barDia = qobject_cast< BarDiagram* >( diagram() );
00481 LineDiagram* lineDia = qobject_cast< LineDiagram* >( diagram() );
00482 Plotter* plotterDia = qobject_cast< Plotter* >( diagram() );
00483
00484
00485
00486
00487
00488
00489 #define SET_SUB_TYPE(DIAGRAM, SUBTYPE) \
00490 { \
00491 if( DIAGRAM ) \
00492 DIAGRAM->setType( SUBTYPE ); \
00493 }
00494 switch ( subType )
00495 {
00496 case Normal:
00497 SET_SUB_TYPE( barDia, BarDiagram::Normal );
00498 SET_SUB_TYPE( lineDia, LineDiagram::Normal );
00499 SET_SUB_TYPE( plotterDia, Plotter::Normal );
00500 break;
00501 case Stacked:
00502 SET_SUB_TYPE( barDia, BarDiagram::Stacked );
00503 SET_SUB_TYPE( lineDia, LineDiagram::Stacked );
00504
00505 break;
00506 case Percent:
00507 SET_SUB_TYPE( barDia, BarDiagram::Percent );
00508 SET_SUB_TYPE( lineDia, LineDiagram::Percent );
00509 SET_SUB_TYPE( plotterDia, Plotter::Percent );
00510 break;
00511 case Rows:
00512 SET_SUB_TYPE( barDia, BarDiagram::Rows );
00513 break;
00514 default:
00515 Q_ASSERT_X ( false,
00516 "Widget::setSubType", "Sub-type not supported!" );
00517 break;
00518 }
00519
00520 }
00521
00525 Widget::ChartType Widget::type() const
00526 {
00527
00528 AbstractDiagram * const dia = const_cast<Widget*>( this )->diagram();
00529 if ( qobject_cast< BarDiagram* >( dia ) )
00530 return Bar;
00531 else if ( qobject_cast< LineDiagram* >( dia ) )
00532 return Line;
00533 else if ( qobject_cast< Plotter* >( dia ) )
00534 return Plot;
00535 else if( qobject_cast< PieDiagram* >( dia ) )
00536 return Pie;
00537 else if( qobject_cast< PolarDiagram* >( dia ) )
00538 return Polar;
00539 else if( qobject_cast< RingDiagram* >( dia ) )
00540 return Ring;
00541 else
00542 return NoType;
00543 }
00544
00545 Widget::SubType Widget::subType() const
00546 {
00547
00548 Widget::SubType retVal = Normal;
00549
00550 AbstractDiagram * const dia = const_cast<Widget*>( this )->diagram();
00551 BarDiagram* barDia = qobject_cast< BarDiagram* >( dia );
00552 LineDiagram* lineDia = qobject_cast< LineDiagram* >( dia );
00553 Plotter* plotterDia = qobject_cast< Plotter* >( dia );
00554
00555
00556
00557
00558
00559
00560 #define TEST_SUB_TYPE(DIAGRAM, INTERNALSUBTYPE, SUBTYPE) \
00561 { \
00562 if( DIAGRAM && DIAGRAM->type() == INTERNALSUBTYPE ) \
00563 retVal = SUBTYPE; \
00564 }
00565 const Widget::ChartType mainType = type();
00566 switch ( mainType )
00567 {
00568 case Bar:
00569 TEST_SUB_TYPE( barDia, BarDiagram::Normal, Normal );
00570 TEST_SUB_TYPE( barDia, BarDiagram::Stacked, Stacked );
00571 TEST_SUB_TYPE( barDia, BarDiagram::Percent, Percent );
00572 TEST_SUB_TYPE( barDia, BarDiagram::Rows, Rows );
00573 break;
00574 case Line:
00575 TEST_SUB_TYPE( lineDia, LineDiagram::Normal, Normal );
00576 TEST_SUB_TYPE( lineDia, LineDiagram::Stacked, Stacked );
00577 TEST_SUB_TYPE( lineDia, LineDiagram::Percent, Percent );
00578 break;
00579 case Plot:
00580 TEST_SUB_TYPE( plotterDia, Plotter::Normal, Normal );
00581 TEST_SUB_TYPE( plotterDia, Plotter::Percent, Percent );
00582 break;
00583 case Pie:
00584
00585 break;
00586 case Polar:
00587
00588 break;
00589 case Ring:
00590
00591 break;
00592 default:
00593 Q_ASSERT_X ( false,
00594 "Widget::subType", "Chart type not supported!" );
00595 break;
00596 }
00597 return retVal;
00598 }
00599
00600
00604 bool Widget::checkDatasetWidth( int width )
00605 {
00606 if( width == diagram()->datasetDimension() )
00607 {
00608 d->usedDatasetWidth = width;
00609 return true;
00610 }
00611 qDebug() << "The current diagram type doesn't support this data dimension.";
00612 return false;
00613
00614
00615
00616
00617
00618
00619
00620 }
00621
00625 void Widget::justifyModelSize( int rows, int columns )
00626 {
00627 QAbstractItemModel & model = d->m_model;
00628 const int currentRows = model.rowCount();
00629 const int currentCols = model.columnCount();
00630
00631 if ( currentCols < columns )
00632 if ( ! model.insertColumns( currentCols, columns - currentCols ))
00633 qDebug() << "justifyModelSize: could not increase model size.";
00634 if ( currentRows < rows )
00635 if ( ! model.insertRows( currentRows, rows - currentRows ))
00636 qDebug() << "justifyModelSize: could not increase model size.";
00637
00638 Q_ASSERT( model.rowCount() >= rows );
00639 Q_ASSERT( model.columnCount() >= columns );
00640 }