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 <KDChartCartesianCoordinatePlane.h>
00036 #include <KDChartChart.h>
00037 #include <KDChartAbstractCoordinatePlane.h>
00038 #include <KDChartLineDiagram.h>
00039 #include <KDChartPieDiagram.h>
00040 #include <KDChartPolarCoordinatePlane.h>
00041 #include <KDChartPolarDiagram.h>
00042 #include <KDChartRingDiagram.h>
00043 #include <KDChartLegend.h>
00044
00045 #include <QDebug>
00046
00047 #include <KDABLibFakes>
00048
00049 #define d d_func()
00050
00051 using namespace KDChart;
00052
00053 Widget::Private::Private( Widget * qq )
00054 : q( qq ),
00055 layout( q ),
00056 m_model( q ),
00057 m_chart( q ),
00058 usedDatasetWidth( 0 )
00059 {
00060 KDAB_SET_OBJECT_NAME( layout );
00061 KDAB_SET_OBJECT_NAME( m_model );
00062 KDAB_SET_OBJECT_NAME( m_chart );
00063
00064 layout.addWidget( &m_chart );
00065 }
00066
00067 Widget::Private::~Private() {}
00068
00069
00082 Widget::Widget( QWidget* parent ) :
00083 QWidget(parent), _d( new Private( this ) )
00084 {
00085
00086
00087 setType( Line );
00088 }
00089
00093 Widget::~Widget()
00094 {
00095 delete _d; _d = 0;
00096 }
00097
00098 void Widget::init()
00099 {
00100 }
00101
00102 void Widget::setDataset( int column, const QVector< double > & data, const QString& title )
00103 {
00104 if ( ! checkDatasetWidth( 1 ) )
00105 return;
00106
00107 QStandardItemModel & model = d->m_model;
00108
00109 justifyModelSize( data.size(), column + 1 );
00110
00111 for( int i = 0; i < data.size(); ++i )
00112 {
00113 const QModelIndex index = model.index( i, column );
00114 model.setData( index, QVariant( data[i] ), Qt::DisplayRole );
00115 }
00116 if ( ! title.isEmpty() )
00117 model.setHeaderData( column, Qt::Horizontal, QVariant( title ) );
00118 }
00119
00120 void Widget::setDataset( int column, const QVector< QPair< double, double > > & data, const QString& title )
00121 {
00122 if ( ! checkDatasetWidth( 2 ))
00123 return;
00124
00125 QStandardItemModel & model = d->m_model;
00126
00127 justifyModelSize( data.size(), (column + 1) * 2 );
00128
00129 for( int i = 0; i < data.size(); ++i )
00130 {
00131 QModelIndex index = model.index( i, column * 2 );
00132 model.setData( index, QVariant( data[i].first ), Qt::DisplayRole );
00133
00134 index = model.index( i, column * 2 + 1 );
00135 model.setData( index, QVariant( data[i].second ), Qt::DisplayRole );
00136 }
00137 if ( ! title.isEmpty() ){
00138 model.setHeaderData( column * 2, Qt::Horizontal, QVariant( title ) );
00139 model.setHeaderData( column * 2+1, 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 PieDiagram* Widget::pieDiagram()
00368 {
00369 return dynamic_cast<PieDiagram*>( diagram() );
00370 }
00371 RingDiagram* Widget::ringDiagram()
00372 {
00373 return dynamic_cast<RingDiagram*>( diagram() );
00374 }
00375 PolarDiagram* Widget::polarDiagram()
00376 {
00377 return dynamic_cast<PolarDiagram*>( diagram() );
00378 }
00379
00380 AbstractCoordinatePlane* Widget::coordinatePlane()
00381 {
00382 return d->m_chart.coordinatePlane();
00383 }
00384
00385 static bool isCartesian( KDChart::Widget::ChartType type )
00386 {
00387 return (type == KDChart::Widget::Bar || type == KDChart::Widget::Line);
00388 }
00389
00390 static bool isPolar( KDChart::Widget::ChartType type )
00391 {
00392 return (type == KDChart::Widget::Pie
00393 || type == KDChart::Widget::Ring
00394 || type == KDChart::Widget::Polar );
00395 }
00396
00397 void Widget::setType( ChartType chartType, SubType chartSubType )
00398 {
00399 AbstractDiagram* diag = 0;
00400 CartesianCoordinatePlane* cartPlane = 0;
00401 PolarCoordinatePlane* polPlane = 0;
00402
00403
00404 if ( chartType != type() ){
00405 switch ( chartType )
00406 {
00407 case Bar:
00408 diag = new BarDiagram( &d->m_chart, cartPlane );
00409 break;
00410 case Line:
00411 diag = new LineDiagram( &d->m_chart, cartPlane );
00412 break;
00413 case Pie:
00414 diag = new PieDiagram( &d->m_chart, polPlane );
00415 break;
00416 case Polar:
00417 diag = new PolarDiagram( &d->m_chart, polPlane );
00418 break;
00419 case Ring:
00420 diag = new RingDiagram( &d->m_chart, polPlane );
00421 break;
00422 case NoType:
00423 break;
00424 }
00425 if ( diag != NULL )
00426 {
00427 if ( isPolar( type() ) && isCartesian( chartType ) )
00428 {
00429 cartPlane = new CartesianCoordinatePlane( &d->m_chart );
00430 d->m_chart.replaceCoordinatePlane( cartPlane );
00431 }
00432 else if ( isCartesian( type() ) && isPolar( chartType ) )
00433 {
00434 polPlane = new PolarCoordinatePlane( &d->m_chart );
00435 d->m_chart.replaceCoordinatePlane( polPlane );
00436 }
00437 else if ( isCartesian( type() ) && isCartesian( chartType ) )
00438 {
00439 AbstractCartesianDiagram *old =
00440 qobject_cast<AbstractCartesianDiagram*>( d->m_chart.coordinatePlane()->diagram() );
00441 Q_FOREACH( CartesianAxis* axis, old->axes() ) {
00442 old->takeAxis( axis );
00443 qobject_cast<AbstractCartesianDiagram*>(diag)->addAxis( axis );
00444 }
00445 }
00446 diag->setModel( &d->m_model );
00447 coordinatePlane()->replaceDiagram( diag );
00448
00449 LegendList legends = d->m_chart.legends();
00450 Q_FOREACH(Legend* l, legends)
00451 l->setDiagram( diag );
00452 if( d->usedDatasetWidth )
00453 diag->setDatasetDimension( d->usedDatasetWidth );
00454 }
00455 }
00456
00457 if ( chartSubType != subType() )
00458 setSubType( chartSubType );
00459
00460 }
00461
00462 void Widget::setSubType( SubType subType )
00463 {
00464 BarDiagram* barDia = qobject_cast< BarDiagram* >( diagram() );
00465 LineDiagram* lineDia = qobject_cast< LineDiagram* >( diagram() );
00466
00467
00468
00469
00470
00471
00472 #define SET_SUB_TYPE(DIAGRAM, SUBTYPE) \
00473 { \
00474 if( DIAGRAM ) \
00475 DIAGRAM->setType( SUBTYPE ); \
00476 }
00477 switch ( subType )
00478 {
00479 case Normal:
00480 SET_SUB_TYPE( barDia, BarDiagram::Normal );
00481 SET_SUB_TYPE( lineDia, LineDiagram::Normal );
00482 break;
00483 case Stacked:
00484 SET_SUB_TYPE( barDia, BarDiagram::Stacked );
00485 SET_SUB_TYPE( lineDia, LineDiagram::Stacked );
00486 break;
00487 case Percent:
00488 SET_SUB_TYPE( barDia, BarDiagram::Percent );
00489 SET_SUB_TYPE( lineDia, LineDiagram::Percent );
00490 break;
00491 case Rows:
00492 SET_SUB_TYPE( barDia, BarDiagram::Rows );
00493 break;
00494 default:
00495 Q_ASSERT_X ( false,
00496 "Widget::setSubType", "Sub-type not supported!" );
00497 break;
00498 }
00499
00500 }
00501
00505 Widget::ChartType Widget::type() const
00506 {
00507
00508 AbstractDiagram * const dia = const_cast<Widget*>( this )->diagram();
00509 if ( qobject_cast< BarDiagram* >( dia ) )
00510 return Bar;
00511 else if ( qobject_cast< LineDiagram* >( dia ) )
00512 return Line;
00513 else if( qobject_cast< PieDiagram* >( dia ) )
00514 return Pie;
00515 else if( qobject_cast< PolarDiagram* >( dia ) )
00516 return Polar;
00517 else if( qobject_cast< RingDiagram* >( dia ) )
00518 return Ring;
00519 else
00520 return NoType;
00521 }
00522
00523 Widget::SubType Widget::subType() const
00524 {
00525
00526 Widget::SubType retVal = Normal;
00527
00528 AbstractDiagram * const dia = const_cast<Widget*>( this )->diagram();
00529 BarDiagram* barDia = qobject_cast< BarDiagram* >( dia );
00530 LineDiagram* lineDia = qobject_cast< LineDiagram* >( dia );
00531
00532
00533
00534
00535
00536
00537 #define TEST_SUB_TYPE(DIAGRAM, INTERNALSUBTYPE, SUBTYPE) \
00538 { \
00539 if( DIAGRAM && DIAGRAM->type() == INTERNALSUBTYPE ) \
00540 retVal = SUBTYPE; \
00541 }
00542 const Widget::ChartType mainType = type();
00543 switch ( mainType )
00544 {
00545 case Bar:
00546 TEST_SUB_TYPE( barDia, BarDiagram::Normal, Normal );
00547 TEST_SUB_TYPE( barDia, BarDiagram::Stacked, Stacked );
00548 TEST_SUB_TYPE( barDia, BarDiagram::Percent, Percent );
00549 TEST_SUB_TYPE( barDia, BarDiagram::Rows, Rows );
00550 break;
00551 case Line:
00552 TEST_SUB_TYPE( lineDia, LineDiagram::Normal, Normal );
00553 TEST_SUB_TYPE( lineDia, LineDiagram::Stacked, Stacked );
00554 TEST_SUB_TYPE( lineDia, LineDiagram::Percent, Percent );
00555 break;
00556 case Pie:
00557
00558 break;
00559 case Polar:
00560
00561 break;
00562 case Ring:
00563
00564 break;
00565 default:
00566 Q_ASSERT_X ( false,
00567 "Widget::subType", "Chart type not supported!" );
00568 break;
00569 }
00570 return retVal;
00571 }
00572
00573
00577 bool Widget::checkDatasetWidth( int width )
00578 {
00579 if ( d->usedDatasetWidth == width || d->usedDatasetWidth == 0 ) {
00580 d->usedDatasetWidth = width;
00581 diagram()->setDatasetDimension( width );
00582
00583 return true;
00584 }
00585 qDebug() << "It's impossible to mix up the different setDataset() methods on the same widget.";
00586 return false;
00587 }
00588
00592 void Widget::justifyModelSize( int rows, int columns )
00593 {
00594 QAbstractItemModel & model = d->m_model;
00595 const int currentRows = model.rowCount();
00596 const int currentCols = model.columnCount();
00597
00598 if ( currentRows < rows )
00599 if ( ! model.insertRows( currentRows, rows - currentRows ))
00600 qDebug() << "justifyModelSize: could not increase model size.";
00601
00602 if ( currentCols < columns )
00603 if ( ! model.insertColumns( currentCols, columns - currentCols ))
00604 qDebug() << "justifyModelSize: could not increase model size.";
00605 }
00606