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