Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

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-2006 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 <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     // as default we have a cartesian coordinate plane ...
00086     // ... and a line diagram
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  * 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 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 //    coordinatePlane()->show();
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 //FIXME(khz): Add the impl for these chart types - or remove them from here:
00468 //    PieDiagram*   pieDia   = qobject_cast< PieDiagram* >(   diagram() );
00469 //    PolarDiagram* polarDia = qobject_cast< PolarDiagram* >( diagram() );
00470 //    RingDiagram*  ringDia  = qobject_cast< RingDiagram* >(  diagram() );
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 //    coordinatePlane()->show();
00500 }
00501 
00505 Widget::ChartType Widget::type() const
00506 {
00507     // PENDING(christoph) save the type out-of-band:
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     // PENDING(christoph) save the type out-of-band:
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 //FIXME(khz): Add the impl for these chart types - or remove them from here:
00533 //    PieDiagram*   pieDia   = qobject_cast< PieDiagram* >(   diagram() );
00534 //    PolarDiagram* polarDia = qobject_cast< PolarDiagram* >( diagram() );
00535 //    RingDiagram*  ringDia  = qobject_cast< RingDiagram* >(  diagram() );
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            // no impl. yet
00558            break;
00559         case Polar:
00560            // no impl. yet
00561            break;
00562         case Ring:
00563            // no impl. yet
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         //qDebug() << "KDChart::Widget::checkDatasetWidth():  DatasetWidth is set to" << width << "now.";
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 

Generated on Thu May 10 11:06:26 2007 for KD Chart 2 by doxygen 1.3.6