KDChartAbstractDiagram.cpp

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

Generated on Mon Sep 17 16:16:49 2007 for KD Chart 2 by  doxygen 1.5.1