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 #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
00085 return false;
00086 }
00087
00088
00089
00090
00091
00092 return
00093 ( static_cast<const AbstractCartesianDiagram*>(this)->compare( other ) ) &&
00094
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
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
00272
00273
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
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
00316
00317
00318
00319
00320 }
00321 break;
00322 case LineDiagram::Stacked:
00323 {
00324 bool bStarting = true;
00325 for ( int j=0; j< rowCount; ++j ) {
00326
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
00339
00340
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
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
00367 return QPair<QPointF, QPointF> ( bottomLeft, topRight );
00368 }
00369
00370
00371 void LineDiagram::paintEvent ( QPaintEvent*)
00372 {
00373
00374 QPainter painter ( viewport() );
00375 PaintContext ctx;
00376 ctx.setPainter ( &painter );
00377 ctx.setRectangle ( QRectF ( 0, 0, width(), height() ) );
00378 paint ( &ctx );
00379
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
00415 QModelIndex index = model()->index( row, column, rootIndex() );
00416 LineAttributes la = lineAttributes( index );
00417 policy = la.missingValuesPolicy();
00418 }
00419 return policy;
00420 }
00421
00422
00423
00424
00425
00426
00427 void LineDiagram::paint( PaintContext* ctx )
00428 {
00429
00430
00431
00432 if ( !checkInvariants( true ) ) return;
00433 if ( !AbstractGrid::isBoundariesValid(dataBoundaries()) ) return;
00434
00435
00436
00437
00438 const bool shiftCountedXValuesByHalfSection =
00439 (dynamic_cast< BarDiagram* >( referenceDiagram() ) != 0);
00440
00441
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 {
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
00464 switch ( type() )
00465 {
00466 case LineDiagram::Normal:
00467 {
00468 for( int iColumn = datasetDimension()-1;
00469 iColumn <= lastVisibleColumn;
00470 iColumn += datasetDimension() ) {
00471
00472
00473 LineAttributes laPreviousCell;
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
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
00500 case LineAttributes::MissingValuesPolicyIgnored:
00501 lastValueX = valueX;
00502 lastValueY = valueY;
00503 bValuesFound = true;
00504 break;
00505 }
00506 if( ! skipThisCell ){
00507
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
00519
00520
00521 ++iRow;
00522 break;
00523 case LineAttributes::MissingValuesHideSegments:
00524
00525
00526
00527 skipThisCell = true;
00528 ++iRow;
00529 break;
00530 case LineAttributes::MissingValuesShownAsZero:
00531
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
00555
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
00571
00572
00573
00574
00575 if( areas.count() ){
00576 paintAreas( ctx, indexPreviousCell, areas, laPreviousCell.transparency() );
00577 areas.clear();
00578 }
00579 if( bDisplayCellArea ){
00580 QPolygonF poly;
00581 poly << ptNorthWest << ptNorthEast << ptSouthEast << ptSouthWest;
00582
00583
00584
00585
00586
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
00612 case LineDiagram::Percent:
00613 {
00614
00615
00616 const bool isPercentMode = type() == LineDiagram::Percent;
00617 double maxValue = 100;
00618 double sumValues = 0;
00619 QVector <double > percentSumValues;
00620
00621
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
00646 LineAttributes laPreviousCell;
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
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
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
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
00746 {
00747 PainterSaver painterSaver( ctx->painter() );
00748 if ( antiAliasing() )
00749 ctx->painter()->setRenderHint ( QPainter::Antialiasing );
00750 LineAttributesInfoListIterator itline ( lineList );
00751
00752
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
00782 d->paintDataValueTextsAndMarkers( this, ctx, list, true );
00783
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
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
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 );
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
00853 }
00854
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
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
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
00910
00911