KD Chart 2 [rev.2.4]

KDChartAbstractDiagram.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (C) 2001-2012 Klaralvdalens Datakonsult AB.  All rights reserved.
00003 **
00004 ** This file is part of the KD Chart library.
00005 **
00006 ** Licensees holding valid commercial KD Chart licenses may use this file in
00007 ** accordance with the KD Chart Commercial License Agreement provided with
00008 ** the Software.
00009 **
00010 **
00011 ** This file may be distributed and/or modified under the terms of the
00012 ** GNU General Public License version 2 and version 3 as published by the
00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
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 ** Contact info@kdab.com if any conditions of this licensing are not
00019 ** clear to you.
00020 **
00021 **********************************************************************/
00022 
00023 #include "KDChartAbstractDiagram.h"
00024 #include "KDChartAbstractDiagram_p.h"
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 "KDChartAbstractThreeDAttributes.h"
00041 #include "KDChartThreeDLineAttributes.h"
00042 
00043 #include <KDABLibFakes>
00044 
00045 #define PI 3.141592653589793
00046 
00047 using namespace KDChart;
00048 
00049 AbstractDiagram::Private::Private()
00050   : plane( 0 )
00051   , attributesModel( new PrivateAttributesModel(0,0) )
00052   , allowOverlappingDataValueTexts( false )
00053   , antiAliasing( true )
00054   , percent( false )
00055   , datasetDimension( 1 )
00056   , databoundariesDirty(true)
00057   , lastRoundedValue()
00058   , lastX( 0 )
00059   , mCachedFontMetrics( QFontMetrics( qApp->font() ) )
00060 {
00061 }
00062 
00063 AbstractDiagram::Private::~Private()
00064 {
00065   if( attributesModel && qobject_cast<PrivateAttributesModel*>(attributesModel) )
00066     delete attributesModel;
00067 }
00068 
00069 void AbstractDiagram::Private::init()
00070 {
00071 }
00072 
00073 void AbstractDiagram::Private::init( AbstractCoordinatePlane* newPlane )
00074 {
00075     plane = newPlane;
00076 }
00077 
00078 bool AbstractDiagram::Private::usesExternalAttributesModel()const
00079 {
00080     return ( ! attributesModel.isNull() ) &&
00081            ( ! qobject_cast<PrivateAttributesModel*>(attributesModel) );
00082 }
00083 
00084 void AbstractDiagram::Private::setAttributesModel( AttributesModel* amodel )
00085 {
00086     if( !attributesModel.isNull() &&
00087         qobject_cast<PrivateAttributesModel*>(attributesModel) ) {
00088         delete attributesModel;
00089     }
00090     attributesModel = amodel;
00091 }
00092 
00093 AbstractDiagram::Private::Private( const AbstractDiagram::Private& rhs ) :
00094     // Do not copy the plane
00095     plane( 0 ),
00096     attributesModelRootIndex( QModelIndex() ),
00097     attributesModel( rhs.attributesModel ),
00098     allowOverlappingDataValueTexts( rhs.allowOverlappingDataValueTexts ),
00099     antiAliasing( rhs.antiAliasing ),
00100     percent( rhs.percent ),
00101     datasetDimension( rhs.datasetDimension ),
00102     mCachedFontMetrics( rhs.cachedFontMetrics() )
00103 {
00104     attributesModel = new PrivateAttributesModel( 0, 0);
00105     attributesModel->initFrom( rhs.attributesModel );
00106 }
00107 
00108 #define d d_func()
00109 
00110 AbstractDiagram::AbstractDiagram ( QWidget* parent, AbstractCoordinatePlane* plane )
00111     : QAbstractItemView ( parent ), _d( new Private() )
00112 {
00113     _d->init( plane );
00114     init();
00115 }
00116 
00117 AbstractDiagram::~AbstractDiagram()
00118 {
00119     emit aboutToBeDestroyed();
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     update();
00238 }
00239 
00240 void AbstractDiagram::setModel( QAbstractItemModel * newModel )
00241 {
00242     if( model() )
00243     {
00244         disconnect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00245         disconnect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00246         disconnect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00247         disconnect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00248         disconnect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
00249         disconnect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
00250         disconnect( model(), SIGNAL( dataChanged(QModelIndex,QModelIndex) ), this, SIGNAL( modelDataChanged() ));
00251     }
00252     QAbstractItemView::setModel( newModel );
00253     AttributesModel* amodel = new PrivateAttributesModel( newModel, this );
00254     amodel->initFrom( d->attributesModel );
00255     d->setAttributesModel(amodel);
00256     scheduleDelayedItemsLayout();
00257     setDataBoundariesDirty();
00258     if( model() )
00259     {
00260         connect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00261         connect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00262         connect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00263         connect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
00264         connect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
00265         connect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
00266         connect( model(), SIGNAL( dataChanged(QModelIndex,QModelIndex) ), this, SIGNAL( modelDataChanged() ));
00267     }
00268     emit modelsChanged();
00269 }
00270         
00271 void AbstractDiagram::setSelectionModel( QItemSelectionModel* newSelectionModel )
00272 {
00273     if( selectionModel() )
00274     {
00275         disconnect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
00276         disconnect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
00277     }
00278     QAbstractItemView::setSelectionModel( newSelectionModel );
00279     if( selectionModel() )
00280     {
00281         connect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
00282         connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
00283     }
00284     emit modelsChanged();
00285 }
00286 
00292 void AbstractDiagram::setAttributesModel( AttributesModel* amodel )
00293 {
00294     if( amodel->sourceModel() != model() ) {
00295         qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
00296                  "Trying to set an attributesmodel which works on a different "
00297                  "model than the diagram.");
00298         return;
00299     }
00300     if( qobject_cast<PrivateAttributesModel*>(amodel) ) {
00301         qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
00302                  "Trying to set an attributesmodel that is private to another diagram.");
00303         return;
00304     }
00305     d->setAttributesModel(amodel);
00306     scheduleDelayedItemsLayout();
00307     setDataBoundariesDirty();
00308     emit modelsChanged();
00309 }
00310 
00311 bool AbstractDiagram::usesExternalAttributesModel()const
00312 {
00313     return d->usesExternalAttributesModel();
00314 }
00315 
00317 AttributesModel* AbstractDiagram::attributesModel() const
00318 {
00319     return d->attributesModel;
00320 }
00321 
00322 QModelIndex AbstractDiagram::conditionallyMapFromSource( const QModelIndex & index ) const
00323 {
00324     Q_ASSERT( !index.isValid() || index.model() == attributesModel() || index.model() == attributesModel()->sourceModel() );
00325     return index.model() == attributesModel()
00326             ? index
00327             : attributesModel()->mapFromSource( index );
00328 }
00329 
00331 void AbstractDiagram::setRootIndex ( const QModelIndex& idx )
00332 {
00333     QAbstractItemView::setRootIndex(idx);
00334     setAttributesModelRootIndex( d->attributesModel->mapFromSource(idx) );
00335 }
00336 
00338 void AbstractDiagram::setAttributesModelRootIndex( const QModelIndex& idx )
00339 {
00340     d->attributesModelRootIndex=idx;
00341     setDataBoundariesDirty();
00342     scheduleDelayedItemsLayout();
00343 }
00344 
00347 QModelIndex AbstractDiagram::attributesModelRootIndex() const
00348 {
00349     if ( !d->attributesModelRootIndex.isValid() )
00350         d->attributesModelRootIndex = d->attributesModel->mapFromSource( rootIndex() );
00351     return d->attributesModelRootIndex;
00352 }
00353 
00354 void AbstractDiagram::setCoordinatePlane( AbstractCoordinatePlane* parent )
00355 {
00356     d->plane = parent;
00357 }
00358 
00359 void AbstractDiagram::doItemsLayout()
00360 {
00361     if ( d->plane ) {
00362         d->plane->layoutDiagrams();
00363         update();
00364     }
00365     QAbstractItemView::doItemsLayout();
00366 }
00367 
00368 void AbstractDiagram::dataChanged( const QModelIndex &topLeft,
00369                                    const QModelIndex &bottomRight )
00370 {
00371     Q_UNUSED( topLeft );
00372     Q_UNUSED( bottomRight );
00373     // We are still too dumb to do intelligent updates...
00374     setDataBoundariesDirty();
00375     scheduleDelayedItemsLayout();
00376 }
00377 
00378 
00379 void AbstractDiagram::setHidden( const QModelIndex & index, bool hidden )
00380 {
00381     d->attributesModel->setData(
00382         conditionallyMapFromSource( index ),
00383         qVariantFromValue( hidden ),
00384         DataHiddenRole );
00385     emit dataHidden();
00386 }
00387 
00388 void AbstractDiagram::setHidden( int dataset, bool hidden )
00389 {
00390     // To store the flag for a dataset, we use the first column
00391     // that's associated with it. (i.e., with a dataset dimension
00392     // of two, the column of the keys)
00393     d->setDatasetAttrs( dataset, qVariantFromValue( hidden ), DataHiddenRole );
00394     emit dataHidden();
00395 }
00396 
00397 void AbstractDiagram::setHidden( bool hidden )
00398 {
00399     d->attributesModel->setModelData(
00400         qVariantFromValue( hidden ),
00401         DataHiddenRole );
00402     emit dataHidden();
00403 }
00404 
00405 bool AbstractDiagram::isHidden() const
00406 {
00407     return qVariantValue<bool>(
00408         attributesModel()->modelData( DataHiddenRole ) );
00409 }
00410 
00411 bool AbstractDiagram::isHidden( int dataset ) const
00412 {
00413     const QVariant boolFlag( d->datasetAttrs( dataset, DataHiddenRole ) );
00414     if( boolFlag.isValid() )
00415         return qVariantValue< bool >( boolFlag );
00416     return isHidden();
00417 }
00418 
00419 bool AbstractDiagram::isHidden( const QModelIndex & index ) const
00420 {
00421     return qVariantValue<bool>(
00422         attributesModel()->data(
00423             conditionallyMapFromSource(index),
00424             DataHiddenRole ) );
00425 }
00426 
00427 
00428 void AbstractDiagram::setDataValueAttributes( const QModelIndex & index,
00429                                               const DataValueAttributes & a )
00430 {
00431     d->attributesModel->setData(
00432         conditionallyMapFromSource( index ),
00433         qVariantFromValue( a ),
00434         DataValueLabelAttributesRole );
00435     emit propertiesChanged();
00436 }
00437 
00438 
00439 void AbstractDiagram::setDataValueAttributes( int dataset, const DataValueAttributes & a )
00440 {
00441     d->setDatasetAttrs( dataset, qVariantFromValue( a ), DataValueLabelAttributesRole );
00442     emit propertiesChanged();
00443 }
00444 
00445 DataValueAttributes AbstractDiagram::dataValueAttributes() const
00446 {
00447     return qVariantValue<DataValueAttributes>(
00448         attributesModel()->modelData( KDChart::DataValueLabelAttributesRole ) );
00449 }
00450 
00451 DataValueAttributes AbstractDiagram::dataValueAttributes( int dataset ) const
00452 {
00453     /*
00454     The following did not work!
00455     (khz, 2008-01-25)
00456     If there was some attrs specified for the 0-th cells of a dataset,
00457     then this logic would return the cell's settings instead of the header settings:
00458 
00459     return qVariantValue<DataValueAttributes>(
00460         attributesModel()->data( attributesModel()->mapFromSource(columnToIndex( column )),
00461         KDChart::DataValueLabelAttributesRole ) );
00462     */
00463 
00464     const QVariant headerAttrs(
00465         d->datasetAttrs( dataset, KDChart::DataValueLabelAttributesRole ) );
00466     if( headerAttrs.isValid() )
00467         return qVariantValue< DataValueAttributes >( headerAttrs );
00468     return dataValueAttributes();
00469 }
00470 
00471 DataValueAttributes AbstractDiagram::dataValueAttributes( const QModelIndex & index ) const
00472 {
00473     return qVariantValue<DataValueAttributes>(
00474         attributesModel()->data(
00475             conditionallyMapFromSource( index ),
00476             KDChart::DataValueLabelAttributesRole ) );
00477 }
00478 
00479 void AbstractDiagram::setDataValueAttributes( const DataValueAttributes & a )
00480 {
00481     d->attributesModel->setModelData( qVariantFromValue( a ), DataValueLabelAttributesRole );
00482     emit propertiesChanged();
00483 }
00484 
00485 void AbstractDiagram::setAllowOverlappingDataValueTexts( bool allow )
00486 {
00487     d->allowOverlappingDataValueTexts = allow;
00488     emit propertiesChanged();
00489 }
00490 
00491 bool AbstractDiagram::allowOverlappingDataValueTexts() const
00492 {
00493     return d->allowOverlappingDataValueTexts;
00494 }
00495 
00496 void AbstractDiagram::setAntiAliasing( bool enabled )
00497 {
00498     d->antiAliasing = enabled;
00499     emit propertiesChanged();
00500 }
00501 
00502 bool AbstractDiagram::antiAliasing() const
00503 {
00504     return d->antiAliasing;
00505 }
00506 
00507 void AbstractDiagram::setPercentMode ( bool percent )
00508 {
00509     d->percent = percent;
00510     emit propertiesChanged();
00511 }
00512 
00513 bool AbstractDiagram::percentMode() const
00514 {
00515     return d->percent;
00516 }
00517 
00518 
00519 void AbstractDiagram::paintDataValueText( QPainter* painter,
00520                                           const QModelIndex& index,
00521                                           const QPointF& pos,
00522                                           double value )
00523 {
00524     d->paintDataValueText( this, painter, index, pos, value );
00525 }
00526 
00527 
00528 QString AbstractDiagram::roundValues( double value,
00529                                       const int decimalPos,
00530                                       const int decimalDigits ) const
00531 {
00532     return d->roundValues( value, decimalPos, decimalDigits );
00533 }
00534 
00535 void AbstractDiagram::paintDataValueTexts( QPainter* painter )
00536 {
00537     if ( !checkInvariants() ) return;
00538     const int rowCount = model()->rowCount(rootIndex());
00539     const int columnCount = model()->columnCount(rootIndex());
00540     d->clearListOfAlreadyDrawnDataValueTexts();
00541     for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
00542        for ( int j=0; j< rowCount; ++j ) {
00543            const QModelIndex index = model()->index( j, i, rootIndex() );
00544            double value = model()->data( index ).toDouble();
00545            const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
00546            paintDataValueText( painter, index, pos, value );
00547        }
00548     }
00549 }
00550 
00551 
00552 void AbstractDiagram::paintMarker( QPainter* painter,
00553                                    const DataValueAttributes& a,
00554                                    const QModelIndex& index,
00555                                    const QPointF& pos )
00556 {
00557     if ( !checkInvariants() || !a.isVisible() ) return;
00558     const MarkerAttributes ma = a.markerAttributes();
00559     if ( !ma.isVisible() ) return;
00560 
00561     const PainterSaver painterSaver( painter );
00562     // the size of the marker - unscaled
00563     const QSizeF maSize( ma.markerSize().width() / painter->matrix().m11(), 
00564                          ma.markerSize().height() / painter->matrix().m22() );
00565     QBrush indexBrush( brush( index ) );
00566     QPen indexPen( ma.pen() );
00567     if ( ma.markerColor().isValid() )
00568         indexBrush.setColor( ma.markerColor() );
00569 
00570     paintMarker( painter, ma, indexBrush, indexPen, pos, maSize );
00571 
00572     // workaround: BC cannot be changed, otherwise we would pass the
00573     // index down to next-lower paintMarker function. So far, we
00574     // basically save a circle of radius maSize at pos in the
00575     // reverseMapper. This means that ^^^ this version of paintMarker
00576     // needs to be called to reverse-map the marker.
00577     d->reverseMapper.addCircle( index.row(), index.column(), pos, 2 * maSize );
00578 }
00579 
00580 void AbstractDiagram::paintMarker( QPainter* painter,
00581                                    const QModelIndex& index,
00582                                    const QPointF& pos )
00583 {
00584     if ( !checkInvariants() ) return;
00585     paintMarker( painter, dataValueAttributes( index ), index, pos );
00586 }
00587 
00588 void AbstractDiagram::paintMarker( QPainter* painter,
00589                                    const MarkerAttributes& markerAttributes,
00590                                    const QBrush& brush,
00591                                    const QPen& pen,
00592                                    const QPointF& pos,
00593                                    const QSizeF& maSize )
00594 {
00595     const QPen oldPen( painter->pen() );
00596     // Pen is used to paint 4Pixels - 1 Pixel - Ring and FastCross types.
00597     // make sure to use the brush color - see above in those cases.
00598     const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels);
00599     if( isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel) ){
00600         // for high-performance point charts with tiny point markers:
00601         painter->setPen( PrintingParameters::scalePen( QPen( brush.color().light() ) ) );
00602         if( isFourPixels ){
00603             const qreal x = pos.x();
00604             const qreal y = pos.y();
00605             painter->drawLine( QPointF(x-1.0,y-1.0),
00606                                QPointF(x+1.0,y-1.0) );
00607             painter->drawLine( QPointF(x-1.0,y),
00608                                QPointF(x+1.0,y) );
00609             painter->drawLine( QPointF(x-1.0,y+1.0),
00610                                QPointF(x+1.0,y+1.0) );
00611         }
00612         painter->drawPoint( pos );
00613     }else{
00614         const PainterSaver painterSaver( painter );
00615         QPen painterPen( pen );
00616         painter->setPen( PrintingParameters::scalePen( painterPen ) );
00617         painter->setBrush( brush );
00618         painter->setRenderHint ( QPainter::Antialiasing );
00619         painter->translate( pos );
00620         switch ( markerAttributes.markerStyle() ) {
00621             case MarkerAttributes::MarkerCircle:
00622                 painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00623                             maSize.height(), maSize.width()) );
00624                 break;
00625             case MarkerAttributes::MarkerSquare:
00626                 {
00627                     QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2,
00628                                 maSize.width(), maSize.height() );
00629                     painter->drawRect( rect );
00630                     break;
00631                 }
00632             case MarkerAttributes::MarkerDiamond:
00633                 {
00634                     QVector <QPointF > diamondPoints;
00635                     QPointF top, left, bottom, right;
00636                     top    = QPointF( 0, 0 - maSize.height()/2 );
00637                     left   = QPointF( 0 - maSize.width()/2, 0 );
00638                     bottom = QPointF( 0, maSize.height()/2 );
00639                     right  = QPointF( maSize.width()/2, 0 );
00640                     diamondPoints << top << left << bottom << right;
00641                     painter->drawPolygon( diamondPoints );
00642                     break;
00643                 }
00644             // both handled on top of the method:
00645             case MarkerAttributes::Marker1Pixel:
00646             case MarkerAttributes::Marker4Pixels:
00647                     break;
00648             case MarkerAttributes::MarkerRing:
00649                 {
00650                     painter->setBrush( Qt::NoBrush );
00651                     painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
00652                                         maSize.height(), maSize.width()) );
00653                     break;
00654                 }
00655             case MarkerAttributes::MarkerCross:
00656                 {
00657                     // Note: Markers can have outline,
00658                     //       so just drawing two rects is NOT the solution here!
00659                     const qreal w02 = maSize.width() * 0.2;
00660                     const qreal w05 = maSize.width() * 0.5;
00661                     const qreal h02 = maSize.height()* 0.2;
00662                     const qreal h05 = maSize.height()* 0.5;
00663                     QVector <QPointF > crossPoints;
00664                     QPointF p[12];
00665                     p[ 0] = QPointF( -w02, -h05 );
00666                     p[ 1] = QPointF(  w02, -h05 );
00667                     p[ 2] = QPointF(  w02, -h02 );
00668                     p[ 3] = QPointF(  w05, -h02 );
00669                     p[ 4] = QPointF(  w05,  h02 );
00670                     p[ 5] = QPointF(  w02,  h02 );
00671                     p[ 6] = QPointF(  w02,  h05 );
00672                     p[ 7] = QPointF( -w02,  h05 );
00673                     p[ 8] = QPointF( -w02,  h02 );
00674                     p[ 9] = QPointF( -w05,  h02 );
00675                     p[10] = QPointF( -w05, -h02 );
00676                     p[11] = QPointF( -w02, -h02 );
00677                     for( int i=0; i<12; ++i )
00678                         crossPoints << p[i];
00679                     crossPoints << p[0];
00680                     painter->drawPolygon( crossPoints );
00681                     break;
00682                 }
00683             case MarkerAttributes::MarkerFastCross:
00684                 {
00685                     QPointF left, right, top, bottom;
00686                     left  = QPointF( -maSize.width()/2, 0 );
00687                     right = QPointF( maSize.width()/2, 0 );
00688                     top   = QPointF( 0, -maSize.height()/2 );
00689                     bottom= QPointF( 0, maSize.height()/2 );
00690                     painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
00691                     painter->drawLine( left, right );
00692                     painter->drawLine(  top, bottom );
00693                     break;
00694                 }
00695             case MarkerAttributes::NoMarker:
00696                 break;
00697             default:
00698                 Q_ASSERT_X ( false, "paintMarkers()",
00699                             "Type item does not match a defined Marker Type." );
00700         }
00701     }
00702     painter->setPen( oldPen );
00703 }
00704 
00705 void AbstractDiagram::paintMarkers( QPainter* painter )
00706 {
00707     if ( !checkInvariants() ) return;
00708     const int rowCount = model()->rowCount(rootIndex());
00709     const int columnCount = model()->columnCount(rootIndex());
00710     for ( int i=datasetDimension()-1; i<columnCount; i += datasetDimension() ) {
00711        for ( int j=0; j< rowCount; ++j ) {
00712            const QModelIndex index = model()->index( j, i, rootIndex() );
00713            double value = model()->data( index ).toDouble();
00714            const QPointF pos = coordinatePlane()->translate( QPointF( j, value ) );
00715            paintMarker( painter, index, pos );
00716        }
00717     }
00718 }
00719 
00720 
00721 void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen )
00722 {
00723     attributesModel()->setData(
00724         conditionallyMapFromSource( index ),
00725         qVariantFromValue( pen ), DatasetPenRole );
00726     emit propertiesChanged();
00727 }
00728 
00729 void AbstractDiagram::setPen( const QPen& pen )
00730 {
00731     attributesModel()->setModelData(
00732         qVariantFromValue( pen ), DatasetPenRole );
00733     emit propertiesChanged();
00734 }
00735 
00736 void AbstractDiagram::setPen( int dataset, const QPen& pen )
00737 {
00738     d->setDatasetAttrs( dataset, qVariantFromValue( pen ), DatasetPenRole );
00739     emit propertiesChanged();
00740 }
00741 
00742 QPen AbstractDiagram::pen() const
00743 {
00744     return qVariantValue<QPen>(
00745         attributesModel()->data( DatasetPenRole ) );
00746 }
00747 
00748 QPen AbstractDiagram::pen( int dataset ) const
00749 {
00750     const QVariant penSettings( d->datasetAttrs( dataset, DatasetPenRole ) );
00751     if( penSettings.isValid() )
00752         return qVariantValue< QPen >( penSettings );
00753     return pen();
00754 }
00755 
00756 QPen AbstractDiagram::pen( const QModelIndex& index ) const
00757 {
00758     return qVariantValue<QPen>(
00759         attributesModel()->data(
00760             conditionallyMapFromSource( index ),
00761             DatasetPenRole ) );
00762 }
00763 
00764 void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush )
00765 {
00766     attributesModel()->setData(
00767         conditionallyMapFromSource( index ),
00768         qVariantFromValue( brush ), DatasetBrushRole );
00769     emit propertiesChanged();
00770 }
00771 
00772 void AbstractDiagram::setBrush( const QBrush& brush )
00773 {
00774     attributesModel()->setModelData(
00775         qVariantFromValue( brush ), DatasetBrushRole );
00776     emit propertiesChanged();
00777 }
00778 
00779 void AbstractDiagram::setBrush( int dataset, const QBrush& brush )
00780 {
00781     d->setDatasetAttrs( dataset, qVariantFromValue( brush ), DatasetBrushRole );
00782     emit propertiesChanged();
00783 }
00784 
00785 QBrush AbstractDiagram::brush() const
00786 {
00787     return qVariantValue<QBrush>(
00788         attributesModel()->data( DatasetBrushRole ) );
00789 }
00790 
00791 QBrush AbstractDiagram::brush( int dataset ) const
00792 {
00793     const QVariant brushSettings( d->datasetAttrs( dataset, DatasetBrushRole ) );
00794     if( brushSettings.isValid() )
00795         return qVariantValue< QBrush >( brushSettings );
00796     return brush();
00797 }
00798 
00799 QBrush AbstractDiagram::brush( const QModelIndex& index ) const
00800 {
00801     return qVariantValue<QBrush>(
00802         attributesModel()->data( conditionallyMapFromSource( index ), DatasetBrushRole ) );
00803 }
00804 
00811 void AbstractDiagram::setUnitPrefix( const QString& prefix, int column, Qt::Orientation orientation )
00812 {
00813     d->unitPrefixMap[ column ][ orientation ]= prefix;
00814 }
00815 
00821 void AbstractDiagram::setUnitPrefix( const QString& prefix, Qt::Orientation orientation )
00822 {
00823     d->unitPrefix[ orientation ] = prefix;
00824 }
00825 
00832 void AbstractDiagram::setUnitSuffix( const QString& suffix, int column, Qt::Orientation orientation )
00833 {
00834     d->unitSuffixMap[ column ][ orientation ]= suffix;
00835 }
00836 
00842 void AbstractDiagram::setUnitSuffix( const QString& suffix, Qt::Orientation orientation )
00843 {
00844     d->unitSuffix[ orientation ] = suffix;
00845 }
00846 
00854 QString AbstractDiagram::unitPrefix( int column, Qt::Orientation orientation, bool fallback ) const
00855 {
00856     if( !fallback || d->unitPrefixMap[ column ].contains( orientation ) )
00857         return d->unitPrefixMap[ column ][ orientation ];
00858     return d->unitPrefix[ orientation ];
00859 }
00860 
00865 QString AbstractDiagram::unitPrefix( Qt::Orientation orientation ) const
00866 {
00867     return d->unitPrefix[ orientation ];
00868 }
00869 
00877 QString AbstractDiagram::unitSuffix( int column, Qt::Orientation orientation, bool fallback ) const
00878 {
00879     if( !fallback || d->unitSuffixMap[ column ].contains( orientation ) )
00880         return d->unitSuffixMap[ column ][ orientation ];
00881     return d->unitSuffix[ orientation ];
00882 }
00883 
00888 QString AbstractDiagram::unitSuffix( Qt::Orientation orientation ) const
00889 {
00890     return d->unitSuffix[ orientation ];
00891 }
00892 
00893 // implement QAbstractItemView:
00894 QRect AbstractDiagram::visualRect( const QModelIndex &index ) const
00895 {
00896     return d->reverseMapper.boundingRect( index.row(), index.column() ).toRect();
00897 }
00898 
00899 void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint )
00900 {}
00901 
00902 // indexAt ... down below
00903 
00904 QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers )
00905 { return QModelIndex(); }
00906 
00907 int AbstractDiagram::horizontalOffset() const
00908 { return 0; }
00909 
00910 int AbstractDiagram::verticalOffset() const
00911 { return 0; }
00912 
00913 bool AbstractDiagram::isIndexHidden(const QModelIndex &) const
00914 { return true; }
00915 
00916 void AbstractDiagram::setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags command )
00917 {
00918     const QModelIndexList indexes = d->indexesIn( rect );
00919     QItemSelection selection;
00920     KDAB_FOREACH( const QModelIndex& index, indexes )
00921     {
00922         selection.append( QItemSelectionRange( index ) );
00923     }
00924     selectionModel()->select( selection, command );
00925 }
00926 
00927 QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &selection) const
00928 {
00929     QPolygonF polygon;
00930     KDAB_FOREACH( const QModelIndex& index, selection.indexes() )
00931     {
00932         polygon << d->reverseMapper.polygon(index.row(), index.column());
00933     }
00934     return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
00935 }
00936 
00937 QRegion AbstractDiagram::visualRegion(const QModelIndex &index) const
00938 {
00939     QPolygonF polygon = d->reverseMapper.polygon(index.row(), index.column());
00940     return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
00941 }
00942 
00943 void KDChart::AbstractDiagram::useDefaultColors( )
00944 {
00945     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault );
00946 }
00947 
00948 void KDChart::AbstractDiagram::useSubduedColors( )
00949 {
00950     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued );
00951 }
00952 
00953 void KDChart::AbstractDiagram::useRainbowColors( )
00954 {
00955     d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow );
00956 }
00957 
00958 QStringList AbstractDiagram::itemRowLabels() const
00959 {
00960     QStringList ret;
00961     if( model() ){
00962         //qDebug() << "AbstractDiagram::itemRowLabels(): " << attributesModel()->rowCount(attributesModelRootIndex()) << "entries";
00963         const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
00964         for( int i = 0; i < rowCount; ++i ){
00965             //qDebug() << "item row label: " << attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString();
00966             ret << unitPrefix( i, Qt::Horizontal, true ) +
00967                    attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString() +
00968                    unitSuffix( i, Qt::Horizontal, true );
00969         }
00970     }
00971     return ret;
00972 }
00973 
00974 QStringList AbstractDiagram::datasetLabels() const
00975 {
00976     QStringList ret;
00977     if( model() == 0 )
00978         return ret;
00979     
00980     const int columnCount = attributesModel()->columnCount(attributesModelRootIndex());
00981     for( int i = 0; i < columnCount; i += datasetDimension() )
00982         ret << attributesModel()->headerData( i, Qt::Horizontal, Qt::DisplayRole ).toString();
00983     
00984     return ret;
00985 }
00986 
00987 QList<QBrush> AbstractDiagram::datasetBrushes() const
00988 {
00989     QList<QBrush> ret;
00990     if( model() == 0 )
00991         return ret;
00992 
00993     const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
00994     for ( int dataset = 0; dataset < datasetCount; dataset++ )
00995         ret << brush( dataset );
00996 
00997     return ret;
00998 }
00999 
01000 QList<QPen> AbstractDiagram::datasetPens() const
01001 {
01002     QList<QPen> ret;
01003     if( model() == 0 )
01004         return ret;
01005     
01006     const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
01007     for ( int dataset = 0; dataset < datasetCount; dataset++ )
01008         ret << pen( dataset );
01009     
01010     return ret;
01011 }
01012 
01013 QList<MarkerAttributes> AbstractDiagram::datasetMarkers() const
01014 {
01015     QList<MarkerAttributes> ret;
01016     if( model() == 0 )
01017         return ret;
01018     
01019     const int datasetCount = attributesModel()->columnCount(attributesModelRootIndex()) / datasetDimension();
01020     for ( int dataset = 0; dataset < datasetCount; dataset++ )
01021         ret << dataValueAttributes( dataset ).markerAttributes();
01022 
01023     return ret;
01024 }
01025 
01026 bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const
01027 {
01028     if( ! justReturnTheStatus ){
01029         Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()",
01030                     "There is no usable model set, for the diagram." );
01031 
01032         Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()",
01033                     "There is no usable coordinate plane set, for the diagram." );
01034     }
01035     return model() && coordinatePlane();
01036 }
01037 
01038 int AbstractDiagram::datasetDimension( ) const
01039 {
01040     return d->datasetDimension;
01041 }
01042 
01043 void AbstractDiagram::setDatasetDimension( int dimension )
01044 {
01045     Q_UNUSED( dimension );
01046     qDebug() << "Setting the dataset dimension using AbstractDiagram::setDatasetDimension is obsolete. Use the specific diagram types instead.";
01047 }
01048 
01049 void AbstractDiagram::setDatasetDimensionInternal( int dimension )
01050 {
01051     Q_ASSERT( dimension != 0 );
01052     
01053     if ( d->datasetDimension == dimension ) return;
01054     d->datasetDimension = dimension;
01055     setDataBoundariesDirty();
01056     emit layoutChanged( this );
01057 }
01058 
01059 double AbstractDiagram::valueForCell( int row, int column ) const
01060 {
01061     return d->attributesModel->data(
01062             d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toDouble();
01063 }
01064 
01065 void AbstractDiagram::update() const
01066 {
01067     //qDebug("KDChart::AbstractDiagram::update() called");
01068     if( d->plane )
01069         d->plane->update();
01070 }
01071 
01072 QModelIndex AbstractDiagram::indexAt( const QPoint& point ) const
01073 {
01074     return d->indexAt( point );
01075 }
01076 
01077 QModelIndexList AbstractDiagram::indexesAt( const QPoint& point ) const
01078 {
01079     return d->indexesAt( point );
01080 }
01081 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/