KDChartWidget.cpp

Go to the documentation of this file.
00001 /* -*- Mode: C++ -*-
00002    KDChart - a multi-platform charting engine
00003    */
00004 
00005 /****************************************************************************
00006  ** Copyright (C) 2001-2007 Klarälvdalens Datakonsult AB.  All rights reserved.
00007  **
00008  ** This file is part of the KD Chart library.
00009  **
00010  ** This file may be distributed and/or modified under the terms of the
00011  ** GNU General Public License version 2 as published by the Free Software
00012  ** Foundation and appearing in the file LICENSE.GPL included in the
00013  ** packaging of this file.
00014  **
00015  ** Licensees holding valid commercial KD Chart licenses may use this file in
00016  ** accordance with the KD Chart Commercial License Agreement provided with
00017  ** the Software.
00018  **
00019  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021  **
00022  ** See http://www.kdab.net/kdchart for
00023  **   information about KD Chart Commercial License Agreements.
00024  **
00025  ** Contact info@kdab.net if any conditions of this
00026  ** licensing are not clear to you.
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     // as default we have a cartesian coordinate plane ...
00087     // ... and a line diagram
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  * Resets all data.
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 ); // we need this explicit call !
00281 }
00282 
00286 void Widget::addHeaderFooter( HeaderFooter* header )
00287 {
00288     header->setParent( &d->m_chart );
00289     d->m_chart.addHeaderFooter( header ); // we need this explicit call !
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             //checkDatasetWidth( d->usedDatasetWidth );
00467         }
00468         //coordinatePlane()->setGridNeedsRecalculate();
00469     }
00470 
00471     if ( chartType != NoType ){
00472         if ( chartType != oldType || chartSubType != subType() )
00473             setSubType( chartSubType );
00474         d->m_chart.resize( size() ); // triggering immediate update
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 //FIXME(khz): Add the impl for these chart types - or remove them from here:
00485 //    PieDiagram*   pieDia   = qobject_cast< PieDiagram* >(   diagram() );
00486 //    PolarDiagram* polarDia = qobject_cast< PolarDiagram* >( diagram() );
00487 //    RingDiagram*  ringDia  = qobject_cast< RingDiagram* >(  diagram() );
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            //SET_SUB_TYPE( plotterDia, Plotter::Stacked );
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 //    coordinatePlane()->show();
00520 }
00521 
00525 Widget::ChartType Widget::type() const
00526 {
00527     // PENDING(christoph) save the type out-of-band:
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     // PENDING(christoph) save the type out-of-band:
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 //FIXME(khz): Add the impl for these chart types - or remove them from here:
00556 //    PieDiagram*   pieDia   = qobject_cast< PieDiagram* >(   diagram() );
00557 //    PolarDiagram* polarDia = qobject_cast< PolarDiagram* >( diagram() );
00558 //    RingDiagram*  ringDia  = qobject_cast< RingDiagram* >(  diagram() );
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            // no impl. yet
00585            break;
00586         case Polar:
00587            // no impl. yet
00588            break;
00589         case Ring:
00590            // no impl. yet
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 /*    if ( d->usedDatasetWidth == width || d->usedDatasetWidth == 0 ) {
00614         d->usedDatasetWidth = width;
00615         diagram()->setDatasetDimension( width );
00616         return true;
00617     }
00618     qDebug() << "It's impossible to mix up the different setDataset() methods on the same widget.";
00619     return false;*/
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 }

Generated on Thu Mar 4 23:19:13 2010 for KD Chart 2 by  doxygen 1.5.4