# KDChartAbstractDiagram.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  ** Foundation 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 <QPainter>
    00027 #include <QDebug>
    00028 #include <QApplication>
    00029 #include <QAbstractProxyModel>
    00030 #include <QStandardItemModel>
    00031 #include <QSizeF>
    00032
    00033 #include "KDChartAbstractCoordinatePlane.h"
    00034 #include "KDChartChart.h"
    00035 #include "KDChartDataValueAttributes.h"
    00036 #include "KDChartTextAttributes.h"
    00037 #include "KDChartMarkerAttributes.h"
    00038 #include "KDChartAbstractDiagram.h"
    00039 #include "KDChartAbstractDiagram_p.h"
    00040 #include "KDChartAttributesModel.h"
    00041 #include "KDChartAbstractThreeDAttributes.h"
    00042 #include "KDChartThreeDLineAttributes.h"
    00043
    00044 #include <KDABLibFakes>
    00045
    00046
    00047 using namespace KDChart;
    00048
    00049 namespace KDChart {
    00050   class PrivateAttributesModel : public AttributesModel {
    00051     Q_OBJECT
    00052   public:
    00053         explicit PrivateAttributesModel( QAbstractItemModel* model, QObject * parent = 0 )
    00054           : AttributesModel(model,parent) {}
    00055   };
    00056 }
    00057
    00058 AbstractDiagram::Private::Private()
    00059   : plane( 0 )
    00060   , attributesModel( new PrivateAttributesModel(0,0) )
    00061   , allowOverlappingDataValueTexts( false )
    00062   , antiAliasing( true )
    00063   , percent( false )
    00064   , datasetDimension( 1 )
    00065   , databoundariesDirty(true)
    00066   , lastRoundedValue()
    00067   , lastX( 0 )
    00068   , mCachedFontMetrics( QFontMetrics( qApp->font() ) )
    00069 {
    00070 }
    00071
    00072 AbstractDiagram::Private::~Private()
    00073 {
    00074   if( attributesModel && qobject_cast<PrivateAttributesModel*>(attributesModel) )
    00075     delete attributesModel;
    00076 }
    00077
    00078 void AbstractDiagram::Private::init()
    00079 {
    00080 }
    00081
    00082 void AbstractDiagram::Private::init( AbstractCoordinatePlane* newPlane )
    00083 {
    00084     plane = newPlane;
    00085 }
    00086
    00087 bool AbstractDiagram::Private::usesExternalAttributesModel()const
    00088 {
    00089     return ( ! attributesModel.isNull() ) &&
    00090            ( ! qobject_cast<PrivateAttributesModel*>(attributesModel) );
    00091 }
    00092
    00093 void AbstractDiagram::Private::setAttributesModel( AttributesModel* amodel )
    00094 {
    00095     if( !attributesModel.isNull() &&
    00096         qobject_cast<PrivateAttributesModel*>(attributesModel) ) {
    00097         delete attributesModel;
    00098     }
    00099     attributesModel = amodel;
    00100 }
    00101
    00102 AbstractDiagram::Private::Private( const AbstractDiagram::Private& rhs ) :
    00103     // Do not copy the plane
    00104     plane( 0 ),
    00105     attributesModelRootIndex( QModelIndex() ),
    00106     attributesModel( rhs.attributesModel ),
    00107     allowOverlappingDataValueTexts( rhs.allowOverlappingDataValueTexts ),
    00108     antiAliasing( rhs.antiAliasing ),
    00109     percent( rhs.percent ),
    00110     datasetDimension( rhs.datasetDimension ),
    00111     mCachedFontMetrics( rhs.cachedFontMetrics() )
    00112 {
    00113     attributesModel = new PrivateAttributesModel( 0, 0);
    00114     attributesModel->initFrom( rhs.attributesModel );
    00115 }
    00116
    00117 #define d d_func()
    00118
    00119 AbstractDiagram::AbstractDiagram ( QWidget* parent, AbstractCoordinatePlane* plane )
    00120     : QAbstractItemView ( parent ), _d( new Private() )
    00121 {
    00122     _d->init( plane );
    00123 }
    00124
    00125 AbstractDiagram::~AbstractDiagram()
    00126 {
    00127     delete _d;
    00128 }
    00129
    00130 void AbstractDiagram::init()
    00131 {
    00132 }
    00133
    00134
    00135 bool AbstractDiagram::compare( const AbstractDiagram* other )const
    00136 {
    00137     if( other == this ) return true;
    00138     if( ! other ){
    00139         //qDebug() << "AbstractDiagram::compare() cannot compare to Null pointer";
    00140         return false;
    00141     }
    00142     /*
    00143     qDebug() << "\n             AbstractDiagram::compare() QAbstractScrollArea:";
    00144             // compare QAbstractScrollArea properties
    00145     qDebug() <<
    00146             ((horizontalScrollBarPolicy() == other->horizontalScrollBarPolicy()) &&
    00147             (verticalScrollBarPolicy()    == other->verticalScrollBarPolicy()));
    00148     qDebug() << "AbstractDiagram::compare() QFrame:";
    00149             // compare QFrame properties
    00150     qDebug() <<
    00151             ((frameShadow() == other->frameShadow()) &&
    00152             (frameShape()   == other->frameShape()) &&
    00153             (frameWidth()   == other->frameWidth()) &&
    00154             (lineWidth()    == other->lineWidth()) &&
    00155             (midLineWidth() == other->midLineWidth()));
    00156     qDebug() << "AbstractDiagram::compare() QAbstractItemView:";
    00157             // compare QAbstractItemView properties
    00158     qDebug() <<
    00159             ((alternatingRowColors() == other->alternatingRowColors()) &&
    00160             (hasAutoScroll()         == other->hasAutoScroll()) &&
    00161 #if QT_VERSION > 0x040199
    00162             (dragDropMode()          == other->dragDropMode()) &&
    00163             (dragDropOverwriteMode() == other->dragDropOverwriteMode()) &&
    00164             (horizontalScrollMode()  == other->horizontalScrollMode ()) &&
    00165             (verticalScrollMode()    == other->verticalScrollMode()) &&
    00166 #endif
    00167             (dragEnabled()           == other->dragEnabled()) &&
    00168             (editTriggers()          == other->editTriggers()) &&
    00169             (iconSize()              == other->iconSize()) &&
    00170             (selectionBehavior()     == other->selectionBehavior()) &&
    00171             (selectionMode()         == other->selectionMode()) &&
    00172             (showDropIndicator()     == other->showDropIndicator()) &&
    00173             (tabKeyNavigation()      == other->tabKeyNavigation()) &&
    00174             (textElideMode()         == other->textElideMode()));
    00175     qDebug() << "AbstractDiagram::compare() AttributesModel: ";
    00176             // compare all of the properties stored in the attributes model
    00177     qDebug() << attributesModel()->compare( other->attributesModel() );
    00178     qDebug() << "AbstractDiagram::compare() own:";
    00179             // compare own properties
    00180     qDebug() <<
    00181             ((rootIndex().column()            == other->rootIndex().column()) &&
    00182             (rootIndex().row()                == other->rootIndex().row()) &&
    00183             (allowOverlappingDataValueTexts() == other->allowOverlappingDataValueTexts()) &&
    00184             (antiAliasing()                   == other->antiAliasing()) &&
    00185             (percentMode()                    == other->percentMode()) &&
    00186             (datasetDimension()               == other->datasetDimension()));
    00187     */
    00188     return  // compare QAbstractScrollArea properties
    00189             (horizontalScrollBarPolicy() == other->horizontalScrollBarPolicy()) &&
    00190             (verticalScrollBarPolicy()   == other->verticalScrollBarPolicy()) &&
    00191             // compare QFrame properties
    00192             (frameShadow()  == other->frameShadow()) &&
    00193             (frameShape()   == other->frameShape()) &&
    00194             (frameWidth()   == other->frameWidth()) &&
    00195             (lineWidth()    == other->lineWidth()) &&
    00196             (midLineWidth() == other->midLineWidth()) &&
    00197             // compare QAbstractItemView properties
    00198             (alternatingRowColors()  == other->alternatingRowColors()) &&
    00199             (hasAutoScroll()         == other->hasAutoScroll()) &&
    00200 #if QT_VERSION > 0x040199
    00201             (dragDropMode()          == other->dragDropMode()) &&
    00202             (dragDropOverwriteMode() == other->dragDropOverwriteMode()) &&
    00203             (horizontalScrollMode()  == other->horizontalScrollMode ()) &&
    00204             (verticalScrollMode()    == other->verticalScrollMode()) &&
    00205 #endif
    00206             (dragEnabled()           == other->dragEnabled()) &&
    00207             (editTriggers()          == other->editTriggers()) &&
    00208             (iconSize()              == other->iconSize()) &&
    00209             (selectionBehavior()     == other->selectionBehavior()) &&
    00210             (selectionMode()         == other->selectionMode()) &&
    00211             (showDropIndicator()     == other->showDropIndicator()) &&
    00212             (tabKeyNavigation()      == other->tabKeyNavigation()) &&
    00213             (textElideMode()         == other->textElideMode()) &&
    00214             // compare all of the properties stored in the attributes model
    00215             attributesModel()->compare( other->attributesModel() ) &&
    00216             // compare own properties
    00217             (rootIndex().column()             == other->rootIndex().column()) &&
    00218             (rootIndex().row()                == other->rootIndex().row()) &&
    00219             (allowOverlappingDataValueTexts() == other->allowOverlappingDataValueTexts()) &&
    00220             (antiAliasing()                   == other->antiAliasing()) &&
    00221             (percentMode()                    == other->percentMode()) &&
    00222             (datasetDimension()               == other->datasetDimension());
    00223 }
    00224
    00225
    00226 AbstractCoordinatePlane* AbstractDiagram::coordinatePlane() const
    00227 {
    00228     return d->plane;
    00229 }
    00230
    00231 const QPair<QPointF, QPointF> AbstractDiagram::dataBoundaries () const
    00232 {
    00233     if( d->databoundariesDirty ){
    00234         d->databoundaries = calculateDataBoundaries ();
    00235         d->databoundariesDirty = false;
    00236     }
    00237     return d->databoundaries;
    00238 }
    00239
    00240 void AbstractDiagram::setDataBoundariesDirty() const
    00241 {
    00242     d->databoundariesDirty = true;
    00243 }
    00244
    00245 void AbstractDiagram::setModel ( QAbstractItemModel * newModel )
    00246 {
    00247   QAbstractItemView::setModel( newModel );
    00248   AttributesModel* amodel = new PrivateAttributesModel( newModel, this );
    00249   amodel->initFrom( d->attributesModel );
    00250   d->setAttributesModel(amodel);
    00251   scheduleDelayedItemsLayout();
    00252   d->databoundariesDirty = true;
    00253   emit modelsChanged();
    00254 }
    00255
    00261 void AbstractDiagram::setAttributesModel( AttributesModel* amodel )
    00262 {
    00263     if( amodel->sourceModel() != model() ) {
    00264         qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
    00265                  "Trying to set an attributesmodel which works on a different "
    00266                  "model than the diagram.");
    00267         return;
    00268     }
    00269     if( qobject_cast<PrivateAttributesModel*>(amodel) ) {
    00270         qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
    00271                  "Trying to set an attributesmodel that is private to another diagram.");
    00272         return;
    00273     }
    00274     d->setAttributesModel(amodel);
    00275     scheduleDelayedItemsLayout();
    00276     d->databoundariesDirty = true;
    00277     emit modelsChanged();
    00278 }
    00279
    00280 bool AbstractDiagram::usesExternalAttributesModel()const
    00281 {
    00282     return d->usesExternalAttributesModel();
    00283 }
    00284
    00286 AttributesModel* AbstractDiagram::attributesModel() const
    00287 {
    00288     return d->attributesModel;
    00289 }
    00290
    00292 void AbstractDiagram::setRootIndex ( const QModelIndex& idx )
    00293 {
    00294     QAbstractItemView::setRootIndex(idx);
    00295     setAttributesModelRootIndex( d->attributesModel->mapFromSource(idx) );
    00296 }
    00297
    00299 void AbstractDiagram::setAttributesModelRootIndex( const QModelIndex& idx )
    00300 {
    00301   d->attributesModelRootIndex=idx;
    00302   d->databoundariesDirty = true;
    00303   scheduleDelayedItemsLayout();
    00304 }
    00305
    00308 QModelIndex AbstractDiagram::attributesModelRootIndex() const
    00309 {
    00310     if ( !d->attributesModelRootIndex.isValid() )
    00311         d->attributesModelRootIndex = d->attributesModel->mapFromSource( rootIndex() );
    00312   return d->attributesModelRootIndex;
    00313 }
    00314
    00315 QModelIndex AbstractDiagram::columnToIndex( int column ) const
    00316 {
    00317     if( model() )
    00318         return QModelIndex( model()->index( 0, column, rootIndex() ) );
    00319     return QModelIndex();
    00320 }
    00321
    00322 void AbstractDiagram::setCoordinatePlane( AbstractCoordinatePlane* parent )
    00323 {
    00324     d->plane = parent;
    00325 }
    00326
    00327 void AbstractDiagram::doItemsLayout()
    00328 {
    00329     if ( d->plane ) {
    00330         d->plane->layoutDiagrams();
    00331         update();
    00332     }
    00333     QAbstractItemView::doItemsLayout();
    00334 }
    00335
    00336 void AbstractDiagram::dataChanged( const QModelIndex &topLeft,
    00337                                    const QModelIndex &bottomRight )
    00338 {
    00339   // We are still too dumb to do intelligent updates...
    00340   d->databoundariesDirty = true;
    00341   scheduleDelayedItemsLayout();
    00342 }
    00343
    00344
    00345 void AbstractDiagram::setHidden( const QModelIndex & index, bool hidden )
    00346 {
    00347     d->attributesModel->setData(
    00348         d->attributesModel->mapFromSource( index ),
    00349         qVariantFromValue( hidden ),
    00350         DataHiddenRole );
    00351     emit dataHidden();
    00352 }
    00353
    00354 void AbstractDiagram::setHidden( int column, bool hidden )
    00355 {
    00356     d->attributesModel->setHeaderData(
    00357         column, Qt::Vertical,
    00358         qVariantFromValue( hidden ),
    00359         DataHiddenRole );
    00360     emit dataHidden();
    00361 }
    00362
    00363 void AbstractDiagram::setHidden( bool hidden )
    00364 {
    00365     d->attributesModel->setModelData(
    00366         qVariantFromValue( hidden ),
    00367         DataHiddenRole );
    00368     emit dataHidden();
    00369 }
    00370
    00371 bool AbstractDiagram::isHidden() const
    00372 {
    00373     return qVariantValue<bool>(
    00374         attributesModel()->modelData( DataHiddenRole ) );
    00375 }
    00376
    00377 bool AbstractDiagram::isHidden( int column ) const
    00378 {
    00379     return qVariantValue<bool>(
    00380         attributesModel()->data(
    00381             attributesModel()->mapFromSource(columnToIndex( column )),
    00382             DataHiddenRole ) );
    00383 }
    00384 bool AbstractDiagram::isHidden( const QModelIndex & index ) const
    00385 {
    00386     return qVariantValue<bool>(
    00387         attributesModel()->data(
    00388             attributesModel()->mapFromSource(index),
    00389             DataHiddenRole ) );
    00390 }
    00391
    00392
    00393 void AbstractDiagram::setDataValueAttributes( const QModelIndex & index,
    00394                                               const DataValueAttributes & a )
    00395 {
    00396     d->attributesModel->setData(
    00397         d->attributesModel->mapFromSource( index ),
    00398         qVariantFromValue( a ),
    00399         DataValueLabelAttributesRole );
    00400     emit propertiesChanged();
    00401 }
    00402
    00403
    00404 void AbstractDiagram::setDataValueAttributes( int column, const DataValueAttributes & a )
    00405 {
    00406     d->attributesModel->setHeaderData(
    00407         column, Qt::Vertical,
    00408         qVariantFromValue( a ), DataValueLabelAttributesRole );
    00409     emit propertiesChanged();
    00410 }
    00411
    00412 DataValueAttributes AbstractDiagram::dataValueAttributes() const
    00413 {
    00414     return qVariantValue<DataValueAttributes>(
    00415         attributesModel()->modelData( KDChart::DataValueLabelAttributesRole ) );
    00416 }
    00417
    00418 DataValueAttributes AbstractDiagram::dataValueAttributes( int column ) const
    00419 {
    00420     return qVariantValue<DataValueAttributes>(
    00421         attributesModel()->data( attributesModel()->mapFromSource(columnToIndex( column )),
    00422         KDChart::DataValueLabelAttributesRole ) );
    00423 }
    00424
    00425 DataValueAttributes AbstractDiagram::dataValueAttributes( const QModelIndex & index ) const
    00426 {
    00427     return qVariantValue<DataValueAttributes>(
    00428         attributesModel()->data( attributesModel()->mapFromSource(index),
    00429         KDChart::DataValueLabelAttributesRole ) );
    00430 }
    00431
    00432 void AbstractDiagram::setDataValueAttributes( const DataValueAttributes & a )
    00433 {
    00434     d->attributesModel->setModelData( qVariantFromValue( a ), DataValueLabelAttributesRole );
    00435     emit propertiesChanged();
    00436 }
    00437
    00438 void AbstractDiagram::setAllowOverlappingDataValueTexts( bool allow )
    00439 {
    00440     d->allowOverlappingDataValueTexts = allow;
    00441     emit propertiesChanged();
    00442 }
    00443
    00444 bool AbstractDiagram::allowOverlappingDataValueTexts() const
    00445 {
    00446     return d->allowOverlappingDataValueTexts;
    00447 }
    00448
    00449 void AbstractDiagram::setAntiAliasing( bool enabled )
    00450 {
    00451     d->antiAliasing = enabled;
    00452     emit propertiesChanged();
    00453 }
    00454
    00455 bool AbstractDiagram::antiAliasing() const
    00456 {
    00457     return d->antiAliasing;
    00458 }
    00459
    00460 void AbstractDiagram::setPercentMode ( bool percent )
    00461 {
    00462     d->percent = percent;
    00463     emit propertiesChanged();
    00464 }
    00465
    00466 bool AbstractDiagram::percentMode() const
    00467 {
    00468     return d->percent;
    00469 }
    00470
    00471
    00472 void AbstractDiagram::paintDataValueText( QPainter* painter,
    00473                                           const QModelIndex& index,
    00474                                           const QPointF& pos,
    00475                                           double value )
    00476 {
    00477     // paint one data series
    00478     const DataValueAttributes a( dataValueAttributes(index) );
    00479     if ( !a.isVisible() ) return;
    00480
    00481     // handle decimal digits
    00482     int decimalDigits = a.decimalDigits();
    00483     int decimalPos = QString::number(  value ).indexOf( QLatin1Char( '.' ) );
    00484     QString roundedValue;
    00485     if ( a.dataLabel().isNull() ) {
    00486         if ( decimalPos > 0 && value != 0 )
    00487             roundedValue =  roundValues ( value, decimalPos, decimalDigits );
    00488         else
    00489             roundedValue = QString::number(  value );
    00490     } else
    00491         roundedValue = a.dataLabel();
    00492         // handle prefix and suffix
    00493     if ( !a.prefix().isNull() )
    00494         roundedValue.prepend( a.prefix() );
    00495
    00496     if ( !a.suffix().isNull() )
    00497         roundedValue.append( a.suffix() );
    00498
    00499     const TextAttributes ta( a.textAttributes() );
    00500     // FIXME draw the non-text bits, background, etc
    00501     if ( ta.isVisible() ) {
    00502
    00503         QPointF pt( pos );
    00504         /* for debugging:
    00505         PainterSaver painterSaver( painter );
    00506         painter->setPen( Qt::black );
    00507         painter->drawLine( pos - QPointF( 1,1), pos + QPointF( 1,1) );
    00508         painter->drawLine( pos - QPointF(-1,1), pos + QPointF(-1,1) );
    00509         */
    00510
    00511         // adjust the text start point position, if alignment is not Bottom/Left
    00512         const RelativePosition relPos( a.position( value >= 0.0 ) );
    00513         const Qt::Alignment alignBottomLeft = Qt::AlignBottom | Qt::AlignLeft;
    00514         const QFont calculatedFont( ta.calculatedFont( d->plane, KDChartEnums::MeasureOrientationMinimum ) );
    00515         //qDebug() << "calculatedFont's point size:" << calculatedFont.pointSizeF();
    00516         if( (relPos.alignment() & alignBottomLeft) != alignBottomLeft ){
    00517             const QRectF boundRect(
    00518                     d->cachedFontMetrics( calculatedFont, this )->boundingRect( roundedValue ) );
    00519             if( relPos.alignment() & Qt::AlignRight )
    00520                 pt.rx() -= boundRect.width();
    00521             else if( relPos.alignment() & Qt::AlignHCenter )
    00522                 pt.rx() -= 0.5 * boundRect.width();
    00523
    00524             if( relPos.alignment() & Qt::AlignTop )
    00525                 pt.ry() += boundRect.height();
    00526             else if( relPos.alignment() & Qt::AlignVCenter )
    00527                 pt.ry() += 0.5 * boundRect.height();
    00528         }
    00529
    00530         // FIXME draw the non-text bits, background, etc
    00531
    00532         if ( a.showRepetitiveDataLabels() ||
    00533              pos.x() <= d->lastX ||
    00534              d->lastRoundedValue != roundedValue ) {
    00535             d->lastRoundedValue = roundedValue;
    00536             d->lastX = pos.x();
    00537
    00538             PainterSaver painterSaver( painter );
    00539             painter->setPen( ta.pen() );
    00540             painter->setFont( calculatedFont );
    00541             painter->translate( pt );
    00542             painter->rotate( ta.rotation() );
    00543             painter->drawText( QPointF(0, 0), roundedValue );
    00544         }
    00545     }
    00546 }
    00547
    00548
    00549 QString  AbstractDiagram::roundValues( double value,
    00550                                        const int decimalPos,
    00551                                        const int decimalDigits ) const {
    00552
    00553     QString digits( QString::number( value ).mid( decimalPos+1 ) );
    00554     QString num( QString::number( value ) );
    00555     num.truncate( decimalPos );
    00556     int count = 0;
    00557         for (  int i = digits.length(); i >= decimalDigits ; --i ) {
    00558             count += 1;
    00559             int lastval = QString( digits.data() [i] ).toInt();
    00560             int val = QString( digits.data() [i-1] ) .toInt();
    00561             if ( lastval >= 5 ) {
    00562                 val += 1;
    00563                 digits.replace( digits.length() - count,1 , QString::number( val ) );
    00564             }
    00565         }
    00566
    00567     digits.truncate( decimalDigits );
    00568     num.append( QLatin1Char( '.' ) + digits );
    00569
    00570     return num;
    00571
    00572 }
    00573
    00574 void AbstractDiagram::paintDataValueTexts( QPainter* painter )
    00575 {
    00576     if ( !checkInvariants() ) return;
    00577     const int rowCount = model()->rowCount(rootIndex());
    00578     const int columnCount = model()->columnCount(rootIndex());
    00579     for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
    00580        for ( int j=0; j< rowCount; ++j ) {
    00581            const QModelIndex index = model()->index( j, i, rootIndex() );
    00582            double value = model()->data( index ).toDouble();
    00583            const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
    00584            paintDataValueText( painter, index, pos, value );
    00585        }
    00586     }
    00587 }
    00588
    00589
    00590 void AbstractDiagram::paintMarker( QPainter* painter,
    00591                                    const QModelIndex& index,
    00592                                    const QPointF& pos )
    00593 {
    00594
    00595     if ( !checkInvariants() ) return;
    00596     DataValueAttributes a = dataValueAttributes(index);
    00597     if ( !a.isVisible() ) return;
    00598     const MarkerAttributes &ma = a.markerAttributes();
    00599     if ( !ma.isVisible() ) return;
    00600
    00601     PainterSaver painterSaver( painter );
    00602     QSizeF maSize( ma.markerSize() );
    00603     QBrush indexBrush( brush( index ) );
    00604     QPen indexPen( ma.pen() );
    00605     if ( ma.markerColor().isValid() )
    00606         indexBrush.setColor( ma.markerColor() );
    00607
    00608     paintMarker( painter, ma, indexBrush, indexPen, pos, maSize );
    00609 }
    00610
    00611
    00612 void AbstractDiagram::paintMarker( QPainter* painter,
    00613                                    const MarkerAttributes& markerAttributes,
    00614                                    const QBrush& brush,
    00615                                    const QPen& pen,
    00616                                    const QPointF& pos,
    00617                                    const QSizeF& maSize )
    00618 {
    00619
    00620     const QPen oldPen( painter->pen() );
    00621     // Pen is used to paint 4Pixels - 1 Pixel - Ring and FastCross types.
    00622     // make sure to use the brush color - see above in those cases.
    00623     const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels);
    00624     if( isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel) ){
    00625         // for high-performance point charts with tiny point markers:
    00626         painter->setPen( QPen( brush.color().light() ) );
    00627         if( isFourPixels ){
    00628             const qreal x = pos.x();
    00629             const qreal y = pos.y();
    00630             painter->drawLine( QPointF(x-1.0,y-1.0),
    00631                                QPointF(x+1.0,y-1.0) );
    00632             painter->drawLine( QPointF(x-1.0,y),
    00633                                QPointF(x+1.0,y) );
    00634             painter->drawLine( QPointF(x-1.0,y+1.0),
    00635                                QPointF(x+1.0,y+1.0) );
    00636         }
    00637         painter->drawPoint( pos );
    00638     }else{
    00639         PainterSaver painterSaver( painter );
    00640         // we only a solid line surrounding the markers
    00641         QPen painterPen( pen );
    00642         painterPen.setStyle( Qt::SolidLine );
    00643         painter->setPen( painterPen );
    00644         painter->setBrush( brush );
    00645         painter->setRenderHint ( QPainter::Antialiasing );
    00646         painter->translate( pos );
    00647         switch ( markerAttributes.markerStyle() ) {
    00648             case MarkerAttributes::MarkerCircle:
    00649                 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
    00650                             maSize.height(), maSize.width()) );
    00651                 break;
    00652             case MarkerAttributes::MarkerSquare:
    00653                 {
    00654                     QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2,
    00655                                 maSize.width(), maSize.height() );
    00656                     painter->drawRect( rect );
    00657                     painter->fillRect( rect, brush.color() );
    00658                     break;
    00659                 }
    00660             case MarkerAttributes::MarkerDiamond:
    00661                 {
    00662                     QVector <QPointF > diamondPoints;
    00663                     QPointF top, left, bottom, right;
    00664                     top    = QPointF( 0, 0 - maSize.height()/2 );
    00665                     left   = QPointF( 0 - maSize.width()/2, 0 );
    00666                     bottom = QPointF( 0, maSize.height()/2 );
    00667                     right  = QPointF( maSize.width()/2, 0 );
    00668                     diamondPoints << top << left << bottom << right;
    00669                     painter->drawPolygon( diamondPoints );
    00670                     break;
    00671                 }
    00672             // both handled on top of the method:
    00673             case MarkerAttributes::Marker1Pixel:
    00674             case MarkerAttributes::Marker4Pixels:
    00675                     break;
    00676             case MarkerAttributes::MarkerRing:
    00677                 {
    00678                     painter->setPen( QPen( brush.color() ) );
    00679                     painter->setBrush( Qt::NoBrush );
    00680                     painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
    00681                                         maSize.height(), maSize.width()) );
    00682                     break;
    00683                 }
    00684             case MarkerAttributes::MarkerCross:
    00685                 {
    00686                     QRectF rect( maSize.width()*-0.5, maSize.height()*-0.2,
    00687                                  maSize.width(), maSize.height()*0.4 );
    00688                     painter->drawRect( rect );
    00689                     rect.setTopLeft(QPointF( maSize.width()*-0.2, maSize.height()*-0.5 ));
    00690                     rect.setSize(QSizeF( maSize.width()*0.4, maSize.height() ));
    00691                     painter->drawRect( rect );
    00692                     break;
    00693                 }
    00694             case MarkerAttributes::MarkerFastCross:
    00695                 {
    00696                     QPointF left, right, top, bottom;
    00697                     left  = QPointF( -maSize.width()/2, 0 );
    00698                     right = QPointF( maSize.width()/2, 0 );
    00699                     top   = QPointF( 0, -maSize.height()/2 );
    00700                     bottom= QPointF( 0, maSize.height()/2 );
    00701                     painter->setPen( QPen( brush.color() ) );
    00702                     painter->drawLine( left, right );
    00703                     painter->drawLine(  top, bottom );
    00704                     break;
    00705                 }
    00706             default:
    00707                 Q_ASSERT_X ( false, "paintMarkers()",
    00708                             "Type item does not match a defined Marker Type." );
    00709         }
    00710     }
    00711     painter->setPen( oldPen );
    00712 }
    00713
    00714 void AbstractDiagram::paintMarkers( QPainter* painter )
    00715 {
    00716     if ( !checkInvariants() ) return;
    00717     const int rowCount = model()->rowCount(rootIndex());
    00718     const int columnCount = model()->columnCount(rootIndex());
    00719     for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
    00720        for ( int j=0; j< rowCount; ++j ) {
    00721            const QModelIndex index = model()->index( j, i, rootIndex() );
    00722            double value = model()->data( index ).toDouble();
    00723            const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
    00724            paintMarker( painter, index, pos );
    00725        }
    00726     }
    00727 }
    00728
    00729
    00730 void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen )
    00731 {
    00732     attributesModel()->setData(
    00733         attributesModel()->mapFromSource( index ),
    00734         qVariantFromValue( pen ), DatasetPenRole );
    00735     emit propertiesChanged();
    00736 }
    00737
    00738 void AbstractDiagram::setPen( const QPen& pen )
    00739 {
    00740     attributesModel()->setModelData(
    00741         qVariantFromValue( pen ), DatasetPenRole );
    00742     emit propertiesChanged();
    00743 }
    00744
    00745 void AbstractDiagram::setPen( int column,const QPen& pen )
    00746 {
    00747     attributesModel()->setHeaderData(
    00748         column, Qt::Vertical,
    00749         qVariantFromValue( pen ),
    00750         DatasetPenRole );
    00751     emit propertiesChanged();
    00752 }
    00753
    00754 QPen AbstractDiagram::pen() const
    00755 {
    00756     return qVariantValue<QPen>(
    00757         attributesModel()->data( DatasetPenRole ) );
    00758 }
    00759
    00760 QPen AbstractDiagram::pen( int dataset ) const
    00761 {
    00762     return qVariantValue<QPen>(
    00763         attributesModel()->data(
    00764             attributesModel()->mapFromSource( columnToIndex( dataset ) ),
    00765             DatasetPenRole ) );
    00766 }
    00767
    00768 QPen AbstractDiagram::pen( const QModelIndex& index ) const
    00769 {
    00770     return qVariantValue<QPen>(
    00771         attributesModel()->data(
    00772             attributesModel()->mapFromSource( index ),
    00773             DatasetPenRole ) );
    00774 }
    00775
    00776 void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush )
    00777 {
    00778     attributesModel()->setData(
    00779         attributesModel()->mapFromSource( index ),
    00780         qVariantFromValue( brush ), DatasetBrushRole );
    00781     emit propertiesChanged();
    00782 }
    00783
    00784 void AbstractDiagram::setBrush( const QBrush& brush )
    00785 {
    00786     attributesModel()->setModelData(
    00787         qVariantFromValue( brush ), DatasetBrushRole );
    00788     emit propertiesChanged();
    00789 }
    00790
    00791 void AbstractDiagram::setBrush( int column, const QBrush& brush )
    00792 {
    00793     attributesModel()->setHeaderData(
    00794         column, Qt::Vertical,
    00795         qVariantFromValue( brush ),
    00796         DatasetBrushRole );
    00797     emit propertiesChanged();
    00798 }
    00799
    00800 QBrush AbstractDiagram::brush() const
    00801 {
    00802     return qVariantValue<QBrush>(
    00803         attributesModel()->data( DatasetBrushRole ) );
    00804 }
    00805
    00806 QBrush AbstractDiagram::brush( int dataset ) const
    00807 {
    00808     return qVariantValue<QBrush>(
    00809         attributesModel()->data(
    00810             attributesModel()->mapFromSource( columnToIndex( dataset ) ),
    00811             DatasetBrushRole ) );
    00812 }
    00813
    00814 QBrush AbstractDiagram::brush( const QModelIndex& index ) const
    00815 {
    00816     return qVariantValue<QBrush>(
    00817         attributesModel()->data(
    00818             attributesModel()->mapFromSource( index ),
    00819             DatasetBrushRole ) );
    00820 }
    00821
    00822 // implement QAbstractItemView:
    00823 QRect AbstractDiagram::visualRect(const QModelIndex &) const
    00824 {
    00825     return QRect();
    00826 }
    00827
    00828 void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint )
    00829 {}
    00830
    00831 QModelIndex AbstractDiagram::indexAt(const QPoint &) const
    00832 { return QModelIndex(); }
    00833
    00834 QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers )
    00835 { return QModelIndex(); }
    00836
    00837 int AbstractDiagram::horizontalOffset() const
    00838 { return 0; }
    00839
    00840 int AbstractDiagram::verticalOffset() const
    00841 { return 0; }
    00842
    00843 bool AbstractDiagram::isIndexHidden(const QModelIndex &) const
    00844 { return true; }
    00845
    00846 void AbstractDiagram::setSelection(const QRect &, QItemSelectionModel::SelectionFlags)
    00847 {}
    00848
    00849 QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &) const
    00850 { return QRegion(); }
    00851
    00852
    00853 void KDChart::AbstractDiagram::useDefaultColors( )
    00854 {
    00855     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault );
    00856 }
    00857
    00858 void KDChart::AbstractDiagram::useSubduedColors( )
    00859 {
    00860     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued );
    00861 }
    00862
    00863 void KDChart::AbstractDiagram::useRainbowColors( )
    00864 {
    00865     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow );
    00866 }
    00867
    00868 QStringList AbstractDiagram::itemRowLabels() const
    00869 {
    00870     QStringList ret;
    00871     //qDebug() << "AbstractDiagram::itemRowLabels(): " << attributesModel()->rowCount(attributesModelRootIndex()) << "entries";
    00872     const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
    00873     for( int i = 0; i < rowCount; ++i ){
    00874         //qDebug() << "item row label: " << attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString();
    00875         ret << attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString();
    00876     }
    00877     return ret;
    00878 }
    00879
    00880 QStringList AbstractDiagram::datasetLabels() const
    00881 {
    00882     QStringList ret;
    00883     //qDebug() << "AbstractDiagram::datasetLabels(): " << attributesModel()->columnCount(attributesModelRootIndex()) << "entries";
    00884     const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
    00885     for( int i = datasetDimension()-1; i < columnCount; i += datasetDimension() ){
    00886         //qDebug() << "dataset label: " << attributesModel()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString();
    00887         ret << attributesModel()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString();
    00888     }
    00889     return ret;
    00890 }
    00891
    00892 QList<QBrush> AbstractDiagram::datasetBrushes() const
    00893 {
    00894     QList<QBrush> ret;
    00895     const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
    00896     for( int i = datasetDimension()-1; i < columnCount; i += datasetDimension() ) {
    00897         QBrush brush = qVariantValue<QBrush>( attributesModel()->headerData( i, Qt::Vertical, DatasetBrushRole ) );
    00898         ret << brush;
    00899     }
    00900
    00901     return ret;
    00902 }
    00903
    00904 QList<QPen> AbstractDiagram::datasetPens() const
    00905 {
    00906     QList<QPen> ret;
    00907     const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
    00908     for( int i = datasetDimension()-1; i < columnCount; i += datasetDimension() ) {
    00909         QPen pen = qVariantValue<QPen>( attributesModel()->headerData( i, Qt::Vertical, DatasetPenRole ) );
    00910         ret << pen;
    00911     }
    00912     return ret;
    00913 }
    00914
    00915 QList<MarkerAttributes> AbstractDiagram::datasetMarkers() const
    00916 {
    00917     QList<MarkerAttributes> ret;
    00918     const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
    00919     for( int i = datasetDimension()-1; i < columnCount; i += datasetDimension() ) {
    00920         DataValueAttributes a =
    00921             qVariantValue<DataValueAttributes>( attributesModel()->headerData( i, Qt::Vertical, DataValueLabelAttributesRole ) );
    00922         const MarkerAttributes &ma = a.markerAttributes();
    00923         ret << ma;
    00924     }
    00925     return ret;
    00926 }
    00927
    00928 bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const
    00929 {
    00930     if( ! justReturnTheStatus ){
    00931         Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()",
    00932                     "There is no usable model set, for the diagram." );
    00933
    00934         Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()",
    00935                     "There is no usable coordinate plane set, for the diagram." );
    00936     }
    00937     return model() && coordinatePlane();
    00938 }
    00939
    00940 int AbstractDiagram::datasetDimension( ) const
    00941 {
    00942     return d->datasetDimension;
    00943 }
    00944
    00945 void AbstractDiagram::setDatasetDimension( int dimension )
    00946 {
    00947     if ( d->datasetDimension == dimension ) return;
    00948     d->datasetDimension = dimension;
    00949     d->databoundariesDirty = true;
    00950     emit layoutChanged( this );
    00951 }
    00952
    00953 double AbstractDiagram::valueForCell( int row, int column ) const
    00954 {
    00955     return d->attributesModel->data(
    00956             d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toDouble();
    00957 }
    00958
    00959 void AbstractDiagram::update() const
    00960 {
    00961     //qDebug("KDChart::AbstractDiagram::update() called");
    00962     if( d->plane )
    00963         d->plane->update();
    00964 }
    00965
    00966
    00967 #include "KDChartAbstractDiagram.moc"