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

KDChartLineDiagram.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002  ** Copyright (C) 2006 Klarävdalens Datakonsult AB.  All rights reserved.
00003  **
00004  ** This file is part of the KD Chart library.
00005  **
00006  ** This file may be distributed and/or modified under the terms of the
00007  ** GNU General Public License version 2 as published by the Free Software
00008  ** Foundtion and appearing in the file LICENSE.GPL included in the
00009  ** packaging of this file.
00010  **
00011  ** Licensees holding valid commercial KD Chart licenses may use this file in
00012  ** accordance with the KD Chart Commercial License Agreement provided with
00013  ** the Software.
00014  **
00015  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00016  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00017  **
00018  ** See http://www.kdab.net/kdchart for
00019  **   information about KDChart Commercial License Agreements.
00020  **
00021  ** Contact info@kdab.net if any conditions of this
00022  ** licensing are not clear to you.
00023  **
00024  **********************************************************************/
00025 
00026 #include <QDebug>
00027 #include <QPainter>
00028 #include <QString>
00029 #include <QPainterPath>
00030 #include <QPen>
00031 #include <QVector>
00032 
00033 #include "KDChartLineDiagram.h"
00034 #include "KDChartLineDiagram_p.h"
00035 #include "KDChartBarDiagram.h"
00036 #include "KDChartPalette.h"
00037 #include "KDChartPosition.h"
00038 #include "KDChartTextAttributes.h"
00039 #include "KDChartThreeDLineAttributes.h"
00040 #include "KDChartAttributesModel.h"
00041 #include "KDChartAbstractGrid.h"
00042 #include "KDChartDataValueAttributes.h"
00043 
00044 #include <KDABLibFakes>
00045 
00046 
00047 using namespace KDChart;
00048 
00049 LineDiagram::Private::Private()
00050   :lineType ( Normal )
00051 {
00052 }
00053 
00054 LineDiagram::Private::~Private() {}
00055 
00056 
00057 #define d d_func()
00058 
00059 
00060 LineDiagram::LineDiagram( QWidget* parent, CartesianCoordinatePlane* plane ) :
00061     AbstractCartesianDiagram( new Private(), parent, plane )
00062 {
00063     init();
00064 }
00065 
00066 void LineDiagram::init()
00067 {
00068 }
00069 
00070 LineDiagram::~LineDiagram()
00071 {
00072 }
00073 
00074 LineDiagram * LineDiagram::clone() const
00075 {
00076     return new LineDiagram( new Private( *d ) );
00077 }
00078 
00079 
00080 bool LineDiagram::compare( const LineDiagram* other )const
00081 {
00082     if( other == this ) return true;
00083     if( ! other ){
00084         //qDebug() << "LineDiagram::compare() cannot compare to Null pointer";
00085         return false;
00086     }
00087     /*
00088     qDebug() <<"\n             LineDiagram::compare():";
00089             // compare own properties
00090     qDebug() << (type() == other->type());
00091     */
00092     return  // compare the base class
00093             ( static_cast<const AbstractCartesianDiagram*>(this)->compare( other ) ) &&
00094             // compare own properties
00095             (type() == other->type());
00096 }
00097 
00098 
00099 void LineDiagram::setType( const LineType type )
00100 {
00101    if ( d->lineType == type ) return;
00102    if ( type != LineDiagram::Normal && datasetDimension() > 1 ) {
00103        Q_ASSERT_X ( false, "setType()",
00104                     "This line chart type can't be used with multi-dimensional data." );
00105        return;
00106    }
00107    d->lineType = type;
00108    // AbstractAxis settings - see AbstractDiagram and CartesianAxis
00109    setPercentMode( type == LineDiagram::Percent );
00110    setDataBoundariesDirty();
00111    emit layoutChanged( this );
00112    emit propertiesChanged();
00113 }
00114 
00115 LineDiagram::LineType LineDiagram::type() const
00116 {
00117    return d->lineType;
00118 }
00119 
00120 void LineDiagram::setLineAttributes( const LineAttributes & ta )
00121 {
00122      d->attributesModel->setModelData(
00123         qVariantFromValue( ta ),
00124         LineAttributesRole );
00125    emit propertiesChanged();
00126 }
00127 
00128 void LineDiagram::setLineAttributes(
00129         int column,
00130     const LineAttributes & ta )
00131 {
00132     d->attributesModel->setHeaderData(
00133             column,
00134             Qt::Vertical,
00135             qVariantFromValue( ta ),
00136             LineAttributesRole );
00137     emit propertiesChanged();
00138 }
00139 
00140 void LineDiagram::resetLineAttributes( int column )
00141 {
00142     d->attributesModel->resetHeaderData(
00143             column, Qt::Vertical, LineAttributesRole );
00144     emit propertiesChanged();
00145 }
00146 
00147 void LineDiagram::setLineAttributes(
00148         const QModelIndex & index,
00149     const LineAttributes & ta )
00150 {
00151     d->attributesModel->setData(
00152             d->attributesModel->mapFromSource(index),
00153     qVariantFromValue( ta ),
00154     LineAttributesRole );
00155     emit propertiesChanged();
00156 }
00157 
00161 void LineDiagram::resetLineAttributes( const QModelIndex & index )
00162 {
00163     d->attributesModel->resetData(
00164             d->attributesModel->mapFromSource(index), LineAttributesRole );
00165     emit propertiesChanged();
00166 }
00167 
00168 LineAttributes LineDiagram::lineAttributes() const
00169 {
00170     return qVariantValue<LineAttributes>(
00171         d->attributesModel->data( KDChart::LineAttributesRole ) );
00172 }
00173 
00174 LineAttributes LineDiagram::lineAttributes( int column ) const
00175 {
00176     return qVariantValue<LineAttributes>(
00177         d->attributesModel->data(
00178             d->attributesModel->mapFromSource( columnToIndex( column ) ),
00179             KDChart::LineAttributesRole ) );
00180 }
00181 
00182 LineAttributes LineDiagram::lineAttributes(
00183     const QModelIndex & index ) const
00184 {
00185     return qVariantValue<LineAttributes>(
00186         d->attributesModel->data(
00187             d->attributesModel->mapFromSource(index),
00188             KDChart::LineAttributesRole ) );
00189 }
00190 
00191 void LineDiagram::setThreeDLineAttributes(
00192     const ThreeDLineAttributes & ta )
00193 {
00194     setDataBoundariesDirty();
00195     d->attributesModel->setModelData(
00196         qVariantFromValue( ta ),
00197         ThreeDLineAttributesRole );
00198    emit propertiesChanged();
00199 }
00200 
00201 void LineDiagram::setThreeDLineAttributes(
00202     int column,
00203     const ThreeDLineAttributes & ta )
00204 {
00205     setDataBoundariesDirty();
00206     d->attributesModel->setHeaderData(
00207         column,
00208         Qt::Vertical,
00209         qVariantFromValue( ta ),
00210         ThreeDLineAttributesRole );
00211    emit propertiesChanged();
00212 }
00213 
00214 void LineDiagram::setThreeDLineAttributes(
00215     const QModelIndex & index,
00216     const ThreeDLineAttributes & ta )
00217 {
00218     setDataBoundariesDirty();
00219     d->attributesModel->setData(
00220         d->attributesModel->mapFromSource(index),
00221         qVariantFromValue( ta ),
00222         ThreeDLineAttributesRole );
00223    emit propertiesChanged();
00224 }
00225 
00226 ThreeDLineAttributes LineDiagram::threeDLineAttributes() const
00227 {
00228     return qVariantValue<ThreeDLineAttributes>(
00229         d->attributesModel->data( KDChart::ThreeDLineAttributesRole ) );
00230 }
00231 
00232 ThreeDLineAttributes LineDiagram::threeDLineAttributes( int column ) const
00233 {
00234     return qVariantValue<ThreeDLineAttributes>(
00235         d->attributesModel->data(
00236             d->attributesModel->mapFromSource( columnToIndex( column ) ),
00237             KDChart::ThreeDLineAttributesRole ) );
00238 }
00239 
00240 ThreeDLineAttributes LineDiagram::threeDLineAttributes(
00241     const QModelIndex & index ) const
00242 {
00243     return qVariantValue<ThreeDLineAttributes>(
00244         d->attributesModel->data(
00245             d->attributesModel->mapFromSource( index ),
00246             KDChart::ThreeDLineAttributesRole ) );
00247 }
00248 
00249 double LineDiagram::threeDItemDepth( const QModelIndex & index ) const
00250 {
00251     return threeDLineAttributes( index ).validDepth();
00252 }
00253 
00254 double LineDiagram::threeDItemDepth( int column ) const
00255 {
00256     return qVariantValue<ThreeDLineAttributes>(
00257         d->attributesModel->headerData (
00258             column,
00259             Qt::Vertical,
00260             KDChart::ThreeDLineAttributesRole ) ).validDepth();
00261 }
00262 
00263 void LineDiagram::resizeEvent ( QResizeEvent* )
00264 {
00265 }
00266 
00267 const QPair<QPointF, QPointF> LineDiagram::calculateDataBoundaries() const
00268 {
00269     if ( !checkInvariants( true ) ) return QPair<QPointF, QPointF>( QPointF( 0, 0 ), QPointF( 0, 0 ) );
00270 
00271     // note: calculateDataBoundaries() is ignoring the hidden flags.
00272     //       That's not a bug but a feature: Hiding data does not mean removing them.
00273     // For totally removing data from KD Chart's view people can use e.g. a proxy model ...
00274 
00275     const int rowCount = d->attributesModel->rowCount(attributesModelRootIndex());
00276     const int colCount = d->attributesModel->columnCount(attributesModelRootIndex());
00277     double xMin = 0;
00278     double xMax = rowCount -1;
00279     double yMin = 0, yMax = 0;
00280     bool bOK;
00281 
00282     // calculate boundaries for different line types Normal - Stacked - Percent - Default Normal
00283     switch ( type() ){
00284     case LineDiagram::Normal:
00285     {
00286         bool bStarting = true;
00287         for( int i = datasetDimension()-1; i < colCount; i += datasetDimension() ) {
00288             for ( int j=0; j< rowCount; ++j ) {
00289                 const double value = valueForCellTesting( j, i, bOK );
00290                 double xvalue;
00291                 if( datasetDimension() > 1 && bOK )
00292                     xvalue = valueForCellTesting( j, i-1, bOK );
00293                 if( bOK ){
00294                     if( bStarting ){
00295                         yMin = value;
00296                         yMax = value;
00297                     }else{
00298                         yMin = qMin( yMin, value );
00299                         yMax = qMax( yMax, value );
00300                     }
00301                     if ( datasetDimension() > 1 ) {
00302                         if( bStarting ){
00303                             xMin = xvalue;
00304                             xMax = xvalue;
00305                         }else{
00306                             xMin = qMin( xMin, xvalue );
00307                             xMax = qMax( xMax, xvalue );
00308                         }
00309                     }
00310                     bStarting = false;
00311                 }
00312             }
00313         }
00314 
00315         // the following code is replaced by CartesianCoordinatePlane's automatic range / zoom adjusting
00316         //if( yMin > 0 && yMax / yMin >= 2.0 )
00317         //    yMin = 0;
00318         //else if( yMax < 0 && yMax / yMin <= 0.5 )
00319         //    yMax = 0;
00320     }
00321     break;
00322     case LineDiagram::Stacked:
00323     {
00324         bool bStarting = true;
00325         for ( int j=0; j< rowCount; ++j ) {
00326             // calculate sum of values per column - Find out stacked Min/Max
00327             double stackedValues = 0;
00328             for( int i = datasetDimension()-1; i < colCount; i += datasetDimension() ) {
00329                 const double value = valueForCellTesting( j, i, bOK );
00330                 if( bOK )
00331                     stackedValues += value;
00332             }
00333             if( bStarting ){
00334                 yMin = stackedValues;
00335                 yMax = stackedValues;
00336                 bStarting = false;
00337             }else{
00338                 // Pending Michel:
00339                 // I am taking in account all values negatives or positives
00340                 // take in account all stacked values
00341                 yMin = qMin( qMin( yMin,  0.0 ), stackedValues );
00342                 yMax = qMax( yMax, stackedValues );
00343             }
00344         }
00345     }
00346     break;
00347     case LineDiagram::Percent:
00348     {
00349         for( int i = datasetDimension()-1; i < colCount; i += datasetDimension() ) {
00350             for ( int j=0; j< rowCount; ++j ) {
00351                 // Ordinate should begin at 0 the max value being the 100% pos
00352                 const double value = valueForCellTesting( j, i, bOK );
00353                 if( bOK )
00354                     yMax = qMax( yMax, value );
00355             }
00356         }
00357     }
00358     break;
00359     default:
00360         Q_ASSERT_X ( false, "calculateDataBoundaries()",
00361                      "Type item does not match a defined line chart Type." );
00362     }
00363 
00364     QPointF bottomLeft( QPointF( xMin, yMin ) );
00365     QPointF topRight(   QPointF( xMax, yMax ) );
00366     //qDebug() << "LineDiagram::calculateDataBoundaries () returns ( " << bottomLeft << topRight <<")";
00367     return QPair<QPointF, QPointF> ( bottomLeft, topRight );
00368 }
00369 
00370 
00371 void LineDiagram::paintEvent ( QPaintEvent*)
00372 {
00373 //qDebug() << "starting LineDiagram::paintEvent ( QPaintEvent*)";
00374     QPainter painter ( viewport() );
00375     PaintContext ctx;
00376     ctx.setPainter ( &painter );
00377     ctx.setRectangle ( QRectF ( 0, 0, width(), height() ) );
00378     paint ( &ctx );
00379 //qDebug() << "         LineDiagram::paintEvent ( QPaintEvent*) ended.";
00380 }
00381 
00382 
00383 double LineDiagram::valueForCellTesting( int row, int column,
00384                                          bool& bOK,
00385                                          bool showHiddenCellsAsInvalid ) const
00386 {
00387     double value;
00388     if( showHiddenCellsAsInvalid && isHidden( model()->index( row, column, rootIndex() ) ) )
00389         bOK = false;
00390     else
00391         value = d->attributesModel->data(
00392                     d->attributesModel->index( row, column, attributesModelRootIndex() )
00393                 ).toDouble( &bOK );
00394     return bOK ? value : 0.0;
00395 }
00396 
00397 
00398 LineAttributes::MissingValuesPolicy LineDiagram::getCellValues(
00399       int row, int column,
00400       bool shiftCountedXValuesByHalfSection,
00401       double& valueX, double& valueY ) const
00402 {
00403     LineAttributes::MissingValuesPolicy policy;
00404 
00405     bool bOK = true;
00406     valueX = ( datasetDimension() > 1 && column > 0 )
00407            ? valueForCellTesting( row, column-1, bOK, true )
00408            : ((shiftCountedXValuesByHalfSection ? 0.5 : 0.0) + row);
00409     if( bOK )
00410         valueY = valueForCellTesting( row, column, bOK, true );
00411     if( bOK ){
00412         policy = LineAttributes::MissingValuesPolicyIgnored;
00413     }else{
00414         // missing value: find out the policy
00415         QModelIndex index = model()->index( row, column, rootIndex() );
00416         LineAttributes la = lineAttributes( index );
00417         policy = la.missingValuesPolicy();
00418     }
00419     return policy;
00420 }
00421 
00422 /*commenting this include: used for testing
00423 notice: Windows compilers need this include to
00424 be written before the #define d(d_func()) above*/
00425 //#include <QTime>
00426 
00427 void LineDiagram::paint( PaintContext* ctx )
00428 {
00429 //qDebug() << "    start diag::paint()";
00430     // note: Not having any data model assigned is no bug
00431     //       but we can not draw a diagram then either.
00432     if ( !checkInvariants( true ) ) return;
00433     if ( !AbstractGrid::isBoundariesValid(dataBoundaries()) ) return;
00434 
00435     // Make sure counted x values (== in diagrams with 1-dimensional data cells)
00436     // get shifted by 0.5, if the diagram's reference diagram is a BarDiagram.
00437     // So we get the lines to start/end at the middle of the respective bar groups.
00438     const bool shiftCountedXValuesByHalfSection =
00439             (dynamic_cast< BarDiagram* >( referenceDiagram() ) != 0);
00440 
00441     //QTime t = QTime::currentTime();
00442 
00443     const QPair<QPointF, QPointF> boundaries = dataBoundaries();
00444     const QPointF bottomLeft = boundaries.first;
00445     const QPointF topRight = boundaries.second;
00446 
00447     int maxFound = 0;
00448     {   // find the last column number that is not hidden
00449         const int columnCount = d->attributesModel->columnCount(attributesModelRootIndex());
00450         for( int iColumn =  datasetDimension()-1;
00451             iColumn <  columnCount;
00452             iColumn += datasetDimension() )
00453             if( ! isHidden( iColumn ) )
00454                 maxFound = iColumn;
00455     }
00456     const int lastVisibleColumn = maxFound;
00457     const int rowCount = d->attributesModel->rowCount(attributesModelRootIndex());
00458 
00459     DataValueTextInfoList list;
00460     LineAttributesInfoList lineList;
00461     LineAttributes::MissingValuesPolicy policy;
00462 
00463     // paint different line types Normal - Stacked - Percent - Default Normal
00464     switch ( type() )
00465     {
00466         case LineDiagram::Normal:
00467         {
00468             for( int iColumn  = datasetDimension()-1;
00469                      iColumn <= lastVisibleColumn;
00470                      iColumn += datasetDimension() ) {
00471 
00472                 //display area can be set by dataset ( == column) and/or by cell
00473                 LineAttributes laPreviousCell; // by default no area is drawn
00474                 QModelIndex indexPreviousCell;
00475                 QList<QPolygonF> areas;
00476 
00477                 bool bValuesFound = false;
00478                 double lastValueX, lastValueY;
00479                 double valueX, valueY;
00480                 for ( int iRow = 0; iRow < rowCount; ++iRow ) {
00481                     bool skipThisCell = false;
00482                     // trying to find a fromPoint
00483                     policy = getCellValues( iRow, iColumn,
00484                                             shiftCountedXValuesByHalfSection,
00485                                             valueX, valueY );
00486                     switch( policy ){
00487                         case LineAttributes::MissingValuesAreBridged:
00488                             if( bValuesFound ){
00489                                 valueX = lastValueX;
00490                                 valueY = lastValueY;
00491                             }else{
00492                                 skipThisCell = true;
00493                             }
00494                             break;
00495                         case LineAttributes::MissingValuesHideSegments:
00496                             skipThisCell = true;
00497                             break;
00498                         case LineAttributes::MissingValuesShownAsZero:
00499                             // fall through intended
00500                         case LineAttributes::MissingValuesPolicyIgnored:
00501                             lastValueX = valueX;
00502                             lastValueY = valueY;
00503                             bValuesFound = true;
00504                             break;
00505                     }
00506                     if( ! skipThisCell ){
00507                         // trying to find a toPoint
00508                         double nextValueX, nextValueY;
00509                         bool foundToPoint = false;
00510                         int iNextRow = iRow+1;
00511                         while ( ! (foundToPoint || skipThisCell || iNextRow >= rowCount) ) {
00512                             policy = getCellValues(
00513                                     iNextRow, iColumn,
00514                                     shiftCountedXValuesByHalfSection,
00515                                     nextValueX, nextValueY );
00516                             switch( policy ){
00517                                 case LineAttributes::MissingValuesAreBridged:
00518                                     // The cell has no valid value, so we  make sure that
00519                                     // this cell will not be processed by the next iteration
00520                                     // of the iRow loop:
00521                                     ++iRow;
00522                                     break;
00523                                 case LineAttributes::MissingValuesHideSegments:
00524                                     // The cell has no valid value, so we  make sure that
00525                                     // this cell will not be processed by the next iteration
00526                                     // of the iRow loop:
00527                                     skipThisCell = true;
00528                                     ++iRow;
00529                                     break;
00530                                 case LineAttributes::MissingValuesShownAsZero:
00531                                     // fall through intended
00532                                 case LineAttributes::MissingValuesPolicyIgnored:
00533                                     foundToPoint = true;
00534                                     break;
00535                             }
00536                             ++iNextRow;
00537                         }
00538                         if( ! skipThisCell ){
00539                             const bool isPositive = (valueY >= 0.0);
00540                             const QModelIndex index = model()->index( iRow, iColumn, rootIndex() );
00541                             const LineAttributes laCell = lineAttributes( index );
00542                             const bool bDisplayCellArea = laCell.displayArea();
00543 
00544                             QPointF fromPoint = coordinatePlane()->translate( QPointF( valueX, valueY ) );
00545 
00546                             const QPointF ptNorthWest(
00547                                 (bDisplayCellArea && ! isPositive)
00548                                 ? coordinatePlane()->translate( QPointF( valueX, 0.0 ) )
00549                                 : fromPoint );
00550                             const QPointF ptSouthWest(
00551                                 (bDisplayCellArea && isPositive)
00552                                 ? coordinatePlane()->translate( QPointF( valueX, 0.0 ) )
00553                                 : fromPoint );
00554                             //qDebug() << "--> ptNorthWest:" << ptNorthWest;
00555                             //qDebug() << "--> ptSouthWest:" << ptSouthWest;
00556                             QPointF ptNorthEast;
00557                             QPointF ptSouthEast;
00558 
00559                             if( foundToPoint ){
00560                                 QPointF toPoint = coordinatePlane()->translate( QPointF( nextValueX, nextValueY ) );
00561                                 lineList.append( LineAttributesInfo( index, fromPoint, toPoint ) );
00562                                 ptNorthEast =
00563                                     (bDisplayCellArea && ! isPositive)
00564                                     ? coordinatePlane()->translate( QPointF( nextValueX, 0.0 ) )
00565                                     : toPoint;
00566                                 ptSouthEast =
00567                                     (bDisplayCellArea && isPositive)
00568                                     ? coordinatePlane()->translate( QPointF( nextValueX, 0.0 ) )
00569                                     : toPoint;
00570                                 // we can't take as a condition the line attributes
00571                                 // to be different from a cell to another.
00572                                 // e.g the user should be able to have different brush
00573                                 // which is not reflected in the line attributes
00574                                 // see examples/Area which show such an option
00575                                 if( areas.count() /*&& laCell != laPreviousCell*/ ){
00576                                     paintAreas( ctx, indexPreviousCell, areas, laPreviousCell.transparency() );
00577                                     areas.clear();
00578                                 }
00579                                 if( bDisplayCellArea ){
00580                                     QPolygonF poly;
00581                                     poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest;
00582                                     //qDebug() << "ptNorthWest:" << ptNorthWest;
00583                                     //qDebug() << "ptNorthEast:" << ptNorthEast;
00584                                     //qDebug() << "ptSouthEast:" << ptSouthEast;
00585                                     //qDebug() << "ptSouthWest:" << ptSouthWest;
00586                                     //qDebug() << "polygon:" << poly;
00587                                     areas << poly;
00588                                     laPreviousCell = laCell;
00589                                     indexPreviousCell = index;
00590                                 }
00591                             }else{
00592                                 ptNorthEast = ptNorthWest;
00593                                 ptSouthEast = ptSouthWest;
00594                             }
00595 
00596                             const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest );
00597                             d->appendDataValueTextInfoToList( this, list, index, pts,
00598                                     Position::NorthWest, Position::SouthWest,
00599                                     valueY );
00600                         }
00601                     }
00602                 }
00603                 if( areas.count() ){
00604                     paintAreas( ctx, indexPreviousCell, areas, laPreviousCell.transparency() );
00605                     areas.clear();
00606                 }
00607             }
00608         }
00609             break;
00610         case LineDiagram::Stacked:
00611             // fall-through intended
00612         case LineDiagram::Percent:
00613         {
00614             //FIXME(khz): add LineAttributes::MissingValuesPolicy support for LineDiagram::Stacked and ::Percent
00615 
00616             const bool isPercentMode = type() == LineDiagram::Percent;
00617             double maxValue = 100; // always 100%
00618             double sumValues = 0;
00619             QVector <double > percentSumValues;
00620 
00621             //calculate sum of values for each column and store
00622             if( isPercentMode ){
00623                 for ( int j=0; j<rowCount ; ++j ) {
00624                     for( int i =  datasetDimension()-1;
00625                         i <= lastVisibleColumn;
00626                         i += datasetDimension() ) {
00627                             double tmpValue = valueForCell( j, i );
00628                             if ( tmpValue > 0 )
00629                                 sumValues += tmpValue;
00630                             if ( i == lastVisibleColumn ) {
00631                                 percentSumValues <<  sumValues ;
00632                                 sumValues = 0;
00633                             }
00634                         }
00635                 }
00636             }
00637 
00638             QList<QPointF> bottomPoints;
00639             bool bFirstDataset = true;
00640 
00641             for( int iColumn =  datasetDimension()-1;
00642                  iColumn <= lastVisibleColumn;
00643                  iColumn += datasetDimension() ) {
00644 
00645                 //display area can be set by dataset ( == column) and/or by cell
00646                 LineAttributes laPreviousCell; // by default no area is drawn
00647                 QModelIndex indexPreviousCell;
00648                 QList<QPolygonF> areas;
00649                 QList<QPointF> points;
00650 
00651                 for ( int iRow = 0; iRow< rowCount; ++iRow ) {
00652                     const QModelIndex index = model()->index( iRow, iColumn, rootIndex() );
00653                     const LineAttributes laCell = lineAttributes( index );
00654                     const bool bDisplayCellArea = laCell.displayArea();
00655 
00656                     double stackedValues = 0, nextValues = 0;
00657                     for ( int iColumn2 = iColumn;
00658                           iColumn2 >= datasetDimension()-1;
00659                           iColumn2 -= datasetDimension() )
00660                     {
00661                         const double val = valueForCell( iRow, iColumn2 );
00662                         if( val > 0 || ! isPercentMode )
00663                             stackedValues += val;
00664                         //qDebug() << valueForCell( iRow, iColumn2 );
00665                         if ( iRow+1 < rowCount ){
00666                             const double val = valueForCell( iRow+1, iColumn2 );
00667                             if( val > 0 || ! isPercentMode )
00668                                 nextValues += val;
00669                         }
00670                     }
00671                     if( isPercentMode ){
00672                         if ( percentSumValues.at( iRow ) != 0  )
00673                             stackedValues = stackedValues / percentSumValues.at( iRow ) * maxValue;
00674                         else
00675                             stackedValues = 0.0;
00676                     }
00677                     //qDebug() << stackedValues << endl;
00678                     QPointF nextPoint = coordinatePlane()->translate( QPointF( iRow, stackedValues ) );
00679                     points << nextPoint;
00680 
00681                     const QPointF ptNorthWest( nextPoint );
00682                     const QPointF ptSouthWest(
00683                             bDisplayCellArea
00684                             ? ( bFirstDataset
00685                                 ? coordinatePlane()->translate( QPointF( iRow, 0.0 ) )
00686                                 : bottomPoints.at( iRow )
00687                               )
00688                             : nextPoint );
00689                     QPointF ptNorthEast;
00690                     QPointF ptSouthEast;
00691 
00692                     if ( iRow+1 < rowCount ){
00693                         if( isPercentMode ){
00694                             if ( percentSumValues.at( iRow+1 ) != 0  )
00695                                 nextValues = nextValues / percentSumValues.at( iRow+1 ) * maxValue;
00696                             else
00697                                 nextValues = 0.0;
00698                         }
00699                         QPointF toPoint = coordinatePlane()->translate( QPointF( iRow+1, nextValues ) );
00700                         lineList.append( LineAttributesInfo( index, nextPoint, toPoint ) );
00701                         ptNorthEast = toPoint;
00702                         ptSouthEast =
00703                             bDisplayCellArea
00704                             ? ( bFirstDataset
00705                                 ? coordinatePlane()->translate( QPointF( iRow+1, 0.0 ) )
00706                                 : bottomPoints.at( iRow+1 )
00707                               )
00708                             : toPoint;
00709                         if( areas.count() && laCell != laPreviousCell ){
00710                             paintAreas( ctx, indexPreviousCell, areas, laPreviousCell.transparency() );
00711                             areas.clear();
00712                         }
00713                         if( bDisplayCellArea ){
00714                             QPolygonF poly;
00715                             poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest;
00716                             areas << poly;
00717                             laPreviousCell = laCell;
00718                             indexPreviousCell = index;
00719                         }else{
00720                             //qDebug() << "no area shown for row"<<iRow<<"  column"<<iColumn;
00721                         }
00722                     }else{
00723                         ptNorthEast = ptNorthWest;
00724                         ptSouthEast = ptSouthWest;
00725                     }
00726 
00727                     const PositionPoints pts( ptNorthWest, ptNorthEast, ptSouthEast, ptSouthWest );
00728                     d->appendDataValueTextInfoToList( this, list, index, pts,
00729                             Position::NorthWest, Position::SouthWest,
00730                             valueForCell( iRow, iColumn ) );
00731                 }
00732                 if( areas.count() ){
00733                     paintAreas( ctx, indexPreviousCell, areas, laPreviousCell.transparency() );
00734                     areas.clear();
00735                 }
00736                 bottomPoints = points;
00737                 bFirstDataset = false;
00738             }
00739         }
00740             break;
00741         default:
00742             Q_ASSERT_X ( false, "paint()",
00743                          "Type item does not match a defined line chart Type." );
00744     }
00745     // paint all lines and their attributes
00746     {
00747         PainterSaver painterSaver( ctx->painter() );
00748         if ( antiAliasing() )
00749             ctx->painter()->setRenderHint ( QPainter::Antialiasing );
00750         LineAttributesInfoListIterator itline ( lineList );
00751 
00752         //qDebug() << "Rendering 1 in: " << t.msecsTo( QTime::currentTime() ) << endl;
00753 
00754         QBrush curBrush;
00755         QPen curPen;
00756         QPolygonF points;
00757         while ( itline.hasNext() ) {
00758             const LineAttributesInfo& lineInfo = itline.next();
00759             const QModelIndex& index = lineInfo.index;
00760             const ThreeDLineAttributes td = threeDLineAttributes( index );
00761             if( td.isEnabled() ){
00762                 paintThreeDLines( ctx, index, lineInfo.value, lineInfo.nextValue, td.depth() );
00763             }else{
00764                 const QBrush br( brush( index ) );
00765                 const QPen   pn( pen(   index ) );
00766                 if( points.count() && points.last() == lineInfo.value && curBrush == br && curPen == pn ){
00767                     points << lineInfo.nextValue;
00768                 }else{
00769                     if( points.count() )
00770                         paintPolyline( ctx, curBrush, curPen, points );
00771                     curBrush = br;
00772                     curPen   = pn;
00773                     points.clear();
00774                     points << lineInfo.value << lineInfo.nextValue;
00775                 }
00776             }
00777         }
00778         if( points.count() )
00779             paintPolyline( ctx, curBrush, curPen, points );
00780     }
00781     // paint all data value texts and the point markers
00782     d->paintDataValueTextsAndMarkers( this, ctx, list, true );
00783     //qDebug() << "Rendering 2 in: " << t.msecsTo( QTime::currentTime() ) << endl;
00784 }
00785 
00786 
00787 void LineDiagram::paintPolyline( PaintContext* ctx,
00788                                  const QBrush& brush, const QPen& pen,
00789                                  const QPolygonF& points ) const
00790 {
00791     ctx->painter()->setBrush( brush );
00792     ctx->painter()->setPen(
00793         QPen( pen.color(),
00794               pen.width(),
00795               pen.style(),
00796               Qt::FlatCap,
00797               Qt::MiterJoin ) );
00798     ctx->painter()->drawPolyline( points );
00799 }
00800 
00801 
00802 /* old:
00803 void LineDiagram::paintLines( PaintContext* ctx, const QModelIndex& index,
00804                               const QPointF& from, const QPointF& to )
00805 {
00806     ThreeDLineAttributes td = threeDLineAttributes(index);
00807     if ( td.isEnabled() ) {
00808         const double lineDepth = td.depth();
00809         paintThreeDLines( ctx, index, from, to, lineDepth );
00810     } else {
00811         ctx->painter()->setBrush( brush( index ) );
00812         ctx->painter()->setPen( pen( index ) );
00813         if ( index.row() + 1 < d->attributesModel->rowCount(attributesModelRootIndex()) ) {
00814             if ( ctx->rectangle().contains( from ) || ctx->rectangle().contains( to ) ) {
00815                 ctx->painter()->drawLine( from, to );
00816             }
00817         }
00818     }
00819 }
00820 */
00821 
00822 
00823 void LineDiagram::paintAreas( PaintContext* ctx, const QModelIndex& index, const QPolygonF& area, const uint transparency )
00824 {
00825     QColor trans( brush(index).color() );
00826     QPen indexPen( pen(index) );
00827     trans.setAlpha( transparency );
00828     indexPen.setColor( trans );
00829     PainterSaver painterSaver( ctx->painter() );
00830     if ( antiAliasing() )
00831         ctx->painter()->setRenderHint ( QPainter::Antialiasing );
00832     ctx->painter()->setPen( indexPen );
00833     ctx->painter()->setBrush( trans ) ;
00834     ctx->painter()->drawPolygon( area );//pol );
00835 }
00836 
00837 void LineDiagram::paintAreas( PaintContext* ctx, const QModelIndex& index, const QList<QPolygonF>& areas, const uint transparency )
00838 {
00839     QColor trans( brush(index).color() );
00840     trans.setAlpha( transparency );
00841     QPen indexPen( pen(index) );
00842     indexPen.setColor( trans );
00843     PainterSaver painterSaver( ctx->painter() );
00844     if ( antiAliasing() )
00845         ctx->painter()->setRenderHint ( QPainter::Antialiasing );
00846     ctx->painter()->setPen( indexPen );
00847     ctx->painter()->setBrush( trans );
00848     QPainterPath path;
00849     for( int i=0; i<areas.count(); ++i ){
00850         path.addPolygon( areas[i] );
00851         path.closeSubpath();
00852         //qDebug() << "LineDiagram::paintAreas() adding path:"<<areas[i];
00853     }
00854     //qDebug() << endl;
00855     ctx->painter()->drawPath( path );
00856 }
00857 
00864 const QPointF LineDiagram::project( QPointF point, QPointF maxLimits, double z, const QModelIndex& index ) const
00865 {
00866   ThreeDLineAttributes td = threeDLineAttributes( index );
00867 
00868     //Pending Michel FIXME - the rotation does not work as expected atm
00869     double xrad = DEGTORAD( td.lineXRotation() );
00870     double yrad = DEGTORAD( td.lineYRotation() );
00871     QPointF ret = QPointF(point.x()*cos( yrad ) + z * sin( yrad ) ,  point.y()*cos( xrad ) - z * sin( xrad ) );
00872     return ret;
00873 }
00874 
00875 void LineDiagram::paintThreeDLines(PaintContext* ctx, const QModelIndex& index, const QPointF& from, const QPointF& to, const double depth  )
00876 {
00877     // retrieve the boundaries
00878     const QPair<QPointF, QPointF> boundaries = dataBoundaries ();
00879     QPointF maxLimits = boundaries.second;
00880     QVector <QPointF > segmentPoints;
00881     QPointF topLeft = project( from, maxLimits, depth, index  );
00882     QPointF topRight = project ( to, maxLimits, depth, index  );
00883 
00884     segmentPoints << from << topLeft << topRight << to;
00885     QPolygonF segment ( segmentPoints );
00886     QBrush indexBrush ( brush( index ) );
00887     PainterSaver painterSaver( ctx->painter() );
00888     if ( antiAliasing() )
00889         ctx->painter()->setRenderHint ( QPainter::Antialiasing );
00890     ctx->painter()->setBrush( indexBrush );
00891     ctx->painter()->setPen( pen( index ) ) ;
00892     ctx->painter()->drawPolygon( segment );
00893 }
00894 
00895 void LineDiagram::resize ( const QSizeF& )
00896 {
00897 }
00898 
00899 const int LineDiagram::numberOfAbscissaSegments () const
00900 {
00901     return d->attributesModel->rowCount(attributesModelRootIndex());
00902 }
00903 
00904 const int LineDiagram::numberOfOrdinateSegments () const
00905 {
00906     return d->attributesModel->columnCount(attributesModelRootIndex());
00907 }
00908 
00909 //#endif
00910 
00911 

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